#この記事でやること
ディープラーニングでは、使用するバックエンドによって実装手順がことなる。そのため、公式のドキュメントを読み込んだり、解説している参考書などを参照しながら使い方を学んでいく。この記事ではその使い方の流れを説明している。
#kerasを使った場合の実装手順
##1.訓練データを定義する
##2.入力値を目的値にマッピングする複数の層からなるネットワークを定義する。
##3.損失関数、オプティマイザ、監視する指標を選択することで学習プロセスを設定する。
##4.モデルのfitメソッドを呼び出すことで、訓練データを繰り返し学習する。
#kerasのpython環境の構築
anaconda上に新しい仮想環境を作り、tensorflow及びkerasをインストールする。今後は作った環境の上で実行していく。anaconda prompt上で以下を実行する。
conda create -n keras_env python=3.6 #仮想環境の作成
conda activate keras_env #環境の切り替え
conda install tensorflow==1.12.0
conda isntall keras==2.2.4
#具体的な手順
##データセットの読み込み
from keras.datasets import imdb
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)
##データの前処理
###データのベクトル化
ニューラルネットワークの入力値と目的値はすべて浮動小数点のデータのテンソルでなければならない。音声、画像、テキストなど、処理しなければならないデータがどのようなものであったとしても、まずそれらをテンソルに変換する必要がある。
クラス分類のラベルをベクトル化するにはone-hotエンコーディング**を行う。
from keras.utils.np_utils import to_categorical
one_hot_train_labels = to_categorical(train_labels)
one_hot_test_labels = to_categorical(test_labels)
###データの正規化
画像データは0~255の範囲のグレースケール値を表す整数としてエンコードされている。このデータをニューラルネットワークに供給するためには、float32型でキャストしてから255で割ることで0~1の範囲の浮動小数点に変換する。
ネットワークに範囲の異なる特徴量を供給するのはどう考えても問題である。そこで範囲を同じにするために正規化を行う。特徴量の平均値を引き、標準偏差で割るという処理を行う。そうすると、特徴量の中心が0になり、標準偏差が1になる。
##モデルの定義
各層ごとに活性化関数とニューロン数を設定する。順伝播させたい順にadd()
で追加していけば良い。
from keras import models
from keras import layers
model = models.Sequential()
model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(16, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
model.add(Dense(200))
model.add(Activation("relu"))
##モデルのコンパイル
**オプティマイザと損失関数を選択する。**以下の場合は文字列で指定しているが、これが可能なのはkerasの一部としてパッケージ化されているためである。
model.compile(optimizer='rmsprop',#文字指定
loss='binary_crossentropy',
metrics=['accuracy'])
オプティマイザのパラメータ引数を指定したい場合は以下のようにオプティマイザクラスのインスタンスを指定して、メソッドを呼び出す。
from keras import optimizers
model.compile(optimizer=optimizers.RMSprop(lr=0.001),#メソッド指定
loss='binary_crossentropy',
metrics=['accuracy'])
独自の損失関数や指標関数を使用したい場合は、lossパラメータか、metricsパラメータに引数として関数オブジェクトを指定する。
from keras import losses
from keras import metrics
model.compile(optimizer=optimizers.RMSprop(lr=0.001),
loss=losses.binary_crossentropy,
metrics=[metrics.binary_accuracy])
##検証データセット(validating data set)の設定
全く新しいデータでモデルを訓練するときに正解率を監視するには、もとの訓練データセットから取り分けておいたサンプルを使って検証データセットを作成する。以下では10000個のサンプルを取り出す場合。
x_val = x_train[:10000] #検証データの取り出し
partial_x_train = x_train[10000:] #
y_val = y_train[:10000] #正解検証データの取り出し
partial_y_train = y_train[10000:]
###k分割交差検証
データの数が少ないと検証データはかなり小さなものになってしまう。結果として、検証と訓練にどのデータ点を選択したかによって検証スコアが大きく変化することになるかもしれない。つまり、検証データセットの分割方法によっては、検証スコアの分散が高くなり、過学習に陥ってしまう。それを防ぐ最適な方法がk分割交差検証である。詳しくは説明しないので、調べてみてほしい。
##モデルの訓練
8のミニバッチで20エポックの訓練を行う。xは訓練データyは正解データであることが多い。
取り分けておいた10000サンプルでの損失値と正解率を監視する。検証データはvalidation_dataパラメータに引数として渡す。
history = model.fit(partial_x_train,
partial_y_train,
epochs=20,
batch_size=8,
validation_data=(x_val, y_val))
fitメソッドは1エポックごとに訓練した出力と、検証データの出力を辞書型で返す。今回はhistory
オブジェクトに保存している。以下のコードを実行すると
history_dict = history.history
history_dict.keys()
dict_keys(['val_acc', 'acc', 'val_loss', 'loss'])
となる。
##訓練データと検証データでの損失値をプロット
損失値をmatplotlibを使ってプロットする。history
オブジェクトに訓練の記録がされているのでここから呼び出す。この結果を元にしてハイパーパラメータを調整する。
import matplotlib.pyplot as plt
acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(1, len(acc) + 1)
# "bo" is for "blue dot"
plt.plot(epochs, loss, 'bo', label='Training loss')
# b is for "solid blue line"
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()
#CNNで画像認識する場合の手順
##画像のコピー
訓練画像(train)を保存するフォルダと検証画像(validation)を保存するフォルダを作り、学習に使うために集めた画像をコピーして振り分ける。検証データの画像枚数はかんで決めるが、だいたい全画像数のの20%~40%で調整するといいだろう。後の前処理の工程で出てくるflow_from_directory()
のフォルダパスにここで作ったフォルダのパスを指定する。
##CNNのインスタンス化
from keras import layers
from keras import models
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(Dense(2))
model.add(Activation("softmax"))
CNNの入力テンソルの形状は(image_height,image_width,image_channels)だ。第3引数は画像のチャンネル数である。RGB画像の場合はチャンネル数が3になる。
Conv2D(出力特徴の深さ,フィルタサイズ)
padding='same'
の引数を指定すると出力の幅と高さが入力と同じになるようにパディングする。
ちなみにmodel.summary()
で作成したモデルを確認できる。
画像分類の場合、最終層はDense
(全結合層)にし、引数には分類するクラス数を指定する。出力は判定の確率になるので損失関数はsoftmaxを選択する。
#モデルのコンパイル
損失関数とオプティマイザの設定。
from keras import optimizers
model.compile(loss='binary_crossentropy',
optimizer=optimizers.RMSprop(lr=1e-4),
metrics=['acc'])
##データの前処理
データをCNNに供給するには、その前に浮動小数点型のテンソルとして適切に処理しておく必要がある。手順は以下の通り、
1.画像ファイルを読み込む
2.JPEGファイルの内容をRGBのピクセルグリッドにデコードする。
3.これらのピクセルを浮動小数点型のテンソルに変換する。
4.ピクセル(0~255)の尺度に取り直し、[0,1]の範囲の値にする。
kerasには、上記の手順を自動的に処理するユーティリティが用意されている。ImageDataGenerator
クラスを利用すれば、ディスク上の画像ファイルを前処理されたテンソルのバッチに自動的に変換できるpythonジェネレータをセットできる。
ImageDataGeneratorを使ってディレクトリから画像を読み込む
from keras.preprocessing.image import ImageDataGenerator
# All images will be rescaled by 1./255
train_datagen = ImageDataGenerator(rescale=1./255)
test_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
# This is the target directory
train_dir,
# All images will be resized to 150x150
target_size=(150, 150),
batch_size=20,
# Since we use binary_crossentropy loss, we need binary labels
class_mode='binary')
validation_generator = test_datagen.flow_from_directory(
validation_dir,
target_size=(150, 150),
batch_size=20,
class_mode='binary')
##モデルの訓練
モデルを訓練させるにはfit_generator()
関数を利用する。
steps_per_epoch
は1エポックで進行するステップ数。validation_steps
は1エポックの中で何枚ずつ画像を検証するかを表す。
history = model.fit_generator(
train_generator,
steps_per_epoch=10,
epochs=30,
validation_data=validation_generator,
validation_steps=5)
##ネットワークの保存
訓練を終えたネットワークのパラメータを保存するにはsave()
関数を利用する。kerasでは.h5
という拡張子のファイルで保存される。h5ファイルを呼び出せば次回以降はこのパラメータで画像の予測をさせることができる。
model.save('cats_and_dogs_small_1.h5')
##正解率のプロット
import matplotlib.pyplot as plt
acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(len(acc))
plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()
plt.figure()
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()
##保存したネットワークでの推定
model = models.Sequential()
にしていた部分を以下のように変えるだけ。load_model
の引数には保存したネットワークファイルのパスを指定する。
学習済みネットワークを使うので、学習のときにあったadd()
系は不要。学習したモデルがそのまま読み込まれる。
model=keras.models.load_model('cats_and_dogs_small_1.h5')
#参考
https://qiita.com/GushiSnow/items/8c946208de0d6a4e31e7#%E5%85%B7%E4%BD%93%E7%9A%84%E3%81%AA%E5%AE%9F%E8%A3%85%E4%BE%8B
https://qiita.com/tsunaki/items/608ff3cd941d82cd656b
https://qiita.com/tomo_20180402/items/e8c55bdca648f4877188
https://ymgsapo.com/2019/02/28/keras-dog-and-cat/