終末 A.I.

データいじりや機械学習するエンジニアのブログ

TensorFlow の cifar10 サンプルを動かす

一般的な DNN、RNN と続いて、今回は CNN を TensorFlow の cifar10 サンプルを元に動かしてみたいと思います。

AWSでのGPU環境の整備や、TensorFlow の基本的な使い方については、手前味噌ですが下記の記事をご覧ください。

また、CNNって何?どういう仕組なの?という方は、以下の書籍が入門用によくまとまっていますのでご一読をおすすめします。

深層学習 (機械学習プロフェッショナルシリーズ)

深層学習 (機械学習プロフェッショナルシリーズ)

深層学習 Deep Learning (監修:人工知能学会)

深層学習 Deep Learning (監修:人工知能学会)

この記事で実際に学習および評価に使用したコードは、記事の一番下に記載してあります。Python は 3.4.3、TensorFlow は 0.9 を使用していますが、しばらくはバージョンが上がっても微調整でちゃんと動くのではないかと思います。

さて前置きはこれくらいにしまして、TensorFlow の cifar10 の識別用CNNを作成するサンプルですが、TensorFlow 独特の実装を行っているポイントが2つあります。 一つが読み込んだデータを元にミニバッチごとのデータを出力する部分。もう一つが TensrFlow の API を利用した CNN に必要となる Covolution 層、Pooling 層、正規化層の利用方法です。早速それぞれがどのように実装されているかを見てみましょう。

まずデータを読み込んでミニバッチ用のデータを生成する処理ですが、TensorFlow の HowTo ページの Reading dataソースコードに添付されている examples/how_tos/reading_data のサンプルコードに記載のあるように、処理用のデータを逐次読みだすための仕組みによって実現されています。

TensorFlow に付属しているサンプルコードでは、cifar10_input.py 内でバイナリ形式で保存された cifar10 のファイルを読み込んで、データをシャッフルした上でミニバッチで使用する数だけ出力するという処理を、tf.train.string_input_producer、tf.FixedLengthRecordReader、tf.train.batch を使用して実現しています。このコードでは、キューに登録してあるファイルを開いて、必要な時に必要な量だけそのファイルからメモリにロードするといった処理が行われることになります。

私が書いた方のコードでは、Python 用に公開されている Pickle 形式で保存された cifar10 のデータをひとまず全部メモリにロードしておき、ミニバッチの処理に必要な量だけを逐次 Tensor オブジェクトに変換し出力するという処理を行っており、下記のような実装になります。

# 元データをバッチで使用できる形式に変更する
label, image = tf.train.slice_input_producer([raw_data[0], raw_data[1]], shuffle=True, seed=1)
    
# データをエンキューしてバッチ化する
labels, images = tf.train.batch([label, image], batch_size=batch_size)

いずれにせよ、このミニバッチの結果出力される labels と images は Tensor 型のオブジェクトとなるため、http://ksksksks2.hatenadiary.jp/entry/20160718/1468833883 のように一から自身で TensorFlow で使えるようにしたデータとほぼ同じように使用することができます。

"ほぼ”という条件付きなのは、あらかじめ Session に関連付けた QueueRunner をデータの読み出しを行う前に起動しておく必要があるからです。とはいえ、tf.train.start_queue_runners を学習や評価の前に呼び出せばいいだけですので難しい話ではありません。呼び出してしまえば、意識しなくても毎回適当なデータ組を読みだしてくれるため大変便利に使うことができます。

次に、CNN にはかかせない Convolution 層、Pooling 層、正規化層の使い方についてです。とはいえこれも全然難しくなく、tf.nn.conv2d、tf.nn.max_pool、tf.nn.lrn 関数を利用して実装していくだけとなります。それぞれ、2次元画像用のConvolution、Max Pooling、Local Response Normalization を実現するための層となります。ちなみに LRN はドキュメントには記載がありませんが、 C++ で記述されているコアコードにはしっかり定義があるので使えなくなることは無いと思われます。Convolution層の重みの初期値を設定するために関数を独自実装していますが、これは重みのL2ロスをバッチのロスに加えるためのヘルパー関数となります。

以上で段取りは完了です。あとはGPUマシンで学習を実行し、5,6時間待っていただければ精度85%くらいの識別器の完成です。

TensorFlow Basic CNN