iMind Developers Blog

iMind開発者ブログ

Tensorflow2.0 alphaのBEGINNER TUTORIALSを読む - その1

概要

Tensorflow2.0のalpha版が出ていたのでBIGGINER TUTORIALSを読む。

バージョン情報

  • tensorflow-gpu==2.0.0a0
  • Python 3.7.3

読んだページ

Get started with TensorFlow 2.0 for beginnersのクイックスタート服の分類問題回帰モデルの保存とリストアあたり。

環境構築

condaで仮想環境作ってそこにインストールしておく。pip, jupyter, matplotlib, pandas, scikit-learnは仮想環境でも使えるようにしておく。

$ conda create -n tensorflow2-alpha pip jupyter matplotlib pandas scikit-learn
$ source activate tensorflow2-alpha

tensorflow2 alphaのインストール。

# CPU版
$ pip install tensorflow==2.0.0-alpha0

# GPU版
$ pip install tensorflow-gpu==2.0.0-alpha0

GPU版はcudaのバージョンが10.0に上げないといけないので、試すだけならCPU版の方が良いかもしれない。

手書き文字の分類

手始めのMNIST手書き数字分類のところ。定番の分類問題をkerasで短手数でさらっと実行している。

まずはデータの読込み。

import tensorflow as tf
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()

trainデータは6万件で28×28。

x_train.shape
    #=> (60000, 28, 28)

テストデータは1万件。

x_test.shape
    #=> (10000, 28, 28)

28×28の値は0(黒)〜255(白)の間を取る。

0〜255の分布をヒストグラムで見るとこんな感じ。

from matplotlib import pylab as plt
plt.hist(x_train[0].flatten(), bins=25)

f:id:imind:20190506200950p:plain

だいたいが黒(背景)で、一部が白(数字の部分)という分布になっている。

実際に30枚を画像としてplotしてみる。

f, ax_list = plt.subplots(3, 10)
f.subplots_adjust(left=0, bottom=0.05, right=0.95, top=0.45, wspace=0.1, hspace=0.1)
for idx, img in enumerate(x_train[0:30]):
    ax = ax_list[int(idx / 10)][idx % 10]
    ax.tick_params(bottom=False, left=False, right=False, top=False)
    ax.set_xticklabels([]) 
    ax.set_yticklabels([]) 
    ax.imshow(img.reshape(28, 28), cmap=plt.cm.Greys_r)

f:id:mwsoft:20190427033229p:plain

0〜255のデータを0〜1に変換する。

x_train, x_test = x_train / 255.0, x_test / 255.0

modelの記述とfit / evaluate。Tensorflow1.0をそのまま使うケースと比べてかなり短い記述になっている。

# モデルの設定
model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Dense(10, activation='softmax')
])

# 学習
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])
model.fit(x_train, y_train, epochs=5)

# 評価
model.evaluate(x_test, y_test)

実行結果

Epoch 1/5
60000/60000 [==============================] - 2s 40us/sample - loss: 1.1932 - accuracy: 0.6968
Epoch 2/5
60000/60000 [==============================] - 2s 39us/sample - loss: 0.5224 - accuracy: 0.8565
Epoch 3/5
60000/60000 [==============================] - 2s 39us/sample - loss: 0.4080 - accuracy: 0.8847
Epoch 4/5
60000/60000 [==============================] - 2s 38us/sample - loss: 0.3622 - accuracy: 0.8959
Epoch 5/5
60000/60000 [==============================] - 2s 38us/sample - loss: 0.3323 - accuracy: 0.9042
10000/10000 [==============================] - 0s 25us/sample - loss: 0.2835 - accuracy: 0.9174

epochが5回なのでaccuracyは0.9174止まり。30回くらい回したら0.98まではいった。

出来上がったモデルを使って予測処理をしてみる。試しにtestデータ最初の10件で。

model.predict_classes(x_test[0:30])
    #=> array([7, 2, 1, 0, 4, 1, 4, 9, 5, 9, 0, 6, 9, 0, 1, 5, 9, 7, 3, 4])

実際の値画像。

f, ax_list = plt.subplots(2, 10)
f.subplots_adjust(left=0, bottom=0.05, right=0.95, top=0.35, wspace=0.1, hspace=0.1)
for idx, img in enumerate(x_test[0:20]):
    ax = ax_list[int(idx / 10)][idx % 10]
    ax.axis('off')
    ax.imshow(img.reshape(28, 28), cmap=plt.cm.Greys_r)

f:id:mwsoft:20190427033605p:plain

全部合ってる。簡易なモデルな割に優秀。

違っているものだけ抽出して表示してみる。

pred = model.predict_classes(x_test)
false_indices = pred != y_test
x_false = x_test[false_indices]
print('正解', y_test[false_indices][0:10])
print('予測', pred[false_indices][0:10])
f, ax_list = plt.subplots(1, 10)
f.subplots_adjust(left=0, bottom=0.05, right=0.95, top=0.35, wspace=0.1, hspace=0.1)
for idx, img in enumerate(x_false[0:10]):
    ax = ax_list[idx]
    ax.axis('off')
    ax.imshow(img.reshape(28, 28), cmap=plt.cm.Greys_r)

実行結果

正解 [4 2 5 6 3 8 2 7 8 0]
予測 [6 7 3 0 5 2 1 3 4 6]

f:id:mwsoft:20190427033712p:plain

人の目で見ても読みづらいものが多いけど、一応読めないこともないレベルの文字が並んでいる。

不正解データのprobabilityを出してみる。

import numpy as np
f, ax_list = plt.subplots(4, 3)
f.subplots_adjust(left=0, bottom=0.2, right=1.7, top=2.2, wspace=0.1, hspace=0.3)
probas = model.predict_proba(x_false[0:6])
for idx, img in enumerate(x_false[0:6]):
    ax = ax_list[int(idx / 3) * 2][idx % 3]
    ax.set_title(str(y_false[idx]))
    ax.axis('off')
    ax.imshow(img.reshape(28, 28), cmap=plt.cm.Greys_r)
    ax = ax_list[int(idx / 3) * 2 + 1][idx % 3]
    ax.set_yticklabels([]) 
    ax.bar(np.arange(10), probas[idx].flatten())

上が元画像、下がprobabilityの分布。

f:id:mwsoft:20190427034106p:plain

正解と不正解の答えの間で迷ったようなprobabilityがついていることを期待したが、そうした結果になっているのは下段中央(人の目で見ても5に見える)だけだった。

洋服の分類

続いてfashion MNISTデータを使った分類問題。

fashion_mnistのデータをロードする。

(x_train, y_train), (x_test, y_test) = tf.keras.datasets.fashion_mnist.load_data()

yに入っているラベルの紐付けは下記。

labels = {
    0: 'T-shirt/top',
    1: 'Trouser',
    2: 'Pullover',
    3: 'Dress',
    4: 'Coat',
    5: 'Sandal',
    6: 'Shirt',
    7: 'Sneaker',
    8: 'Bag',
    9: 'Ankle boot'
}

中に入っている画像データを見てみる。

from matplotlib import pylab as plt
f, ax_list = plt.subplots(3, 5)
f.subplots_adjust(left=0, bottom=0.05, right=1.5, top=1.5, wspace=0.1, hspace=0.1)
for idx, img in enumerate(x_train[0:15]):
    ax = ax_list[int(idx / 5)][idx % 5]
    ax.axis('off')
    ax.set_title(labels[y_train[idx]])
    ax.imshow(img.reshape(28, 28), cmap=plt.cm.Greys_r)

f:id:mwsoft:20190427131744p:plain

手書き数字とまったく同じコードで分類してみるepochsは50で。

x_train, x_test = x_train / 255.0, x_test / 255.0
model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Dense(10, activation='softmax')
])

model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.fit(x_train, y_train, epochs=50)
model.evaluate(x_test, y_test)
Epoch 1/50
60000/60000 [==============================] - 3s 45us/sample - loss: 0.5307 - accuracy: 0.8132
Epoch 2/50
60000/60000 [==============================] - 3s 42us/sample - loss: 0.4005 - accuracy: 0.8561
Epoch 3/50
60000/60000 [==============================] - 3s 43us/sample - loss: 0.3652 - accuracy: 0.8670
Epoch 4/50
60000/60000 [==============================] - 3s 46us/sample - loss: 0.3472 - accuracy: 0.8725
Epoch 5/50
60000/60000 [==============================] - 3s 43us/sample - loss: 0.3301 - accuracy: 0.8784

中略

Epoch 48/50
60000/60000 [==============================] - 3s 44us/sample - loss: 0.1757 - accuracy: 0.9326
Epoch 49/50
60000/60000 [==============================] - 3s 42us/sample - loss: 0.1761 - accuracy: 0.9321
Epoch 50/50
60000/60000 [==============================] - 3s 50us/sample - loss: 0.1717 - accuracy: 0.9327
10000/10000 [==============================] - 0s 28us/sample - loss: 0.4164 - accuracy: 0.8893

accuracy: 0.8893までいった。

ちゃんと実装すると93%くらいはすぐいくらしいので、下記URLを参考にCNNで実装してみる。

https://github.com/cmasch/zalando-fashion-mnist

# shapeを[28, 28]から[28, 28, 1]に
x_train = x_train.reshape([60000, 28, 28, 1])
x_test = x_test.reshape([10000, 28, 28, 1])

# CNNのモデルを生成
from tensorflow.keras import layers
model = tf.keras.models.Sequential([
    layers.Convolution2D(64, (4, 4), activation='relu', input_shape=(28, 28, 1)),
    layers.MaxPooling2D((2, 2)),
    layers.Dropout(0.1),
    layers.Convolution2D(64, (4, 4), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    layers.Dropout(0.3),
    layers.Flatten(),
    layers.Dense(256, activation='relu'),
    layers.Dropout(0.5),
    layers.Dense(64, activation='relu'),
    layers.BatchNormalization(),
    layers.Dense(10, activation='softmax')
])

model.summary()
Model: "sequential_24"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_43 (Conv2D)           (None, 25, 25, 64)        1088      
_________________________________________________________________
max_pooling2d_34 (MaxPooling (None, 12, 12, 64)        0         
_________________________________________________________________
dropout_24 (Dropout)         (None, 12, 12, 64)        0         
_________________________________________________________________
conv2d_44 (Conv2D)           (None, 9, 9, 64)          65600     
_________________________________________________________________
max_pooling2d_35 (MaxPooling (None, 4, 4, 64)          0         
_________________________________________________________________
dropout_25 (Dropout)         (None, 4, 4, 64)          0         
_________________________________________________________________
flatten_20 (Flatten)         (None, 1024)              0         
_________________________________________________________________
dense_49 (Dense)             (None, 256)               262400    
_________________________________________________________________
dropout_26 (Dropout)         (None, 256)               0         
_________________________________________________________________
dense_50 (Dense)             (None, 64)                16448     
_________________________________________________________________
batch_normalization_v2_20 (B (None, 64)                256       
_________________________________________________________________
dense_51 (Dense)             (None, 10)                650       
=================================================================

これで学習してみる。i7-8550UのCPUで学習した場合で1周35秒くらい。epchが50でおよそ30分。これの前に書いた簡易なモデルだと1周3秒なので10倍くらいの重さ。

とはいえこの程度ならCPU版でもなんとかなるしGPU使えばすぐ終わるレベル。

model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.fit(x_train, y_train, epochs=50)
model.evaluate(x_test, y_test)
Epoch 1/50
60000/60000 [==============================] - 34s 563us/sample - loss: 0.5737 - accuracy: 0.7923
Epoch 2/50
60000/60000 [==============================] - 34s 572us/sample - loss: 0.3969 - accuracy: 0.8558
Epoch 3/50
60000/60000 [==============================] - 36s 603us/sample - loss: 0.3554 - accuracy: 0.8675

中略

Epoch 48/50
60000/60000 [==============================] - 33s 547us/sample - loss: 0.1650 - accuracy: 0.9387
Epoch 49/50
60000/60000 [==============================] - 33s 551us/sample - loss: 0.1644 - accuracy: 0.9394
Epoch 50/50
60000/60000 [==============================] - 33s 548us/sample - loss: 0.1626 - accuracy: 0.9400
10000/10000 [==============================] - 1s 137us/sample - loss: 0.2410 - accuracy: 0.9179

0.9179までいった。

historyを見るとまだサチってはいなさそう。

plt.plot(history.history['accuracy'])

f:id:mwsoft:20190427160557p:plain

もう100回追加で学習してみたところ、0.9229まではいってほぼサチった。もうちょっと。

続く

長くなったのでその2に続く。

改定履歴

Author: Masato Watanabe, Date: 2019-05-06 記事投稿