#!/usr/bin/env python # coding: utf-8 # # TensorFlow による 3LP MNIST 実習
ハンズオン資料 #

2016/04/16 機械学習 名古屋 第3回勉強会

# ## はじめに # + この資料は、TensorFlow を用いて、3LP(3層パーセプトロン)により MNIST の学習を実施することを目的とするものです。 # + この資料に掲載のコードは、本日の読書会の資料([第2章](http://antimon2.github.io/MLNGY_201604/slides/Chapter2_FeedforwardNeuralNetwork.slides.html)・[第3章](http://antimon2.github.io/MLNGY_201604/slides/Chapter3_StochasticGradientDescent.slides.html))、および TensorFlow 公式のチュートリアル [MNIST For ML Beginners](https://www.tensorflow.org/versions/master/tutorials/mnist/beginners/) を元に構築しております。 # ## 目標 # + TensorFlow を用いた基本的な DeepLearning を自分で書ける。 # + 正則化や、学習係数・モメンタム等の工夫を加えて、学習の精度を上げる(オプション、もしくは宿題) # ## 環境等 # 以下の環境を前提とします。 # # + Python(必須)(2.7.x / 3.x どちらでもOK) # + TensorFlow(必須)(0.6 / 0.7 / 0.8[New!] どれでもOK) # + matplotlib(任意、結果を確認する際に利用) # + IPython(任意) # ## TensorFlow # + [公式サイト](https://www.tensorflow.org/) # + Google 製の「データフローグラフを用いた数値計算ライブラリ」(公式の説明を私訳) # + DeepLearning 用の機能も豊富。 # + つい先日 [v0.8がリリース(2016/04/13)](http://googleresearch.blogspot.com/2016/04/announcing-tensorflow-08-now-with.html) # インストールの詳細省略。 # インストールが成功していれば、Python のインタラクティブシェル(もしくは ipython, Jupyter 等)で↓以下のようにすれば利用開始。 # In[ ]: import tensorflow as tf # ※ 今回は TensorBoard は不使用。 # ## MNIST # + 機械学習定番の、多クラス分類(教師あり学習)問題「手書き数字認識」のサンプルデータ。 # + 多くの機械学習ライブラリで、手軽に体験できるよう「MNIST をロードする関数(またはサンプル)」が用意されている。 # TensorFlow では、以下のようにすると MNIST データセット(訓練データおよびテストデータ)を扱えるようになる: # In[ ]: from tensorflow.examples.tutorials.mnist import input_data mnist = input_data.read_data_sets("MNIST_data/", one_hot=True) # ※↑データが存在しなければネットワーク経由でダウンロードから開始。 #  ダウンロード後(or ダウンロード済のデータが存在する場合)そのデータを読み込んでくれる。 # ※⇒既にダウンロード済のデータ(4つの.gzファイル)を持っていたらそれを所定の場所に置いておくだけでもOK。 # ## 3LP 構築 # ### 訓練データ(及び正解データ)用の変数(プレースホルダ)用意 # In[ ]: # 訓練データ:長さ784のベクトルデータ(=28x28 の画像データ) x = tf.placeholder(tf.float32, [None, 784]) # 正解データ:長さ10のベクトルデータ(0,1,…,9 の対応する要素のみ 1、他は 0) d = tf.placeholder(tf.float32, [None, 10]) # ### 第1層 # + 入力サイズ:784(訓練データのサイズ) # + 出力サイズ:128 # + 重み初期化:ガウス分布による乱数で初期化(平均 0.0, 分散 0.05) # + バイアス初期化:ゼロ値 # + 活性化関数:正規化線形関数(ReLU) # In[ ]: W1 = tf.Variable(tf.random_normal([784, 128], mean=0.0, stddev=0.05)) b1 = tf.Variable(tf.zeros([128])) z1 = tf.nn.relu(tf.matmul(x, W1) + b1) # ### 第2層 # + 入力サイズ:128(前の層の出力サイズ) # + 出力サイズ:64 # + 重み初期化:ガウス分布による乱数で初期化(平均 0.0, 分散 0.05) # + バイアス初期化:ゼロ値 # + 活性化関数:正規化線形関数(ReLU) # In[ ]: W2 = tf.Variable(tf.random_normal([128, 64], mean=0.0, stddev=0.05)) b2 = tf.Variable(tf.zeros([64])) z2 = tf.nn.relu(tf.matmul(z1, W2) + b2) # ### 第3層(出力層) # + 入力サイズ:64(前の層の出力サイズ) # + 出力サイズ:10(正解データの要素数) # + 重み初期化:ガウス分布による乱数で初期化(平均 0.0, 分散 0.05) # + バイアス初期化:ゼロ値 # + 活性化関数:ソフトマックス関数 # In[ ]: W3 = tf.Variable(tf.random_normal([64, 10], mean=0.0, stddev=0.05)) b3 = tf.Variable(tf.zeros([10])) y = tf.nn.softmax(tf.matmul(z2, W3) + b3) # ### 誤差関数(=交差エントロピー) # In[ ]: x_entropy = -tf.reduce_sum(d * tf.log(y)) # ### 最適化(=確率的勾配降下法) # + 以下では `tf.train.GradientDescentOptimizer` を利用した例を示す。 # + 引数(=学習係数)は 0.01 # + 他に、`tf.train.AdagradOptimizer`、`tf.train.MomentumOptimizer` 等を利用しても良い。 # In[ ]: optimizer = tf.train.GradientDescentOptimizer(0.01) train_step = optimizer.minimize(x_entropy) # ## 学習 # ### TensorFlow による学習の流れ # 0. 変数の初期化 # 1. セッションの開始 # 2. ミニバッチを利用した学習ステップのループ # 3. (オプション)精度の確認 # 4. (オプション)推測結果確認 # ### 1. 変数の初期化 # In[ ]: init = tf.initialize_all_variables() # ※↑これも「変数を初期化する」という命令を宣言しているだけ。 #  この後 `sess.run(init)` することで(そのセッション内で実際に)変数の初期化が実行される。 # ### 2. セッションの開始 # In[ ]: sess = tf.Session() sess.run(init) # ↑実際にはここで始めて各変数が初期化される # ### 2.5. (先に)精度の確認(の準備) # 今回は分かりやすくするため、ループ中にも随時精度を確認してみる。 # そのため先に精度を確認する各種準備。 # In[ ]: # y(=学習結果の出力)と d(正解データ)で一致しているかどうかを確認 correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(d, 1)) # 平均(=一致している個数÷全データ数)を計算 accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) # ### 3. ミニバッチを利用した学習ステップのループ # In[ ]: # ループ回数は 2000回 # バッチサイズは 100 # 200イテレーションごとに現在の精度を算出し出力 for i in range(1, 2001): batch_xs, batch_ys = mnist.train.next_batch(100) sess.run(train_step, feed_dict={x: batch_xs, d: batch_ys}) if i % 200 == 0: train_accuracy = sess.run(accuracy, feed_dict={x: batch_xs, d: batch_ys}) print(' step, accurary = %6d: %6.3f' % (i, train_accuracy)) # ### 4. 精度の確認 # テストデータを利用して精度の確認。 # In[ ]: print(sess.run(accuracy, feed_dict={x: mnist.test.images, d: mnist.test.labels})) # ↑だいたい0.96前後になる(と思われます)。 # ### 5. 推測結果の確認 # matplotlib が入っている場合、以下を実行して実際のデータと推測結果を確認してみる。 # In[ ]: get_ipython().run_line_magic('matplotlib', 'inline') # ↑Jupyter 上で実行するときに必要 import matplotlib import numpy as np import matplotlib.pyplot as plt import matplotlib.cm as cm import random # In[ ]: n = len(mnist.test.images) i = random.randrange(n) imageData = mnist.test.images[i] label = mnist.test.labels[i] result = sess.run(y, feed_dict={x: [imageData], d: [label]}) print("Classified as: %d" % np.argmax(result)) image = np.reshape(imageData, [28, 28]) plt.imshow(image, cmap = cm.Greys) # plt.show() # ↑Jupyter 以外では必要 # ## 発展 # ### さらなる精度向上のためにできること # + イテレーション回数を調整する # + TensorBoard を利用するか、自分で matplotlib を用いるなどして学習曲線を引く # + 層を増やしてみる(4層、5層、…) # + 各層のユニット数(サイズ)を変えてみる # + 学習係数を変更してみる # + 正則化項を追加してみる # + `tf.train.GradientDescentOptimizer` の代わりに、`tf.train.AdagradOptimizer` や `tf.train.MomentumOptimizer` を試してみる。 # + `optimizer = tf.train.MomentumOptimizer(0.1, 0.9)` とするだけでもかなり変わる(はず) # + **CNN に手を出してみる** # + 次回は↑をやる予定。 # In[ ]: