FPGA開発日記

FPGAというより、コンピュータアーキテクチャかもね! カテゴリ別記事インデックス https://sites.google.com/site/fpgadevelopindex/

機械学習初心者がTensorFlowのチュートリアルを勉強して分かったことをまとめる(1)

TensorFlowのチュートリアルが面白そうなので、少しずつやっていって、分かったことをまとめていこう。 ちなみに当方、機械学習は全くの初心者なので、もしかしたら間違ったことを書いているかもしれない。あしからず。

まずはTensorFlowのチュートリアルを読み進めていこう

機能は、TensorFlowを実行するための環境を整えた。

msyksphinz.hatenablog.com

github.com

一番最初は、MNISTを使った多クラス分類だ。

http://tensorflow.org/tutorials/mnist/beginners/index.md

何度も言うように、当方機械学習の初心者なので、いろんなところに脱線しながら進んでいく。 あと、時々次の節(Deep MNIST for Experts)の内容まで突っ込んで(というか間違えて読んで)いるのであしからず。

MNISTの導入

MNISTはMixed National Institute of Standards and Technologyの略称らしい。手書き文字認識のためのデータベースのことを、MNIST databaseと呼ぶ。
これを使って学習するのが、まずはTensorflowの最初のチュートリアルだ。
手書き文字認識なんて、やったことも無いので、まずは良いチュートリアルだ。

まずは機械学習やTensorflowについて勉強したかったら、このチュートリアルから始めると良い。既にMNISTやsoftmaxについて知っているようだったら、
このチュートリアルを省略して次のチュートリアルに進んでも良い。
MNISTの手書き認識は、プログラミング言語におけるHello Worldのようなもので、まずはこれから始めることになる。

セットアップ

モデルを作成する前に、MNISTのデータベースをロードして、Tensorflowのセッションをスタートしよう。

MNISTデータのロード まずは簡単化のために、MNISTを自動的にダウンロードするスクリプトを用意した。MNISTのデータをダウンロードするための'MNIST_data'というディレクトリを作成し、ダウンロードする。 このスクリプトは、tensorflowのソースディレクトリ tensorflow/tensorflow/g3doc/tutorials/mnist/inpput_data.pyに格納されている。 これを自分の作業ディレクトリにコピーして使ってみよう。

>>> import input_data
>>> mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
Succesfully downloaded train-images-idx3-ubyte.gz 9912422 bytes.
Extracting MNIST_data/train-images-idx3-ubyte.gz
Succesfully downloaded train-labels-idx1-ubyte.gz 28881 bytes.
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Succesfully downloaded t10k-images-idx3-ubyte.gz 1648877 bytes.
Extracting MNIST_data/t10k-images-idx3-ubyte.gz
Succesfully downloaded t10k-labels-idx1-ubyte.gz 4542 bytes.
Extracting MNIST_data/t10k-labels-idx1-ubyte.gz

mnistという変数はNumPyの配列であり、トレーニングデータと、検証、テスト用データが格納されている。

TensorFlowの計算方法 - InteractiveSession -

以下チュートリアルの翻訳。

Tensorflowはその計算を実行するために非常に効率的なC++のバックエンドに依存している。
このバックエンドとの接続のことをセッションと呼ぶ。
Tensorflowプログラムの共通の使い方は、まずはグラフを作り、セッションを起動する。

ここでは、便利なInteracitveSessionクラスを用い、Tensorflowを使ってより柔軟にコードを構築できるようにする。
このクラスを用いることにより、インタラクティブに計算グラフを作成したるすることができる。
このクラスは、iPythonのようなインテラクティブなコンテキストを利用する場合などに特に便利である。
もしInteractiveSessionクラスを用いないならば、セッションを開始させ、グラフを作成する前に、全ての計算グラフを構築する必要がある。

InteractiveSessionを使うことにより、途中でいろいろ確認しながら進めることができるということかな?良く分からない。 とにかく、TensorFlowによって機械学習をやらせるためには、このInteractiveSessionクラスのインスタンスをまずは作る必要があるらしい。

>>> import tensorflow as tf
>>> sess = tf.InteractiveSession()
I tensorflow/core/common_runtime/local_device.cc:25] Local device intra op parallelism threads: 1
I tensorflow/core/common_runtime/local_session.cc:45] Local session inter op parallelism threads: 1

TensorFlowの計算方法 - 計算グラフ -

以下チュートリアルの翻訳。

* 計算グラフについて
効率的にPythonで計算するためには、NumPyなどの高機能なライブラリを利用することができる。このNumPyライブラリは行列の乗算などを
Pythonの外側、つまり別の言語で記述された、より効率的な実装を呼び出すことで実現している。
この際に問題になるのが、Pythonからこれらの高機能関数を呼び出す際のオーバヘッドだ。Pythonのそれぞれの処理を実行するために、
Python外のライブラリを呼び出していたら、それはかなりのオーバヘッドになるだろう。特にGPUや、分散処理をさせる環境では、この
オーバヘッドは深刻なものになる。
なので、Tensorflowでは計算グラフというグラフを構築して、Pythonの外でこのグラフを処理させることでPythonを介すすることなく効率的に計算を実行する。
このアプローチはTheanoやTorchの取っている手法に似ている。

このグラフを構築するために、Pythonを利用する。そして実際の計算では、計算部が全体の時間を支配するように配慮をするわけだ。
より詳細については、Computation Graph節およびBasic Usageの章を見て欲しい。

そもそもPythonは、ライブラリを使用して外部の別言語で記述された実装を呼び出すというのを知らなかった。だけど、まあこの手法は驚くべきことでもない。 確かに、計算方法というか、計算の順序が確率されているならば、このようにした方が良いに決まっている。

ここらへんも直訳。誤訳が入っている可能性もあるので注意。

まずは、入力画像と出力クラスを格納するためのノードから作成しよう。

x = tf.placeholder("float", shape=[None, 784])
y_ = tf.placeholder("float", shape=[None, 10])

xとyがプレースホルダで、TensorFlowに計算をさせる際にここに値が格納されることになる。

xには、2次元の浮動小数点のテンソルが格納される。784はMNISTイメージをフラットにした場合の次元数だ。
Noneは最初の次元を示しており、バッチサイズに該当するが、任意の数を指定することができる。
y_も2次元のテンソルを格納するが、各要素はワンホットの10次元のベクトルであり、MNISTの画像がどの数字に分類されるかを示すことになる。
placeholderのshape引数は省略することができるが、互換性の無い値を挿入するとTensorFlowは自動的にバグをキャッチすることができるようになる。
  • 変数(Variable)について

ここらへんも直訳。誤訳が入っている可能性もあるので注意。

次に、重みWとバイアスbを定義するが、TensorFlowではこれらをVariable(変数、直訳?)として定義する。これにより、より便利にこれらの値を処理することができるようになる。 VaribleはTensorFlowの計算グラフの中で参照することができ、また計算中に変更することもできる。 機械学習のアプリケーションでは、モデルのパラメータは一般的にVaribleと呼ばれる。

W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))

Wとbを定義し、Varibleとして初期化した。この場合にh、Wとbを784×10の行列(これは784個の入力と10個の出力が存在するからである)および10次元のベクトルとして定義し、 初期値を全て0としている。

セッション内でVaribleが利用される前に、そのセッションを使ってそのVariableを初期化しなければならない。 この処理には既に指定した初期値が必要である(この場合には全て0という初期値を指定した)。 そしてこれらを各Variableに割り当てなければならない。このようなVaribleのための処理は、以下で一度に実行可能である。

sess.run(tf.initialize_all_variables())

ソフトマックス関数について

機械学習のエキスパートならこんなの常識かもしれないが、僕は全くの門外漢なので分からない。 ソフトマックスのモデルとは何ぞや?英語のチュートリアルを読んでも良く分からない。

ヒントは、「深層学習」の本に書いてあった。

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

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

2.4.4 に「多クラス分類」という、まさにピッタリの節がある。

出力層l=Lの総出力を{u_k^{(L)}}とするならば、

{ \displaystyle
y_k\equiv z_k^{(L)} = \frac{\sum_{j=1}^K exp(u_j^{(L)})}{\exp(u_k^{(L)})}
}

多層のニューラルネットワークの場合、{k}番目のユニットの出力を上記のように表現する。 この場合、出力y_1,...y_Kの総和は常に1となることがポイントらしい。 また、kの出力はk層の入力だけでなく、1からkまでの出力に依存していることもポイントだ。

と、まずはここまで。とりあえずは、TensorFlowの概要については何となく理解した気がする。いよいよ、TensorFlowと使って、機械学習のより具体的な学習方法についての勉強だ。