0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

TensorFlowによるMNIST文字認識

Posted at

※以下、個人的な勉強のためのレポートです。
※間違い多々あると存じますが、現在の理解レベルのスナップショットのようなものです。
※勉強のためWebサイトや書籍からとても参考になったものを引用させていただいております。
http://ai999.careers/rabbit/

MNIST

https://weblabo.oscasierra.net/python/ai-mnist-data-detail.html
・手書きで書かれた数字を画像にした画像データ(image)と、その画像に書かれた数字(0~9)を表すラベルデータ(label)から構成される
・ペアは、学習用に60,000個、検証用に10,000個の数提供されている
  train-images-idx3-ubyte: 学習用の画像セット
  train-labels-idx1-ubyte: 学習用のラベルセット
  t10k-images-idx3-ubyte: 検証用の画像セット
  t10k-labels-idx1-ubyte: 検証用のラベルセット
・28×28の升目(ピクセル)と、その値(チャネル、ピクセル値:0~255までの値、0が白,255が黒)

実装

# 入力xのプレースホルダ、28*28=784
x = tf.placeholder(tf.float32, [None, 784])
# 出力dのプレースホルダ、0-9までの10分類
d = tf.placeholder(tf.float32, [None, 10])
# 重み。784個の数値から出力層10個へのそれぞれの重み。標準偏差0.01で初期化。
W = tf.Variable(tf.random_normal([784, 10], stddev=0.01))
# バイアス。出力層10個それぞれについて一つずつ。0で初期化。
b = tf.Variable(tf.zeros([10]))
# 計算ノード。分類問題なのでソフトマックス関数を使用。
y = tf.nn.softmax(tf.matmul(x, W) + b)

# 誤差関数には交差エントロピーの値を使用。
cross_entropy = -tf.reduce_sum(d * tf.log(y), reduction_indices=[1])
loss = tf.reduce_mean(cross_entropy)
train = tf.train.GradientDescentOptimizer(0.1).minimize(loss)

結果

image.png
100の学習で、正解率 約87%

実際のデータの確認

plt.imshow(x_batch[0].reshape(28,28))

image.png

3層化

中間層を二つ作成するため、600と300で用意する。
入力層784⇒中間層600⇒中間層300⇒出力層10

hidden_layer_size_1 = 600
hidden_layer_size_2 = 300

# 3層化されたので、重み、バイアスともに3つ用意する
W1 = tf.Variable(tf.random_normal([784, hidden_layer_size_1], stddev=0.01))
W2 = tf.Variable(tf.random_normal([hidden_layer_size_1, hidden_layer_size_2], stddev=0.01))
W3 = tf.Variable(tf.random_normal([hidden_layer_size_2, 10], stddev=0.01))

b1 = tf.Variable(tf.zeros([hidden_layer_size_1]))
b2 = tf.Variable(tf.zeros([hidden_layer_size_2]))
b3 = tf.Variable(tf.zeros([10]))

dropoutにより、過学習を抑制する。

dropout_rate = 0.5
keep_prob = tf.placeholder(tf.float32)
drop = tf.nn.dropout(z2, keep_prob)

結果

image.png
正解率が約90%に改善

ハイパーパラメータの変更

中間層のノード数を、600/300から、100/50に変更
image.png
⇒パラメータ数が減少することでマシンの処理は軽くなるが、学習精度は落ちる
中間層のノード数を、1000/500に変更
image.png
⇒パラメータ数が増大することでマシンの処理負荷は重たくなる。しかし学習精度は約91%まで改善。

NNにおいては、中間層のノード数は、速度と精度のトレードオフを考慮する必要がある

最適化関数の変更

momentum
image.png
⇒精度が94%まで改善
Adagrad
image.png
⇒精度 約90%
RMSProp
image.png
⇒96.75%を達成!

実際には、各最適化関数が頭打ちになるまで学習回数を上げて比較すると良い。

CNN(Convolutional Neural Network:畳み込みニューラルネットワーク)

構造

conv - relu - pool - conv - relu - pool - affin - relu - dropout - affin - softmax

実装

# 第一層のweightsとbiasのvariable
# 最初の5*5がCNNのフィルターサイズ。1チャネルのものを32チャネルに拡張。
W_conv1 = tf.Variable(tf.truncated_normal([5, 5, 1, 32], stddev=0.1))
b_conv1 = tf.Variable(tf.constant(0.1, shape=[32]))

# 第一層のconvolutionalとpool
# strides[0] = strides[3] = 1固定
# ストライドは1、パディングはSHAPEが変わらないような値を設定。
h_conv1 = tf.nn.relu(tf.nn.conv2d(x_image, W_conv1, strides=[1, 1, 1, 1], padding='SAME') + b_conv1)
# プーリングサイズ n*n にしたい場合 ksize=[1, n, n, 1]
# max_poolが2,2、ストライドが2,2
h_pool1 = tf.nn.max_pool(h_conv1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

# 第二層
W_conv2 = tf.Variable(tf.truncated_normal([5, 5, 32, 64], stddev=0.1))
b_conv2 = tf.Variable(tf.constant(0.1, shape=[64]))
h_conv2 = tf.nn.relu(tf.nn.conv2d(h_pool1, W_conv2, strides=[1, 1, 1, 1], padding='SAME') + b_conv2)
h_pool2 = tf.nn.max_pool(h_conv2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

# 第一層と第二層でreduceされてできた特徴に対してrelu
# affinの実装部分
# max_poolの出力が7*7*64になっているので、reshapeで1次元に直す。
W_fc1 = tf.Variable(tf.truncated_normal([7 * 7 * 64, 1024], stddev=0.1))
b_fc1 = tf.Variable(tf.constant(0.1, shape=[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)

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

# 出来上がったものに対してSoftmax
W_fc2 = tf.Variable(tf.truncated_normal([1024, 10], stddev=0.1))
b_fc2 = tf.Variable(tf.constant(0.1, shape=[10]))
y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)

# 交差エントロピー
loss = -tf.reduce_sum(d * tf.log(y_conv))

train = tf.train.AdamOptimizer(1e-4).minimize(loss)

correct = tf.equal(tf.argmax(y_conv,1), tf.argmax(d,1))
accuracy = tf.reduce_mean(tf.cast(correct, tf.float32))

結果

image.png
⇒計算負荷は高い。しかし精度は最高で96%を記録。計算回数を増加させることで、99%まで高まる可能性もある。

ハイパーパラメータの変更

dropout_ratioを0.0に変更(dropoutさせない)
image.png
⇒あまり変わらない。やや下がる。

論文からの実装

State of the Art:現時点で一番精度が高い技術
ex)「VGG16 arxiv」で検索。
※arXiv(アーカイヴ、archiveと同じ発音)は、物理学、数学、計算機科学、量的生物学、計量ファイナンス、統計学の、プレプリント(英語版)を含む様々な論文が保存・公開されているウェブサイト
⇒PDF版の論文が閲覧可能
ex)ブログなどでの考察
ex)githubの実装コード。実装が入手できる。

JDLAの例題

image.png

(答え)a
必要なパラメータ数は増加するが、その分スパース(Sparse:「すかすか」、「少ない」の意)な演算になる。よってdense(密)ではない。

image.png

(答え)a
Auxiliary calssifiresを導入して、calssifiresを増加させて計算量を減少させているわけではない。
image.png
image.png
image.png

(答え)a、a、a
いわゆるskipコネクション。これにより層を深くしても学習が進むことになった。

image.png

(答え)あ
転移学習の問題。(あ)は、転移学習の例としては不適切。

image.png

(答え)a
b
最大ではなく、必ず定義された2つの候補領域は生成されるように実装されている
c
2つの誤差の単純和ではなく、位置特定誤差と各クラスの確信度に対する二つの誤差の重みづけまで表現されている。
d
出力についてはカテゴリの+の確率と、二つの候補領域が出力されるというところが間違い。

確認テスト

VGG/GoogleNet/ResNetの特徴をそれぞれ述べよ
http://thunders1028.hatenablog.com/entry/2017/11/01/035609
〇VGG
AlexNetをより深くした、畳み込み層とプーリング層から成るどノーマルなCNNで、重みがある層(畳み込み層や全結合層)を16層、もしくは19層重ねたもの。それぞれVGG16やVGG19と呼ばれる。小さいフィルターを持つ畳み込み層を2〜4つ連続して重ね、それをプーリング層でサイズを半分にするというのを繰り返し行う構造が特徴。パラメータも多い。大きいフィルターで画像を一気に畳み込むよりも小さいフィルターを何個も畳み込む(=層を深くする)方が特徴をより良く抽出できる。
〇GoogleNet
通常の入力層から出力層まで縦一直線な構造ではなく、インセプション構造と呼ばれる横にも層が広がる構造をしている。このため、Inceptionモデルとも呼ばれる。横への層の広がりは、異なるサイズのフィルターの畳み込み層を複数横に並べて、それを結合するという形になっている。
〇ResNet
これまでのネットワークでは層を深くしすぎると性能が落ちるという問題があったが、それを「スキップ構造」によって解決し、152層もの深さを実現した。スキップ構造は、ある層への入力をバイパスし層をまたいで奥の層へ入力してしまうというもので、これにより勾配の消失や発散を防止し、超多層のネットワークを実現している。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?