TensorFlow MNISTの例題
    • PDF

    TensorFlow MNISTの例題

    • PDF

    Article Summary

    Classic/VPC環境で利用できます。

    TensorFlow MNIST の例題

    ここでは TensorFlow ホームページから提供するTensorFlow初級者のためのMNIST基礎例題及び専門家のためのMNIST上級例題を取り扱っています。

    MNIST データセットを利用してSoftmax回帰及びCNN分類モデルを作成してモデルがイメージデータを使用して数字をどれだけ上手く予測できるかというモデル性能を評価してみます。

    それぞれの概念や用語は例題コードを理解するにあたって必要なレベルで説明します。正確な理解のためにMachine Learning 及びDeep Learningについては別途学習が必要です。

    MNISTデータセットのご説明

    MNIST データセットは以下のように手書きの数字イメージをベクターで表示した imagesと、そのイメージが意味することを表すlabelsで成り立っています。下のイメージラベルはそれぞれ5, 0, 4, 1であり、ラベルは0~9まで10個の固有の値で成り立っています。

    tensorflow-1-3-101_ja.png

    MNISTデータセットはまた55,000個の学習データ(mnist.train), 10,000個のテストデータ(mnist.test), 5,000個の検証用データ(mnist.validation)で成り立っており、それぞれは上で説明したimagesとlabelsに分かれます。

    一つのイメージは28x28(=784)ピクセルであるため、これは784次元のベクターで保存されており、784次元には濃さの程度によって0~1の間の値が入っています。

    tensorflow-1-3-102_ja.png

    下のコードを通じてTensorFlowから提供するデータをダウンロードしてdataフォルダへ保存します。
    'one_hot=True' オプション(one hot encoding)を使用してlabelを0~9間の数字値1つで定義せず10次元ベクターで定義します。one hot encoding データについては以下の例題でもう一度ご説明します。

    """ TensorFlow パッケージ import : 今後 tfで使用します。 """
    import tensorflow as tf
    import numpy as np
    import matplotlib.pyplot as plt
    
    
    """ データダウンロード及びロード
    TensorFlowから提供する MNISTデータファイル4つをダウンロードしてdataフォルダに保存して読み取ります。
    最初に実行の際のみデータをダウンロードし、2回目からは保存されたデータを読み取るだけで済むので時間が短縮されます。"""
    from tensorflow.examples.tutorials.mnist import input_data
    %time mnist = input_data.read_data_sets("data/", one_hot=True)  # %timeを通じて全体の実行時間を残すことができます。
    
    Successfully downloaded train-images-idx3-ubyte.gz 9912422 bytes.
    Extracting data/train-images-idx3-ubyte.gz
    Successfully downloaded train-labels-idx1-ubyte.gz 28881 bytes.
    Extracting data/train-labels-idx1-ubyte.gz
    Successfully downloaded t10k-images-idx3-ubyte.gz 1648877 bytes.
    Extracting data/t10k-images-idx3-ubyte.gz
    Successfully downloaded t10k-labels-idx1-ubyte.gz 4542 bytes.
    Extracting data/t10k-labels-idx1-ubyte.gz
    CPU times: user 447 ms, sys: 454 ms, total: 901 ms
    Wall time: 36.1 s
    

    以下のコードを通じてデータを確認してみると、 imagesは28x28ピクセルを表示する784次元ベクターになっており、labelsは 'one_hot=True' オプション(one hot encoding)を使用してデータを読み取ったため '7'というレベルを '[ 0. 0. 0. 0. 0. 0. 0. 1. 0. 0.]'で表していることが確認できます。(0は[ 1. 0. 0. 0. 0. 0. 0. 0. 0. 0.], 1は[ 0. 1. 0. 0. 0. 0. 0. 0. 0. 0.], 2は [ 0. 0. 1. 0. 0. 0. 0. 0. 0. 0.]で表示).

    # images/labels データ構造の確認
    print 'train データセット(55,000件):', mnist.train.images.shape, mnist.train.labels.shape
    print 'test データセット(10,000件):', mnist.test.images.shape, mnist.test.labels.shape
    print 'validation データセット(5,000件):', mnist.validation.images.shape, mnist.validation.labels.shape
    
    # サンプルイメージデータの確認
    print '\nlabel :', mnist.train.labels[0]
    label = np.argmax(mnist.train.labels[0])  # 一番大きい値(つまり1がある所)
    
    im = np.reshape(mnist.train.images[0], [28,28])
    plt.imshow(im, cmap='Greys')
    plt.title('label:' + str(label))
    plt.show()
    
    train データセット(55,000件): (55000, 784) (55000, 10)
    test データセット(10,000件): (10000, 784) (10000, 10)
    validation データセント(5,000件): (5000, 784) (5000, 10)
    
    label: [ 0.  0.  0.  0.  0.  0.  0.  1.  0.  0.]
    

    回帰モデル

    この例題コードはTensorFlowからTensorFlow初級者のために提供するMNIST基礎例を取り扱っています。
    回帰モデルを作成して訓練させてからlabelを予測してモデルの正確度を確認してみます。

    Implementing the Regression

    イメージと正解レイブルを盛り込む placeholderと学習結果である荷重値(weight)とバイアス(bias)を盛り込むVariableを定義してSoftmax Regressionモデルを定義します。

    """ placeholder 定義 : データが入るところ所
    イメージと正解レイブル用の2次元tensorを作成する。
    Noneはどんなlengthも可能であることを意味する。 """
    # イメージデータ用 placeholder
    x = tf.placeholder(tf.float32, [None, 784])
    # 正解レイブル用 placeholder
    y_ = tf.placeholder(tf.float32, [None, 10])
    
    """ Variable 定義 : 学習結果が保存される荷重値(weight)とバイアス(bias) """
    # 0に初期化する
    W = tf.Variable(tf.zeros([784, 10])) # wは784次元のイメージベクターを掛けて、10次元(one hot encodingされた0~9)の結果を出すためのもの
    b = tf.Variable(tf.zeros([10]))      # bは結果に足すため10次元
    
    """ モデル定義 : Softmax Regression
    10個の値の中、最も確率の高いものを選ぶためSoftmaxを使用 """
    y = tf.nn.softmax(tf.matmul(x, W) + b)
    

    Training

    モデル訓練が必要なLoss 関数と学習率(Learning Rate)を定義して100個ずつサンプリングしてモデルを1000回学習させます。
    サンプリングのデータ数を増やすと正確度が高まりますが学習時間が増えます。
    ランダムにサンプリングした小さな配置で学習することをStochastic Trainingと言い、コストが安くて比較的似た結果を生み出すことができるため多く使われています。

    """ モデル訓練 """
    # Loss関数定義
    cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))
    # learning rateを0.5に定義
    train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
    
    # セッション開始前に全ての変数を初期化する
    init = tf.global_variables_initializer()
    
    sess = tf.Session()
    sess.run(init)
    
    # 100個ずつサンプリングして1000回学習を進める
    for i in range(1000):
        batch_xs, batch_ys = mnist.train.next_batch(100)  # 学習データセットから無作為でサンプリングした100個のデータで構成された'batch'を呼び出す
        sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})    # placeholder x, y_にサンプリングされたbatch_xs, batch_ysを供給する
    

    Evaluating Model

    tf.argmaxを通じて最も高い確率のlabelを探し
    tf.equalを通じて予測値(y)と正解(y_)が同じものを探すようにcorrect_predictionとaccuracy tensorを定義します。

    モデルを評価するためにtestデータを利用して正確度を確認します。
    以下では0.9163で約91%の正確度が確認されましたが、モデルを再度訓練させる度に結果が少しずつ異なってきます。

    """ モデル評価 """
    correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
    
    # 正確度
    print sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels})
    
    0.915
    
    # 分類結果の確認
    correct_vals = sess.run(correct_prediction,
                            feed_dict={x: mnist.test.images, y_: mnist.test.labels})
    pred_vals = sess.run(y, feed_dict={x: mnist.test.images} )
    
    print '全体のテストデータ', len(correct_vals), 'の中の正解数:', len(correct_vals[correct_vals == True]), \
          ', 不正解数:', len(correct_vals[correct_vals == False])
    
    
    # 正確に分類されたイメージ3つのみ確認
    fig = plt.figure(figsize=(10,3))
    img_cnt = 0
    for i, cv in enumerate(correct_vals):
        if cv==True:  # 正常分類
            img_cnt +=1
            ax = fig.add_subplot(1,3,img_cnt)
            im = np.reshape(mnist.test.images[i], [28,28])
            label = np.argmax(mnist.test.labels[i])
            pred_label = np.argmax(pred_vals[i])
            ax.imshow(im, cmap='Greys')
            ax.text(2, 2, 'true label=' + str(label) + ', pred label=' + str(pred_label))
    
        if img_cnt == 3:  # 3つのみ確認
            break
    plt.show()
    
    全体のテストデータ10000の中の正解数: 9150, 不正解数: 850
    
    # 誤って分類されたイメージ3つのみ確認
    fig = plt.figure(figsize=(10,3))
    img_cnt = 0
    for i, cv in enumerate(correct_vals):
        if cv==False:  # 誤った分類
            img_cnt +=1
            ax = fig.add_subplot(1,3,img_cnt)
            im = np.reshape(mnist.test.images[i], [28,28])
            label = np.argmax(mnist.test.labels[i])
            pred_label = np.argmax(pred_vals[i])
            ax.imshow(im, cmap='Greys')
            ax.text(2, 2, 'true label=' + str(label) + ', pred label=' + str(pred_label))
    
        if img_cnt == 3:  # 3つのみ確認
            break
    plt.show()
    
    # 実行が全て終わればSessionを閉じる
    sess.close()
    

    CNN モデル

    この例題コードはTensorFlowからTensorFlow専門家のために提供されるMNIST Deep Learningの上級例を取り扱っています。
    Deep Learningの一つであるCNN(Convolutional Neural Network)モデルを作成して訓練させてからlabelを予測してモデルの正確度を探ってみます。

    荷重値(weight)とバイアス(bias)の初期化

    対称性を破って gradientが0になるのを防ぐために若干のnoiseを与えて荷重値を初期化し、
    ReLU neuronを用いるので死んだニューロンになるのを防ぐためにバイアスを小さい正数値である0.1に初期化します。

    """ 荷重値の初期化 """
    def weight_variable(shape):
        initial = tf.truncated_normal(shape, stddev=0.1)
        return tf.Variable(initial)
    
    """ Biasの初期化 """
    def bias_variable(shape):
        initial = tf.constant(0.1, shape=shape)
        return tf.Variable(initial)
    

    ConvolutionとPoolingの定義

    以下のコードを通じて Convolution Layerのstrideを1に設定して、出力の大きさが入力と同じになるようにパディングを0に設定します。
    プーリングは2x2サイズのマックスプーリングを適用してstrideを2に設定します。

    """ Convolutionの定義 """
    def conv2d(x, W):
        return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
    
    """ Poolingの定義 """
    def max_pool_2x2(x):
        return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
    

    Convolutional Layerの定義

    以下のコードは28x28イメージが2回のConvolutional Layerを経てから7x7イメージに変わる姿を表示しています。

    つまり、28x28イメージが一番目のConvolutional Layer(5x5フィルタ、ストライド1)を経て24x24になり、一番目の Max Pooling上下左右のパディング後28x28, ストライド2を経て14x14になります。

    また二番目のConvolutional Layer(5x5フィルタ、ストライド1)を経て10x10になり、
    二番目のMax Pooling上下左右パディング後14x14, ストライド2を経て7x7になります。

    # 入力データを 4D テンソルに再定義
    # 二番目/三番目パラメータはイメージの横/縦長さ
    # 最後のパラメータカラーチャンネル数は白黒イメージであるため1である
    x_image = tf.reshape(x, [-1,28,28,1])
    
    """ First Convolutional Layerの定義 """
    # 荷重値テンソルの定義(patch size, patch size, input channel, output channel).
    # 5x5のウィンドウ(patchとも言う)サイズを持つ32個のfeature(kernel, filter)を使用
    # 白黒イメージであるためinput channelは1である
    W_conv1 = weight_variable([5, 5, 1, 32])
    # バイアステンソルの定義
    b_conv1 = bias_variable([32])
    # x_imageと荷重値テンソルに畳み込みを適用して、バイアスを足した後、ReLU関数を適用
    h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
    # 出力値を探すためのマックスプーリングを適用
    h_pool1 = max_pool_2x2(h_conv1)
    
    """ Second Convolutional Layerの定義 """
    # 荷重値テンソルの定義(patch size, patch size, input channel, output channel)
    # 5x5のウィンドウ(patchとも言う)サイズを持つ64個のfeatureを使用
    # 以前のレイヤーのoutput channelのサイズ32がここではinput channelになる
    W_conv2 = weight_variable([5, 5, 32, 64])
    # バイアステンソルの定義
    b_conv2 = bias_variable([64])
    # First Convolutional Layerの出力値であるh_pool1と荷重値テンソルの畳み込みを適用して、バイアスを足した後ReLU関数を適用
    h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
    # 出力値を探すためのマックスプーリングを適用
    h_pool2 = max_pool_2x2(h_conv2)
    
    """ 完全連結レイヤー(Fully-Connected Layer)の定義 """
    #  7×7サイズの64このフィルタ、任意に選択したニューロンの個数(ここでは1024)
    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)
    
    """ Dropoutの定義 """
    keep_prob = tf.placeholder(tf.float32)
    h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
    
    """ 最終ソフトマックス階層の定義 """
    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)
    

    モデルの訓練及び評価

    以下のコードを通じてモデルを訓練させ、その正確度を評価してみると一番目の回帰モデルより正確度が高いことが確認できます。

    TensorBoardを確認するためにはウェブブラウザを開いて [パブリックIPアドレス:18888]でアクセスしてください。
    アクセスできない場合はターミナルサーバに接続して 'jup tb-start' 命令語でTensorBoardプロセスを始めてください('TensorBoardプロセㇲの管理' を参照)。

    # モデルの訓練及び評価
    cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y_conv), reduction_indices=[1]))
    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, tf.float32))
    
    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
    
        # 100個ずつサンプリングして2000回学習を進める
        for i in range(2000):
            batch = mnist.train.next_batch(100)
            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})
    
    step 0, training accuracy 0.17
    step 100, training accuracy 0.81
    step 200, training accuracy 0.93
    step 300, training accuracy 0.89
    step 400, training accuracy 0.92
    step 500, training accuracy 0.95
    step 600, training accuracy 0.99
    step 700, training accuracy 0.98
    step 800, training accuracy 0.93
    step 900, training accuracy 0.94
    step 1000, training accuracy 0.97
    step 1100, training accuracy 0.95
    step 1200, training accuracy 0.97
    step 1300, training accuracy 0.99
    step 1400, training accuracy 0.95
    step 1500, training accuracy 0.98
    step 1600, training accuracy 0.97
    step 1700, training accuracy 0.96
    step 1800, training accuracy 0.98
    step 1900, training accuracy 0.97
    test accuracy 0.9795
    

    この記事は役に立ちましたか?

    Changing your password will log you out immediately. Use the new password to log back in.
    First name must have atleast 2 characters. Numbers and special characters are not allowed.
    Last name must have atleast 1 characters. Numbers and special characters are not allowed.
    Enter a valid email
    Enter a valid password
    Your profile has been successfully updated.