TensorFlowを動かしてみた

Google先生が出している機械学習ライブラリ、TensorFlowを動かしてみました。

Pythonで触れるとのこと。

インストールはAnacondaからpipコマンドで入れてみます。

以下のサイトなどを参考にしてみます。

 

qiita.com

最初は上手く動かなかったのですが、TensorFlowのVersionをちょっと古いのに指定すると何とか動いてくれました。

 

というわけで、早速チュートリアル???のコードを動かしてみる。

GetStartでゲットできるコード、簡単な線形回帰分析で試してみます。

以下のサイトを参考にしてみました。

qiita.com

y=0.1x+0.3

のプロット上の点を100点ほどサンプル取得して、0.1とか0.3という方程式のパラメタを推定するという問題。

 

------------------------------

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):
    if step % 20 == 0:
        print((step, sess.run(W), sess.run(b)))
    sess.run(train)

# Learns best fit is W: [0.1], b: [0.3]

------------------------------

 

TensorFlowの使い方という意味ではとても良いサンプルなんだろうけど、どうしてもAPIブラックボックス化していてよくわからない。

自分なりに、色々考えて何をやっているかを分析してみました。

どうやら、w,bというパラメタを初期値を適当に決めて、最小二乗のコスト関数に対して最急勾配法を用いて収束演算をしているようです。

ja.wikipedia.org

アルゴリズム自体は大したことは無く、評価関数に対してパラメタの1回偏微分を更新量としてアップデートすればOK。

具体的には・・・サンプルを以下のように定義する。(今回の例ではN=100っぽい)

f:id:tubarin:20200320074923j:plain

このとき、x_nとy_nの関係は以下のようになるように構成しています。

(今回の例では、w=0.1,b=0.3が真値)

f:id:tubarin:20200320074953j:plain

そして、コスト関数はというと、残差の二乗和なので、以下のようになります。

w、bは初期パラメータと考えればOKです。

f:id:tubarin:20200320075103j:plain

もちろん、w,bが正しい値のときには、めでたくL(w,b)=0となるので、Lを最小化するw,bを探せばよいわけですね。

最急勾配法では、初期パラメタの更新を1回偏微分で実施するので、それぞれ求めておきます。

f:id:tubarin:20200320075215j:plain

f:id:tubarin:20200320075533j:plain

これを利用すると、あるパラメタ初期値、w^(k),b^(k)を更新するには以下のようにしていくようです。

f:id:tubarin:20200320075554j:plain

大変申し訳ないのですが、天下り的に、係数αを以下のように決めます。これはTensorFlowのライブラリに渡す係数の特徴から決めています。

f:id:tubarin:20200320075722j:plain

β・・・なんか名前があるんだろうか?ここを収束の設定パラメタとして最初に決めるようです。今回のサンプルだとβ=0.5とします。

 

というわけで、自前のClassを作って検証してみます。

以下の感じでどうでしょうか?

 

--------------------------

class calcWB:
 def __init__(self,x,y,w,b):
  self.x = x
  self.y = y
  self.w = w
  self.b = b
  # get length of sample data
  self.N = len(x)

 def run(self,beta):
  # calculate current redisual
  residual = self.y - (self.w*self.x + self.b)
  # calc dL/dw
  dw = -2*np.dot(residual,self.x)
  # calc dL/db
  db = -2*sum(residual)
  # calc alpha
  alpha = beta/self.N
  # update param(w,b)
  self.w = self.w - alpha*dw
  self.b = self.b - alpha*db
  return self.w,self.b

----------------------

 

初期化用のメソッドと、学習用のrunというメソッドの2つのみ。

これを使って、最初のサンプルを変更すると、以下のようになりそうです。

 

------------------------

# setting param init data
w_init = np.random.rand()-.5
b_init = np.random.rand()-.5

# GradientDescentOptimizer parameter
beta = 0.5

# 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], -10, 10))
W = tf.Variable(w_init)
#b = tf.Variable(tf.zeros([1]))
b = tf.Variable(b_init)
y = W * x_data + b

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

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

# Launch the graph.
sess = tf.Session()
sess.run(init)


# create calcWB object
objCalcWB = calcWB(x_data,y_data,w_init,b_init)

# Fit the line.
for step in range(201):
 sess.run(train)
 w_tmp,b_tmp = objCalcWB.run(beta)

 if step % 20 == 0:
  #print(step, sess.run(W), sess.run(b))
  print('[from TensorFlow] k=%d w=%.10f b=%.10f' % (step, sess.run(W), sess.run(b)))
  print('[from calcWB] k=%d w=%.10f b=%.10f' % (step,w_tmp,b_tmp))

# Learns best fit is W: [0.1], b: [0.3]

------------------

 

実行結果を見てみると・・・

------------------

 [from TensorFlow] k=0 w=0.4332985282 b=0.2284004837
[from calcWB]         k=0 w=0.4332985584 b=0.2284004998
[from TensorFlow] k=20 w=0.1567724198 b=0.2680215836
[from calcWB]        k=20 w=0.1567724287 b=0.2680215712
[from TensorFlow] k=40 w=0.1113634855 b=0.2935992479
[from calcWB]        k=40 w=0.1113634986 b=0.2935992433
[from TensorFlow] k=60 w=0.1022744998 b=0.2987188399
[from calcWB]        k=60 w=0.1022745020 b=0.2987188350
[from TensorFlow] k=80 w=0.1004552618 b=0.2997435629
[from calcWB]        k=80 w=0.1004552578 b=0.2997435619
[from TensorFlow] k=100 w=0.1000911444 b=0.2999486625
[from calcWB]        k=100 w=0.1000911188 b=0.2999486686
[from TensorFlow] k=120 w=0.1000182480 b=0.2999897301
[from calcWB]        k=120 w=0.1000182499 b=0.2999897517
[from TensorFlow] k=140 w=0.1000036523 b=0.2999979556
[from calcWB]        k=140 w=0.1000036551 b=0.2999979575
[from TensorFlow] k=160 w=0.1000007242 b=0.2999995947
[from calcWB]        k=160 w=0.1000007308 b=0.2999995937
[from TensorFlow] k=180 w=0.1000001431 b=0.2999999225
[from calcWB]        k=180 w=0.1000001444 b=0.2999999224
[from TensorFlow] k=200 w=0.1000000909 b=0.2999999523
[from calcWB]        k=200 w=0.1000000255 b=0.2999999832

------------------

 となり、大体小数点以下7桁ぐらいまであっているので、考え方としてはよさそうです。

なるほど、TensorFlowのGradientDescentOptimizerがやっていることを少し理解できた気がします。

 

 

 

と、技術的な内容を書いてしまいましたが、やっぱり普通のブログにこういう記事は無理があるかも???

数式も画像だし、ソースコードを貼り付けるとスペースが消えたりするし。

素直にQiitaへ投稿すべきかもしれませんね。

いずれちょっと転記も検討してみようと思います。