近年、注目を浴びているディープラーニングや画像認識。
テレビやネットなどでも、大きく取り扱われています。
しかし、
「CNNってなに?」
「画像認識をやりたいけどどうすればいいのか分からない」
と、分からないことだらけですよね。
ということでこの記事では、CNN(Convolutional Neural Network、畳込みニューラルネットワーク)を使って画像認識(画像分類)のハンズオンをします。
CNNは畳み込み層とプーリング層という、いうなれば画像処理に特化したレイヤーを持っています。
CNNの画像処理における優位性は未だに並び立つものがなく、CNNベースの様々なアルゴリズムが発表されています。
まずはCNNの基礎的な実装を覚えて、ディープラーニングに入門しましょう!
この記事の内容
- CNNとは?
- CNNのTensorflow/Keras実装
- CNNを使った画像分類問題に挑戦
※この記事のコードは、Ubuntu 18.04、Python 3.6.7、TensorFlow 1.12.0で動作を確かめました。
CNNとは
CNNとは、畳み込み層とプーリング層という二つの特殊なレイヤーを持ったニューラルネットワークです。
CNNのイメージ図:http://nkdkccmbr.hateblo.jp/entry/2016/10/06/222245より
CNNの具体的な解説については、他の記事で紹介したいと思っています。
CNNの解説については、以下のスライドがおすすめです。
また、CNNのより実用的な知識が書かれているスライドとしては以下の記事がおすすめです。
そして最後に、最新の研究動向がまとめられたスライドです。
Tensorflow/KerasによるTensorflowの実装
ライブラリのimport
まずはライブラリをimportしましょう。
import tensorflow as tf from tensorflow import keras import numpy as np import matplotlib.pyplot as plt
importしたライブラリは以下の通りです。
- tensorflow (version 1.12.0)
- 深層学習でGPUを簡単に使うことができる行列計算ライブラリ
- tensorflow.keras
- tensorflowの上位ラッパー
- よりニューラルネットワークの実装の際に便利な機能がまとめられたライブラリ
- numpy
- CPUでの行列計算ライブラリ
- Pythonで科学計算を行うならほぼ必ず必要になる
- matplotlib
- Pythonのデファクトスタンダードな可視化ライブラリ
データの読み込み
kerasのdatasetsモジュールを使って深層学習で使うデータセットをダウンロードします。
(train_images, train_labels), (test_images, test_labels) = keras.datasets.fashion_mnist.load_data()
使い方はsklearnと同様なので簡単ですね。
この関数で読み込めるものは以下の4つです。
- 教師データ
- 教師ラベル
- テストデータ
- テストラベル
また、クラスの名前は以下のリストをみてください。
ラベルはone hot表現にしたいので、kerasのto_categorical関数を使いましょう。
class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot'] train_labels_onehot = keras.utils.to_categorical(train_labels, 10) test_labels_onehot = keras.utils.to_categorical(test_labels, 10)
ちなみに……
one hot表現とは、
「あるデータのクラスが1でクラスが全部で5個ある場合、[0,1,0,0,0]」
「あるデータのクラスが3でクラスが全部で5個ある場合、[0,0,0,1,0]」
のように表現する方法です。
次に、データのスケールを0~1の範囲に直すために、255で割ります。
(8bitカラーなら2**8で256階調なので、0スタートで255までのため)
train_images = train_images.astype("float32") / 255.0 test_images = test_images.astype("float32") / 255.0
データの可視化
ここまででデータの準備ができたので、実際に分類する画像を表示してみてみましょう。
plt.figure(figsize=(10,10)) for i in range(25): plt.subplot(5,5,i+1) plt.xticks([]) plt.yticks([]) plt.imshow(train_images[i], cmap=plt.cm.binary) plt.xlabel(class_names[train_labels[i]])
教師データとそれに対応するラベルを25個表示してみました。
似たような画像ファイルがテストデータにも入っているので、画像ファイルからラベルを予測していきます。
CNNのモデル構築
画像分類を行うCNNを実装します。
model = keras.Sequential([ keras.layers.Conv2D(filters=64, kernel_size=2, padding="same", activation="relu", input_shape=(28,28,1)), keras.layers.MaxPooling2D(pool_size=(2,2)), keras.layers.Dropout(0.3), keras.layers.Conv2D(filters=32, kernel_size=2, padding="same", activation="relu"), keras.layers.MaxPooling2D(pool_size=(2,2)), keras.layers.Dropout(0.3), keras.layers.Flatten(), keras.layers.Dense(256, activation="relu"), keras.layers.Dropout(0.5), keras.layers.Dense(10, activation="softmax") ])
kerasのニューラルネットワークは、keras.Sequentialにリスト形式でレイヤーを追加していくことで実装ができます。
kerasのレイヤを構成するクラスはすべてlayersの下にあるので、そこから選んで使いましょう。
- Conv2D
- 畳込み層
- 特徴量の畳み込みを行う
- MaxPooling2D
- マックスプーリング
- レイヤーを縮小して使いやすくする
- Dropout
- ドロップアウト
- ネットワークの結合を削って過学習を防ぐ
- Flatten
- 8×8の二次元配列を64要素の一次元配列に直す
- (あんまりニューラルネット関係なし)
- Dense
- 全結合層
- t層目のすべてのニューロンがt+1層目のすべてのニューロンに繋がっているレイヤ
フィルタサイズ、カーネルサイズ、paddingの設定などがCNNで大切になる部分です。
これらについては最初に貼ったスライドなどでCNNの仕組みを覚えてから設定してください。
わからなければこの値のままで。
model.compile(optimizer=tf.train.AdamOptimizer(), loss='categorical_crossentropy', metrics=["accuracy"])
kerasで作ったモデル(素のtesnorflowで作ったモデルも)はコンパイルという作業が必要になります。
この際に、以下のような設定をします。
- オプティマイザ(optimizer)
- ニューラルネットの学習を効率的に行ってくれるものです
- SGD
- Adam
- 他にもたくさん
- 損失関数(loss)
- ニューラルネットの学習の際に、この関数の値を小さくするようにパラメータを調整します
- タスクによって損失関数は変わります
- categorical_crossentropy
- binary_crossentropy
- 他にもたくさん
- メトリクス(metrix)
- 学習の監視に使う関数です。
- あくまでも監視なので、この関数が学習には影響しません。
CNNの学習学習
学習はfitメソッドを使って行います(sklearnっぽいですね)。
教師データ、教師ラベル、epoch数、batch_sizeなどの基本的な設定をして関数を実行してください。
モニタリング用のログが表示されながら学習の様子が表示され始めます。
model.fit( train_images[:,:,:,None], train_labels_onehot, epochs=20, batch_size=64, )
[学習中のログ]
Epoch 1/20 60000/60000 [==============================] - 6s 102us/step - loss: 0.5929 - acc: 0.7817 Epoch 2/20 60000/60000 [==============================] - 4s 74us/step - loss: 0.4117 - acc: 0.8512 Epoch 3/20 60000/60000 [==============================] - 4s 74us/step - loss: 0.3738 - acc: 0.8640 Epoch 4/20 60000/60000 [==============================] - 4s 74us/step - loss: 0.3410 - acc: 0.8751 Epoch 5/20 60000/60000 [==============================] - 4s 74us/step - loss: 0.3228 - acc: 0.8818 Epoch 6/20 60000/60000 [==============================] - 4s 74us/step - loss: 0.3085 - acc: 0.8863 Epoch 7/20 60000/60000 [==============================] - 4s 74us/step - loss: 0.2965 - acc: 0.8900 Epoch 8/20 60000/60000 [==============================] - 4s 74us/step - loss: 0.2847 - acc: 0.8951 Epoch 9/20 60000/60000 [==============================] - 4s 74us/step - loss: 0.2778 - acc: 0.8985 Epoch 10/20 60000/60000 [==============================] - 4s 74us/step - loss: 0.2674 - acc: 0.9015 Epoch 11/20 60000/60000 [==============================] - 4s 74us/step - loss: 0.2603 - acc: 0.9039 Epoch 12/20 60000/60000 [==============================] - 4s 74us/step - loss: 0.2563 - acc: 0.9045 Epoch 13/20 60000/60000 [==============================] - 4s 74us/step - loss: 0.2471 - acc: 0.9092 Epoch 14/20 60000/60000 [==============================] - 4s 74us/step - loss: 0.2441 - acc: 0.9086 Epoch 15/20 60000/60000 [==============================] - 4s 74us/step - loss: 0.2402 - acc: 0.9117 Epoch 16/20 60000/60000 [==============================] - 4s 74us/step - loss: 0.2337 - acc: 0.9113 Epoch 17/20 60000/60000 [==============================] - 4s 74us/step - loss: 0.2287 - acc: 0.9139 Epoch 18/20 60000/60000 [==============================] - 4s 74us/step - loss: 0.2286 - acc: 0.9150 Epoch 19/20 60000/60000 [==============================] - 4s 74us/step - loss: 0.2244 - acc: 0.9161 Epoch 20/20 60000/60000 [==============================] - 4s 74us/step - loss: 0.2202 - acc: 0.9180 <tensorflow.python.keras.callbacks.History at 0x7f4a2ffd9278>
教師データの正答率は91パーセプトロンくらいまで上がっていますね。
結果の確認
以上で学習は終わりましたが、実際にクラス分類を行ったのでその精度を見てみましょう。
テストデータに対して予測ラベルを出すには、predictメソッドを使います。
labels = model.predict(test_images[:,:,:,None])
また、評価にはevaluateメソッドを使います。
score = model.evaluate(test_images[:,:,:,None], test_labels_onehot) # scoreの値は [3.6148554523468017, 0.7712]でした。
scoreはリストになっていて、ここでは1つ目がloss、2つ目がaccでした。
そして最後にテストデータと予測ラベルを表示してみましょう。
正解を緑色に、不正解を赤色にします。
figure = plt.figure(figsize=(20, 8)) for i, index in enumerate(np.random.choice(test_images.shape[0], size=15, replace=False)): ax = figure.add_subplot(3, 5, i + 1, xticks=[], yticks=[]) ax.imshow(np.squeeze(test_images[index])) predict_index = np.argmax(labels[index]) true_index = np.argmax(test_labels_onehot[index]) ax.set_title("{} ({})".format(class_names[predict_index], class_names[true_index]), color=("green" if predict_index == true_index else "red"))
最後に
この記事ではCNNを使った画像認識として画像分類タスクを解いてみました。
CNNはDeep Learningの中でもホットなアルゴリズムです。
是非覚えてDeep Learningの最新動向を追いかけましょう!