- Neural NetworkとTensorflowについて
- 画像の処理について
- CNNの学習(Keras)について
- CNNに学習させてモデルを保存する(今回記事)
- 保存した学習したモデルを使って予測を行う
- Google Colabについて
- AutoKerasについて
数字を認識するConvolutional Neural Network (CNN)をkerasで作っていきます。前回の記事では自分で用意した学習用の画像を、CNNに学習させるための形(numpy array)にしました。今回はいよいよCNNを学習させます。
学習させるところまでのコードは以下のように書きます。コードの下に解説を載せます。
# 1画像データの読み込み
import numpy as np
X_train =np.load("C:\\Users\\X_train.npy")
Y_train =np.load("C:\\Users\\Y_train.npy")
# 2tensorflowのsequentialモデルを作成する(起動する)
from tensorflow.keras.models import Sequential
model = Sequential()
# 3CNNの設計をする
from tensorflow.keras.layers import Conv2D,Activation, MaxPool2D, Flatten,Dropout,Dense
input = X_train[0].shape
model.add(Conv2D(filters=32,kernel_size=11,input_shape=input))
model.add(Activation('relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Conv2D(filters=64,kernel_size=3))
model.add(Activation('relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(units=514))
model.add(Activation('relu'))
model.add(Dropout(rate=0.1))
model.add(Dense(units=10))
model.add(Activation('softmax'))
model.compile(optimizer="adam", loss='categorical_crossentropy', metrics=["accuracy"])
model.summary()
# 4訓練させる
model.fit(x = X_train, y= Y_train,
epochs = 10,
validation_split=0.1,
batch_size=32)
# 5モデルを評価する
X_test =np.load("C:\\Users\\X_test.npy")
Y_test =np.load("C:\\Users\\Y_test.npy")
print(model.evaluate(X_test,Y_test))
# 6モデルを保存する
model.save("C:\\Users\\CNNmodel.h5")
1 画像データの読み込み
前回の記事で4つのnumpy array(訓練データ、訓練データの正解ラベル、テストデータ、テストデータの正解ラベル)を作成し保存しました。numpy arrayは、npyという拡張子で保存されています。それをnp.load()で読み込みます。モデルを学習させるため、訓練データと訓練データの正解ラベルが必要なので読み込みます。
2 Kerasのsequentialモデルを作成する(起動する)
sequentialオブジェクトを作成します。tensorflow内のkerasを起動するような感じです。現在、tensorflowの中にkerasが入っています。pip install tensorflowだけでkerasもついてきます。インターネットの記事を探していると、import keras.~~という書き方がありますが、kerasがtensorflowに組み込まれる前の書き方だと思います。また、keras単独でpip install することもできます。その場合は、tensorflowの中のkerasを使っているのではなく、kerasパッケージを使っています。
from tensorflow.keras.models import Sequential
model = Sequential()
これからmodelというオブジェクトに層を追加していきます。
3 CNNの設計をする
ここがキモです。まずこの書き方は、Sequential APIの書き方です。kerasの書き方は複数あり、一番簡単なのがSequential APIです。もうちょっと複雑なことをしたければ、Functional APIの書き方をします。複数の訓練済みモデルを平行に組み合わせたり、層の途中に分岐を作ったりと自由度が高まります。
基本的なCNNの構造
Conv2D → MaxPool → Conv2D → MaxPool → Flatten → Dense → Dense
これは、暗記です。これをベースに自分の好きな設計をして、最強モデルを作って下さい。まずは上記のモデルで試してみて、追加、削減しながら精度が上がるかを見ていくことになります。
このモデルは、網膜と脳の神経伝達経路を模倣したものです。Conv2D→MaxPoolは、目の網膜の光の受容体の働きを模しています。Denseは、脳のシナプス伝達の仕組みを模しています。
1つのシナプスをみると、前のシナプスから受け取った数値を、どれくらいの数値でかけて、どれくらいの数値を足して、次のシナプスに渡すかという数学的な問題と捉えることができます。
パラメーター1×前のシナプスから来た数値 + パラメーター2
予測値と正解が同じになるようにパラメータ1とパラメータ2を変化させていきます。
設計上のメモ
・Conv2D → Conv2D → MaxPoolもあり。
・Denseに入る前にFlattenしないとエラーになります。
コード解説
これから使う層をimportします。ここでimportしないとエラーになります。
from tensorflow.keras.layers import Conv2D,Activation, MaxPool2D, Flatten,Dropout,Dense
第1層に、CNNに読み込ませる訓練データの形を指定する必要があります。そのため、訓練データの形をあらかじめ変数に入れておきます。X_trainはの形は、(50000, 150, 300, 3)です。0軸は画像枚数、1軸は横アスペクト、2軸は縦アスペクト、3軸はBGR(RGB)の層です。3軸はグレースケールだと1になります。画像枚数はinputの形として必要ない情報なので、1軸、2軸、3軸だけを取り出します。
input = X_train[0].shape → (150, 300, 1)
1つづつ、訓練データ側からlayerを追加していきます。一番上の層には、input_shapeを指定します。まずはConvolution Layerを追加します。フィルターの枚数32,フィルターの大きさkernel_size = (11 , 11) は kernel_size = 11と同じです。input_shapeはさきほど作った変数を代入します。フィルターの枚数は2の倍数が慣習です。kernel_sizeは奇数じゃないと都合が悪いので奇数にしてください。
model.add(Conv2D(filters=32,
kernel_size=11,
input_shape=input))
アクティベーション関数を追加します。これは層というより、上の層の出力に活性化関数を指定しているイメージです。reluは、シナプスの発火を模した関数です。刺激の強さがある数値(0)を超えるまでは発火せず、数値を超えたら刺激の大きさと比例して発火の強さが大きくなります。
model.add(Activation(‘relu’))
次は、Maxpooling 層を追加します。これは、前の層から入ってきたピクセル値をpoolの中で最大値を抽出する層です。
model.add(MaxPool2D(pool_size=(2,2)))
もう1つ、Convolution Layer → Maxpooling layerを追加します。
model.add(Conv2D(filters=64,kernel_size=3))
model.add(Activation(‘relu’))
model.add(MaxPool2D(pool_size=(2,2)))
そろそろ画像の特徴を抽出できてきたころだと思います。次のDense layerにつなげるために、データを1列にします。Flatten layerで、1列にします。
model.add(Flatten())
Dense layerは、Fully connected layerとも呼ばれます。シナプスの刺激伝達経路を模しています。Denseのunits数は、シナプスの数です。activationは層ではなく、Dense層の出力方法を指定します。
model.add(Dense(units=514))
model.add(Activation(‘relu’))
Dropout層を追加してみました。これは、過学習を防ぐ目的です。ランダムに神経回路を遮断することで、特定のシナプスに頼ることなく全体で学習するように仕向けることができます。
model.add(Dropout(rate=0.1))
最後のDense層を追加します。ここは大事な層です。unitsの数は、分類するクラスの数にします。今回は10クラスの分類問題なので10にします。
model.add(Dense(units=10))
Dense層の活性化関数も大事です。最終層の活性化関数は、以下のように選択します。3クラス以上の分類をするのでsoftmaxを使用します。
Problem | 最終層 activation 関数 |
Regression | linear(マイナス数値あり) relu(マイナスはなくマイナス数値は0にする) |
Classification 2クラス | sigmoid |
Classification 3クラス以上 | softmax |
model.add(Activation(‘softmax’))
Tips
上記のモデルに、正規化BatchNormalization()をConv2DとActivationの間に、DenseとDenseの間に入れると良いかもしれません。
さて、CNNの設計図が完成しました。今度は、竣工に移ります。
model.compile()で、モデルを完成させます。この時のパラメーターで必要なのは、optimizerとlossとmetricsです。
model.compile(optimizer=”adam”, loss=’categorical_crossentropy’, metrics=[“accuracy”])
loss
CNNが予測した結果と正解がどれほど違うかという指標です。これらの指標が大きければ大きいほど、予測と正解が異なるということです。以下の表を参考にして下さい。
Problem | loss function |
Regression | mean_squared_error mean_absolute_error |
Classification 2クラス | binary_crossentropy |
Classification 3クラス以上 | categorical_crossentropy |
optimizer
lossを0にするために、CNN内のパラメーターを動かしていきます。Adadelta、Adagrad、Adam、Adamax、Ftrl、Nadam、RMSprop、SGD。どれを使うか指針はないようです。大文字小文字は関係ないです。このoptimizerを使って、パラメーターの移動方向を決めます。
metrics
モデルの評価の指標です。パラメーターの移動方向には一切使われません。最初、lossがあるのになぜmetricが必要なのかわかりませんでした。lossは直観的にはわかりにくいけど、optimizer的にはわかりやすい評価関数なんだと思います。lossは、正解に近づくにつれ下がっていきます。merticはaccuracyといったわかりやすいのが使われます。accuracyは、正解に近づくにつれ上がっていきます。
ちなみに、opitimizerの学習率(learning rate)を変更することもできます。以下のようにします。学習率を小さくすることで、パラメーターの動き方を小さくすることができます。
from tensorflow.keras.optimizers import Adam
adam = Adam(lr=0.001)
model.compile(optimizer=adam, loss=’categorical_crossentropy’, metrics=[“accuracy”])
最後は、モデルの形をみましょう。
model.summary()
Layer (type) | Output Shape | Param # |
conv2d (Conv2D) | (None, 140, 290, 32) | 11648 |
activation (Activation) | (None, 140, 290, 32) | 0 |
max_pooling2d (MaxPooling2D) | (None, 70, 145, 32) | 0 |
conv2d_1 (Conv2D) | (None, 68, 143, 64) | 18496 |
activation_1 (Activation) | (None, 68, 143, 64) | 0 |
max_pooling2d_1 (MaxPooling2D) | (None, 34, 71, 64) | 0 |
flatten (Flatten) | (None, 154496) | 0 |
dense (Dense) | (None, 514) | 79411458 |
activation_2 (Activation) | (None, 514) | 0 |
dropout (Dropout) | (None, 514) | 0 |
dense_1 (Dense) | (None, 10) | 5150 |
activation_3 (Activation) | (None, 10) | 0 |
Total params: 79,446,752
Trainable params: 79,446,752
Non-trainable params: 0
4 訓練させる
さきほどのCNNはmodelというオブジェクトに入っています。このmodelをつかってfitさせます。xは訓練データ、yは訓練の正解ラベル、validation_splitは訓練データの中で評価用にどれだけのデータを残しておきvalidationに使うか、epochsは何回訓練データを勉強させるか、batch_sizeは1回の訓練に扱う枚数です。
model.fit(x = X_train, y= Y_train,
validation_split=0.1,
epochs = 10,
batch_size=32)
batchsizeは慣習的に2の倍数を指定します。例えば、5000枚の訓練データがあるとします。validation_split=0.1を指定すると5000*0.1の500枚は訓練されません。4500枚で訓練します。バッチを32で指定すると4500÷32枚 ≒ 141グループできます。バッチを16枚と指定すると282グループできます。1グループ終わるごとに、パラメータの調整(back propagation)を行い学習していきます。
以下は、サンプル数5000、validation_split=0.1、バッチ32で指定したときの学習の様子です。fitを行うとコンソールにepochごとに結果が表示されます。
Epoch 2/10
141/141 [==========] – 17s 118ms/step – loss: 5.5452e-05 – accuracy: 1.0000 – val_loss: 1.2317e-05 – val_accuracy: 1.0000
141というのはグループ数です。lossとaccuracyは、訓練データ内の数値です。val_lossとval_accuracyは、訓練させずにとっておいたvalidationセットの数値です。epochは、全グループの学習が何回終わったかということです。
epoch数が上がるにつれ、val_lossが上がってくる場合(val_accuracyが下がる)には過学習の恐れがあります。
val_accuracyが全然上がらない。こういう症状がある場合には、1学習データがシャッフルされているか2モデルの設計がおかしくないかを確認してください。1学習データがシャッフルされていないと、バッチ内が全部同じラベルのデータなのでうまく学習できません。
5 モデルを評価する
訓練に使っていないデータを使って、モデルの性能を評価します。
X_test =np.load(“C:\\Users\\X_test.npy”)
Y_test =np.load(“C:\\Users\\Y_test.npy”)
print(model.evaluate(X_test,Y_test))
[0.0021925168111920357, 0.9993642568588257] のように、さきほど指定したlossとmetricの順に表示されます。今回は、categorical_crossentropy、accuracyということになります。
6モデルを保存する
モデルをh5形式で保存します。モデルを読み込むときは、このファイル1つだけを読み込めばいいです。
model.save(“C:\Users\CNNmodel.h5”)
(注)GPUを使おうと思っていない人は読み飛ばしてください
GPUを使う目的でNVIDIA GPU ドライバ、CUDAツールキット、cuDNN SDKをセットアップした後には、tensorflow-gpuを入れていない仮想環境でもtensorflowを実行すると以下のコードが必要になってしまいました。
参考:実行環境
・tensorflow-gpu 2.4.1
・CUDA Toolkit 11.2.1
・cuDNN v8.1.1
GPUを使うとき
from tensorflow.compat.v1 import ConfigProto
from tensorflow.compat.v1 import InteractiveSession
config = ConfigProto()
config.gpu_options.allow_growth = True
session = InteractiveSession(config=config)
CPUを使うとき
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
次は、モデルを読み込んで予想をします。
以下も参考にしてください。