「.NET 開発基盤部会 Wiki」は、「Open棟梁Project」,「OSSコンソーシアム .NET開発基盤部会」によって運営されています。
学習フェーズでは、信号は逆方向に伝播する。
人間が(暗黙的な学習によって、)これらを判別することはできる。
従って、人間の脳も、一部は、このようなデータ駆動で動いているのかもしれない。
入力画像データから、本質的なデータを抽出できるように設計された変換器を指す。
ベクトル化された画像データを機械学習のSVMやKNNなどの識別器で学習させる。
深層学習(deep learning)においては、特徴量についても機会が学習する。
ニューラルネットワークの出力と正解となる教師データの各要素の差の二乗の総和の2分の一。
2 E = 1/2 Σ (yk-tk) k
"""This is a test program.""" import numpy as np def mean_squared_error(yk, tk): """損失関数(2乗和誤差)""" return 0.5 * np.sum((yk - tk)**2) tk = np.array([0, 0, 1, 0, 0, 0, 0, 0, 0, 0]) yk = np.array([0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]) print(mean_squared_error(yk, tk)) yk = np.array([0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]) print(mean_squared_error(yk, tk))
0.0975
0.5975
E = - Σ tk log yk k
"""This is a test program.""" import numpy as np def cross_entropy_error(yk, tk): """損失関数(交差エントロピー誤差)""" delta = 1e-7 # log(0)はマイナス∞になるのを微小な値を足して防止。 return -np.sum(tk * np.log(yk + delta)) tk = np.array([0, 0, 1, 0, 0, 0, 0, 0, 0, 0]) yk = np.array([0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]) print(cross_entropy_error(yk, tk)) yk = np.array([0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]) print(cross_entropy_error(yk, tk))
0.510825457099
2.30258409299
E = -1/N ΣΣ tnk log ynk n k
"""This is a test program.""" import numpy as np def mean_squared_error(ynk, tnk): """損失関数(交差エントロピー誤差)""" print("tnk:" + str(tnk)) print("ynk:" + str(ynk)) batch_size = ynk.shape[0] print("batch_size:" + str(batch_size)) delta = 1e-7 # log(0)はマイナス∞になるのを微小な値を足して防止。 return - 1 / batch_size * (np.sum(tnk * np.log(ynk + delta))) TNK = np.array([[0, 0, 1, 0, 0, 0, 0, 0, 0, 0], \ [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]]) YNK = np.array([[0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0], \ [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]]) print("mean_squared_error:" + str(mean_squared_error(YNK, TNK))) YNK = np.array([[0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0], \ [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]]) print("mean_squared_error:" + str(mean_squared_error(YNK, TNK)))
"""This is a test program.""" import numpy as np def mean_squared_error(ynk, tnk): """損失関数(交差エントロピー誤差)""" print("tnk:" + str(tnk)) print("ynk:" + str(ynk)) batch_size = ynk.shape[0] print("batch_size:" + str(batch_size)) delta = 1e-7 # log(0)はマイナス∞になるのを微小な値を足して防止。 ynk = ynk + delta print("arange:" + str(ynk[np.arange(batch_size), tnk])) return - 1 / batch_size * (np.sum(np.log(ynk[np.arange(batch_size), tnk]))) TNK = np.array([2, 2]) YNK = np.array([[0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0], \ [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]]) print("mean_squared_error:" + str(mean_squared_error(YNK, TNK))) YNK = np.array([[0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0], \ [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]]) print("mean_squared_error:" + str(mean_squared_error(YNK, TNK)))
勾配法では、(パラメタの微分を計算して得た)勾配の情報を使って進む方向を決める。
ある瞬間の変化の量(=グラフの接線の傾き的な)。
df(x) yの増量 f(x+h) - f(x) f(x+h) - f(x) ── = ─── = lim ────── = lim ────── dx xの増量 h→0 (x+h) - (x) h→0 h
式の展開によって微分を求める(誤差がない)。
2 y = x
df(x) yの増量 (x+h)^2 - x^2 (x^2+2hx+h^2) - (x^2) ── = ─── = lim ────── = lim ────────── dx xの増量 h→0 (x+h) - (x) h→0 h
dy 2hx+h^2 ── = lim ──── = lim 2x+h = 2x dx h→0 h h→0
計算によって微分を求める(誤差がある)。
"""This is a test program.""" import numpy as np import matplotlib.pyplot as plt def numerical_diff(f, x): """数値微分""" h = 1e-4 # 微小な値hとして1の-4乗を用いる return (f(x + h) - f(x - h)) / (2 * h) # 前方差分から中心差分にして誤差減 def function_1(x): """f(x)=0.01x^2+0.1x""" return 0.01 * x ** 2 + 0.1 * x X=5 print("X=" + str(X) + " : " + str(numerical_diff(function_1, X))) X=10 print("X=" + str(X) + " : " + str(numerical_diff(function_1, X))) X = np.arange(0.0, 20.0, 0.1) Y = function_1(X) plt.xlabel("x") plt.ylabel("f(x)") plt.plot(X, Y) plt.show()
#ref(): File not found: "graf.png" at page "ニューラルネットワーク(学習)"
X=5 : 0.1999999999990898 X=10 : 0.2999999999986347
#ref(): File not found: "gradient_1d.png" at page "ニューラルネットワーク(学習)"
2 2 f(x0, x1) = x0 + x1
"""This is a test program.""" import numpy as np def function_2(x): """f(x0, x1) = x0^2 + x1^2""" return x[0] ** 2 + x[1] ** 2 # or return np.sum(x ** 2)
df(x0, x1) ───── = 2 * x0 dx0 df(x0, x1) ───── = 2 * x1 dx1
numerical_diff"""This is a test program.""" import numpy as np def numerical_diff(f, x): """数値微分""" h = 1e-4 # 微小な値hとして1の-4乗を用いる return (f(x + h) - f(x - h)) / (2 * h) # 前方差分から中心差分にして誤差減 def function_tmp1(x0): """x0=3, x1=4 の場合の x0 に対する偏微分用""" return x0 ** 2 + 4.0 ** 2 def function_tmp2(x1): """x0=3, x1=4 の場合の x1 に対する偏微分用""" return 3.0 ** 2.0 + x1 ** 2 print(numerical_diff(function_tmp1, 3.0)) print(numerical_diff(function_tmp2, 4.0))
6.00000000000378 (2 * x0 = 2 * 3 = 6) 7.999999999999119 (2 * x1 = 2 * 4 = 8)
勾配の示す方向は、各場所で関数の値を最も減らす方向。
df(x0, x1) df(x0, x1) ───── , ───── dx0 dx1
"""This is a test program.""" import numpy as np def numerical_gradient(f, x01): """偏微分""" h = 1e-4 # 微小な値hとして1の-4乗を用いる grad = np.zeros_like(x01) # x01と同じ形状で要素が0。 for idx in range(x01.size): tmp_val = x01[idx] # 前方差分から中心差分にして誤差減 # f(x + h) fxh1 = f(tmp_val + h) # f(x - h) fxh2 = f(tmp_val - h) # (f(x + h) - f(x - h)) / 2 * h grad[idx] = (fxh1 - fxh2) / (2 * h) return grad def function_2(x): return np.sum(x**2) print(numerical_gradient(function_2, np.array([3.0, 4.0]))) print(numerical_gradient(function_2, np.array([0.0, 2.0]))) print(numerical_gradient(function_2, np.array([3.0, 0.0])))
[ 6. 8.] [ 0. 4.] [ 6. 0.]
#ref(): File not found: "gradient_2d.png" at page "ニューラルネットワーク(学習)"
df(x0, x1) x0 = x0 - η ───── dx0 df(x0, x1) x1 = x1 - η ───── dx1
2 2 f(x0, x1) = x0 + x1
import numpy as np def numerical_gradient(f, x01): """偏微分""" h = 1e-4 # 微小な値hとして1の-4乗を用いる grad = np.zeros_like(x01) # x01と同じ形状で要素が0。 # print("x01:" + str(x01)); for idx in range(x01.size): tmp_val = x01[idx] # 前方差分から中心差分にして誤差減 # f(x + h) fxh1 = f(tmp_val + h) # f(x - h) fxh2 = f(tmp_val - h) # (f(x + h) - f(x - h)) / 2 * h grad[idx] = (fxh1 - fxh2) / (2 * h) return grad def gradient_descent(f, init_x01, lr, step_num): print("ln : step_num = " + str(lr) + " : " + str(step_num)) x01 = init_x01 for i in range(step_num): grad = numerical_gradient(f, x01) x01 -= lr * grad return x01 def function_2(x): return np.sum(x**2) init_x = np.array([-3.0, 4.0]) print(gradient_descent(function_2, init_x, 0.1, 100)) # 学習率が大きすぎる。 init_x = np.array([-3.0, 4.0]) print(gradient_descent(function_2, init_x, 10.0, 100)) # 学習率が小さすぎる。 init_x = np.array([-3.0, 4.0]) print(gradient_descent(function_2, init_x, 1e-10, 100))
ln : step_num = 0.1 : 100 [ -6.11110793e-10 8.14814391e-10] ln : step_num = 10.0 : 100 [ -1.91613251e+13 -1.26893162e+12] ln : step_num = 1e-10 : 100 [-2.99999994 3.99999992]
ニューラルネットワークの学習における勾配は、
重みパラメタに関する損失関数の勾配となる。
┌ w11 w21 vw31 ┐ W = │ │ └ w12 w22 vw32 ┘ ┌ dL dL dL ┐ │ ── ── ── │ dL │ dw11 dw21 dw31 │ ── =│ │ dW │ dL dL dL │ │ ── ── ── │ └ dw12 dw22 dw32 ┘
predict ---> softmax ---> cross_entropy_error
- predict(推論する)
- softmax(ソフトマックス関数)
- cross_entropy_error(交差エントロピー誤差)
C:\deep-learning-from-scratch-master\ch04>python Untitled-1.py
import sys, os sys.path.append(os.pardir) # 親ディレクトリのファイルをインポートするための設定 import numpy as np from common.functions import softmax, cross_entropy_error from common.gradient import numerical_gradient from gradient_simplenet import simpleNet print("==================================================") print("==================================================") net = simpleNet() print("W:" + str(net.W)) x = np.array([0.6, 0.9]) p = net.predict(x) print("p:" + str(p)) t = np.array([0, 0, 1]) l = net.loss(x, t) print("loss:" + str(l))
W:[[ 1.92087598 0.63971089 -0.26820797] [ 0.58411529 -0.04610929 -0.88999594]] p:[ 1.67822935 0.34232817 -0.96192113] loss:2.92853604814
import sys, os sys.path.append(os.pardir) # 親ディレクトリのファイルをインポートするための設定 import numpy as np from common.functions import softmax, cross_entropy_error from common.gradient import numerical_gradient from gradient_simplenet import simpleNet print("==================================================") print("==================================================") net = simpleNet() print("W:" + str(net.W)) x = np.array([0.6, 0.9]) t = np.array([0, 0, 1]) f = lambda w: net.loss(x, t) dW = numerical_gradient(f, net.W) print("dW:" + str(dW))
================================================== ================================================== W:[[ 1.83160192 0.4900981 -0.94188042] [-0.24946104 2.91410946 -0.00695892]] dW:[[ 0.06708443 0.51711391 -0.58419835] [ 0.10062665 0.77567087 -0.87629752]]
W : [[ w11 = 1.83160192 w21 = 0.4900981 w31 = -0.94188042] [ w12 = -0.24946104 w22 = 2.91410946 w32 = -0.00695892]] dL/dW : [[ dL/dw11 = 0.06708443 dL/dw21 = 0.51711391 dL/dw31 = -0.58419835] [ dL/dw12 = 0.10062665 dL/dw22 = 0.77567087 dL/dw32 = -0.87629752]]
重みパラメタを勾配の方向に微小量だけ更新する。
TwoLayerNet?クラス
https://github.com/oreilly-japan/deep-learning-from-scratch/blob/master/ch04/two_layer_net.py
# | 変数 | 説明 | |
1 | params | ニューラルネットワークの重みパラメタのディクショナリ変数 | |
1-1 | params['W1'] | 第1層の重み | |
1-2 | params['b1'] | 第1層のバイアス | |
1-3 | params['W2'] | 第2層の重み | |
1-4 | params['b2'] | 第2層のバイアス | |
2 | grads | numerical_gradientで計算された勾配を保持するディクショナリ変数 | |
1-1 | params['W1'] | 第1層の重みの勾配 | |
1-2 | params['b1'] | 第1層のバイアスの勾配 | |
1-3 | params['W2'] | 第2層の重みの勾配 | |
1-4 | params['b2'] | 第2層のバイアスの勾配 |
# | メソッド シグネチャ | 引数 | 説明 |
1 | __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01): | コンストラクタ | |
1-1 | self | インスタンス | |
1-2 | input_size | 入力層のニューロンの数 | |
1-3 | hidden_size | 隠れニューロンの数 | |
1-4 | output_size | 出力層のニューロンの数 | |
1-5 | weight_init_std | ・・・ | |
2 | predict(self, x): | 推論を行う | |
2-1 | self | インスタンス | |
2-2 | x | 画像データ | |
3 | loss(self, x, t): | 損失関数の値を求める | |
3-1 | self | インスタンス | |
3-2 | x | 画像データ | |
3-3 | t | 正解ラベル | |
4 | accuracy(self, x, t): | 認識精度を求める | |
4-1 | self | インスタンス | |
4-2 | x | 画像データ | |
4-3 | t | 正解ラベル | |
5 | numerical_gradient(self, x, t): | lossを使用し各重みパラメタの勾配を求める | |
5-1 | self | インスタンス | |
5-2 | x | 画像データ | |
5-3 | t | 正解ラベル | |
6 | gradient(self, x, t): | numerical_gradientの高速版 | |
6-1 | self | インスタンス | |
6-2 | x | 画像データ | |
6-3 | t | 正解ラベル |
(784, x = 100)
(1, x = 100)
(100, x = 100)
(100, x = 100)
(x = 100, 10)
(1, 10)
(100, 10) # 0-9の数字
# coding: utf-8 import sys, os sys.path.append(os.pardir) # 親ディレクトリのファイルをインポートするための設定 import numpy as np import matplotlib.pyplot as plt from dataset.mnist import load_mnist from two_layer_net import TwoLayerNet # データの読み込み (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True) network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10) iters_num = 10000 # 繰り返しの回数を適宜設定する train_size = x_train.shape[0] batch_size = 100 learning_rate = 0.1 train_loss_list = [] for i in range(iters_num): print(str(i) + " / " + str(iters_num)) batch_mask = np.random.choice(train_size, batch_size) x_batch = x_train[batch_mask] t_batch = t_train[batch_mask] # 勾配の計算 #grad = network.numerical_gradient(x_batch, t_batch) grad = network.gradient(x_batch, t_batch) # パラメータの更新 for key in ('W1', 'b1', 'W2', 'b2'): network.params[key] -= learning_rate * grad[key] loss = network.loss(x_batch, t_batch) train_loss_list.append(loss) plt.xlabel("Iteration") plt.ylabel("loss") plt.plot(range(iters_num), train_loss_list) plt.show()
0 / 10000 ... 9999 / 10000
学習結果を使用して、学習データとテストデータを推論する。
train acc, test acc | 0.102183333333, 0.101 train acc, test acc | 0.783416666667, 0.7894 train acc, test acc | 0.874916666667, 0.8791 train acc, test acc | 0.8964, 0.8991 train acc, test acc | 0.907433333333, 0.9092 train acc, test acc | 0.913616666667, 0.9147 train acc, test acc | 0.9184, 0.9185 train acc, test acc | 0.923366666667, 0.9238 train acc, test acc | 0.926316666667, 0.9275 train acc, test acc | 0.9294, 0.9298 train acc, test acc | 0.932666666667, 0.9318 train acc, test acc | 0.9341, 0.9341 train acc, test acc | 0.936816666667, 0.9367 train acc, test acc | 0.940133333333, 0.9382 train acc, test acc | 0.94175, 0.9397 train acc, test acc | 0.943566666667, 0.9417 train acc, test acc | 0.945233333333, 0.9435
人間が手動で設定するパラメタ
iters_num = 10000
batch_size = 100
learning_rate = 0.1