TensorFlowでDeepLearningを学習する ~MNISTでHello, World!~

前回PythonとWindows用TensorFlowをインストールして開発環境が整ったのでTensorFlowで機械学習の勉強を進めていきます。

機械学習界のHello, World!と呼ばれているMNISTを使います。

”認識率は○%でした!”で終わるのではなく学習結果の保存・呼出・自分で書いた手書き文字の認識まで行って次につなげる一歩にしたいと思います。

MNIST

Googleの初心者向けドキュメントを参考にMNISTを使って進めていきます。

MNISTとは

MNIST、MNISTって言ってきましたがMNISTって何でしょう?MNISTのサイトがありました。

こちらで何が配布されているかというと

The MNIST database of handwritten digits, available from this page, has a training set of 60,000 examples, and a test set of 10,000 examples.

このページから入手可能な手書き数字のMNISTデータベースは、60,000例のトレーニングセットと10,000例のテストセットを持っています。

By Google翻訳

手書き数字のデータとそのラベル(正解データ)です。60,000個のトレーニングデータと10,000個のテストデータから成ります。

今回は使いませんがさらに800,000以上のデータが含まれるNISTというのもあるそうです。

サンプルプログラム”mnist_softmax.py”

学習をすすめるにあたってソースは上記のTensorFlowのサイトで用意されているmnist_softmax.pyをGithubから落としてきます。

プログラムの実行

このソースをダウンロードしてコマンドプロンプトを起動して実行します。私はAnaconda上でTensorFlow用環境を作成したのでまずそれをActivateします。

C:> activate tensorflow
(tensorflow)C:>

ダウンロードしたmnist_softmax.pyを実行します。

(tensorflow)C:>python mnist_softmax.py

実行すると先ほどのMNISTのデータを自動的にダウンロードしてきて学習を始めます。しばらく時間がかかりますが

Extracting /tmp/tensorflow/mnist/input_data\train-images-idx3-ubyte.gz
Extracting /tmp/tensorflow/mnist/input_data\train-labels-idx1-ubyte.gz
Extracting /tmp/tensorflow/mnist/input_data\t10k-images-idx3-ubyte.gz
Extracting /tmp/tensorflow/mnist/input_data\t10k-labels-idx1-ubyte.gz
2017-08-17 20:29:38.020768: W c:\tf_jenkins\home\workspace\release-win\m\windows-gpu\py\35\tensorflow\core\platform\cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE instructions, but these are available on your machine and could speed up CPU computations.
2017-08-17 20:29:38.020855: W c:\tf_jenkins\home\workspace\release-win\m\windows-gpu\py\35\tensorflow\core\platform\cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE2 instructions, but these are available on your machine and could speed up CPU computations.
2017-08-17 20:29:38.022032: W c:\tf_jenkins\home\workspace\release-win\m\windows-gpu\py\35\tensorflow\core\platform\cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE3 instructions, but these are available on your machine and could speed up CPU computations.
2017-08-17 20:29:38.024475: W c:\tf_jenkins\home\workspace\release-win\m\windows-gpu\py\35\tensorflow\core\platform\cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE4.1 instructions, but these are available on your machine and could speed up CPU computations.
2017-08-17 20:29:38.024697: W c:\tf_jenkins\home\workspace\release-win\m\windows-gpu\py\35\tensorflow\core\platform\cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE4.2 instructions, but these are available on your machine and could speed up CPU computations.
2017-08-17 20:29:38.025328: W c:\tf_jenkins\home\workspace\release-win\m\windows-gpu\py\35\tensorflow\core\platform\cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use AVX instructions, but these are available on your machine and could speed up CPU computations.
2017-08-17 20:29:38.025606: W c:\tf_jenkins\home\workspace\release-win\m\windows-gpu\py\35\tensorflow\core\platform\cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use AVX2 instructions, but these are available on your machine and could speed up CPU computations.
2017-08-17 20:29:38.026238: W c:\tf_jenkins\home\workspace\release-win\m\windows-gpu\py\35\tensorflow\core\platform\cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use FMA instructions, but these are available on your machine and could speed up CPU computations.
2017-08-17 20:29:38.298739: I c:\tf_jenkins\home\workspace\release-win\m\windows-gpu\py\35\tensorflow\core\common_runtime\gpu\gpu_device.cc:940] Found device 0 with properties:
name: GeForce GTX 1080
major: 6 minor: 1 memoryClockRate (GHz) 1.835
pciBusID 0000:01:00.0
Total memory: 8.00GiB
Free memory: 6.60GiB
2017-08-17 20:29:38.298832: I c:\tf_jenkins\home\workspace\release-win\m\windows-gpu\py\35\tensorflow\core\common_runtime\gpu\gpu_device.cc:961] DMA: 0
2017-08-17 20:29:38.300167: I c:\tf_jenkins\home\workspace\release-win\m\windows-gpu\py\35\tensorflow\core\common_runtime\gpu\gpu_device.cc:971] 0: Y
2017-08-17 20:29:38.300996: I c:\tf_jenkins\home\workspace\release-win\m\windows-gpu\py\35\tensorflow\core\common_runtime\gpu\gpu_device.cc:1030] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX 1080, pci bus id: 0000:01:00.0)
0.9193

完了しました。認識率91.93%です。

わ~い、以上!

で終わってしまったらちょっと勿体無いので一歩踏み込んでみます。ここから私がやりたいのは

  • 一度学習したら次回からはその学習結果を使う
  • 自分の手書き文字を認識してもらう

です。

mnist_softmax.pyの流れ

このソースが何をやってるのか流れを見てみました。

① MNISTデータのダウンロード

② 初期化

③ 学習

④ テスト初期化

⑤ テスト&結果報告

改造してみる

流れが分かったので改造してみます。

学習結果の保存・呼出

まずは③の学習が終わった後に学習結果を保存して次回からは学習結果があればそれを読み込み、学習をスキップするようにしてみます。

変数の読込と保存については以下のページに記載がありました。

tf.train.Saverクラスがモデルの読込と保存を担当するようです。

保存は

第1引数はセッション、第2引数は保存先のファイルです。ここではカレントフォルダにmodel.ckptという名前で保存しました。すると

  • checkpoint
  • model.ckpt.data-00000-of-00001
  • model.ckpt.index
  • model.ckpt.meta

という4つのファイルが作成されます。

読込は

引数はsave()と同じです。

保存したモデルが存在するかは

でチェック可能です。引数にはチェックしたいパスを指定します。

なお、restoreする場合は変数の初期化がいらないそうです。

なのでこれらをまとめて該当部分はこんな感じになりました。

テストしてみます。まずは学習データがない状態で実行すると

(tensorflow)C:>python mnist_softmax.py
(略)
Training...
Saved to ./model.ckpt
0.9174

フォルダを見ると4つのファイルも作成されています。再度実行してみます。

(tensorflow)C:>python mnist_softmax.py
(略)
Restoring...
0.9174

ちゃんとRestoreされました。4つのファイルを消して再実行します。

(tensorflow)C:>python mnist_softmax.py
(略)
Training...
Saved to ./model.ckpt
0.916

再びトレーニングされ、またファイルが作成されました。ちゃんと機能してそうです。

自分の手書き文字の認識

さらに自分の、というか任意の手書き文字を認識できるようにします。

手書き文字は画像ファイルとして作成し、そのファイルをコマンドラインから指定することにします。こんな感じです。

(tensorflow)C:>python mnist_softmax.py --image_file target.png

コマンドライン引数”–image_file”を受け付けるようにargparseに追加します。

ファイルの指定があればテストを行わず指定された画像を認識、指定がなければ今まで通りテストを行います。

画像を扱うので画像ライブラリをインストールします。私はanaconda使っているのでcondaでインストールしました。なお、管理者権限がいるのでコマンドプロンプトを管理者モードで起動しなおします。

(tensorflow)C:>conda install pillow

他に必要なライブラリも一緒にインストールするか聞かれるので”y”を選んでインストールします。

ファイルの指定があればファイルを読み込みMNISTのデータ形式に合わせるように画像に加工を行います。

  1. 28×28に縮小
  2. グレースケールに変換
  3. 0~255の数値を反転(0なら255, 255なら0)させるため255から引く
  4. 0~1の間に値をとるように255で割る
  5. 1次元配列に変換

上記の処理を行った後、TensorFlowにデータとして渡します。配列の処理にnumpyを使用しています。

yは要素10個の配列でそれぞれ0から9までの確立を表します。tf.argmaxでその中で一番数値が大きいもの(確率が高いもの)を選んでprintします。

手書き文字をペイントソフトで0から9まで0.png, 1.png, …という名前で作成しました。スクリプト側でサイズを縮小するので大きさは適当です。

0から順に試してみました。

(tensorflow)C:>python mnist_.py --file 0.png
(略)
Restoring...
Recognizing 0.png...
[0]

結果は

  • 0 … 正解
  • 1 … 正解
  • 2 … 正解
  • 3 … 正解
  • 4 … 正解
  • 5 … 正解
  • 6 … はずれ(5と勘違い)
  • 7 … はずれ(2と勘違い)
  • 8 … はずれ(5と勘違い)
  • 9 … はずれ(8と勘違い)

後半は認識が結構残念でしたがとりあえず動作はしているようです。

画像の処理がかなり適当です。本来MNISTのデータは20×20のデータを28×28サイズの中心に持ってきているそうです。そのデータをもとにトレーニングしたので本当は同じように加工しないといけないのですが、今回はあくまでも全体の流れをつかむのが目的ということでやってません。

次は…

機械学習のHello, World!と呼ばれるMNISTデータを使ったサンプルを試しました。また個人的な目標だった

  • 一度学習したら次回からはその学習結果を使う
  • 自分の手書き文字を認識してもらう

も達成できました。

正直、かなりの部分を理解もしないまま使用しているというのが本当のところです。しかし可能な限りブラックボックスとして扱うというのが私の裏目標でもあったりします。

だって、数学わかんないし…

次に何をどうしたら認識率が上がる/下がるのか、もう少しMNISTと戯れてみます。

今回の最終ソースはこちらです。

拡張子をtxtに変えてますので適当に修正してください。