はじめに
前回の続きです。 yaju3d.hatenablog.jp
前回の計算が本当に合っているのか、Pythonを使って実証してみたいと思います。
プログラム
重みの更新
①現在の重みで推測値を求める
import numpy as np a = np.array([10, 20]) b = np.array([[1,3,5],[3,1,7]]) print(np.dot(a,b))
[ 70, 50, 190]
全体の誤差を求める。
二乗誤差は、mean_squared_error の名前です。
def mean_squared_error(y, t): return 0.5 * np.sum((y - t)**2) y = np.array([70, 50, 190]) t = np.array([190, 330, 660]) print(mean_squared_error(y, t))
156850.0
②勾配を計算する
勾配は、gradient の名前です。転置は x.T とTを付けるだけなんですね。
def gradient(y, t, x): return np.dot((y - t),x.T) t = np.array([190, 330, 660]) y = np.array([70, 50, 190]) x = np.array([[1,3,5],[3,1,7]]) print(gradient(y, t, x))
[-3310 -3930]
③重みを更新する
②で求めた勾配 を用いて、現在の重み を更新します。学習係数 は 0.02 としています。
def weight(w, lr, gd): return w - lr * gd t = np.array([190, 330, 660]) y = np.array([70, 50, 190]) x = np.array([[1,3,5],[3,1,7]]) w = np.array([10, 20]) print(weight(w, 0.02, gradient(y, t, x)))
[ 76.2 98.6]
2回目の①現在の重みで推測値を求める
a = weight(w, 0.02, gradient(y, t, x)) b = np.array([[1,3,5],[3,1,7]]) print(np.dot(a,b))
[ 372. 327.2 1071.2]
全体の誤差を求める。
二乗誤差は、mean_squared_error の名前です。
y = np.dot(a,b) t = np.array([190, 330, 660]) print(mean_squared_error(y, t))
101108.64
というのを繰り返す。
import numpy as np # 二乗誤差を求める def mean_squared_error(y, t): return 0.5 * np.sum((y - t)**2) # 勾配を求める def gradient(y, t, x): return np.dot((y - t),x.T) # 重みを求める def weight(w, lr, gd): return w - lr * gd # 教師データ t = np.array([190, 330, 660]) # 重み w = np.array([10, 20]) # 入力データ(個数) x = np.array([[1,3,5],[3,1,7]]) y = None for i in range(100): if y is not None: # 勾配を求める grad = gradient(y, t, x) # 重みを求める w = weight(w, 0.02, grad) # 推測値を求める y = np.dot(w, x) # 誤差を求める l = mean_squared_error(y, t) if (i + 1) % 10 == 0: print("step=%3d, a1=%6.2f, a2=%6.2f, loss=%.2f" % (i + 1, w[0], w[1], l)) print("Estimated: a1=%6.2f, a2=%6.2f" % (w[0], w[1]))
step= 10, a1= 78.84, a2= 48.86, loss=4531.39 step= 20, a1= 89.41, a2= 32.85, loss=564.82 step= 30, a1= 94.92, a2= 27.91, loss=264.21 step= 40, a1= 97.30, a2= 26.05, loss=217.63 step= 50, a1= 98.28, a2= 25.30, loss=209.89 step= 60, a1= 98.68, a2= 25.00, loss=208.59 step= 70, a1= 98.84, a2= 24.88, loss=208.38 step= 80, a1= 98.91, a2= 24.83, loss=208.34 step= 90, a1= 98.94, a2= 24.81, loss=208.33 step=100, a1= 98.95, a2= 24.80, loss=208.33 Estimated: a1= 98.95, a2= 24.80
実行結果
リンゴ 98.95 ≒ 99、ミカン 24.80 ≒ 25 → 99 x 2 + 25 x 4 ≒ 297
以前、TensorFlowで組んだ際の結果とほぼ同じになったのでこれでいいかな。
リンゴ 98.81 ≒ 99、ミカン 24.90 ≒ 25 → 99 x 2 + 25 x 4 ≒ 297
yaju3d.hatenablog.jp
上記サイトでTensorFlowで組んだのに近付けるために、train_x と train_y を縦ベクトル に変更してみました。
import numpy as np # 二乗誤差を求める def mean_squared_error(y, t): return 0.5 * np.sum((y - t)**2) # 勾配を求める def gradient(y, t, x): return np.dot((y.T - t.T), x) # 重みを求める def weight(w, lr, gd): return w - lr * gd train_x = np.array([[1., 3.], [3., 1.], [5., 7.]]) train_y = np.array([190, 330, 660]).reshape(3, 1) y = None for i in range(100): if y is not None: # 勾配を求める grad = gradient(y, train_y, train_x) # 重みを求める(横ベクトルを一次元に変換) w = weight(w, 0.02, grad).reshape(-1,) else: # 初期重み w = np.array([10, 20]) # 推測値を求める y = np.dot(w, train_x.T) # 誤差を求める l = mean_squared_error(y, train_y) if (i + 1) % 10 == 0: print("step=%3d, a1=%6.2f, a2=%6.2f, loss=%.2f" % (i + 1, w[0], w[1], l)) print("Estimated: a1=%6.2f, a2=%6.2f" % (w[0], w[1]))