Tech Blog機械学習 

Keras 対応された最新 CNTK v2.0 を試す

最近 GPU を触るのが楽しくて仕方がないデータ事業部の石川 (@hoto17296) です。

猫も杓子も深層学習(Deep Learning)というこのご時世ですが、最近のニュースで言うと CNTK のバージョン 2.0 がリリース されましたね。 CNTK とは、Microsoft が OSS として公開しているディープラーニングライブラリです。

CNTK v2.0 で追加された目玉機能のひとつに「Keras のバックエンドとして使用できるようになった」というのがあります。

今回はこの新機能を使って Keras から CNTK v2.0 を試してみたいと思います。

Keras とは

Keras は Python 用のディープラーニングライブラリです。

とは言っても、Keras 自身が計算を行うわけではなく、Theano や TensorFlow といった別のディープラーニングライブラリをバックエンドとして使用します。 「CNTK v2.0 から Keras のバックエンドとして使用できるようになった」というのは、Keras の裏で使用するライブラリとして CNTK を選択できるようになった、ということです。

「裏で別のライブラリを利用しているなら直接それを使えば良いんじゃないの?」と思うかもしれません。

Keras の公式ドキュメント には以下のような文章があります。

Kerasは機械向けでなく,人間向けに設計されたライブラリです.ユーザーエクスペリエンスを前面と中心においています

TensorFlow や CNTK は 深層学習(Deep Learning)のための計算を効率よく行うための、言わば機械向けのライブラリ であるのに対して、Keras はそれらのライブラリを 人間が簡単に扱えるようなインタフェースを提供するライブラリである、というイメージです。

CNTK は macOS 非対応

CNTK は Windows と Linux をサポートしていますが macOS はサポートしていません。 自分は仕事でもプライベートでも Mac を使っているのでこの点は残念です・・・。

しかし Linux で動くのであれば、今の時代なら Docker を使うことで Mac でも CNTK を動かせそうです。

今回の趣旨からは少し外れますが、Docker で CNTK + Keras を動かす方法について簡単に紹介します。

CNTK の公式 Docker イメージをベースに Keras を入れる

CNTK はものすごく巨大なライブラリです。 一度 CTNK をソースからビルドしてみたことがありますが、それなりに良いマシンでも4時間くらいかかって大変でした。

ソースからビルドして CNTK イメージを作るのはカジュアルではないので、CNTK の公式 Docker イメージ をベースに Keras をインストールしていきます。

FROM microsoft/cntk:2.0-cpu-python3.5

RUN /root/anaconda3/envs/cntk-py35/bin/pip install keras h5py

ENV KERAS_BACKEND=cntk

デフォルト (latest) だと GPU 版になってしまうので、CPU (GPU 無し) 環境で利用する場合には 2.0-cpu-python3.5 タグを指定する必要があります。

また CNTK はベースイメージだけでも 4.7GB (GPU 版は 6.0 GB) あるので、ストレージの容量には注意しましょう。

$ docker build . -t cntk-keras

これで cntk-keras という名前のイメージが作成できたはずです。

ビルドしたイメージを利用する

さきほどビルドしたイメージからコンテナを起動してみます。

$ docker run -it cntk-keras

コンテナの起動コマンドを省略していますが、省略するとこのイメージの場合は bash が実行されます。 Bash プロンプトが表示され、コンテナにログインできたかと思います。

CNTK と Python 3.5 と Keras がインストールされたコンテナにログインできたので、このコンテナの中で以降の作業を進めていきます。

MNIST で試してみる

では実際に MNIST データセットを分類するモデルを CNTK + Keras で実装してみましょう。

モデルを作る

以下のコードは、畳み込み層が2層と全結合層が1層からなるシンプルな CNN です。

最適化アルゴリズムには確率的勾配降下法 (SGD) を使用します。 学習率などのパラメータはデフォルト値のままです。

import keras
from keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPooling2D, Reshape

# 分類するクラスの数
num_classes = 10

# モデルを定義する
model = keras.models.Sequential()
model.add(Reshape((28, 28, 1), input_shape=(28, 28)))
model.add(Conv2D(32, (3, 3), activation='relu'))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D())
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))

# モデルをコンパイルする
model.compile(loss=keras.losses.categorical_crossentropy,
              optimizer=keras.optimizers.SGD(),
              metrics=['accuracy'])

モデルのサマリを表示する (model.summery()) と、以下のようになります。

_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
reshape_1 (Reshape)          (None, 28, 28, 1)         0
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 26, 26, 32)        320
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 24, 24, 64)        18496
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 12, 12, 64)        0
_________________________________________________________________
dropout_1 (Dropout)          (None, 12, 12, 64)        0
_________________________________________________________________
flatten_1 (Flatten)          (None, 9216)              0
_________________________________________________________________
dense_1 (Dense)              (None, 128)               1179776
_________________________________________________________________
dropout_2 (Dropout)          (None, 128)               0
_________________________________________________________________
dense_2 (Dense)              (None, 10)                1290
=================================================================
Total params: 1,199,882
Trainable params: 1,199,882
Non-trainable params: 0
_________________________________________________________________

パラメータ数は約120万です。 この程度であればまだ CPU だけでも学習できそうです。

学習させる

それでは MNIST データセットを読み込んでモデルに学習させてみましょう。

MNIST データセットは配布元からダウンロードしてきてもいいですが、Keras には主要なデータセットをダウンロードして読み込んでくれる機能があるため今回はこちらを利用します。

# MNIST データを読み込む
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()

# ラベルデータを行列の形式に変換する
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)

# 学習させる
model.fit(x_train, y_train, batch_size=128, epochs=10)

# 評価する
score = model.evaluate(x_test, y_test)
print('Test loss:', score[0])
print('Test accuracy:', score[1])

実行した結果は以下のようになりました。

Test loss: 0.0359941334482
Test accuracy: 0.9878

テストデータでの精度が 98.7% なので、うまく学習することができたようです。

まとめ

Keras を使うことで、CNTK で直接実装するよりも遥かにコード量を少なく、可読性が高くすることができました。

実は今回実装した程度のシンプルなモデルであれば、バックエンドを CNTK から TensorFlow に切り替えてもそのまま動いたりします。

バックエンドが簡単に切り替えられるというのは、あるバックエンドでうまくいかなかった際に簡単に別のバックエンドを試すことができるので便利です。

Keras といえばバックエンドは TensorFlow というイメージが強いですが、ぜひ CNTK も試してみてはいかがでしょうか。

このページをシェアする:



DATUM STUDIOは、クライアントの事業成長と経営課題解決を最適な形でサポートする、データ・ビジネスパートナーです。
データ分析の分野でお客様に最適なソリューションをご提供します。まずはご相談ください。