def mean_squared_error(y, t):
return 0.5 * np.sum((y - t)**2)
def cross_entropy_error(y, t):
delta = le-7 # 给y加上一个微小值,防止负无限大
return -np.sum(t * np.log(y + delta))
使用训练数据进行学习严格来说就是针对训练数据计算损失函数的值,找出尽可能小的参数,因此计算损失函数时必须将所有的训练数据作为对象
当训练数据较大时,可以从中选出一批数据(称为mini-batch,小批量)
实现
# mini-batch
train_size = x_train.shape[0]
batch_size = 10
# choice(a, b)表示从0~(a-1)个数据中随机选择b个数据
batch_mask = np.random.choice(train_size, batch_size)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
def cross_entropy_error2(y, t):
"""
1.当y的维度为1时,即求单个数据的交叉熵误差时,需要改变数据的形状
2.举例:当y=[0.3, 0.1, 0.6]时,y.shape=(3,),y.shape[0]=3
3.因此要使得shape[0]能够提取出单个数据和批量数据的个数,需要对单个数据用reshape(1, t.size)
"""
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 + le-7)) / batch_size
def cross_entropy_error3(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(np.log(y[np.arange(batch_size), t] + le - 7)) / batch_size
对y[np.arange(batch_size), t] 的解释:
"""
这里我们我们举例:
y = np.array([[0,1,0.1,0,0,0,0,0,0,0],[0,0,0.2,0.8,0,0,0,0,0,0]])
t = np.array([1, 3])
batch_size = y.shape[0] = 2
"""
# 1.np.arange(a)会生成一个0到a-1的数组
>>>np.arange(batch_size)
array([0, 1])
# 2.用y[np.arange(batch_size), t]抽出各个数据的正确解标签对应的神经网络的输出
>>>k = y[np.arange(batch_size), t] # y[[0, 1], [1, 3]]
>>>print(k)
[1. 0.8]
梯度法使用梯度的信息决定前进的方向,以下介绍梯度是什么,有什么性质等
像$(\frac{\partial f}{\partial {x_0}},\frac{\partial f}{\partial {x_1}})$ 这样由全部变量的偏导数汇总而成的向量称为梯度
实现
# 示例函数
def function_2(x):
return x[0]**2 + x[1]**2
def numerical_gradient(f, x):
h = 1e-4 # 0.0001
grad = np.zeros_like(x) # 生成和x形状相同,所有元素为0的数组
for idx in range(x.size):
tmp_val = x[idx]
# f(x+h)的计算
x[idx] = tmp_val + h
fxh1 = f(x)
# f(x-h)的计算
x[idx] = tmp_val - h
fxh2 = f(x)
grad[idx] = (fxh1 - fxh2) / (2*h)
x[idx] = tmp_val # 还原值
return grad
上述提到:
注意:
梯度法:函数的取值从当前位置沿着梯度方向前进一段距离,然后在新的地方重新求梯度,再沿着新梯度方向前进一定距离,如此反复,不断沿着梯度方向前进,逐渐减小函数值。
公式:
学习率:公式中的表示更新率,在神经网络的学习中,称为学习率,决定了在一次学习中,应该学习多少,以及在多大程度上更新参数。
代码
# 梯度下降法
"""
f是要进行最优化的函数
init_x是初始值,lr是学习率(learning rate)
step_num是梯度法的重复次数
"""
def gradient_descent(f, init_x, lr=0.01, step_num=100):
x = init_x
for i in range(step_num):
grad = numerical_gradient(f, x)
x -= lr * grad
return x
神经网络的学习也要求梯度,是指损失函数关于权重参数的梯度
公式:
实现:
class simpleNet:
def __init__(self):
self.W = np.random.randn(2,3)
def predict(self, x):
return np.dot(x, self.W)
def loss(self, x, t):
z = self.predict(x)
y = softmax(z)
loss = cross_entropy_error3(y, t)
return loss
分析:
求出神经网络的梯度后,接下来只需要根据梯度法,更新权重参数即可
首先,复习一下神经网络的学习步骤:
以上方法称为随机梯度下降法(stochastic gradient descent, SGD)
下面我们来实现手写数字识别的神经网络
import os
import sys
import numpy as np
from ch3_NeuralNetworks.SigmoidFunction import sigmoid
from ch3_NeuralNetworks.SoftmaxFunction import softmax
from ch4_trainNeuralnet.gradient_method import numerical_gradient
from ch4_trainNeuralnet.loss_function import cross_entropy_error
sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定
class TwoLayerNet:
# 初始化
def __init__(self, input_size, hidden_size, output_size,weight_init_std=0.01):
# params 保存神经网络的参数
# 权重:通过randn(i, h),得到一组i*h的符合标准正态分布的随机数
# 偏置:通过zeros(h),得到一个全为0的矩阵
self.params = {'W1': weight_init_std * np.random.randn(input_size, hidden_size),
'b1': np.zeros(hidden_size),
'W2': weight_init_std * np.random.randn(hidden_size, output_size),
'b2': np.zeros(output_size)}
# 推理,x:图像数据
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 = sigmoid(a1)
a2 = np.dot(z1, W2) + b2
y = softmax(a2)
return y
# 计算损失值,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)
accurancy = np.sum(y == t) / float(x.shape[0])
return accurancy
# 计算权重参数的梯度,x:输入数据,t:监督数据
def numerical_grandient(self, x, t):
loss_W = lambda W: self.loss(x, t) # def loss_W(x):...
# grads 保存梯度
grads = {'W1': numerical_gradient(loss_W, self.params['W1']),
'b1': numerical_gradient(loss_W, self.params['b1']),
'W2': numerical_gradient(loss_W, self.params['W2']),
'b2': numerical_gradient(loss_W, self.params['b2'])}
return grads
# 误差反向传播法,高速计算梯度(下一章介绍)
def gradient(self, x, t):
W1, W2 = self.params['W1'], self.params['W2']
b1, b2 = self.params['b1'], self.params['b2']
grads = {}
batch_num = x.shape[0]
# forward
a1 = np.dot(x, W1) + b1
z1 = sigmoid(a1)
a2 = np.dot(z1, W2) + b2
y = softmax(a2)
# backward
dy = (y - t) / batch_num
grads['W2'] = np.dot(z1.T, dy)
grads['b2'] = np.sum(dy, axis=0)
da1 = np.dot(dy, W2.T)
dz1 = self.sigmoid_grad(a1) * da1
grads['W1'] = np.dot(x.T, dz1)
grads['b1'] = np.sum(dz1, axis=0)
return grads
def sigmoid_grad(x):
return (1.0 - sigmoid(x)) * sigmoid(x)
numerical_grandient(self, x, t) 计算梯度基于数值微分,下一章会介绍高速计算梯度的方法,称为误差反向传播法grandient(self, x, t)
numerical_grandient(self, x, t) 的计算速度很慢很慢,还要迭代10000次,所以,我们先直接使用误差反向传播法grandient(self, x, t)以上述实现的TwoLayerNet类为对象,使用MNIST数据集进行学习
import numpy as np
from ch4_trainNeuralnet.two_layer_net import TwoLayerNet
from mnist import load_mnist
# 载入数据集,并将图像的像素值正规化为0.0~1.0,标签采用one-hot表示
# (训练图象,训练标签),(测试图象,测试标签)
(x_train, t_train), (x_test, t_test) = \\
load_mnist(normalize=True, one_hot_label=True)
# 记录学习过程中的损失值
train_loss_list = []
# 超参数
iters_num = 10000 # 迭代次数
train_size = x_train.shape[0]
batch_size = 100 # 批数量
learing_rate = 0.1 # 学习率
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
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.gradient(x_batch, t_batch)
# 更新参数,正方向更新梯度为负的权重,反方向更新梯度为正的权重
for key in ('W1', 'b1', 'W2', 'b2'):
network.params[key] -= learing_rate * grad[key]
# 记录学习过程
loss = network.loss(x_batch, t_batch)
train_loss_list.append(loss)
绘制损失函数值的图像,观察学习情况
x = np.arange(iters_num)
plt.plot(x, train_loss_list)
plt.xlabel("iters_num") # x轴标签
plt.ylabel("loss") # y轴标签
plt.show()
max(train_size / batch_size, 1) ,因为在循环语句中一直计算识别精度开销太大,且只要大方向上把握识别精度的推移就够了import numpy as np
from matplotlib import pyplot as plt
from ch4_trainNeuralnet.two_layer_net import TwoLayerNet
from mnist import load_mnist
# 载入数据集,并将图像的像素值正规化为0.0~1.0,标签采用one-hot表示
# (训练图象,训练标签),(测试图象,测试标签)
(x_train, t_train), (x_test, t_test) = \\
load_mnist(normalize=True, one_hot_label=True)
# 超参数
iters_num = 10000 # 迭代次数
train_size = x_train.shape[0] # 训练数据条数
batch_size = 100 # 批数量
learing_rate = 0.1 # 学习率
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
# 记录学习过程中的损失值、**训练数据的识别精度、测试数据的识别精度**
train_loss_list = []
**train_acc_list = []
test_acc_list = []
# 平均每个epoch的重复次数
iter_per_epoch = max(train_size / batch_size, 1)**
for i in range(iters_num):
print("第", i, "次迭代")
# 获取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_grandient(x_batch, t_batch)
grad = network.gradient(x_batch, t_batch)
# 更新参数,正方向更新梯度为负的权重,反方向更新梯度为正的权重
for key in ('W1', 'b1', 'W2', 'b2'):
network.params[key] -= learing_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)
print("train acc, test acc | " + str(train_acc) + ", " + str(test_acc))**
# 绘制损失函数值的图像
print("绘制损失函数值的图像")
x = np.arange(iters_num)
plt.plot(x, train_loss_list)
plt.xlabel("iters_num") # x轴标签
plt.ylabel("loss") # y轴标签
plt.show()
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- fenyunshixun.cn 版权所有 湘ICP备2023022495号-9
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务