Kerasが2.0にアップデートされました。
Python向けディープラーニング・フレームワークのKerasが2.0にアップデートしました。
https://blog.keras.io/introducing-keras-2.html
今回は2.0のアップデート情報と、プログラムの書き方の変更箇所をおおまかにまとめていきます。
加えてKeras1.2とKeras2.0の違いをCifar10で比較してみたいと思います。
アップデートによる変更箇所
変更内容を掻い摘んで訳していきます。
即興で意訳してます、間違いが合ったらご指摘くださいm(_ _)m。
TensorFlow連携
KerasのバックエンドとしてTensorFlowを2015年12月からサポートしていましたが、TensorFlowのコードベースからKeras APIは隔離していました。
Keras2.0ではTensorFlow1.2ベースで直接呼び出し可能なAPIを提供します。
加えて2つの実装を提供します。
- internal backendとして、TensorFlowと機能互換なtf.kerasを提供。TensorFlowで書かれている。
- external backendとして、TheanoやTensorFlowをサポート。
そして将来的にはより多くのバックエンドをサポート。
さらにはScalaやJavaScriptからKeras APIを呼び出す開発も進んでいます。
ScalNet: https://github.com/deeplearning4j/ScalNet
Keras.js: https://github.com/transcranial/keras-js
Kerasはディープラーニング・フレームワークのリンガ・フランカ(共通語)になることを目指しているようですね。
APIの変更
Keras2.0 APIを主流とし、コードベースKerasも同様にサポートしていくため、API仕様を大幅に変更しました。
- Layer APIの変更:Dense、BatchNormalization、Convolution系のAPIに変更を加えました。ただし、Keras1.xのプログラムもKeras2.0で引き続き動作するよう、互換性を持たせています。なお、Keras2.0でKeras1.xプログラムを実行すると、Warningが出ます。
- Training、Evaluation系APIの変更:たとえばfit_generator, predict_generator, evaluate_generatorが変更されていますが、Keras1.xプログラムも引き続きKeras2.0で動作します。
- fitのnb_epochはepochsに変更されました。
- ファイルに保存されたweightのフォーマットの変更:Keras1.xも以下略
- objectivesモジュールはlossesに名称変更
というわけで、Keras1.xプログラムも引き続きKeras2.0で動くようです。ご安心ください。
根本的な変更~Breaking Changes~
上記の通りKeras1.xの互換性を保とうとしましたが、どうしても大きく変えなければならない箇所もあったようです。
- MaxoutDense, TimeDistributedDense, Highwayは終焉。
- メトリック、損失関数ファンクションの多くを終焉。
- BatchNormalizationからmodeの削除。
- Kerasの内部実装を変更したため、カスタム・レイヤーも修正する必要があります。比較的少ない変更なので、以下を参考に修正してください。
https://keras.io/layers/writing-your-own-keras-layers/ - Kerasドキュメント未記載(=未サポート?)のコードは動かなくなる可能性があります。
変更の詳細
より詳しい変更は以下リリース・ノートまとまっています。
https://github.com/fchollet/keras/wiki/Keras-2.0-release-notes
Keras1.xモジュールのKeras2.0変更対応一覧になっています。
便利です。
Keras2.0の導入方法
pip installでインストールできるKerasは2.0になっています。
既にKerasを使っていて2.0へのアップデートをしたい場合は以下でOKです。
pip install keras --upgrade
Cifar10 at Keras2.0
Keras1.2で書いたCifar10のCNNをKeras2.0版に書き換えてみました。
まず、Keras1.2版のCifar10です。
# coding: utf-8
import keras
from keras.datasets import cifar10
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Convolution2D, MaxPooling2D
from keras.utils import np_utils
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
y_train = np_utils.to_categorical(y_train, 10)
y_test = np_utils.to_categorical(y_test, 10)
model = Sequential()
model.add(Convolution2D(32, 3, 3, border_mode='same', input_shape=x_train.shape[1:]))
model.add(Activation('relu'))
model.add(Convolution2D(32, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Convolution2D(64, 3, 3, border_mode='same'))
model.add(Activation('relu'))
model.add(Convolution2D(64, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(512))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(10))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
model.summary()
model.fit(x_train, y_train, batch_size=100, nb_epoch=25, validation_split=0.1)
score = model.evaluate(x_test, y_test)
print('Test loss:', score[0])
print('Test accuracy:', score[1])
続いて、Keras2.0版のCifar10です。
# coding: utf-8
import keras
from keras.datasets import cifar10
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras.utils import np_utils
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
y_train = np_utils.to_categorical(y_train, 10)
y_test = np_utils.to_categorical(y_test, 10)
model = Sequential()
model.add(Conv2D(32, (3, 3), padding="same", input_shape=x_train.shape[1:]))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Conv2D(64, (3, 3), padding='same'))
model.add(Activation('relu'))
model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(512))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(10))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
model.summary()
model.fit(x_train, y_train, batch_size=100, epochs=25, validation_split=0.1)
score = model.evaluate(x_test, y_test)
print('Test loss:', score[0])
print('Test accuracy:', score[1])
間違い探しか?ってくらい、ほとんど何も変わっているように見えませんね。
具体的な変更箇所は以下です。
Convolution2D → Conv2D
# Keras1.x
from keras.layers import Convolution2D, MaxPooling2D
# Keras2.0
from keras.layers import Conv2D, MaxPooling2D
・・・
# Keras1.x
model.add(Convolution2D(32, 3, 3, border_mode='same', input_shape=x_train.shape[1:]))
# Keras2.0
model.add(Conv2D(32, (3, 3), padding="same", input_shape=x_train.shape[1:]))
np_epoch → epochs
# Keras1.x
model.fit(x_train, y_train, batch_size=100, nb_epoch=25, validation_split=0.1)
# Keras2.0
model.fit(x_train, y_train, batch_size=100, epochs=25, validation_split=0.1)
ほとんど違いはありませんね。
しかもKeras1.x版を修正せずとも、Warningが出るだけで普通に動きます。
修正方法もアドバイスしてくれました(笑)
ちなみにKeras1.xとKeras2.0の、Cifar10(25エポック)の結果は以下でした。
バージョン | Loss | Accuracy |
---|---|---|
Keras1.x | 0.66 | 0.80 |
Keras2.0 | 0.66 | 0.79 |
同じネットワークですし、やはり結果に大差ありませんね(笑)