post Image
超入門訳TensorFlow MNIST For ML Beginners

はじめによりはじめに

プログラミングもデータ分析も初心者、高校数学しか知らないのにTensorFllowに手を出したのですが、TensorFllow入門で調べてみても、全く入門でなかったのでTensorFlow MNIST For ML Beginnersチュートリアルを訳してくださっていたものを自分なりに解釈して書き換えました。

せっかくなので投稿します。

自分のために作ったので、よくわからないところは赤字、分かった気になったところは太字にしてあります。

理解の助けとなるサイト等ありましたら教えていたただけると幸いです。

はじめに

このチュートリアルは機械学習と TensorFlow の初心者を想定しています。もしMNISTやsoftmax(多項ロジスティック)回帰について知っているなら、より早いペースのチュートリアル が良いかもしれません。

プログラムを学ぶ時、最初に “Hello World.” を表示するという慣例があります。機械学習では “MNIST” があります。
MNIST は簡単なコンピュータ・ビジョンのデータセットで、手書き数字の画像から成ります。

データセットには、どの数字かを示すラベルもあります。上の画像のラベルは 5, 0, 4, 1 です。

このチュートリアルでは、画像を見てどの数字かを予測できるモデルをつくります。目的は手の込んだモデルを訓練することではなく(後々やります)、とりあえず TensorFlow での一歩を踏み出すことなので非常に簡単なモデルをつくります、Softmax (多項ロジスティック)回帰というものです。

このチュートリアルのコードは非常に短く、全ての興味深いことはわずか3行の内に発生しますが、背景にある考えを理解することは非常に重要で、どのように TensorFlow が動作するかと、機械学習の重要な概念を学べます。注意深くコードに取り組んでいきましょう。

このチュートリアルについて
このチュートリアルは mnist_softmax.py コードにおいて何が起きているのかの、1行ずつの説明です。

このチュートリアルはいくつかの方法で利用できます、それは

  • 各行の説明を読み通してから各コード・スニペット(切れ端)を1行ずつ python 環境にコピー&ペーストする。
  • まずはmnist_softmax.py Python ファイルを実行し、そしてコードのわからない行の説明だけを読む。

このチュートリアルで達成すること

  • MNIST データと softmax 回帰について学習する。
  • 画像の全てのピクセルの情報を基に、数字を認識するモデル(=関数)を作る。
  • TensorFlow を使い、数千のサンプルを “見させる” ことで、数字を認識するようにモデルを訓練する。 (最初のTensorFlow sessionを実行)
  • テストデータでつくったモデルの精度をチェックする。

MNISTデータとは

MNISTデータは Yann LeCun’s website によって提供されています。もしこのチュートリアルのコードをコピー&ペーストしているなら、MNISTデータを自動でダウンロードして読み込むこの2行のコードから始めましょう。

mnist_softmax.py
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

ダウンロードしたデータは3つに分かれます、訓練データが 55,000個 (mnist.train)、テストデータが10,000個 (mnist.test) そして検証データが5,000個 (mnist.validation) です。この分割は非常に重要です : 機械学習において学習には使わない隔離されたデータを持つことは重要なのです。これにより学習したモデルが本当に一般化されているかを確かめられます!

先に言及したように、全てのMNISTデータは2つの情報を持ちます。手書き数字の画像と該当ラベルです。

画像を “x” そしてラベルを “y” とします。訓練イメージは mnist.train.images のことで、訓練ラベルは mnist.train.labels のことです。

各画像は 28 ピクセル x 28 ピクセルです。これは数値の大きな配列と解釈できます。

この配列を 28 x 28 = 784 数値のベクタ(同じ型のデータを連続的に並べた1次元配列)に平坦化できます。画像間で一貫していればどのように配列を平坦化するかは問題ではありません。この見方では、MNISTの画像は very rich structure (訳注: 計算集約型視覚化)を持つ、784次元(748の方向がある)ベクタ(ベクトル)空間のたくさんの点と言えます。

この、データの平坦化は画像の2D構造についての情報を捨てています。これはまずくないのでしょうか? 確かに、ベストな方法ではこの2D構造を利用しますので、後々はそうしましょう。しかし今回扱う単純な方法(softmax 回帰)では利用しません。

結果的にmnist.train.images は [55000, 784] の shape(形状)を持つテンソルになります。最初の次元は画像の数の情報で、2つめの次元は各画像のピクセルの数の情報です。テンソルの各要素は特定の画像の、特定のピクセルのための0~1のピクセル濃度です。

また、各ラベルは 0~9 の数字で、与えられた画像がどの数字であるかを示します。

このチュートリアルの目的のためにはラベルは “one-hot ベクタ” であることを望みます。one-hot ベクタはほとんどの次元で 0 で、一つの次元で 1 であるベクタです。この場合、n 番目の数字は n 番目の次元が 1 のベクタとして表されます。例えば、3 は [0,0,0,1,0,0,0,0,0,0] になります。結果的に、mnist.train.labels は float の [55000, 10] 配列になります。

これで、モデルを作成する準備ができました!

Softmax 回帰

MNIST の全ての画像が、数字の画像であることはわかっています。

今回は画像を見て、その画像がどの数字であるかの確率を求めたいのです。例えば、モデルは 9 の画像を見て、その画像が 9 であることが 80 % 確かであり、しかし(上部に円があるので) 8 である 5 % の可能性を与え、そして確信が持てないために全ての他の数字にも少しの可能性を与える、という風に。

これは softmax 回帰を使うのが自然で簡単なモデルとなる古典的なケースです。いくつかの異なるものの一つであるオブジェクトに確率を割り当てたいならば、softmax がこれを行なってくれます。softmax は合計すると 1 になる0 と 1 の間の値を与えてくれるのです。後々、より洗練されたモデルを訓練する時でも、最終ステップは softmax 層になります。

softmax 回帰は2つのステップを持ちます : 一つは、入力が、どれにどれほど当てはまるかの値、証拠 (evidence) を集計すること、そしてその値を確率に変換します。

与えられた画像がある特定の情報にどれほど当てはまるかを計算するために、ピクセル濃度の加重和(重みつき和)を取ります。高い濃度を持つピクセルがある特定の情報に属することへの反証となるのであれば重みはネガティブ(負値)です。そして補強する証拠であればポジティブ(正値)です。

次の図は一つのモデルが特定の情報について学習した重みを示しています。赤色はネガティブな重みを表し、青色はポジティブな重みを表しています。

更に、バイアスと呼ばれる、特別な証拠も追加します。基本的には、入力からは独立的にある事象が起きやすいと言いたいために導入します。

最終的に入力 xが与えられた時、特定の情報 i である可能性は

\text{evidence}_i = \sum_j W_{i,~ j} x_j + b_i

と、表されます。 Wiは重みで、biは情報iのためのバイアス、そしてjは入力画像xのどのピクセルかの情報?です。元の文は j is an index for summing over the pixels in our input image x

そしてこのevidenceを softmax(多項ロジスティック)関数を使って予測確率yに変換します。

y = \text{softmax}(\text{evidence})

softmax(多項ロジスティック)関数は活性化関数(入力信号の総和を出力信号に変換する関数)あるいはリンク関数(0~1の間で合計が1になる値に変換する関数)として機能し、望ましい形式に整形された線形関数の出力をします (今回は10ケースの確率分布です)

これはevidenceの値を、入力xが特定の情報である確率に変換していると考えることができます。

softmax(多項ロジスティック)関数は次のように定義されます。

\text{softmax}(evidence) = \text{normalize}(\exp(evidence))

normalizeは正規化?
exp(x)=e^x
この式を展開すれば、次を得ます。つまり正規化(normalize)とはこういうことです

\text{softmax}(evidence)_i = \frac{\exp(evidence_i)}{\sum_j \exp(evidence_j)}

しかし softmax を展開前の式で考えることはしばしば有用です。入力のべき乗(指数関数)を求めて正規化しています。べき乗によって、証拠の値の1単位増加が任意の仮説への重みを乗法的に増加することになります。逆に、証拠の1単位の減少は、仮説への重みの減少を意味します。どの仮説も 0 や負の重みは決して持ちません。Softmax はそしてこれらの重みを正規化して総計は 1 になり、有効な確率分布を形成します。(softmax 関数についてより直感的な知識を得たいのであれば、対話的な視覚化を完備する、Michael Nieslen の本のそれについての セクション を詳細に参照してください。)

softmax 回帰は次のような感じで図示できます、実際にはより多くの x を持ちますが、各出力に対して、x の重み合計を計算し、バイアスを加え、そして softmax を適用します。

数式で書くならば、以下を得ます。

この手続きは、行列の乗算とベクタの加算に変換することによりベクタ化(ベクトルの成分表示的な表示にする)できます。これは計算効率のために有用です。(考えるにもまた良い方法です。)

よりコンパクトに単に

y = \text{softmax}(Wx + b)

とも書けます。

さてこれを TensorFlow で記述しましょう。

回帰を実装する

Python における効率的な数値計算を行なうためには、通常は NumPy のようなライブラリを用います。他の言語で実装された効率化されたコードを用い、Python の外で行列の乗算のような高コストな演算を実行します。

不運なことに、全ての演算において依然として Python への切り替えの時たくさんのオーバーヘッド(関わることだから仕方ないんだけど、別にそれをやりたいわけじゃないんだよね的な処理)があります。このオーバーヘッド(要らない処理)は、データ転送に高いコストがかかる、GPU 上や分散手法で計算を実行したい場合、特に良くないです。

TensorFlow でも重たい演算を Python の外に持ち出しますが、このオーバーヘッドを回避するために物事を一歩先に進めています。TensorFlow では高負荷な演算をPython から独立的に一回だけ実行するのではなく、 Python の外で完全に走る、相互作用する演算の記述を可能にしているのです。(このようなアプローチはいくつかの機械学習ライブラリで見られます。)

TensorFlow を使うためには、import する必要があります。

mnist_softmax.py
import tensorflow as tf

シンボリック(抽象的)な変数を操作することにより、相互作用する演算を記述します。一つ作成してみましょう。

mnist_softmax.py
x = tf.placeholder(tf.float32, [None, 784])

x は特定の値ではありません。これはプレースホルダーです。TensorFlow に外部での計算の実行を依頼する時に値を入れられます。

今回は784次元ベクタに平坦化された MNIST 画像を任意の個数入力したいのでこれを shape [None, 784] を持つ浮動小数点数値の2Dテンソルとして表します。(ここでは None は次元が任意の長さを取りうることを意味しています。)

今回のモデルには重みとバイアスも必要です。これらを追加の入力のように扱うことも考えられますが、TensorFlow はより良い方法を持っています。変数 (Variable) です。変数は変更可能なテンソルで、TensorFlowが行う外部での演算の中で使えます。計算に利用可能で、計算によって変更可能でもあります。機械学習のアプリケーションは、一般に、モデルパラメータを変数として持ちます。

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

変数の初期値を tf.Variable に与えることによってこれらの変数を作成できます。この場合、全てゼロのテンソルとして W も b も初期化します。W と b の値を学習していくので、最初にどのような値であるかはそれほど重要ではありません。

W は [784, 10] の shape を持つことに注意してください。Wを784次元ベクタ画像のxに乗算することによって、どれにどれほど当てはまるかを表す10次元ベクタのevidenceを生成することになる
からです。b は [10] の shape を持ち、出力に加算します。

これでモデルが実装できます。それを定義するためにわずか1行しかいりません!

mnist_softmax.py
y = tf.nn.softmax(tf.matmul(x, W) + b)

最初に tf.matmul(x, W) という式で x に W を乗算します。この式では、上の説明の式で乗算した時、つまりW掛けるxであった時とは順序がひっくり返されていますが、これは x を複数の入力をもつ 2D テンソルとして扱うための小さなトリックです。それから b を加算し、最後に tf.nn.softmax を適用します。

これで全部です。数行のセットアップ後、モデルを定義するのに1行しかいりません。これはTensorFlow が softmax 回帰を特に簡単にするように設計されているからではなく、機械学習モデルから物理シミュレーションまで、多くの種類の数値計算を記述するのに柔軟だからです。さらに一度定義すれば、モデルは異なるデバイスでも実行できます。貴方のコンピュータの CPU、GPU そしてスマホでさえもです!

訓練

モデルを訓練するためには、モデルが良いとはどういうことかを定義する必要がありますが、実際のところ、機械学習ではモデルが悪いとはどういうことかを定義します。これをコスト、あるいは損失と呼び、それはモデルが望ましい結果からどの程度離れているかを表します。エラーを最小化しようとして、エラー・マージンが小さくなればモデルもより良くなるのです。

非常に一般的で良いコスト関数の一つは “交差(クロス)エントロピー”です。交差エントロピーは情報理論において情報圧縮コード (information compressing codes) について考えることから発生しています。しかし、それはギャンブルから機械学習まで、幅広い領域で重要なアイデアとなっています。交差エントロピーは以下で定義されます。


H_{y'}(y) = -\sum_i y'_i \log(y_i)

yは予測した確率分布で、y′は(入力する one-hot ベクタの)本当の分布、正解です。大雑把な意味では、交差エントロピーは我々の予測が真実 (truth) を記述するにどのくらい非効率であるかをを計測しています。交差エントロピーについてより詳細に踏み込むのはこのチュートリアルの範囲を超えていますが、理解する価値は十分にあるでしょう。

交差エントロピーを実装するには、正解を入れておくための新しいプレースホルダーの追加が最初に必要です。

mnist_softmax.py
y_ = tf.placeholder(tf.float32, [None, 10])

これにより交差エントロピーが実装できます。

mnist_softmax.py
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))

最初に、tf.log は 予測y の各要素の対数を計算します。次に、正解y_の各要素と tf.log(y) の該当する要素を乗算します。それから tf.reduce_sum が reduction_indices=[1] パラメータによって、予測y の2番目の次元における要素を加算します。最後に、tf.reduce_mean がバッチ(一回分)の全てのサンプルに渡り平均を計算します。

ソースコードでは、この式を使っていないことに注意してください、数値的に不安定だからです。代わりに、正規化されていないロジット上で tf.nn.softmax_cross_entropy_with_logits を適用しています。(e.g., tf.matmul(x, W) + b 上で softmax_cross_entropy_with_logits を呼び出しています。)この数値的により安定的な関数が内部的に softmax 活性を計算するからです。貴方のコードでは、代わりにこの tf.nn.softmax_cross_entropy_with_logits を使用することを考えましょう。

モデルに何をさせるかを知った今、TensorFlow で訓練をさせることは非常に容易です。TensorFlow は貴方の演算グラフの全体を知っているので、変数がどのように最小化したいコストに影響を与えるかを求めるために、自動の バックプロパゲーション・アルゴリズム を使用することができます。そして貴方の選択した最適化アルゴリズムを適用して変数を変更しコストを減じます。

mnist_softmax.py
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)

この例では、0.01 の学習率で勾配降下法アルゴリズムを使って TensorFlow に交差エントロピーを最小化させることを依頼しています。勾配降下法(微分で極小値まで行く)は単純な手続きで、コストを減少させる方向に各変数をほんの少しシフトします。TensorFlow は他にも多くの最適化アルゴリズム を提供しています。一つを使用することは一行調整する程度に簡単です。
ここで TensorFlow が裏で実際に行なうことは、バックプロパゲーション と勾配降下法をを実装する新しい演算をグラフに追加することです。そして TensorFlow は一つの演算を返します。これは、実行した時に、勾配降下法を行ない、コストを減少させるために変数を微調整する演算です。

これで InteractiveSession でモデルを launch できます。

mnist_softmax.py
sess = tf.InteractiveSession()

最初に作成した変数を初期化するための演算を作成しなければなりません。(おまじない)

mnist_softmax.py
tf.global_variables_initializer().run()

訓練しましょう。訓練ステップ 1000 回を実行します!

mnist_softmax.py
for _ in range(1000):
  batch_xs, batch_ys = mnist.train.next_batch(100)
  sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})

ループの各ステップで、訓練セットから 100 のランダムなデータポイントのバッチ(一回分)を取得します。プレースフォルダーをに入れるバッチ(一回分の)データを供給 (feed) して train_step を実行します。ランダム・データの小さなバッチ(一回分)を使用することを確率的訓練、この例では確率的勾配降下法、と呼びます。理想的には、訓練の全てのステップで全てのデータを使用したいのですが(より良いセンスを与えてくれるからです)高くつきます。代わりに、毎回異なるデータセットを使用します。行なうのは安価で、同じくらい多くの恩恵があります。

モデルを評価する

訓練したモデルはどの程度上手くやるでしょうか?

まずは最も高く正解だと予測した番号を把握しましょう。tf.argmax は非常に有用な関数で、ある軸に沿ったテンソルのもっとも高い要素の情報を与えます。例えば、tf.argmax(y,1) はモデルが各入力に対して一番ありそうと考えるラベルで、一方で tf.argmax(y_,1) は正解のラベルです。予測が正解と合っているか確認するためには tf.equal が利用できます。

mnist_softmax.py
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))

これはブール値(true false)のリストを与えます。正解した割合を決定するために、浮動小数点数値にキャスト(変換)して平均を取ります。例えば、[True, False, True, True] は [1,0,1,1] となり、これは 0.75 となります。

mnist_softmax.py
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

最後に、テストデータ上で精度を求めます。

mnist_softmax.py
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))

約 92 % になるでしょう。これは良いのでしょうか?そうでもないです。むしろかなり悪いです。今回は非常に単純なモデルを使っているからです。幾つかの小さな変更で、97% にまで到達できます。ベストなモデルは 99.7% を超えた精度に到達できます!(更なる情報は、結果のリスト を見てください。)

重要なのはこのモデルから学んだことです。結果について少しがっかりしているのであれば、次のチュートリアル をチェックしてください。多くの改良を行ない、TensorFlow を使ったより洗練されたモデルを構築する方法を学べます!

おわり

参考サイト様

IT用語辞典
「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典
Data Science by R and Python 「線形モデルを簡単にわかりやすく! -データに直線を引いて、傾向を捉えるときの注意点-」
高校数学の美しい物語 「数学記号exp,ln,lgの意味」


『 機械学習 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。