tensorflow1.xでNeural Network2

tensorflow1.xでNeural Network2

3日坊主の病が発病しそうな私です。そのため今回の記事は2日かけて作成しました。

さて、今回はNeuralNetworkの学習についての説明を行おうと思います。

NeuralNetworkの学習

Neural Networkの学習は、一般的にいくつかの段階に分かれて行われます。今回は、その中でも現代で一般的に用いられる学習の流れを見ていきましょう。

まずはじめに、Neural Networkの学習は以下の3段階に分かれます。

  1. 訓練データを使用した予想
  2. 予想結果と回答を比較
  3. 比較結果を使用した学習

1段階目は、前回の記事で説明した数式を用いての予想です。予想する入力は、あらかじめ回答が分かっているデータ(訓練データ、教師データなどという)を使用します。ここでは、予想結果が正しいかどうか、どれぐらいあっているかなどは考慮しません。

2段階目は1段階目で予想した結果と予想に使用したデータの回答があっているかを確認します。この回答と予想結果があっているかというのは、比較に使用する式によって尺度が異なります。今回は、今後の記事で最もよく使うであろう二乗誤差について説明します。二乗誤差は非常にシンプルな数式で、とてもわかりやすいため、学習用途から実際での運用まで幅広く使われています。では、その式を見ていきましょう。

$$
l=(y-t)^2
$$

この式において、\(y\)は予想された回答を、\(t\)は正しい回答を示します。つまりこの式は、予想した結果が回答に近いほど0に近づき、回答と遠ければ正の方向へ向かっていくというものです。

今回は、二乗誤差を説明しましたが、それ以外の方法でも全く問題ありません。様々な式を使用してみてください。

3段階目は、2段階目で算出した誤差値(回答と予想結果の差)を出来るだけなくすために、誤差値を使って重みやバイアスといったパラメータを修正します。この誤差を修正する方法は一般的にOptimizer(オプティマイザー)と呼ばれ、様々なものがあります。しかし、Optimizerの説明には、多くの数式を使わなくてはいけないため、今回の記事では解説を省略させていただき、有名な方法の名前と特徴のみを説明します。詳しい手法が知りたい方は、「back propagation」や「誤差逆電波法」、「Optimizer」といった内容で検索するか、書籍を探して読んでください。気が向いたらこのサイトでも詳しい解説を行おうと思います。

Optimizerの有名な例と特徴をいかに挙げます。

  • SGD:最も単純な手法。学習率という値によって変数が学習する量を調整できる
  • Momentum SGD:SGDに慣性の法則を適用し、改良したもの
  • Adam:現状で最も高く評価されている手法。tensorflowでは学習率なしで可

本サイトでは、基本的にはSGD(確率的勾配降下法)を使用しようと考えています。

数式の学習

では、前回の記事で使った式を学習で求めてみようと思います。目的の重みとバイアスは

$$
\omega
=
(5,2)
$$

$$b=10$$

です。また、入力の\(x\)はshape=(2,1)、出力の\(y\)はshape=(1,1)です。

上記の設定から、学習データは

$$y=5x_1+2x_2+10$$

で生成できることがわかります。今回は1000個のデータを生成して、1つずつ試してみましょう。ちなみに、今回の学習には二乗誤差とSGDを使用します。SGDはtensorflowの関数を使用しますが、その使用方法は

  • tf.GradientDescentOptimizer(学習率).minimize(誤差関数)

です。ではプログラムを見ていきましょう。

#インポート
import tensorflow as tf
import random

#式の定義

# 重みの定義
# tf.zeros(shape,型):shapeサイズの0行列を定義
weight=tf.Variable(tf.zeros([1,2],tf.float32))

# バイアスの定義
b=tf.Variable(tf.zeros([1,1],tf.float32))

# 入力の定義
x=tf.placeholder(tf.float32,(2,1))

# 教師データの定義
t=tf.placeholder(tf.float32,(1,1))

# 式の設定
y=tf.add(tf.matmul(weight,x),b)

# 誤差関数の定義(二乗誤差)
# tf.square(n)=n^2の関数
loss=tf.square(y-t)

# 学習方法の定義(SGD, learning rate=0.01)
train=tf.train.GradientDescentOptimizer(0.01).minimize(loss)

#式の定義終了

#セッションの開始
with tf.Session() as s:
s.run(tf.global_variables_initializer()) #変数の初期化 (重要!)

for i in range(0,1000,1): #1000回学習を行う
#教師データの生成
x_1=random.uniform(0,10)
x_2=random.uniform(0,10)
train_y=[[5.0*x_1+2.0*x_2+10.0]]
train_x=[[x_1],[x_2]]

#重みとバイアスの遷移を確認
if i%100==0:
print("Step:",i)
print("\tweight=",s.run(weight))
print("\tbias=",s.run(b))

#学習の実行
s.run(train,feed_dict={x:train_x,t:train_y})

#結果の出力
print("Step:",i+1)
print("\tweight=",s.run(weight))
print("\tbias=",s.run(b))
<実行結果>
Step: 0
weight= [[0. 0.]]
bias= [[0.]]
Step: 100
weight= [[6.3341823 2.696506 ]]
bias= [[3.6507967]]
Step: 200
weight= [[5.621875 2.33228 ]]
bias= [[5.3215523]]
Step: 300
weight= [[5.494213 2.3474045]]
bias= [[6.451512]]
Step: 400
weight= [[5.8472013 2.0943046]]
bias= [[7.5707026]]
Step: 500
weight= [[5.272698 2.3371224]]
bias= [[8.141498]]
Step: 600
weight= [[5.0878334 2.1333199]]
bias= [[8.436589]]
Step: 700
weight= [[5.016867 2.1196682]]
bias= [[8.784444]]
Step: 800
weight= [[5.170677 1.9638484]]
bias= [[9.051755]]
Step: 900
weight= [[5.130745 2.0097928]]
bias= [[9.335207]]
Step: 1000
weight= [[5.0407014 2.0339506]]
bias= [[9.532385]]

1000回も行う必要は無かったですねw。元の式にとても近い結果が出たことがわかります。皆さんも学習回数などを変化させてみてくださいね。

誤差がある場合の学習

さて、先の章で数式の学習が出来たと思います。しかし、先の例は予想する数式に関して完全に正しい\(x\)と\(y\)の関係を与えていました。しかし、先のような例を現実で応用する場合には、年間の気温や日本の平均年収の変化などを学習させることになると思います。しかし、これらのものは完全に綺麗な数式の関係になるとは限りません。つまり、\(x\)と\(y\)の関係に誤差が入ってしまうのです、では、そのような場合にNeuralNetworkはどのような出力を行なうのでしょうか?実際にプログラムを書いて確認してみようと思います。

今回は、誤差を人工的に作成するために、正しい式の値に-10~+10のランダムな浮動小数点数を足してみようと思います。では、プログラムを見てみましょう。プログラムは先ほどのものとほとんど変わらないので、教師データの生成部分と実行結果だけ注目してくださいね。

#インポート
import tensorflow as tf
import random

#式の定義

# 重みの定義
# tf.zeros(shape,型):shapeサイズの0行列を定義
weight=tf.Variable(tf.zeros([1,2],tf.float32))

# バイアスの定義
b=tf.Variable(tf.zeros([1,1],tf.float32))

# 入力の定義
x=tf.placeholder(tf.float32,(2,1))

# 教師データの定義
t=tf.placeholder(tf.float32,(1,1))

# 式の設定
y=tf.add(tf.matmul(weight,x),b)

# 誤差関数の定義(二乗誤差)
# tf.square(n)=n^2の関数
loss=tf.square(y-t)

# 学習方法の定義(SGD)
train=tf.train.GradientDescentOptimizer(0.01).minimize(loss)

#式の定義終了

#セッションの開始
with tf.Session() as s:
s.run(tf.global_variables_initializer()) #変数の初期化 (重要!)

for i in range(0,1000,1): #1000回学習を行う
#教師データの生成
x_1=random.uniform(0,10)
x_2=random.uniform(0,10)
noise=random.uniform(-10,10)
train_y=[[5.0*x_1+2.0*x_2+10.0+noise]]
train_x=[[x_1],[x_2]]


#重みとバイアスの遷移を確認
if i%100==0:
print("Step:",i)
print("\tweight=",s.run(weight))
print("\tbias=",s.run(b))

#学習の実行
s.run(train,feed_dict={x:train_x,t:train_y})

#結果の出力
print("Step:",i+1)
print("\tweight=",s.run(weight))
print("\tbias=",s.run(b))
<実行結果>
Step: 0
weight= [[0. 0.]]
bias= [[0.]]
Step: 100
weight= [[6.122146 1.6358068]]
bias= [[2.0587955]]
Step: 200
weight= [[4.376486 0.94254154]]
bias= [[4.1033163]]
Step: 300
weight= [[3.2946622 1.5833774]]
bias= [[6.385468]]
Step: 400
weight= [[6.5751715 2.3931665]]
bias= [[7.314698]]
Step: 500
weight= [[5.0242863 1.7033927]]
bias= [[7.8665204]]
Step: 600
weight= [[6.0198026 2.1621714]]
bias= [[8.213294]]
Step: 700
weight= [[3.3249807 6.9534197]]
bias= [[9.748796]]
Step: 800
weight= [[3.2814853 5.249816 ]]
bias= [[11.014596]]
Step: 900
weight= [[3.9173417 2.5547924]]
bias= [[11.215666]]
Step: 1000
weight= [[5.76473 2.9821804]]
bias= [[10.926173]]

先ほどの結果と比較してみると、最終的な結果が正しいものと離れていますね。しかし、入力値に誤差が存在する場合でもある程度正しい値を導いていることがわかります。

ちなみに、このような誤差の結果は学習元のデータ数と学習回数の増加、学習率の調整、重みやバイアスの初期値の調整などをすることによって軽減することができます。試しに先のプログラムの学習回数を100000回、学習率を0.0001にして試してみましょう

<実行結果>
Step: 0
weight= [[0. 0.]]
bias= [[0.]]
Step: 10000
weight= [[5.664785 2.5702906]]
bias= [[3.0718572]]
Step: 20000
weight= [[5.404597 2.5159144]]
bias= [[4.79958]]
Step: 30000
weight= [[5.243263 2.4508018]]
bias= [[6.102368]]
Step: 40000
weight= [[5.2848277 2.306048 ]]
bias= [[7.0635843]]
Step: 50000
weight= [[5.168893 2.1761227]]
bias= [[7.757717]]
Step: 60000
weight= [[5.197392 2.1993303]]
bias= [[8.369234]]
Step: 70000
weight= [[5.1870613 2.108672 ]]
bias= [[8.704726]]
Step: 80000
weight= [[5.0881906 2.0128388]]
bias= [[9.009314]]
Step: 90000
weight= [[5.0097246 2.1022604]]
bias= [[9.3196535]]
Step: 100000
weight= [[5.0234857 2.0715072]]
bias= [[9.549063]]

実際に先ほどの結果より正しい値に近づいていることがわかります。しかし、微々たる量ですよね。しかし、この微々たる量を正解に近づけることが重要になるのです。ちなみに、Deep Learningの学習に膨大な量のデータ(ビックデータなどとも言ったり)と高いスペックが必要と言われる理由がこれです。

今日は以上!

まとめ

  • Neural Networkの学習は3段階に分かれて行われる
  • 学習データの入出力に誤差があっても、ある程度正しい値になる
  • 学習データを大量に使用し、学習を多く行うことで精度が向上する
  • SGD:tf.GradientDescentOptimizer(学習率).minimize(誤差関数)


コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です