鱼书-第五章

第五章 误差反向传播法

1.计算图

计算图主要集中精力于局部计算,可以将中间结果保存,通过反向传播高效计算导数。

2.反向传播

在这里插入图片描述
   如图所示,反向传播的计算顺序是,将信号E乘以节点的局部导数,然后将结果传递给下一个节点。这里所说的局部导数是指正向传播中y = f(x),的导数,也就是y关于x的导数。
   假设y = f(x)=x^{2},,则局部导数为 = 2x
把这个局部导数乘以上游传过来的值(本例中为E),然后传递给前面的节点。

  • 乘法规则:乘法的反向传播会将上游的值乘以正向传播时的输入信号的“翻转值”后传递给下游。
class MulLayer:
 	def __init__(self):
 		 self.x = None
		 self.y = None
	def forward(self, x, y):
		 self.x = x
 		 self.y = y
	     out = x * y
   		 return out
	def backward(self, dout):
 		 dx = dout * self.y # 翻转x和y
 		 dy = dout * self.x
		 return dx, dy

调用backward()的顺序与调用forward()的顺序相反。此外,要注意backward()的参数中需要输入“关于正向传播时的输出变量的导数”。

  • 加法规则:backward()将上游传来的导数(dout)原封不动地传递给下游。
class AddLayer:
 	def __init__(self):
 		 pass
 	def forward(self, x, y):
		 out = x + y
 		 return out
 	def backward(self, dout):
 		 dx = dout * 1
		 dy = dout * 1
		 return dx, dy

3.链式法则和计算图

在这里插入图片描述
   如图所示,计算图的反向传播从右到左传播信号。反向传播的计算顺序是,先将节点的输入信号乘以节点的局部导数(偏导数),然后再传递给下一
个节点。比如,反向传播时,“**2”节点的输入是z对z的偏导 ,将其乘以局部导数 (因为正向传播时输入是t、输出是z,所以这个节点的局部导数是z对t ),然后传递给下一个节点。另外,图5-7中反向传播最开始的信号 在前面的数学式中没有出现,这是因为 ,所以在刚才的式子中被省略了。

4.激活函数层的实现

  在神经网络的层的实现中,一般假定forward()和backward()的参数是NumPy数组。

  • ReLU

在这里插入图片描述

  Relu类有实例变量mask。这个变量mask是由True/False构成的NumPy数组,它会把正向传播时的输入x的元素中小于等于0的地方保存为True,其他地方(大于0的元素)保存为False。

  如果正向传播时的输入值小于等于0,则反向传播的值为0。因此,反向传播中会使用正向传播时保存的mask,将从上游传来的dout的mask中的元素为True的地方设为0。

代码示例:

class Relu:
 	def __init__(self):
 		self.mask = None
 	def forward(self, x):
 		self.mask = (x <= 0)
 		out = x.copy()
 		out[self.mask] = 0
 		return out
 	def backward(self, dout):
 		dout[self.mask] = 0
 		dx = dout
 		return dx
  • Sigmoid
    公式:
    在这里插入图片描述
    在这里插入图片描述

代码示例:

class Sigmoid:
 	def __init__(self):
 		self.out = None
 		def forward(self, x):
 		out = 1 / (1 + np.exp(-x))
 		self.out = out
 		return out
 	def backward(self, dout):
 		dx = dout * (1.0 - self.out) * self.out
 		return dx

5.Affine/Softmax层的实现

  • Affine层

定义:神经网络的正向传播中进行的矩阵的乘积运算在几何学领域被称为“仿射变换”。因此,这里将进行仿射变换的处理实现为“Affine层”。
在这里插入图片描述
在这里插入图片描述
代码示例:

class Affine:
 	def __init__(self, W, b):
 		self.W = W
 		self.b = b
 		self.x = None
 		self.dW = None
 		self.db = None
 	def forward(self, x):
 		self.x = x
 		out = np.dot(x, self.W) + self.b
 		return out
 	def backward(self, dout):#dout是输出梯度
 		dx = np.dot(dout, self.W.T)#使用输入 x 的转置 self.x.T 与输出梯度 dout 计算输入梯度
 		self.dW = np.dot(self.x.T, dout)#计算权重矩阵梯度
 		self.db = np.sum(dout, axis=0)#偏执矩阵梯度
 		return dx
  • Softmax-with-Loss 层
    softmax函数会将输入值正规化之后再输出。在这里插入图片描述

神经网络中进行的处理有推理(inference)和学习两个阶段。神经网络的学习阶段则需要 Softmax层。

6.神经网络学习

  • 前提

神经网络中有合适的权重和偏置,调整权重和偏置以便拟合训练数据的过程称为学习。神经网络的学习分为下面4个步骤。

  • 步骤1(mini-batch)

从训练数据中随机选择一部分数据。

  • 步骤2(计算梯度)

计算损失函数关于各个权重参数的梯度。

  • 步骤3(更新参数)

将权重参数沿梯度方向进行微小的更新。

  • 步骤4(重复)

重复步骤1、步骤2、步骤3。

7.4.误差反向传播算法的实现

数值微分需要花费较多的时间,误差反向传播算法可以高效的计算梯度。

import sys, os
sys.path.append(os.pardir)
import numpy as np
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]#获取训练数据集 x_train 的样本数量,确定训练集的大小。
batch_size = 100
learning_rate = 0.1
train_loss_list = []
train_acc_list = []
test_acc_list = []
iter_per_epoch = max(train_size / batch_size, 1)
#计算每个迭代中要遍历的训练数据的数量
#采用 max 函数来确保即使 train_size 不是 batch_size 的整数倍,iter_per_epoch 也至少是 1,以确保至少遍历一次整个数据集。
for i in range(iters_num):
 	batch_mask = np.random.choice(train_size, batch_size)
 	x_batch = x_train[batch_mask]
 	t_batch = t_train[batch_mask]
 #这两行使用 batch_mask 来从训练数据中选择相应的输入数据 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)
 	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)#记录训练集上的准确率随时间的变化

在正向传播的时候使用OrderdDict(有序字典)来添加元素,反向传播的时候按照相反的方顺序调用即可。
梯度确认:确认数值微分和误差反向传播算法求出的结果是否一致。(计算各个权重参数中对应元素差的绝对值,并计算其平均值)

# 求各个权重的绝对误差的平均值
for key in grad_numerical.keys():
 diff = np.average( np.abs(grad_backprop[key] - grad_numerical[key]) )
 print(key + ":" + str(diff))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值