デジタル・デザイン・ラボラトリーな日々

アラフィフプログラマーが数学と物理と英語を基礎からやり直す。https://qiita.com/yaju

TensorFlowコトハジメ 手書き文字認識(MNIST)による多クラス識別問題

はじめに

手書き文字認識(MNIST)による多クラス識別問題をやってみる。

前回に引き続きこの資料を基に理解していく。

MNISTとは

手書きの文字列を認識するもので、画像認識では定番と言えるテーマだ。 手書き文字の認識データは、機械学習の著名な研究者であるYann LeCun氏のwebsiteで公開しており、0-9のいずれかの数字が学習用、テスト用それぞれで60000枚と10000枚含まれている。
各数字画像の大きさは28×28ピクセルの単色画像で、RGBではなくGray-scaleの色空間となっている。
f:id:Yaju3D:20160422062644p:plain

多クラス識別問題

前回の八百屋の識別問題が、買えるか買えないかの2クラスの分類であったが、今回は手書き文字を0-9と多クラスの分類となる。

手書き文字認識

f:id:Yaju3D:20160422063603p:plain

機械学習の流れ

f:id:Yaju3D:20160422063746p:plain

one-hot ベクトル (one-of-K表現)

f:id:Yaju3D:20160422073005p:plain

案1: ロジスティック回帰を拡張

f:id:Yaju3D:20160422064743p:plain
f:id:Yaju3D:20160422064833p:plain
ソフトマックス関数と呼ばれており、シグモイド関数を多クラス問題に対応させた活性化関数である。
ソフトマックス関数を使うと出力層の各ユニットの和が1になります。つまり、出力値が各クラスである確率と見なせるようになります。

案2: さらに中間層を追加

f:id:Yaju3D:20160422064903p:plain

1. 予測式(モデル)を記述

TensorFlowによる実装

# 入力変数と出力変数のプレースホルダを生成
x = tf.placeholder(tf.float32, [None, 784])
y_ = tf.placeholder(tf.float32, [None, 10])
# モデルパラメータ(入力層:784ノード, 隠れ層:100ノード, 出力層:10ノード)
W1 = tf.Variable(tf.truncated_normal([784, 100]))
b1 = tf.Variable(tf.zeros([100]))
W2 = tf.Variable(tf.truncated_normal([100, 10]))
b2 = tf.Variable(tf.zeros([10]))
# モデル式
h = tf.sigmoid(tf.matmul(x, W1) + b1) # 入力層->隠れ層
u = tf.matmul(h, W2) + b2             # 隠れ層->出力層 (ロジット)
y = tf.nn.softmax(u)                  # 隠れ層->出力層 (ソフトマックス後)

f:id:Yaju3D:20160422071235p:plain

2. 誤差関数と最適化手法を記述

# 誤差関数(loss)
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(u, y_))
# 最適化手段(最急降下法)
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(loss)
# 正答率(学習には用いない)
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
acc = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
  • 誤差関数を変更
    多クラス識別(分類)問題
    →多クラス用クロスエントロピー(softmax_cross_entropy_with_logits)

3. 学習実行

# (2) バッチ型確率的勾配降下法でパラメータ更新
for i in range(10000):
    # 訓練データから100サンプルをランダムに取得
    batch_xs, batch_ys = mnist.train.next_batch(100)
    # 学習
    _, l = sess.run([train_step, loss], feed_dict={x: batch_xs, y_: batch_ys})
    if (i + 1) % 1000 == 0:
        print "step=%3d, loss=%.2f" % (i + 1, l)
  • 大規模なデータで学習する時の工夫
    各ステップで、100個の訓練データをランダムに取り出して学習 (確率的勾配降下法)
    →速く学習が進む

参考: 学習結果

f:id:Yaju3D:20160422071950p:plain

4. 予測

# (1) テスト用データを1000サンプル取得
new_x = mnist.test.images[0:1000]
new_y_ = mnist.test.labels[0:1000]

# (2) 予測と性能評価
accuracy, new_y = sess.run([acc, y], feed_dict={x:new_x , y_:new_y_ })
print "Accuracy (for test data): %6.2f%%" % accuracy
print "True Label:", np.argmax(new_y_[0:15,], 1)
print "Est Label:", np.argmax(new_y[0:15, ], 1)

ここはこれまでと同様

【実行結果例】

Accuracy(test data): 80.0% 
True Label: [7 2 1 0 4 1 4 9 5 9 0 6 9 0 1]
Est Label: [7 2 1 0 9 1 4 9 2 9 0 6 9 0 1]

最終ソースコード

# coding: utf-8
import numpy as np
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

# MNISTデータの取得
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

# 1. 学習したいモデルを記述する
# 入力変数と出力変数のプレースホルダを生成
x = tf.placeholder(tf.float32, [None, 784])
y_ = tf.placeholder(tf.float32, [None, 10])
# モデルパラメータ(入力層:784ノード, 隠れ層:100ノード, 出力層:10ノード)
W1 = tf.Variable(tf.truncated_normal([784, 100]))
b1 = tf.Variable(tf.zeros([100]))
W2 = tf.Variable(tf.truncated_normal([100, 10]))
b2 = tf.Variable(tf.zeros([10]))
# モデル式
h = tf.sigmoid(tf.matmul(x, W1) + b1) # 入力層->隠れ層
u = tf.matmul(h, W2) + b2             # 隠れ層->出力層 (ロジット)
y = tf.nn.softmax(u)                  # 隠れ層->出力層 (ソフトマックス後)

# 2. 学習やテストに必要な関数を定義する
# 誤差関数(loss)
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(u, y_))
# 最適化手段(最急降下法)
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(loss)
# 正答率(学習には用いない)
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
acc = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

# 3. 実際に学習処理を実行する
# (1) セッションを準備し,変数を初期化
sess = tf.Session()
init = tf.initialize_all_variables()
sess.run(init)

# (2) バッチ型確率的勾配降下法でパラメータ更新
for i in range(10000):
    # 訓練データから100サンプルをランダムに取得
    batch_xs, batch_ys = mnist.train.next_batch(100)
    # 学習
    _, l = sess.run([train_step, loss], feed_dict={x: batch_xs, y_: batch_ys})
    if (i + 1) % 1000 == 0:
        print("step=%3d, loss=%.2f" % (i + 1, l))

# 4. テスト用データに対して予測し,性能を確認
# (1) テスト用データを1000サンプル取得
new_x = mnist.test.images[0:1000]
new_y_ = mnist.test.labels[0:1000]

# (2) 予測と性能評価
accuracy, new_y = sess.run([acc, y], feed_dict={x:new_x , y_:new_y_ })
print("Accuracy (for test data): %6.2f%%" % accuracy)
print("True Label:", np.argmax(new_y_[0:15,], 1))
print("Est Label:", np.argmax(new_y[0:15, ], 1))

# 5. 後片付け
# セッションを閉じる
sess.close()

最終結果

Extracting MNIST_data/train-images-idx3-ubyte.gz
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Extracting MNIST_data/t10k-images-idx3-ubyte.gz
Extracting MNIST_data/t10k-labels-idx1-ubyte.gz
step=1000, loss=2.03
step=2000, loss=1.43
step=3000, loss=0.90
step=4000, loss=0.84
step=5000, loss=1.04
step=6000, loss=0.76
step=7000, loss=0.63
step=8000, loss=0.66
step=9000, loss=0.48
step=10000, loss=0.77
Accuracy (for test data):   0.79%
True Label: [7 2 1 0 4 1 4 9 5 9 0 6 9 0 1]
Est Label: [7 2 1 0 4 1 4 4 6 7 0 6 9 0 1]

チュートリアル(MNISTビギナー編)

チュートリアルのMNIST For ML Beginners用の本来のソースリストは使わず、今回は、株式会社ブレインパッドの技術エントリーTensorFlowを遊び倒す! 1-1. MNIST For ML Beginnersのソースリストを動くように変更したものを使います。

チュートリアルは2015年11月時点の記事を参考にしても、ディレクトリ配置が変わってしまったようなので注意が必要です。
tensorflow/g3doc/tutorials/mnist/ → tensorflow/examples/tutorials/mnist/

#変更箇所
import input_data  → from tensorflow.examples.tutorials.mnist import input_data
tf.device("/gpu:1") → tf.device("/cpu:0")
printprint()

ソースリスト

# coding: utf-8
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data


def main():
    # mnistのダウンロード
    mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
    
    # 複数GPUがあるので指定
    with tf.device("/cpu:0"):
        # n * 784 の可変2階テンソル
        x = tf.placeholder("float", [None, 784])
        
        # 重み行列とバイアスの宣言
        W = tf.Variable(tf.zeros([784, 10]))
        b = tf.Variable(tf.zeros([10]))
        
        # ソフトマックス層を定義
        y = tf.nn.softmax(tf.matmul(x, W) + b)

        # 正解用2階テンソルを用意
        y_ = tf.placeholder("float", [None, 10])

        # 誤差関数の交差エントロピー誤差関数を用意
        cross_entropy = -tf.reduce_sum(y_*tf.log(y))

        # 学習方法を定義 0.01は学習率
        train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

    # 変数の初期化 ここでGPUにメモリ確保か
    init = tf.initialize_all_variables()
    sess = tf.Session()
    sess.run(init)

    # 1に一番近いインデックス(予測)が正解とあっているか検証し、その平均
    correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))

    # 学習開始
    for i in range(1000):
        batch_xs, batch_ys = mnist.train.next_batch(100)
        sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
        #print(sess.run(accuracy, feed_dict={x: batch_xs, y_: batch_ys}))


    print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))

if __name__ == "__main__":
    main()

実行結果

Successfully downloaded train-images-idx3-ubyte.gz 9912422 bytes.
Extracting MNIST_data/train-images-idx3-ubyte.gz
Successfully downloaded train-labels-idx1-ubyte.gz 28881 bytes.
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Successfully downloaded t10k-images-idx3-ubyte.gz 1648877 bytes.
Extracting MNIST_data/t10k-images-idx3-ubyte.gz
Successfully downloaded t10k-labels-idx1-ubyte.gz 4542 bytes.
Extracting MNIST_data/t10k-labels-idx1-ubyte.gz
0.9139

参照

チュートリアル(MNISTエキスパート編)

チュートリアルのMNIST For ML Beginners用の本来のソースリストは使わず、株式会社ブレインパッドの技術エントリーTensorFlowを遊び倒す! 2-1. MNIST For Expertsのソースリストを動くように変更したものを使います。

#変更箇所
import input_data  → from tensorflow.examples.tutorials.mnist import input_data
tf.device("/gpu:1") → tf.device("/cpu:0")
strides=[1, 1, 1, 1], # 真ん中2つが縦横のストライド → コメント移動
strides=[1, 2, 2, 1], # 真ん中2つが縦横のストライド → コメント移動
printprint()

ソースリスト

# coding: utf-8
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

def weight_variable(shape):
    """適度にノイズを含んだ(対称性の除去と勾配ゼロ防止のため)重み行列作成関数
    """

    initial = tf.truncated_normal(shape, stddev=0.1)
    return tf.Variable(initial)

def bias_variable(shape):
    """バイアス行列作成関数
    """
    initial = tf.constant(0.1, shape=shape)
    return tf.Variable(initial)

def conv2d(x, W):
    """2次元畳み込み関数
       strides 真ん中2つが縦横のストライド
    """
    return tf.nn.conv2d(x,
                        W,
                        strides=[1, 1, 1, 1],
                        padding='SAME')

def max_pool_2x2(x):
    """2x2マックスプーリング関数
       strides 真ん中2つが縦横のストライド
    """
    return tf.nn.max_pool(x,
                          ksize=[1, 2, 2, 1],
                          strides=[1, 2, 2, 1],
                          padding='SAME')

def main():
    # mnistのダウンロード
    mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

    sess = tf.InteractiveSession()
    with tf.device("/cpu:0"):
        # データ用可変2階テンソルを用意
        x = tf.placeholder("float", shape=[None, 784])
        # 正解用可変2階テンソルを用意
        y_ = tf.placeholder("float", shape=[None, 10])

        # 画像をリシェイプ 第2引数は画像数(-1は元サイズを保存するように自動計算)、縦x横、チャネル
        x_image = tf.reshape(x, [-1, 28, 28, 1])

        ### 1層目 畳み込み層

        # 畳み込み層のフィルタ重み、引数はパッチサイズ縦、パッチサイズ横、入力チャネル数、出力チャネル数
        # 5x5フィルタで32チャネルを出力(入力は白黒画像なので1チャンネル)
        W_conv1 = weight_variable([5, 5, 1, 32])
        # 畳み込み層のバイアス
        b_conv1 = bias_variable([32])
        # 活性化関数ReLUでの畳み込み層を構築
        h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)

        ### 2層目 プーリング層

        # 2x2のマックスプーリング層を構築
        h_pool1 = max_pool_2x2(h_conv1)

        ### 3層目 畳み込み層

        # パッチサイズ縦、パッチサイズ横、入力チャネル、出力チャネル
        # 5x5フィルタで64チャネルを出力
        W_conv2 = weight_variable([5, 5, 32, 64])
        b_conv2 = bias_variable([64])
        h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)

        ### 4層目 プーリング層
        h_pool2 = max_pool_2x2(h_conv2)

        ### 5層目 全結合層

        # オリジナル画像が28x28で、今回畳み込みでpadding='SAME'を指定しているため
        # プーリングでのみ画像サイズが変わる。2x2プーリングで2x2でストライドも2x2なので
        # 縦横ともに各層で半減する。そのため、28 / 2 / 2 = 7が現在の画像サイズ

        # 全結合層にするために、1階テンソルに変形。画像サイズ縦と画像サイズ横とチャネル数の積の次元
        # 出力は1024(この辺は決めです) あとはSoftmax Regressionと同じ
        W_fc1 = weight_variable([7 * 7 * 64, 1024])
        b_fc1 = bias_variable([1024])

        h_pool2_flat = tf.reshape(h_pool2, [-1, 7 * 7 * 64])
        h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)

        # ドロップアウトを指定
        keep_prob = tf.placeholder("float")
        h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

        ### 6層目 Softmax Regression層

        W_fc2 = weight_variable([1024, 10])
        b_fc2 = bias_variable([10])

        y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)

    # 評価系の関数を用意
    cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))
    train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
    correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
    sess.run(tf.initialize_all_variables())

    for i in range(20000):
        batch = mnist.train.next_batch(50)
        if i%100 == 0:
            train_accuracy = accuracy.eval(feed_dict={x:batch[0],
                                                      y_: batch[1],
                                                      keep_prob: 1.0})
            print("step %d, training accuracy %g"%(i, train_accuracy))
        train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})

    print("test accuracy %g"%accuracy.eval(feed_dict={
        x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))

if __name__ == "__main__":
    main()

実行結果 CPUのみとしたため、3時間程度かかりました。

自PCは「Intel Core i7-4700MQ 2.4GHz」です。
akiraakさんのブログには「Intel Core i7-6700K 4GHz」で30分、「NVIDIA TITAN X」のGPU実行では1分30秒に短縮されますとのこと。速いは正義!

Extracting MNIST_data/train-images-idx3-ubyte.gz
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Extracting MNIST_data/t10k-images-idx3-ubyte.gz
Extracting MNIST_data/t10k-labels-idx1-ubyte.gz
step 0, training accuracy 0.1
step 100, training accuracy 0.78
step 200, training accuracy 0.94
step 300, training accuracy 0.88

(中略)

step 19800, training accuracy 1
step 19900, training accuracy 1
test accuracy 0.9926

実行前の注意点(2016/05/28追記)

Docker上で実行した場合、"The Kernel appears to have died."という表示とともに計算が停止したとのコメントを頂きました。
TensorFlowコトハジメ Automatic Colorization(白黒画像の自動彩色)の記事内のメモリ不足を参考に、VirtualBoxのdefaultを4GByteに、docker runに「-m 4g」のオプションを付けて実行してください。
実行後にfreeコマンドでメモリ状況を参照したところ使用メモリが「1138420」となっていました。defaultマシンの初期メモリは1GByteなのでメモリが足りなかったのでしょう。

             total       used       free     shared    buffers     cached                                                                                     
Mem:       4045692    1138420    2907272      91824      10164     108692                                                                                     
-/+ buffers/cache:    1019564    3026128                                                                                                                      
Swap:      1946364     244772    1701592 

参照

TensorFlowコトハジメ 八百屋で識別問題

はじめに

前回、八百屋で勾配降下法を実行したので、次の識別問題をやってみる。 yaju3d.hatenablog.jp

前回に引き続きこの資料を基に理解していく。

識別問題とは

入力データから判断して分類させる問題。今回の例では買えるのか買えないのかを判断させる。
識別分類器としてロジスティック回帰を使う。

ロジスティック回帰とは

ロジスティック回帰は、発生確率を予測する手法です。
基本的な考え方は線形回帰分析と同じなのですが、予測結果が 0 から 1 の間を取るように数式やその前提に改良が加えられています。 今回のように購入有無(買える or 買えない)の2値しかとりえない値を従属変数の実績値として用い、説明変数を用いてその発生確率を説明するという構造になっています。

例題2

たかしくんは八百屋へ財布を預かってお使いに行きました。
しかし、たかしくんはお金を 数えられません。

気まぐれおやじ曰く、
リンゴ2個+ミカン3個、リンゴ0個+ミカン16個 なら買えるが、リンゴ3個+ミカン1個、 リンゴ2個+ミカン8個は買えないとのこと。

リンゴ1個+ミカン11個は買えますか? → 識別問題 f:id:Yaju3D:20160421011949p:plain

式で表そうとしてみる…
f:id:Yaju3D:20160421012015p:plain f:id:Yaju3D:20160421012037p:plain

シグモイド曲線

f:id:Yaju3D:20160421012100p:plain
※シグモイド曲線とは、入力した値を0から1の間に収めてくれる関数の1つ
 多くの自然界に存在する事柄は、このようなS字曲線を取る。
 生物の神経細胞、細胞の生存率曲線などなど

予測式(モデル)が作れた!
f:id:Yaju3D:20160421012204p:plain

ロジスティック回帰
f:id:Yaju3D:20160421012219p:plain

予測式(モデル)を記述

# 1. 予測式(モデル)を記述する
# 入力変数と出力変数のプレースホルダを生成
x = tf.placeholder(tf.float32, shape=(None, 2), name="x")
y_ = tf.placeholder(tf.float32, shape=(None, 1), name="y")
# モデルパラメータ
a = tf.Variable(-10 * tf.ones((2, 1)), name="a")
b = tf.Variable(200., name="b")
# モデル式
u = tf.matmul(x, a) + b
y = tf.sigmoid(u)

補足説明
tf.onesは、要素が全て「1」である1行列をセット 参照:TensorflowのAPIについて

今回の予測式に合わせてモデルとパラメーターを修正
f:id:Yaju3D:20160421012251p:plain

誤差関数と最適化手法を記述

# 2. 学習に必要な関数を定義する
# 誤差関数(loss)
loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=u, labels=y_))
# 最適化手段を選ぶ(最急降下法)
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss)

・誤差関数を変更
 識別(分類)問題→クロスエントロピー
f:id:Yaju3D:20160421012315p:plain

訓練データを作成(or読込)

# 3. 実際に学習処理を実行する
# (1) 訓練データを生成する
train_x = np.array([[2., 3.], [0., 16.], [3., 1.], [2., 8.]])
train_y = np.array([1., 1., 0., 0.]).reshape(4, 1)
print("x=", train_x)
print("y=", train_y)

学習実行

# (2) セッションを準備し,変数を初期化
sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)

# (3) 最急勾配法でパラメータ更新 (100回更新する)
for i in range(1000):
    _, l, a_ = sess.run([train_step, loss, a], feed_dict={x: train_x, y_: train_y})
    if (i + 1) % 100 == 0:
        print("step=%3d, a1=%6.2f, a2=%6.2f, loss=%.2f" % (i + 1, a_[0], a_[1], l))
        
# (4) 学習結果を出力
est_a, est_b = sess.run([a, b], feed_dict={x: train_x, y_: train_y})
print("Estimated: a1=%6.2f, a2=%6.2f, b=%6.2f" % (est_a[0], est_a[1], est_b))   

線形回帰とほぼ同じ
【変更箇所】

  • パラメータbの出力を追加
  • 更新回数を100回→1000回に
    ※更新回数は、対象問題やデータ、初期値、モデルなどでまちまちです。

学習結果

f:id:Yaju3D:20160421012400p:plain

予測結果

# 4. 新しいデータに対して予測する
# (1) 新しいデータを用意
new_x = np.array([1., 11.]).reshape(1, 2)

# (2) 学習結果をつかって,予測実施
new_y = sess.run(y, feed_dict={x: new_x})
print(new_y)

0.95848435 ≒ 0.96 f:id:Yaju3D:20160424232047p:plain

最終ソースコード

# 必要なモジュールを読み込む
# coding: utf-8
import numpy as np
import tensorflow as tf

# TensorFlow でロジスティック回帰する

# 1. 学習したいモデルを記述する
# 入力変数と出力変数のプレースホルダを生成
x = tf.placeholder(tf.float32, shape=(None, 2), name="x")
y_ = tf.placeholder(tf.float32, shape=(None, 1), name="y")
# モデルパラメータ
a = tf.Variable(-10 * tf.ones((2, 1)), name="a")
b = tf.Variable(200., name="b")
# モデル式
u = tf.matmul(x, a) + b
y = tf.sigmoid(u)

# 2. 学習やテストに必要な関数を定義する
# 誤差関数(loss)
loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=u, labels=y_))
# 最適化手段(最急降下法)
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss)


# 3. 実際に学習処理を実行する
# (1) 訓練データを生成する
train_x = np.array([[2., 3.], [0., 16.], [3., 1.], [2., 8.]])
train_y = np.array([1., 1., 0., 0.]).reshape(4, 1)
print("x=", train_x)
print("y=", train_y)

# (2) セッションを準備し,変数を初期化
sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)

# (3) 最急勾配法でパラメータ更新 (1000回更新する) 
for i in range(1000): 
    _, l, a_, b_ = sess.run([train_step, loss, a, b], feed_dict={x: train_x, y_: train_y})
    if (i + 1) % 100 == 0:
        print("step=%3d, a1=%6.2f, a2=%6.2f, b=%6.2f, loss=%.2f" % (i + 1, a_[0], a_[1], b_, l))

# (4) 学習結果を出力
est_a, est_b = sess.run([a, b], feed_dict={x: train_x, y_: train_y})
print("Estimated: a1=%6.2f, a2=%6.2f, b=%6.2f" % (est_a[0], est_a[1], est_b))

# 4. 新しいデータに対して予測する
# (1) 新しいデータを用意
new_x = np.array([1., 11.]).reshape(1, 2)

# (2) 学習結果をつかって,予測実施
new_y = sess.run(y, feed_dict={x: new_x})
print(new_y)

# 5. 後片付け
# セッションを閉じる
sess.close()

実行結果

0.95848435 ≒ 0.96 リンゴ 59.68 ≒ 60、ミカン 11.40 ≒ 11 → σ(185 - (60 x 1 + 11 x 11)) = 0.96(買えそう)

x= [[  2.   3.]
 [  0.  16.]
 [  3.   1.]
 [  2.   8.]]
y= [[ 1.]
 [ 1.]
 [ 0.]
 [ 0.]]
step=100, a1=-22.50, a2=-12.28, b=196.26, loss=42.75
step=200, a1=-35.00, a2=-12.06, b=192.68, loss=25.84
step=300, a1=-47.36, a2=-11.78, b=189.14, loss=9.24
step=400, a1=-55.13, a2=-11.51, b=186.75, loss=2.54
step=500, a1=-58.92, a2=-11.29, b=185.58, loss=0.02
step=600, a1=-59.26, a2=-11.23, b=185.47, loss=0.01
step=700, a1=-59.43, a2=-11.19, b=185.43, loss=0.00
step=800, a1=-59.53, a2=-11.17, b=185.39, loss=0.00
step=900, a1=-59.62, a2=-11.15, b=185.37, loss=0.00
step=1000, a1=-59.68, a2=-11.14, b=185.35, loss=0.00
Estimated: a1=-59.68, a2=-11.14, b=185.35
[[ 0.95848435]]

TensorFlowコトハジメ 八百屋で勾配降下法

はじめに

予測モデルを推測する分かりやすいサンプルを見つけたので、この資料を基に理解していく。

機会学習勉強会 (2016.2.27)のつぶやき

  • 実績データからパラメータを推定。パラメータを使って、結果を予測
  • パラメータ特定できない場合、合計金額の誤差が小さくなるような単価を採用する
  • 全ての組み合わせを検証するのではなく、少ない計算で最短距離で行う
  • 学習:予測式、誤差の計算、誤差の最小とする組み合わせ
  • 先程の例を線形回帰(線形重回帰)の式にする
  • 誤差を決める。誤差関数と最適化手法を記述
  • 学習率が大きすぎても失敗する。

勾配降下法とは

誤差の最小値を求める手法。
パラメータの特定できない場合、誤差が小さくなるような値を採用する。
イメージ例
f:id:Yaju3D:20160419021022p:plain

例題1

たかしくんは八百屋へお使いに行きました。
リンゴ1個とミカン3個を買うと190円,リンゴ3個とミカン1個を買うと330円するようです。
リンゴ2個とミカン4個を買うといくらになるでしょうか? f:id:Yaju3D:20160417225841p:plain f:id:Yaju3D:20160417225852p:plain
このくらいの問題なら、暗算で求めることが出来ます。
f:id:Yaju3D:20160417230109p:plain f:id:Yaju3D:20160417230118p:plain
では、次はどうでしょうか?
f:id:Yaju3D:20160417230234p:plain f:id:Yaju3D:20160417230455p:plain
f:id:Yaju3D:20160417230639p:plain
条件が当てはまる最小の値をひたすら繰り返し計算する。
f:id:Yaju3D:20160417230656p:plain f:id:Yaju3D:20160417230833p:plain
少ない計算で最小値を見つけたい。
f:id:Yaju3D:20160417230848p:plain f:id:Yaju3D:20171029162934p:plain

TensorFlowで同じように書いていく

f:id:Yaju3D:20160417231609p:plain

TensorFlow のほか高速な配列演算パッケージであるNumPyやプロットしたい場合はmatplotlib.pyplotなど使用するライブラリをロードする。

# 必要なモジュールを読み込む
import numpy as np
import tensorflow as tf

予測式(モデル)を記述

# 1. 予測式(モデル)を記述する
# 入力変数と出力変数のプレースホルダを生成
x = tf.placeholder(tf.float32, shape=(None, 2), name="x")
y_ = tf.placeholder(tf.float32, shape=(None, 1), name="y")
# モデルパラメータ
a = tf.Variable(tf.zeros((2, 1)), name="a")
# モデル式
y = tf.matmul(x, a)
  • 値を入れる"箱"を作成
    入出力 → placeholder,パラメータ → Variable
    (注意)shape = (訓練データの数, 次元数)
    ※"訓練データの数"は None にすると可変長扱い

補足説明
プレースホルダ(placeholder)とは、実際の内容を後から挿入するために仮に確保した場所のこと
tf.placeholderでセットした変数 x や y_ は特定の値ではなくplaceholderと呼ばれ
TensorFlowに計算を実行しろと頼むときに入力する値です。

tf.zerosは、要素が全て「0」である0行列をセット 参照:TensorflowのAPIについて

shape=(行, 列)は、各次元の要素数 (行数, 列数)。
shape=(None, 2)は、2列で後でサイズが決まるような場合に使用する。
f:id:Yaju3D:20160619200824p:plain
shape=(None, 1)は、1列で後でサイズが決まるような場合に使用する。
f:id:Yaju3D:20160619200836p:plain

tf.matmulは行列の掛け算(ここでは定義で実際に使うのは、loss = tf.reduce_mean(tf.square(y_ - y)) )
 { \displaystyle \binom{190}{330} = \binom{1\, \, 3}{3\, \, 1}\binom{a1}{a2}}
行列式を使った連立方程式の解き方
ke!san 連立方程式

  • 予測式(モデル)を記述
    f:id:Yaju3D:20160419002003p:plain

.誤差関数と最適化手法を記述

# 2. 学習に必要な関数を定義する
# 誤差関数(loss)
loss = tf.reduce_mean(tf.square(y_ - y))
# 最適化手段を選ぶ(最急降下法)
train_step = tf.train.GradientDescentOptimizer(0.02).minimize(loss)

mean も average も「平均値」ですが、mean のほうが学術用語で、average のほうが普通語です。
参照:meanとaverageの違いは?

  • 誤差関数を記述
    ふつうの回帰問題 → 平均二乗誤差  {\displaystyle \frac{1}{N}\sum_{i}^{n}{{(y_{i} - \tilde{y}_{i})^{2}}}}

yaju3d.hatenablog.jp

  • 最適化手法を選ぶ
    ・入門 → 最急降下法(勾配降下法) GradientDescent~
     ※どれを選ぶかで学習(最適化)の速さが変わる
    ・引数に適度な"学習率"を指定する
     ※大きすぎると学習失敗(発散)、小さすぎると学習が遅い

訓練データを作成(or読込)

# 3. 実際に学習処理を実行する
# (1) 訓練データを生成する
train_x = np.array([[1., 3.], [3., 1.], [5., 7.]])
train_y = np.array([190., 330., 660.]).reshape(3, 1)
print("x=", train_x)
print("y=", train_y)

f:id:Yaju3D:20160419005112p:plain
※予測式で定義した形状(shape)に合わせること
※実用場面では,外部データを(ファイルやSQLなどから) 読みとって2次元配列に整形する。

# (2) セッションを準備し,変数を初期化
sess = tf.Session()
init = tf.initialize_all_variables()
sess.run(init)

# (3) 最急勾配法でパラメータ更新 (100回更新する)
for i in range(100):
    _, l, a_ = sess.run([train_step, loss, a], feed_dict={x: train_x, y_: train_y})
    if (i + 1) % 10 == 0:
        print("step=%3d, a1=%6.2f, a2=%6.2f, loss=%.2f" % (i + 1, a_[0], a_[1], l))


# (4) 学習結果を出力
est_a = sess.run(a, feed_dict={x: train_x, y_: train_y})
print("Estimated: a1=%6.2f, a2=%6.2f" % (est_a[0], est_a[1]))

sess.run ( [出力, ...], feed_dict={入力リスト} )
sess.run を呼び出すことで、"出力"に指定した データフローグラフが計算される
※学習を回すには、先ほど作成した最適化手段(train_step)を出力値に指定して sess.run を呼び出す。

参考: 実行結果

f:id:Yaju3D:20160419010123p:plain

f:id:Yaju3D:20160419010158p:plain

# 4. 新しいデータに対して予測する
# (1) 新しいデータを用意
new_x = np.array([2., 4.]).reshape(1, 2)

# (2) 学習結果をつかって,予測実施
new_y = sess.run(y, feed_dict={x: new_x})
print(new_y)

予測でも sess.run を用いる
feed_dictには新しい入力値を指定することに留意。(当然ですが...)
f:id:Yaju3D:20160419010502p:plain

最終ソースコード

# coding: utf-8
# 必要なモジュールを読み込む
import numpy as np
import tensorflow as tf

# 1. 予測式(モデル)を記述する
# 入力変数と出力変数のプレースホルダを生成
x = tf.placeholder(tf.float32, shape=(None, 2), name="x")
y_ = tf.placeholder(tf.float32, shape=(None, 1), name="y")
# モデルパラメータ
a = tf.Variable(tf.zeros((2, 1)), name="a")
# モデル式
y = tf.matmul(x, a)

# 2. 学習に必要な関数を定義する
# 誤差関数(loss)
loss = tf.reduce_mean(tf.square(y_ - y))
# 最適化手段を選ぶ(最急降下法)
train_step = tf.train.GradientDescentOptimizer(0.02).minimize(loss)


# 3. 実際に学習処理を実行する
# (1) 訓練データを生成する
train_x = np.array([[1., 3.], [3., 1.], [5., 7.]])
train_y = np.array([190., 330., 660.]).reshape(3, 1)
print("x=", train_x)
print("y=", train_y)

# (2) セッションを準備し,変数を初期化
sess = tf.Session()
init = tf.initialize_all_variables()
sess.run(init)

# (3) 最急勾配法でパラメータ更新 (100回更新する)
for i in range(100):
    _, l, a_ = sess.run([train_step, loss, a], feed_dict={x: train_x, y_: train_y})
    if (i + 1) % 10 == 0:
        print("step=%3d, a1=%6.2f, a2=%6.2f, loss=%.2f" % (i + 1, a_[0], a_[1], l))


# (4) 学習結果を出力
est_a = sess.run(a, feed_dict={x: train_x, y_: train_y})
print("Estimated: a1=%6.2f, a2=%6.2f" % (est_a[0], est_a[1]))

# 4. 新しいデータに対して予測する
# (1) 新しいデータを用意
new_x = np.array([2., 4.]).reshape(1, 2)

# (2) 学習結果をつかって,予測実施
new_y = sess.run(y, feed_dict={x: new_x})
print(new_y)

# 5. 後片付け
# セッションを閉じる
sess.close()

実行結果

リンゴ 98.81 ≒ 99、ミカン 24.90 ≒ 25 → 99 x 2 + 25 x 4 ≒ 297  

x= [[ 1.  3.]
 [ 3.  1.]
 [ 5.  7.]]
y= [[ 190.]
 [ 330.]
 [ 660.]]
step= 10, a1= 70.35, a2= 46.23, loss=2189.06
step= 20, a1= 83.06, a2= 36.70, loss=771.90
step= 30, a1= 90.13, a2= 31.41, loss=334.34
step= 40, a1= 94.05, a2= 28.47, loss=199.24
step= 50, a1= 96.23, a2= 26.84, loss=157.52
step= 60, a1= 97.44, a2= 25.93, loss=144.64
step= 70, a1= 98.12, a2= 25.42, loss=140.67
step= 80, a1= 98.49, a2= 25.14, loss=139.44
step= 90, a1= 98.70, a2= 24.99, loss=139.06
step=100, a1= 98.81, a2= 24.90, loss=138.94
Estimated: a1= 98.81, a2= 24.90
[[ 297.22738647]]

TensorFlowコトハジメ フィボナッチ数列

はじめに

前回、TensorFlowの概要記事を書いた。概要としてはまだ足りないのだが、次に進まないとならない。
TensorFlowのプログラムを組むのに簡単な例として、フィボナッチ数列が良さそうなので、これを題材として理解してみる。

ネットで検索したフィボナッチ数列のPython用プログラムを参考とする。
参照:Python(11)再帰のお勉強:フィボナッチの数列

フィボナッチ数列(Fibonacci number)とは

1+1=2、1+2=3、2+3=5、3+5=8… と、前項2つを加えて、次々とできる数の列のことをフィボナッチ数列といいます。
f:id:Yaju3D:20160417173452p:plain
このフィボナッチ数列の隣接する2つの数の比は限りなく黄金比に近づいています。花びらの数、葉のつき方など自然界にもこの周期が現れるものも多くあります。 また、名刺の縦横比、建物や絵画、彫刻などのバランスの美しさにも、この黄金比が現れていることが多いのです。
blog.livedoor.jp

{F_{0}=0}
{F_{1}=1}
{F_{n}=F_{n-1}+F_{n-2}} {(n>1)}

この漸化式で表せる数列です。
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, …

プログラム 1

d136o/tensor_overflow.py

import argparse
import tensorflow as tf
import sys

def flowfib(n):
    # f_n = f_n-1 + f_n-2
    f = [tf.constant(0),tf.constant(1)]
    
    if n>2:
        for i in range(2,n):
            f_i = f[i-1] + f[i-2]
            f.append(f_i)
    
    with tf.Session() as sess:
        result = sess.run(f)
        print(result)

flowfib(20)

#[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181]

説明

[TensorFlow] APIドキュメントを眺める -Tensor編-

整数リテラルを使って生成した Tensor については tf.int32 が要素の数値型として適用される模様です。

import tensorflow as tf
a = tf.constant(0)
a.dtype

# tf.int32

appendは、Pythonの要素追加メソッドです。

f.append(f_i)

プログラム 2

qiita.com

import tensorflow as tf

u = tf.Variable(tf.cast(1,"int64"))
v = tf.Variable(tf.cast(0,"int64"))

update_u = tf.assign(u, tf.add(u,v)) # u = u + v
update_v = tf.assign(v, tf.sub(u,v)) # v = u - v

init = tf.initialize_all_variables()

with tf.Session() as sess:
    sess.run(init)
    for i in range(100):
        print(i, sess.run(v))
        sess.run(update_u)
        sess.run(update_v)

説明

定義の値の更新の代入にはtf.assignを使う。足し算(tf.add)、引き算(tf.sub)を使う。 https://www.tensorflow.org/versions/0.6.0/api_docs/python/state_ops.html#assign

update_u = tf.assign(u, tf.add(u,v)) # u = u + v
update_v = tf.assign(v, tf.sub(u,v)) # v = u - v

セッションの最初に変数を初期化する必要がある。これには、init = tf.initialize_all_variablesを使う。sess.run(init)にて初期化を実行する。

init = tf.initialize_all_variables()

sess.run(init)

sess.runにより値を取ったり、手続きを実行したりします。

print(i, sess.run(v)) #値の取得
sess.run(update_u)   #定義の実行
sess.run(update_v)   #定義の実行

最後に

モデルを定義してから実行するというのが、今までの習っていたプログラムと違うので、慣れる必要がありますね。 mirai-tec.hatenablog.com

TensorFlowコトハジメ 概要

はじめに

静岡Developers勉強会では、今年の勉強会のテーマとして「人工知能ハンズオン」を2016/4/23に開催します。
これまでインストール記事ばかりで中身が書けていなかったので、概要から書いていきます。

TensorFlowとは

読み方は「テンソルフローテンサーフロー」となります。【2017/02/18 訂正】googleの中の人がテンサーフローと呼んで欲しい
Googleが2015年11月10日に公開したオープンソース多層NN(ディープラーニング)に特化したライブラリで現状C++/PythonでのAPIが存在しています。
Tensor(テンソル)のFlow(流れ)で状態記述します。

ディープラーニングやマシーンラーニングの使いやすいライブラリが整ってはいるものの、それらに特化したフレームワークではなく、多次元配列に入る数字を非常に高速に計算するための汎用のHPCフレームワークとしても使うことができます。

Tensor(テンソル)とは

テンソル(英: tensor, 独: Tensor)とは、 線形的な量または線形的な幾何概念を 一般化したもので、基底を選べば、多次元の配列として表現できるようなものである。 Wikipedia

乱暴に言えば多次元配列に相当する

  • 添え字のついた変数(配列)
    { X_{ij} } { Z_{ijk} }
  • スカラー、ベクトル、行列の一般名

f:id:Yaju3D:20160417104606p:plain

テンソルデータ例

  • 濃淡画像  ・・・ 2階のテンソル
  • カラー画像 ・・・ 3階のテンソル(RGB x 濃淡画像)
  • カラー動画 ・・・ 4階のテンソル(フレーム x カラー画像)

可視化する限度は3階までが限界
f:id:Yaju3D:20160417031730p:plain
図1: ユーザ × 商品 × 時間の3階テンソルとして表現された購買データ
テンソルというのはテーブル形式のデータを多次元に拡張したもので、例えば、複数のユーザがいくつかの種類の商品をある時刻に購入したという購買データを考えるとユーザ × 商品 × 時間の3階テンソルとして表現することができます。

また、テンソルとはごく簡単にいえば「任意座標系で表した量」ということになります。図1だと、購入商品(item)の3個(Qty)が量となります。

f:id:Yaju3D:20160417025250p:plain
他にも2次元画像をRGBに分解して、任意座標のピクセル値(R * 2562 + G * 256 + B)が量となります。

Tensor(テンソル)の計算

高校の数学で行列同士の計算(加算、減算、積、商(逆行列))を習いますが、テンソル同士も行列と同じように計算することが出来ます。計算方法はここでは説明しません。 参照:TensorFlow APIドキュメントを眺める -Math編-

計算例 [1.1.1.1.]+[2.2.2.2.]=[3.3.3.3.]

import tensorflow as tf

with tf.Session():
  input1 = tf.constant([1.0, 1.0, 1.0, 1.0])
  input2 = tf.constant([2.0, 2.0, 2.0, 2.0])
  output = tf.add(input1, input2)
  result = output.eval()
  print(result)

#[ 3.  3.  3.  3.]
畳み込み演算とは?

「畳む」…複数ヶ所(連続的)から値を持ってくる
「込む」…積算する
掛け算の結果を足し集める演算からなり、大量な計算が必要になることからコンピュータ処理の得意とするところです。
数学用語ではコンボリューション(Convolution)といいます。

畳み込み演算の簡単な例として、画像処理ソフトウェアで画像を「ぼかす」フィルターをかける場合を考えます。これは、画像の各ピクセルにおいて、その部分の色をその周りのピクセルの色とまぜて平均化した色に置き換えれば実現できます。その際の掛け算の係数は、3×3などのサイズのマトリックスで指定します。参照:空間フィルタリング処理 f:id:Yaju3D:20160417025351p:plain 3×3サイズのマトリックスを1ピクセルずらしながら演算する。
f:id:Yaju3D:20160417025404g:plain
畳み込み結果の画像が入力サイズより一回り小さくなります。もし同サイズにしたい場合には外側に「ふち」をつけて大きくします。
「ふち」の部分の画素は未定なので何らかの方法(最周囲の画素等)で決める必要があります。

TensorFlowの計算処理

テンソルを計算するには、かなりの計算量が必要となります。CPUが複数あれば並列で計算させることで結果が速く出せますし、GPUを使えば多くの計算結果が速く導くことが可能となります。またクラウドを使って、1台ではなく複数台のコンピューターに分散させればそれだけ速く計算結果を求めることが出来るのです。
そのために、TensorFlowは計算処理を「データフローグラフ」(以降 略:グラフ(Graph))構造で表します。

グラフとは

グラフはノード(Node)といわれる計算ブロックのようなものをエッジ(edge)といわれる線で繋げたもので、データはノードからノードへ、エッジのつながり方に従って受け渡され、計算が行われます。 f:id:Yaju3D:20160417025430p:plain

Opノード

TensorFlowではノードは「op」(operation:計算操作の略)と言われます。 f:id:Yaju3D:20160417025458p:plain

セッション

グラフはセッションに割り当てて計算を行います。セッションは、計算可能になったノード(エッジから送られてくる計算結果がすべてそろったノード)を非同期/並列に計算していきます。
計算に際しては、どのデバイス(cpu/gpu)で行うのかの割振りも行います。 f:id:Yaju3D:20160417025520p:plain

計算方法

TensorFlowでは計算処理は2フェイズ(Define & Run)で行います。

  • Define(定義)
    計算のグラフモデルを構築するフェイズで、この時点では計算結果は確定しない
  • Run(実行)
    グラフモデルから計算結果を確定するフェイズでセッション(Session)にモデルを投入し、計算結果を得る
TensorFlowによる計算プログラム

Pythonの通常の計算プログラム

x = 35
y = x + 5
print(y)

TensorFlowで同じように計算プログラム

import tensorflow as tf

x = tf.constant(35, name='x')
y = tf.Variable(x + 5, name='y')

print(y)

これを実行するとエラー<tensorflow.python.ops.variables.Variable object at 0x7f074bfd9ef0>になります。
これはモデルを定義しただけでは計算が出来ないためです。
計算処理は2フェイズ(Define & Run)する必要があり修正したのが下記となります。

import tensorflow as tf

x = tf.constant(35, name='x')
y = tf.Variable(x + 5, name='y')

# 変数を初期化するための OP を追加します。
model = tf.initialize_all_variables()

with tf.Session() as session:
    session.run(model)
    print(session.run(y)

実際にデータを処理するにはtf.Sessionを使います。セッションの最初に変数を初期化する必要があり、これには「tf.initialize_all_variables」を使います。
これにより計算結果「40」が表示されます。
参照:http://learningtensorflow.com/lesson2/

参照

テンソル分解の基礎と 画像・信号処理への応用 - SlideShare
TensorFlowで遊んでみよう! - SlideShare
Generalization of Tensor Factorization and Applications SlideShare
Bci deep learning_juas - SlideShare
第13回助教の会
コンボリューションを用いた画像の平滑化、鮮鋭化とエッジ検出
Image Scaling using Deep Convolutional Neural Networks
How common is it for neural networks to be represented by tensors of rank 3 or greater?
TensorFlow Tutorialの数学的背景 − Deep MNIST for Experts(その1)- めもめも
4.たたみ込み演算による画像処理
TensorFlowを算数で理解する
TensorFlowのキーコンセプト: Opノード、セッション、変数

WindowsユーザーがTensorFlowをインストールしてみた(AWS EC2 Docker版)

はじめに

静岡Developers勉強会では「人工知能ハンズオン」を2016/4/23に開催します。自PC(Windows 10 Home 64bit)にDockerを使ってGoogleが提供しているオープンソース人工知能ライブラリ「TensorFlow」を入れて動かすことが出来たのですが、Dockerって64bit版のみで32bit版がありません。
勉強会なので32bit PCしか持っていない人をどうしようかと思ったら、あるじゃないですか? そう、クラウドならね。

環境

1年間の無料枠で構築

  • Amazon Linux AMI 2016.03 (HVM), SSD Volume Type 64ビット
  • t2.micro

AWS EC2の登録

AWS EC2の登録は長くなるので別記事にしました。DockerとTensorFlowの導入まで記事がかぶってますが・・・ qiita.com

Dockerのインストール

下記サイトを参考にDockerをインストールしました。
EC2にDockerをインストールしてNginxコンテナを作る

Dockerをインストール

sudo yum install -y docker

Dockerを起動

$ sudo service docker start
Starting cgconfig service:                                 [  OK  ]
Starting docker:

ec2-userをdockerグループに追加

$ sudo usermod -a -G docker ec2-user
$ cat /etc/group |grep docker
docker:x:497:ec2-user

グループに追加されていることを確認したら、一度ログアウト(exit)して再度ログインしてください。

dockerグループに所属していれば、sudoなしで ec2-userから Dockerコマンドが使えます。

docker info
  ︙
Kernel Version: 4.4.5-15.26.amzn1.x86_64
Operating System: Amazon Linux AMI 2016.03

DockerにTensorFlowのインストール

TensorflowのサイトのDocker installationにインストールする方法が記載されています。ポートは指定しました。

$ docker run -p 8888:8888 -p 6006:6006 b.gcr.io/tensorflow/tensorflow
         ︙
[I 08:48:55.427 NotebookApp] The Jupyter Notebook is running at: http://[all ip
addresses on your system]:8888/
[I 08:48:55.427 NotebookApp] Use Control-C to stop this server and shut down all
 kernels (twice to skip confirmation).

記載のコマンドを入力するとtensorflowがインストールされていきます。
WebブラウザでdefaultマシンのIPアドレスにポート番号8888を付ければ、Notebook(Jupyter)が動作するとなっています。

Jupyter Notebookの起動

Webブラウザで「http:(パブリックIP):8888/」と入力するとJupyter Notebookが起動されました。
AWS EC2のパブリックIPを指定して下さい。

TensorFlowのサンプル確認

DockerのTensorFlowには、下記のサンプルが最初から用意されています。

  • 1_hellow_tensorflow.ipynb
  • 2_getting_started.ipynb
  • 3_minst_from_scratch.ipynb

※DockerのTensorflowはPython2用となります。

f:id:Yaju3D:20160407003301p:plain

TensorBoradの確認

yaju3d.hatenablog.jp

このサイトの「TensorBoardによる可視化」にあるソースを入力します。
※その上にあるdef x2_plus_b(x, b)関数も入力が必要です。

f:id:Yaju3D:20160407003353p:plain

実行するとlogフォルダが作成されます。 次に右横の「New」で「Terminal」を作成します。

f:id:Yaju3D:20160407003452p:plain

Terminalにて、下記コマンドを入力します。

# tensorboard --logdir=log                                                                                                                                    

f:id:Yaju3D:20160407003516p:plain

これでWebブラウザで「http:(パブリックIP):6006/」と入力すると「TernsorBorad」が表示されます。 f:id:Yaju3D:20160407004805p:plain

※最初にグラフが「No scalar summary tags were found.」のエラーで表示されなかったのですが、Dockerをリスタートしたら表示されるようになりました。

$ docker ps
CONTAINER ID        IMAGE                            COMMAND             CREATED             STATUS              PORTS                                            NAMES
cea774063516        b.gcr.io/tensorflow/tensorflow   "/run_jupyter.sh"   31 hours ago        Up 31 hours         0.0.0.0:6006->6006/tcp, 0.0.0.0:8888->8888/tcp   thirsty_kare
$ docker stop thirsty_kare
$ docker start thirsty_kare

TensorBoradの停止

Runningタブにて該当Terminalの「Shutdown」ボタンをクリックすれば停止します。 f:id:Yaju3D:20160407003537p:plain

WindowsユーザーがTensorFlowをインストールしてみた(Docker版)

はじめに

静岡Developers勉強会では、今年の勉強会のテーマとして「人工知能ハンズオン」を2016/4/23に開催します。 以前、TensorFlowを自PC(Windows 10 64bit)にインストールした記事を書きました。 yaju3d.hatenablog.jp

ですが初心者の人には敷居が高いかと思い、もっと簡単な方法がないか模索していました。
ネットで「Tensorflow Windows インストール」で検索すると、Dockerなら簡単だよというのが見つかるのですが、Dockerってクラウドで使うものだと思い込んでいたために見逃していました。
Dockerを調べるとクラウドでなくても使えることが理解できたので、今回Dockerを使ってのTensorflowのインストールに挑戦してみました。

※Dockerを使用するにはPCが64bitである必要があります。

qiita.com

環境

  • Windows 7 Professional 64bit
  • DockerToolbox 1.10.3
  • VirtualBox 5.0.16

DockerToolboxのインストール

DockerのオフィシャルサイトのDocker ToolboxからDocker Toolboxのインストーラを入手します。このインストーラにはVirtualBoxやGit for Windowsが同梱されてます。

自分はチェックボックスなど気にせずデフォルト状態のままインストールしました。

Docker用の仮想マシンを構築

Docker Quickstart Terminalを起動します。初回のみVirtualBox上にDocker用の仮想マシン(default)を生成します。 その後、Dockerエンジンが動作しているDockerホストの仮想マシンに接続されます。 VirtualBoxを開くとdefaultインスタンスが出来ていることが確認できます。

自PCのWindows 10 Home 64bitではDocker Quickstart Terminalでエラーになりました。その顛末は下記ブログに書いています。 qiita.com

Dockerの動作確認

$ docker-machine ls
NAME      ACTIVE   DRIVER       STATE     URL                         SWARM   ERRORS
default   *        virtualbox   Running   tcp://192.168.99.101:2376

URLにあるIPアドレスは後で入力するので覚えて置いてください。
ちなみにIPアドレスだけを知りたい場合は下記となります。

$ docker-machine ip
192.168.99.100

DockerにTensorFlowのインストール

TensorflowのサイトのDocker installationにインストールする方法が記載されています。

$ docker run -it b.gcr.io/tensorflow/tensorflow
         ︙
[I 08:48:55.427 NotebookApp] The Jupyter Notebook is running at: http://[all ip
addresses on your system]:8888/
[I 08:48:55.427 NotebookApp] Use Control-C to stop this server and shut down all
 kernels (twice to skip confirmation).

記載のコマンドを入力するとtensorflowがインストールされていきます。説明の通りだとWebブラウザでdefaultマシンのIPアドレスにポート番号8888を付ければ、Notebook(Jupyter)が動作するとなっています。

自分はこの通りに入力したのですが、Webブラウザで「http:192.168.99.100:8888/」を入力しても、「このサイトにアクセスできません」のエラーでどうすることも出来なかったため、Control-Cを押すしかありませんでした。

Jupyter Notebookの起動

ネットで調べるとポートを指定するようなことが書かれていました。
How do I start tensorflow docker jupyter notebook

$ docker run -p 8888:8888 -p 6006:6006 b.gcr.io/tensorflow/tensorflow
         ︙
[I 08:48:55.427 NotebookApp] The Jupyter Notebook is running at: http://[all ip
addresses on your system]:8888/
[I 08:48:55.427 NotebookApp] Use Control-C to stop this server and shut down all
 kernels (twice to skip confirmation).

これでWebブラウザで「http:192.168.99.100:8888/」と入力するとJupyter Notebookが起動されました。
※IPアドレスは、Dockerの動作確認した際のURLとなります。

TensorFlowのサンプル確認

DockerのTensorFlowには、下記のサンプルが最初から用意されています。

  • 1_hellow_tensorflow.ipynb
  • 2_getting_started.ipynb
  • 3_minst_from_scratch.ipynb

※DockerのTensorflowはPython2用となります。

f:id:Yaju3D:20160407003301p:plain

TensorBoradの確認

yaju3d.hatenablog.jp

このサイトの「TensorBoardによる可視化」にあるソースを入力します。
※その上にあるdef x2_plus_b(x, b)関数も入力が必要です。

f:id:Yaju3D:20160407003353p:plain

実行するとlogフォルダが作成されます。 次に右横の「New」で「Terminal」を作成します。

f:id:Yaju3D:20160407003452p:plain

Terminalにて、下記コマンドを入力します。

# tensorboard --logdir=log                                                                                                                                    

f:id:Yaju3D:20160407003516p:plain

これでWebブラウザで「http:192.168.99.100:6006/」と入力すると「TernsorBorad」が表示されます。 f:id:Yaju3D:20160407004805p:plain

TensorBoradの停止

Runningタブにて該当Terminalの「Shutdown」ボタンをクリックすれば停止します。 f:id:Yaju3D:20160407003537p:plain

ホストとファイル共有

Dockerはプロセス内にコンテナを生成するので、コンテナ内にファイルを保存してもPC再起動等でプロセスが消えるとコンテナも破棄されます。下記方法でホスト側のフォルダをマウントしておくことでコンテナが破棄されてもファイルが消えることがなくなります。

ホスト側(C:\Users(ユーザー名))の配下に「tensor_share」フォルダ(例)を作成したとします。

$ docker run -d -p 8888:8888 -p 6006:6006 -v /c/Users/(ユーザー名)/tensor_share:/notebooks b.gcr.io/tensorflow/tensorflow

PWDコマンドを使うとカレントディレクトリを取得できます。

$ echo $PWD
/c/Users/(ユーザー名)

$ docker run -d -p 8888:8888 -p 6006:6006 -v $PWD/tensor_share:/notebooks b.gcr.io/tensorflow/tensorflow

qiita.com

スポンサーリンク