Translate

2016年9月8日木曜日

TensorFlowの"GET STARTED"を翻訳してみた

とりあえずCoreOS環境上にTensorFlowコンテナを上げたので
チュートリアルをやってみることにした。

TensorFlowトップページの上にある"GET STARTED"へ進んだIntroductionと
赤と青の錠剤画像リンク先のチュートリアルを翻訳してみた。

以下、参照される方は At your own risk でお願いします。

----------

イントロダクション


TensorFlowを動かせるようにしましょう!

ただ、はじめる前にPython APIを使ったTensorFlowのコードを見てみましょう、そしてどこを目指しているかを感じ取ってみましょう。

ここに、いくつかの2次元データを作成し、一本の線に合わせる小さなPythonプログラムがあります。

import tensorflow as tf
import numpy as np

# Create 100 phony x, y data points in NumPy, y = x * 0.1 + 0.3
x_data = np.random.rand(100).astype(np.float32)
y_data = x_data * 0.1 + 0.3

# Try to find values for W and b that compute y_data = W * x_data + b
# (We know that W should be 0.1 and b 0.3, but TensorFlow will
# figure that out for us.)
W = tf.Variable(tf.random_uniform([1], -1.0, 1.0))
b = tf.Variable(tf.zeros([1]))
y = W * x_data + b

# Minimize the mean squared errors.
loss = tf.reduce_mean(tf.square(y - y_data))
optimizer = tf.train.GradientDescentOptimizer(0.5)
train = optimizer.minimize(loss)

# Before starting, initialize the variables.  We will 'run' this first.
init = tf.initialize_all_variables()

# Launch the graph.
sess = tf.Session()
sess.run(init)
# Fit the line.
for step in range(201):
    sess.run(train)
    if step % 20 == 0:
        print(step, sess.run(W), sess.run(b))
# Learns best fit is W: [0.1], b: [0.3]

このコードの最初の部分は、データフローグラフをビルドしています。セッションが構築され関数が呼び出されるまで、TensorFlowは実際に計算を実行しません。

さらにあなたの食欲をそそらせるために、古典的な機械学習問題がTensorFlowによってどのように実現するのかを確認することを提案します。ニューラルネットワークの国で最も「古典的な」古典問題は MINST手書き数字分類 です。ここで二つのイントロダクションを出します、一つは機械学習初心者向き、もう一つはプロむきのものです。他のパッケージで何十ものMINST実装を 経験した方は、赤いピルを手にとってください。MINSTって何という方は、間違いなく青いピルを飲んでください。どっちかわからない場合は、まず青い方 をざっと眺め、次に赤い方を選んでください。

※上記の2つのリンク先はこの後に翻訳文を掲載しています


TensorFlowを勉強しインストールしたい方は、これらをスキップして前へ進む事もできます。気にしないでください、あなたはまたMNISTを勉強 することになります--TensorFlowの機能を詳しく調べる際の技術的チュートリアル内の例示でMNISTを使っています。


(イントロダクションページ:おわり)
 ----------
青いピル(初心者向け):

MNIST for Beginners


このチュートリアルの読者は機械学習やTensorFlowに不慣れな人向きを対象としています。MINSTとは何かを知っており、softmax (多変量ロジスティック)回帰とはなにか、を知っているのであれば、ペースの早いチュートリアル のほうがよいとおもいます。どちらのチュートリアルも開始前に、 TensorFlowのインストール を実施してください。

プログラムの書き方を学ぶ時、最初に"Hello, World"を表示するチュートリアルがあります。機械学習のMNISTはちょうどこのHello Worldに似ています。

MNISTは単純なコンピュータ画像データセットです。次のような手描きのイメージが含まれています:




それぞれのイメージにはラベルがあり、それがどの数字であるかがわかります。たとえば、上のイメージは、5、0、4、1です。

このチュートリアルでは、イメージを参照してそれがどの数字かを予測するためのモデルとして学習させます。ゴールは、(後でそのようになるコードを提供しますが)最新技術のパフォーマンスを成し遂げるような本当に精巧なモデルを学習させることではなく、むしろTensorFlowにつま先を浸すことにあります。Softmax回帰と呼ばれるとても単純なモデルからはじめます。

実際のコードはとても短く、最も興味のある部分はたった3行です。しかし、その裏には理解するためにはとても重要なことが潜んでいます;TensorFlowがどのように動くのか、そしてコアの機械学習のコンセプトです。このため、注意深くコード見ていく必要があります。


このチュートリアルについて


このチュートリアルでは、コード mnist_softmax.py にてなにがおこっているのかを、1行ごとに説明しています。

このチュートリアルを幾つかの使い方があります:

    Python環境内で、各行の説明をとおして、行ごとに、コードの断片をコピー&ペーストする。
    不明確なコード行を理解するために、説明を読む前もしくは後に、Pythonファイルmnist_softmax.py全体を実行する

どのようにして、このチュートリアルを完遂するのでしょうか:

    MNISTデータやsoftmax回帰について学習する
    イメージの各ピクセルを読み込むことで、数値を理解するモデルの関数を作成する
    TensorFlowを使って数千の例を 見て 数値を理解するモデルを学習させる(そして最初のTensorFlowセッションで語っていたことを実現する)
    テストデータを使ってモデルの精度をチェックする

MNIST データ


MNISTデータは、Yann LeCunのWebサイト にあります。このチュートリアルからコードをコピー&ペーストしたら、この2行のコード、自動的にダウンロードして読み込む、からはじめてください。

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


MNISTデータは3つの部分にわかれます:55,000点の学習データ(mnist.train)、10,000点のテストデータ(mnist.test)、5,000点の評価データ(mnist.validation)。この分割はとても重要です:学習しないデータを分けて実際に学習したものを汎化することは、機械学習の本質です。

前述したとおり、MINSTデータポイントは、手書き数字のイメージと関連するラベルの2つの部分があります。イメージを"x"ラベルを"y"とよびます。学習セットとテストセットは共にイメージとラベルを含んでいます;たとえば、学習セットのイメージはmnist.train.images、学習セットのラベルはmnist.train.labelsにわかれています。

それぞれのイメージは28ピクセル×28ピクセルです。これを数字の大きな配列に解釈することができます。

 

この配列をフラットにすると、28×28=784個の数字になります。イメージ間で一貫した方法であるかぎり、配列をいかに平にするかが重要ではありません。この展望から、MNISTイメージは784次元という、大変リッチな構造 のベクトル空間のたくさんの点であるといえます(警告:計算としては集中的な視覚化)。

データをフラット化することはイメージの2次元構造を捨て去ることになります。それは悪いことでしょうか?もっともよい画像計算手法はこの構造を活用します、それはチュートリアルの後ろのほうでとりあげます。しかし我々がここで使用する、softmax 回帰(定義は後述)では、このシンプルな方法を使います。

結果として、mnist.train.imagesは形が[55000, 784]のテンソル(n次元配列)となります。最初の次元はイメージリストのインデックスで、次の次元は各イメージのそれぞれのピクセルのインデックスです。テンソルの各エンティティは、あるイメージのあるピクセルの強さを、0から1の間で表しています。



MNISTの各イメージは、イメージ上に描かれた0から9までの数字をあらわすラベルをもっています。

このチュートリアルのために、「 one-hot なベクトル(one-hot vector)」としてのラベルを望んでいます。one-hot vectorは、1つの次元だけ1でほかはすべて0であるベクトルのことをいいます。この場合、n番目の数字はn時限目が1であるベクトルをあらわしています。たとえば、3は[0, 0, 0, 1, 0, 0, 0, 0, 0]となります。したがって、mnist.train.labelsは、ある[55000, 10] 次元浮動小数配列です。

これでモデル構築のための準備ができました。

Softmax 回帰(後退)


MNIST内のそれぞれのイメージは、0から9までの手書き数字であると知られています。このため、与えられたイメージはたった10の可能性があるものだけです。我々は、イメージを参照し、それぞれの数字である確率を知りたいということになります。例えば、我々のモデルはある写真に対して、9である確率が80%だが、8である確率が5%(上部のループの判断から)、そしてその他の数字である確率が残り、といったように100%正解をみつけられない場合があります。

これは、softmax回帰が自然で単純なモデルである、古典的なケースです。幾つかの異なったものにから一つを選びたい場合は、softmaxが使われます。なぜならsoftmaxは0と1の間の値のリストを返します。

softmax回帰には、2つのステップがあります:最初に特定のクラス内にあるインプットのエビデンスを追加します。次にエビデンスを確率に変換します。与えられたイメージはある特定のクラスに所属するエビデンスを総計するために、ピクセル強度を荷重和します。高い強度を持つあるピクセルがあるクラスに分類されるイメージに反するエビデンスであれば荷重は否定的(負)となり、正となるエビデンスであれば肯定的(正)となります。

次に続く図は、ある一つのモデルがこれらの分類それぞれから学習した荷重をあらわしています。赤い部分は否定的(負)荷重であることを表し、青い部分は肯定的(正)荷重であることを表しています。



またいくつかのバイアスと呼ばれる追加のエビデンスも加えています。基本的に、若干数のものが無所属のインプットであると言えるようになりたいのです。クラスiに対するインプットをxとすると、エビデンスは次の式で表すことができます:



ここで W_i はクラスiのウェイト(荷重)を、 b_i はクラスiのバイアス、jは入力イメージxのピクセル値の総和をとるためのインデックスをあらわします。次に、"softmax"関数を使って、エビデンス束を予測確率yに変換します:



ここでのsoftmaxは、"活性化(activation)"関数もしくは"リンク(link)"関数として用いられており、我々が望んでいる(ここでは10ケースにおける確率分布)アウトプットを1次関数として作っている。エビデンスの束をインプットがそれぞれのクラスである確率に変換すると判断することができます。次のように表します:



これを展開すると、次の式になります:



しかしsoftmaxを最初の方法(インプットのエキスポネンシャル(指数乗)をとり、正規化する)として判断することはしばしばより役立つことがあります。エキスポネンシャル(指数乗)は、エビデンスの1つ以上の単位がどんな推測(hypothesis)によって与えられるウェイト(荷重)を乗算的に増やすことを意味しています。そして逆に言えば、エビデンスの1に満たない単位は推測(hypothesis)が初期のウェイト(荷重)のわずかを得ることを意味します。推測(hypothesis)は、0以下のウェイト(荷重)を持つことはありません。そしてsoftmaxは、ウェイト(荷重)を正規化します。そのため1加算し、妥当な確率分布としてフォーマットします。(softmax関数についてより直感的に理解するために、Michael Nielsenの書籍のセクション 、双方向可視化による完全性をチェックしてください)

実際にはもっと多くのxが存在しますが、softmax回帰(後退)を次のように図示できます。アウトプットごとに荷重和を計算し、バイアスを加え、その後softmax関数を適用します。



この絵を方程式で書くと、次のようになります:



このプロシージャは、行列の掛け算とベクトル加算に変換して、 "ベクトル化"が可能です。これはわかりやすく計算に便利です。



更にコンパクトに書くと、次のようになります:



TensorFlowが使えるように、変えてみましょう。


回帰(後退)の実装


一般的に、Pythonで効果的な数値計算を実行するために、行列の掛け算のようなコストの掛かる処理を、Pyhton の外部で別の言語で実装された非常に効果的なコードを使って実行する NumPy のようなライブラリを使います。残念なことに、それぞれの処理がPythonに戻ってくることから多くのオーバヘッドが残ります。データ転送のためのコストが高いため、GPU 上や配信された方法で計算を実行したい場合、オーバヘッドは特に悪くなります。

TensorFlow もまた Python 外部で重いリフティングを実行しますが、それは将来オーバヘッドを回避するステップです。Pyhtonから独立して単一のコストのかかる処理を実行する代わりに、TensorFlowは完全にPython外部で実行する双方向処理のグラフで表現させます。(このような手法は、いくつかの機械学習ライブラリでみうけられます)。

TensorFlowを使用するために、最初にインポートが必要になります。

import tensorflow as tf

記号的な変数を操作することにより、これらの双方向処理を表現します。1つ作成してみましょう:

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

xは特定の値ではありません、TensorFlowへ計算の実行を問い合わせる際に入力する値、placefolderです。我々は、フラットにするとそれぞれ784次元ベクトルになるMNISTイメージを大量に入力可能にしたいと考えています。このMNISTイメージを、フォーマットが[None, 784]Noneは任意の長さとする)である浮動小数点数の2次元テンソルとして表現します。

またモデルのために、ウェイト(荷重)とバイアスも必要です。追加のインプットのようにこれらをあつかうように創造することも可能ですが、TensorFlowにはそれらをあつかう更によい方法Variableがあります。Variableは、双方向処理のTensorFlowのグラフに登場する修正可能なテンソルです。計算処理に使用でき、変更することができます。機械学習アプリケーションでは、それを一般的にモデルパラメータをもつ変数(Variables)にします。

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

初期値を与えられたtf.VariableとしたVariableを作成します:この場合、Wbをともにすべて0のテンソルとして初期化しています。一旦学習を始めてしまうと、初期値はあまり重要ではありません。
Wのフォーマットが[784, 10]であることに注意してください。なぜなら、我々は複数の784次元のイメージベクトルに対して、異なるクラスのエビデンスとして10次元ベクトルを作成して増やしたいためです。bのフォーマットは[10]であるため、アウトプットへ追加することができます。

これでモデルを実装することができるようになりました。定義するためには1行だけですみます!

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

最初にtf.matmul(x, W)により、xをWで掛け算します。複数のインプットでxを2次元テンソルとしてあつかうための小さなトリックとして、方程式にてWxとして増やした時にはじき出されました。そして、bを加え、最後にtf.nn.softmaxを適用しています。

それはそれとして。短い2行のセットアップコードの後ろに1行記述するだけでした。それはTensorFlowはsoftmax回帰(後退)は特に簡単に記述できるよう設計されているからではありません。機械学習モデルから物理学シミュレーションまで、多くの種類の数値計算を記述するために非常に柔軟な方法となっています。一度記述したら、どのマシンでも実行することができます:あなたのCPU、GPU、そして携帯電話でさえも!


学習


モデルを学習させるために、何がモデルにとって良いのかを定義する必要があります。機械学習において、実際には何がモデルにとって悪いのかを定義します。これをコスト、もしくは損失と呼び、モデルに対して我々の望む結果からいかにかけ離れているかを表します。我々はエラーを最小化しようとします、そしてエラーマージンがより少ないほど、モデルがより良くなります。

モデルの損失を決定するとても一般的な、とてもすばらしい機能を 交差エントロピー (cross-entropy)といいます。交差エントロピーは、情報学上において情報圧縮コードについての考察を起源としていますが、ゲーミングから機械学習まで多くの領域で重要であると注目されていました。次のように定義されます:



ここで、yは予測された確率分布を表し、y'は実際の分布(数字ラベルのついた one-hot ベクトル)を表しています。若干の粗い感覚として、交差エントロピーは、真実を記述するための我々の予測がいかに能率が悪いかを計測します。交差エントロピーの詳細に立ち入ることは、このチュートリアルのスコープ範囲外ですが、理解する 価値はあります。

交差エントロピーを実装するために、まず最初に正しい答えを入力するための新しいplaceholderを加えます:

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

そして、交差エントロピー関数 を実装することができます:

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

最初にtf.logは要素ylog計算を実行します。次に、各要素y_と関連する要素tf.log(y)を掛け算します。そしてtf.reduce_sumは、reduction_indices=[1]パラメータにより、yの第2次元要素を加算します。最後にtf.reduce_meanは束内のすべてのexampleから平均を計算します。

ここでは、モデルに何をして欲しいかがわかっているので、TensorFlowに学習させることはとても簡単です。なぜならTensorFlow は計算グラフ全体を知っているので、誤差逆伝播法(バックプロパゲーション) アルゴリズムを自動的に使って、損失が最小となるよう影響するようにどのように変数を定義するかを、効果的に定義します。そして、損失を低減するように最適化アルゴリズムを適用して、変数を修正します。

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

この場合、勾配高価アルゴリズム を学習レート0.5で適用し、cross_entropyが最初になるようにTensorFlowに問い合わせています。勾配高価法は簡単な手順であり、単にTensorFlowがコストを下げる方向にすこし各々の変数をシフトするだけです。しかし、TensorFlowは、その他多くの最適化アルゴリズム も提供します:1行つまむのと同じくらい簡単に使うことができます。

ここで、TensorFlowが実際に舞台裏でなにをしていることは、誤差逆電波法(バックプロパゲーション)と勾配降下法を実装するグラフに新しい処理を追加しています。そして、勾配降下学習の1ステップ(損失を低減させるように変数を微調整する)を実行する処理を1つ後ろにします。

これで、モデル学習のためのセットアップができました。学習を開始する前の最後の作業として、作成した変数の初期化するための処理を生成する必要があります。これは定義しますが、まだ実行されないことに注意してください:

init = tf.initialize_all_variables()

Session内でモデルを起動します、そして変数の初期化処理を実行します:

sess = tf.Session()
sess.run(init)

さあ1000回学習ステップを実行しましょう!

for i 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個のランダムデータポイントの"batch"を取得しています。train_stepを実行し、バッチ内でデータをフィードしてplaceholderに変換しています。

ランダムデータの小さなバッチを使うことを確率的訓練(stochastic training)-ここの場合は、確率的勾配降下法(SGD:Stochastic Gradient Descent)-と呼びます。
理想的には、よりよい答えをえるために、すべてのデータを学習に使用したいのですが、それはとても(コストが)高くなります。このため代わりに、毎回異なるサブセットを使用します。これは(コストが)安く、同一の利益を得ることができます。


モデルの評価


モデルをどのようにして評価しましょうか?

ます最初に、正しいラベルをどこで予測したかを見つけてみましょう。tf.argmaxは、いくつかの軸に沿ってテンソル内の最も高いエントリのインデックスを取得するとても役に立つ関数です。たとえば、tf.argmax(y_,1)がただしいラベルである間、tf.argmax(y,1)は、我々のモデルがそれぞれのインプットに最適であると考えるラベルです。tf_equalは予測が真実に合致するかをチェックするために使うことができます。

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

それは、真偽値のリストを返します。どんな分数が正しいかを決めるために、浮動小数点数としてキャストして、平均をとります。例えば[True, False, True, True]は、まず[1,0,1,1]となり、0.75となります。

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

最後に、テストデータ上の精度を問い合わせます。

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

これはおよそ92%でなければなりません。

これは良い値ですか?本当に?実際この値はかなり悪いです。これはとても簡単なモデルを使っているからです。幾つかの細かい変更を加えると、97%になります。もっともよいモデルは99.7%の精度を超える事ができます!(詳細は、この 結果リスト を見てください。)

我々はこのモデルから学んだということが重要です。これらの結果から少し気持ちが下がったのであれば、もっとよい勉強ができる 次のチュートリアル Deep MINST for Experts をチェックしてください。そして、TensorFlowを使ってより洗練されたモデルをビルドする方法を学んでください!

(青いピル:終わり)
----------
赤いピル(経験のある人向け):

Deep MNIST for Experts



TensorFlow は大規模数値計算のための強力なライブラリです。優れているタスクの一つがディープニューラルネットワークの実装と学習です。このチュートリアルでは、深層畳み込みMNIST分類の構築における TensorFlow モデルの基礎的なビルディング部を学習します。

このチュートラルでは、ニューラルネットワークとMNISTデータセットについて熟知していることを前提としています。もし、それらのバックグラウンドを知らないのであれば、初心者向けの概要( MINST For ML Beginners )を確認してください。開始前に、 TensorFlowのインストール を実施してください。


このチュートリアルについて


このチュートリアル解説における最初の部分は、mnist_softmax.py コードにて実行されます。2番めの部分では、精度向上のための幾つかの方法を紹介します。

チュートリアルからコード断片をPython環境へコピー&ペーストしてもよいですし、コードを読み通してもよいでしょう。

このチュートリアルでは次のことを実施します:

    イメージ内の各ピクセルを参照することを元にした、MNIST数字の理解のためのモデルとなるソフトマックス回帰(後退)関数の作成
    TensorFlowを使って数千もの例を"見る"ことで数字を理解するモデルを学習(そして最初のTensorFlowセッションで実行)
    テストデータを使ったモデル精度のチェック
    結果向上のための多層畳み込みニューラルネットワークのビルド、学習、テスト


セットアップ


モデルを作成する前に、まずMNISTデータセットをロードし、TensorFlowを開始します。


MNISTデータのロード


このチュートリアルからコードをコピー&ペーストする場合、データのダウンロードと読み込みを自動で行うこの2行から開始してください:

from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)

上記コードの、mnistはNumPy配列の学習セット、妥当性検査セット、テストセットを格納する軽量クラスです。後続で使用するデータミニバッチを通してのイテレーティングのための関数も提供します。


TensorFlow相互対話セッションの開始


TensorFlow は計算実行のために非常に効果的なC++バックエンドに頼っています。バックエンドとの通信はセッションと呼ばれています。TensorFlowプログラムの一般的な使い方は、最初にグラフを作成し、次にセッション内で起動します。

ここでは、TensorFlowコードをより柔軟に構築するために便利なInteractiveSessionクラスを代わりに使います。TensofFlowで実行するための 計算グラフ のビルド操作を対話式で行うことができます。特にIPythonのように対話を行いながら作業するため便利です。InteractiveSessionを使用しないのであれば、セッション開始や グラフの起動 前に全体の計算グラフをビルドすべきです。

import tensorflow as tf
sess = tf.InteractiveSession()


計算グラフ


Pythonを使って効果的に数値計算を行うために、一般的にNumPyライブラリを使います。NumPyは、Python外部で行列の掛け算のようなコストの高い処理を実行することができ、その他の言語による非常に効果的なコード実装が使えます。不運なことに、スイッチバックからPythonそれぞれの処理へのオーバーヘッドが未だとても大きいです。GPU上での計算や配信された方法では特にオーバヘッドが悪く、データ変換のために高いコストがかかります。

TensorFlowもPython外部でその重いリフティングを実行します。しかし将来的にはこのオーバヘッドを避ける方法がとられるでしょう。Pythonから独立した単一の高コストな処理の実行の代わりに、TensorFlow はPythong外部で全体的に実行する双方向操作のグラフとして記述させます。このアプローチは Theano や Toach に似ています。

Pythonコードの役割はそれゆえこの外部の計算グラフのビルドと、計算グラフのどの部分を実行すべきかの命令です。詳細は、Basic Usage Computation Graph セクションを参照のこと。


ソフトマックス回帰(後退)モデルのビルド


このセクションでは、単一の線形レイヤを使ったsoftmax回帰モデルをビルドします。次のセクションでは、これを複数の畳込みネットワークを使ったsoftmax回帰のケースに拡張します。


Placeholders


インプットイメージやターゲットとなるアウトプット分類のためのノード生成による計算グラフのビルドをはじめます。

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

ここでxやy_は特定の値ではなく、むしろ、placeholder(TensorFlowに計算の実行を問い合わせる時に入力する値)をさします。

インプットイメージxは浮動小数点数の2次元テンソルで構成されています。ここではx[None, 784]形式で割り当てています。ここで、784は28ピクセル×28ピクセルのMNIST入力イメージをフラットに1次元の配列にしており、Noneはバッチサイズに依存してサイズが決まる1次元目をあらわしています。ターゲットアウトプットクラスy_も2次元テンソルで構成されています。そして、それぞれの列が one-hotな 10次元ベクトルとなっており、関連するMNISTイメージが所属する数字分類(0~9)をあらわしています。
placeholderの形式はオプションですが、この指定によりTensorFlow にテンソル形状の矛盾から発生するバグを自動で受け取らせることになります。


Variables


モデルのウェイト(荷重)をW、バイアスをbと定義します。これらを追加的なインプットとしてあつかうことを想定できますが、TensorFlowではこれらをあつかうさらなる良い方法Variableがあります。Variableは、TensorFlowの計算グラフ内であつかう変数のことです。計算に使用したり更新する事が可能です。機械学習アプリケーションでは、一般的にモデルパラメータを保持するものはVariablesです。

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

tf.Variableへのコール内の各引数として初期値を渡しています。このケースでは、Wおよびbにすべてゼロのテンソルで初期化しています。Wは784×10の行列(785のインプットと10のアウトプットがあるため)、bは10-次元ベクトル(10種類の分類をもつため)です。

セッション範囲内でVariablesが使用される前に、初期化する必要があります。このステップでは既に特定されている初期値(このケースではすべてゼロのテンソル)を取得し、それらをVariableへ割り当てています。直ちにすべてのVariablesとして実行します:

sess.run(tf.initialize_all_variables())


予測クラスと損失関数


後退モデルを実装することができます。それはたった1行記述するだけです!ベクトル化されたインプットイメージxにウェイトWを掛け算し、バイアスbを加え、それぞれの分類に割り当てられるsoftmax確率を計算します。

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

簡単にちょうどの損失関数を特定することができます。損失はある一つの例におけるモデルの予測がいかに悪いかの指標です:全ての例に対して学習により最小化させることを試みます。ここでの損失関数は、ターゲットとモデルの予測の間の 交差エントロピー (cross-entropy)です:

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

tf.reduce_sumがすべての分類をとおした総和を計算し、tf.reduce_meanがそれらの総計から平均を計算していることに注意してください。


モデルの学習


モデルと学習損失関数の定義をおこなったので、モデルをTensorFlowを使って学習させることは簡単です。なぜなら、TensorFlowは全体の計算グラフを認識しており、それぞれの変数に関しての損失勾配を発見を自動的に定義することができます。TensorFlowは様々なビルトインされた最適化アルゴリズムを持っています。この例では、ステップ長0.5、交差エントロピーで降下する、最急降下法 (steepest gradient descent) を使用します。

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

TensorFlowでは、計算グラフに新しい操作を追加するために実際には1行で実行しました。これらの処理には降下の計算、パラメータ更新ステップの計算、そしてパラメータへステップを更新する処理がふくまれています。

実行時に、戻ってきたtrain_step処理はパラメータへ勾配降下を適用します。それゆえtrain_stepをクリ消し実行することによりモデルの学習を完遂することができます。

for i in range(1000):
  batch = mnist.train.next_batch(100)
  train_step.run(feed_dict={x: batch[0], y_: batch[1]})

100の学習例をそれぞれのイテレーション内でロードします。そしてtrain_step処理を実行します、その際学習例でplaceholderテンソルxとy_を置き換えるためにfeed_dictを使用しています。feed_dict使って計算グラフのテンソル(placeholderに制限されない)を置き換え可能なことに注意してください。


モデルの評価


我々のモデルはどれくらい良いのでしょうか?

まず、どこで正しいラベルを予測したかが分かります。tf.argmaxは、いくつかの軸に沿ってテンソルの最も高いエントリのインデックスを取得する、とても役に立つ関数です。例えば、 tf.argmax(y_,1)が真実のラベルであるとすると、tf.argmax(y,1)はモデルがそれぞれのインプットに最適であると考えるラベルとなります。tf.equalを予測と真実があっているかチェックするために使用することができます。

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

これは、真偽値リストを返します。割合が正しいを決めるために、浮動小数点数にキャストし、平均をとります。たとえば、[True, False, True, True]はやすとにより[1,0,1,1]となるので、平均は0.75となります。

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

最後に、テストデータにおける精度を評価することができます。ここでは約92%正確とでました。

print(accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.labels}))


多層計算ネットワーク


92%の精度は、MNISTとしては良くありません。というか、気恥ずかしいほど悪い値です。このセクションでは、極めてシンプルなモデルから適度に洗練されたもの、小さな畳み込みニューラルネットワークへ、修正します。これでだいたい99.2%の精度になります--これは最高水準の技術ではありませんが、立派なものです。

ウェイトの初期化


このモデルを作成するためには、たくさんのウェイトやバイアスを作成する必要があります。通常、 対称性の破れ (symmetry breaking)や、0勾配をさけるために、少しノイズの入ったウェイトを初期化します。ReRU ( ランプ関数,正規化線形関数 )ニューロンを使っているので、"dead neurons"を避けるためにそれらをわずかに正値な初期バイアスでそれらを初期化することもよい方法です。モデルのビルド中繰り返しこれを実行する代わりに、二つの便利な関数を作成しましょう。

def weight_variable(shape):
  initial = tf.truncated_normal(shape, stddev=0.1)
  return tf.Variable(initial)

def bias_variable(shape):
  initial = tf.constant(0.1, shape=shape)
  return tf.Variable(initial)


畳込みとプーリング


TensorFlowもまたconvolution(畳み込み:特徴量の畳み込みを行う層)やpooling(プーリング:レイヤの縮小をおこない扱いやすくする層)に対する多くの柔軟性を提供します。バウンダリ(境界)をどのように扱いますか?ストライドのサイズはいくつにしますか?この例では、たいていバニラバージョン(何も手を加えないデフォルト状態)を選択しています。我々の畳み込みではストライドを1で水増しなしで使用しているため、アウトプットはインプットと同じサイズになります。我々のプーリングは2×2ブロックの単純で古いmax pooling(各領域内の最大値をとって圧縮を行う方法)です。コードをきれいに維持するために、関数のそれらの処理も要約してみましょう。

def conv2d(x, W):
  return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

def max_pool_2x2(x):
  return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
                        strides=[1, 2, 2, 1], padding='SAME')

最初の畳み込み層


最初の層を実装します。最初の層には、max poolingにより畳み込みをふくみ、そしてmax poolingが続きます。畳込みでは5×5パッチごとの32の特徴量を計算します。そのウェイトテンソルは[5, 5, 1, 32]という形式です。最初の2つの次元はパッチサイズです。その次は入力チャネルの数で、最後がアウトプットチャネルの数です。各アウトプットチャネルのための構造のバイアスベクトルも持っています。

W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])

レイヤに適用するために、まずxを、2番めそして3番めの次元がイメージの幅と高さに一致していて、4番めの次元が色チャネルの数に一致している4次元テンソルに変換します。

x_image = tf.reshape(x, [-1,28,28,1])

そしてx_imageをウェイトテンソルで畳み込み、バイアスを加え、ReLU関数を適用し、最後にmax poolしています。

h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)


2番めの畳み込み層


深いネットワークを構築するために、このタイプの双をいくつか積み重ねます。2番めのレイヤは各5×5パッチの64個の特徴量を保持します。

W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])

h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)


全結合層(密層)


ここまででイメージサイズは7×7に低減されています。この状態で1024ニューロンの全結合層を加えてイメージ全体処理を許可します。テンソルをプーリング層からベク取りの束に変換し、ウェイトマトリクスで掛け算し、バイアスを加え、ReLUを適用します。

W_fc1 = weight_variable([7 * 7 * 64, 1024])
b_fc1 = bias_variable([1024])

h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)


ドロップアウト


過学習 (overfitting)を減らすために、リードアウト層の前に ドロップアウト を適用します。ドロップアウト中ニューロンのアウトプットが維持される確率のためのplaceholderを作成します。これは学習中ドロップアウトをオンにし、テスト中にドロップアウトをオフにすることを許可します。TensorFlowのtf.nn.dropout opはマスキングに加えニューロンアウトプットのスケーリングを自動的に取り扱います、そしてドロップアウトは追加のスケーリングなしで動作します。

keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

この小さな畳み込みネットワークにおいて、パフォーマンスは実際にはドロップアウトあり、なしでほとんど同じです。ドロップアウトはしばしば過学習の低減するにはとても効果的ですが、とても大きなニューラルネットワークの場合とても役に立ちます。



リードアウト層


最後に、前述のsoftmax後退(回帰)を一つの層にしたような、softmax層を加えます。

W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])

y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)

モデルの学習と評価


このモデルはどのくらいの良さでしょうか?モデルの学習や評価のために、簡単な一つの層のために上のSoftmaxネットワークに近いコードを使用します。

違いは:

    最急勾配降下オプティマイザをより洗練されたADAMオプティマイザに変える
    ドロップアウトレートをコントロールするために、 feed_dict 内にパラメータ keep_prob を追加する
    学習プロセスの各100番めのイテレーションにログ出力を追加する

先にすすみ、このコードを実行してください。20,000繰り返し学習を実施すると、プロセッサによりますが、すこじ時間がかかります(おそらく30分くらい)。

cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y_conv), reduction_indices=[1]))
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
sess.run(tf.initialize_all_variables())
for i in range(20000):
  batch = mnist.train.next_batch(50)
  if i%100 == 0:
    train_accuracy = accuracy.eval(feed_dict={
        x:batch[0], y_: batch[1], keep_prob: 1.0})
    print("step %d, training accuracy %g"%(i, train_accuracy))
  train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})

print("test accuracy %g"%accuracy.eval(feed_dict={
    x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))

コード実行後の最後のテストセットの正確さはおよそ99.2%になります。

これでTensorFlow を使ったかなり洗練されたディープラーニングモデルをいかに早く、簡単にビルド、学習、評価するかを勉強することができました。

(赤いピルおわり)
----------

青い方はナントカわかった..気がする。
コードをjupyter画面(コンテナ上で8888へアクセス)から入れると動くので、なんとなくわかった気がするが..
赤い方はいろいろ足りない、というか機械学習の本を読まんとわからない。

しかもどんな関数があるのかさっぱりわからない状態だし、活性化関数やらバックプロパケゲーションやら勾配降下法やら..畳み込みやプーリング..

イカン、脳がぷすぷすしてきた..


0 件のコメント:

既存アプリケーションをK8s上でコンテナ化して動かす場合の設計注意事項メモ

既存アプリをK8sなどのコンテナにして動かすには、どこを注意すればいいか..ちょっと調べたときの注意事項をメモにした。   1. The Twelve Factors (日本語訳からの転記) コードベース   バージョン管理されている1つのコードベースと複数のデプロイ 依存関係 ...