Kerasでモデルを学習させるときによく使われるのが、fitメソッドとfit_generatorメソッドだ。 各メソッドについて簡単に説明すると、fitは訓練用データを一括で与えると内部でbatch_size分に分割して学習してくれる。 それに対し、fit_generatorではbatch_size分のデータを生成するgeneratorを自分で作成して与える必要がある。 ミニバッチごとに入力の前処理をしたい場合なんかはfit_generatorを使うことになる。
本記事では、これらfitメソッドとfit_generatorメソッドを使って同じモデルを学習させ、学習時間を比較してみる。 なぜ比較するのかというと、「ひょっとして学習時間に差があるのでは?」と気になったからだ。 検証してはっきりさせておくことで、fitとfit_generatorの使い分けに役立てられればいいと思う。
検証は以下のように進める:
- LSTMによる文書分類モデルを構築
- fitとfit_generatorそれぞれで学習時間を計測
モデルの構築
まずは検証に使うモデルを構築する。 文書分類タスクとして、IMDBデータセットを使った評価分析を行うことにする。 また、モデルとしては単純なLSTMのネットワークを構築する。 モデルの構築について順をおって説明する。
まずは必要なモジュールをインポートする。 今回は単純なモデルなので、Functional APIではなくSequentialモデルでモデルを構築していく。 インポートのコードは以下の通り:
import numpy as np from keras.preprocessing import sequence from keras.models import Sequential from keras.layers import Dense, Embedding from keras.layers import LSTM from keras.datasets import imdb
インポートの次はハイパーパラメータを設定する。 今回は語彙数を20000語、文長は80に制限し、バッチサイズは32とした。 ハイパーパラメータの設定は以下の通り:
max_features = 20000 maxlen = 80 batch_size = 32
次に、データのロードと前処理を行う。 ロードしたデータはミニバッチ時に効率よく計算するためにpaddingして長さを揃える。 本来はfit_generatorに与えるgenerator内で前処理すべきだと思うが、今回はfitとfit_generatorの速度を比較したいため、予め前処理して条件を揃える。 コードは以下の通り:
(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=max_features) x_train = sequence.pad_sequences(x_train, maxlen=maxlen) x_test = sequence.pad_sequences(x_test, maxlen=maxlen)
いよいよモデルを構築する。先にも書いたように、今回は単純なモデルなのでSequentialモデルで構築する。 モデルのアーキテクチャは、分散表現をLSTMに入力し、LSTMの出力結果を全結合層に与えてneg/posの確率を出力するというものだ。 モデルを定義するコードは以下の通り:
model = Sequential() model.add(Embedding(max_features, 128)) model.add(LSTM(128, dropout=0.2, recurrent_dropout=0.2)) model.add(Dense(1, activation='sigmoid')) model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
ここまででデータの準備とモデルの構築は完了した。 次は学習を行っていく。
fitメソッドによる学習
いよいよfitメソッドを使って構築したモデルを学習させる。 コードは以下のように書ける:
model.fit(x_train, y_train,
batch_size=batch_size,
epochs=1,
validation_data=(x_test, y_test))
学習結果は以下の通り:
25000/25000 [==============================] - 329s - loss: 0.4559 - acc: 0.7876 - val_loss: 0.3681 - val_acc: 0.8416
学習は329秒で完了している。
fit_generatorメソッドによる学習
次にfit_generatorメソッドで学習を行う。 fit_generatorメソッドには、データを生成するジェネレータとステップ数を与える必要がある。 そのためのジェネレータとステップ数を生成するコードは以下の通り:
def batch_iter(data, labels, batch_size, shuffle=True): num_batches_per_epoch = int((len(data) - 1) / batch_size) + 1 def data_generator(): data_size = len(data) while True: # Shuffle the data at each epoch if shuffle: shuffle_indices = np.random.permutation(np.arange(data_size)) shuffled_data = data[shuffle_indices] shuffled_labels = labels[shuffle_indices] else: shuffled_data = data shuffled_labels = labels for batch_num in range(num_batches_per_epoch): start_index = batch_num * batch_size end_index = min((batch_num + 1) * batch_size, data_size) X = shuffled_data[start_index: end_index] y = shuffled_labels[start_index: end_index] yield X, y return num_batches_per_epoch, data_generator() train_steps, train_batches = batch_iter(x_train, y_train, batch_size) valid_steps, valid_batches = batch_iter(x_test, y_test, batch_size)
いよいよfit_generatorメソッドを使って構築したモデルを学習させる。 コードは以下のように書ける:
model.fit_generator(train_batches, train_steps,
epochs=1,
validation_data=valid_batches,
validation_steps=valid_steps)
学習結果は以下の通り:
782/782 [==============================] - 307s - loss: 0.4601 - acc: 0.7791 - val_loss: 0.3605 - val_acc: 0.8416
学習には307秒かかっている。
結論
fitの学習に329秒とfit_generatorの学習に307秒かかったので学習時間はほぼ同じという結果になった。 したがって、使い分けとしては、予め前処理しておける場合はfitを使い、ミニバッチごとに前処理したい場合はfit_generatorを使えば良さそう。