記事ディレクトリ
序文
この記事では、『ディープラーニング入門』の第 4 章の内容に基づいた手書き数字認識の小さなケースを完成させます。この章の焦点は、ニューラル ネットワークに「学習を学習」させる方法です。ニューラル ネットワークが学習できるようにするために、损失函数
このインジケーターをインポートして、損失関数を最小化する重みパラメーターを見つけます。損失関数の可能な最小値を見つけるために、 を使用します梯度下降法
。
1. 理論的知識
(1) ニューラルネットワークの学習ステップ
- mini-batch : トレーニング データからデータの一部をランダムに選択します。データのこの部分はミニバッチと呼ばれます。ミニバッチ内のデータをネットワークに送信すると、予測結果が得られます。予測結果と正しい結果に従って、損失関数が計算されます。
- 勾配を計算する: ミニバッチ損失関数の値を減らすために、各重みパラメーターの勾配を計算する必要があります。勾配は、損失関数の値が最も減少する方向を表します。
- パラメータの更新: 重みパラメータが勾配方向に沿ってわずかに更新されます。
- 繰り返し: 手順 1 ~ 3 を繰り返します。
(2) 勾配と勾配降下法
勾配: すべての変数の偏導関数によって合計されたベクトルは勾配と呼ばれます。勾配が示す方向は、各点で関数の値が最も減少する方向です。
勾配法:勾配の方向に沿って連続的に進み、関数の値を徐々に減少させる方法。このうち、勾配上昇法とは最大値を求める勾配法を指し、勾配降下法とは最小値を求める勾配法を指します。
(3) 損失関数
損失関数: ニューラル ネットワークの学習に使用される指標は、現在のニューラル ネットワークが教師付きデータにどの程度適合していないかを示すために使用できます。一般的に使用される損失関数は、平均二乗誤差と交差エントロピー誤差です。
均方误差
:
ここで、y_k はニューラル ネットワークの出力を表し、t_k は実際のデータを表し、k はデータの次元を表します。
コード:
def mean_squared_error(y, t):
return 0.5 * np.sum((y-t)**2)
交叉熵误差
:
y_k はニューラル ネットワークの出力 (シグモイドやソフトマックスの出力などの確率です) を表し、t_k は正しい解のラベルです (t_k はワンホットで表されます) コード実装
:
def cross_entropy_error(y, t):
delta = 1e-7
return -np.sum(t * np.log(y + delta))
(4) エポック、iters_num
Epoch : エポックは単位であり、1 エポックは学習内のすべての学習データが 1 回使用されたときの更新回数を表します。10,000 個のトレーニング データの場合、100 データのミニバッチで学習する場合、確率的勾配降下法を 100 回繰り返すと、すべてのトレーニング データが表示されます。したがって、この例では、エポックは 100 です。
iters_num : 勾配法の反復回数。(この手書き数字認識の場合、iters_num は 10000 です。これは、毎回 mini_batch がランダムに選択され、抽出が 10000 回繰り返されることを意味します。)
(5) この場合のニューラルネットワーク構造
このネットワークは 2 層のニューラル ネットワークを使用します。ネットワーク構造はおおよそ次のとおりです。
入力層: 784 ニューロン。
隠れ層: 50 ニューロン。
出力層: 10 ニューロン。
2. すべてのコード
import sys, os
sys.path.append(os.pardir)
import numpy as np
import matplotlib.pyplot as plt
from common.functions import *
from common.gradient import numerical_gradient
from dataset.mnist import load_mnist
from dataset.two_layer_net import TwoLayerNet
def cross_entropy_error(y, t):
if y.ndim == 1:
t = t.reshape(1, t.size)
y = y.reshape(1, y.size)
batch_size = y.shape[0]
return -np.sum(t * np.log(y + 1e-7)) / batch_size
class TwoLayerNet:
def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):
# 初始化权重
self.params = {
}
self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size)
self.params['b1'] = np.zeros(hidden_size)
self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size)
self.params['b2'] = np.zeros(output_size)
def sigmoid(a):
return 1 / (1 + np.exp(-a))
def softmax(a):
exp_a = np.exp(a)
sum = np.sum(exp_a)
y = exp_a / sum
return y
def predict(self, x):
W1, W2 = self.params['W1'], self.params['W2']
b1, b2 = self.params['b1'], self.params['b2']
a1 = np.dot(x, W1) + b1
z1 = self.sigmoid(a1)
a2 = np.dot(z1, W2) + b2
z2 = self.softmax(a2)
return z2
# x是输入数据,t是标签
def loss(self, x, t):
y = self.predict(x)
return cross_entropy_error(y, t) # 交叉熵损失函数
def accuracy(self, x, t):
y = self.predict(x)
y = np.argmax(y, axis=1)
t = np.argmax(t, axis=1)
accuracy = np.sum(y == t) / float(x.shape[0])
return accuracy
def numerical_gradient(self, x, t):
loss_W = lambda W: self.loss(x, t)
grads = {
}
grads['W1'] = numerical_gradient(loss_W, self.params['W1'])
grads['W2'] = numerical_gradient(loss_W, self.params['W2'])
grads['b1'] = numerical_gradient(loss_W, self.params['b1'])
grads['b2'] = numerical_gradient(loss_W, self.params['b2'])
return grads
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)
train_loss_list = []
train_acc_list = []
test_acc_list = []
# 超参数
iters_num = 500
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.1
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
# 平均每个epoch的重复次数
iter_per_epoch = max(train_size / batch_size, 1)
for i in range(iters_num):
# 获取mini-batch
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)
print('hello')
# 更新参数
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)
# 计算每个epoch的识别精度
if i % iter_per_epoch == 0:
train_acc = network.accuracy(x_train, t_train)
test_acc = network.accuracy(x_test, t_test)
train_acc_list.append(train_acc)
test_acc_list.append(test_acc)
# 导入数据
m = list(np.arange(1, iters_num+1))
n = list(np.arange(1, len(train_acc_list)+1))
t = list(np.arange(1, len(test_acc_list)+1))
# 绘图命令
print(train_loss_list)
print(train_acc_list)
print(test_acc_list)
# 画第一个图
plt.subplot(221)
plt.plot(m, train_loss_list)
# show出图形
plt.show()
実行結果:
(下図の横軸は iters_num、縦軸は損失関数の値)