误差反向传播 ¶
约 707 个字 75 行代码 预计阅读时间 4 分钟
高效计算权重参数的梯度的方法——误差反向传播
链式法则 ¶
传递这个局部导数的原理,是基于链式法则(chain rule)的

局部导数 \(\frac{\partial y}{\partial x}\) 乘以上游传来的值 \(E\),然后传递给前面的节点。这就是反向传播的计算顺序。实现的原理是链式法则
\(z=(x+y)^2\)
可以写成两个式子,反向传播图如下所示 $$ z=t^2\ t=x+y $$

反向传播 ¶
加法节点的反向传播 ¶
加法节点的反向传播将上游的值原封不动地输出到下游

乘法节点的反向传播 ¶
乘法的反向传播会将上游的值乘以正向传播时的输入信号的“翻转值”后传递给下游。翻转值表示一种翻转关系,如图 5-12 所示,正向传播时信号是 x 的话,反向传播时则是 y;正向传播时信号是 y 的话,反向传播时则是 x。

加法的反向传播只是将上游的值传给下游,并不需要正向传播的输入信号。但是,乘法的反向传播需要正向传播时的输入信号值
简单层的实现 ¶
### 乘法层的实现
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
dy = dout * self.x
return dx, dy
用前面苹果的例子

# 买苹果
apple = 100
apple_num = 2
tax = 1.1
#layer
mul_apple_layer = MulLayer()
mul_tax_layer = MulLayer()
#forward
apple_price = mul_apple_layer.forward(apple,apple_num)
price = mul_tax_layer.forward(apple_price,tax)
print(price)# 220
加法层的实现 ¶
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
激活函数层的实现 ¶
ReLU 层 ¶
激活函数 ReLU(Rectified Linear Unit)
可求得导数
也就是说,如果正向传播输入 x 大于 0,那么反向传播时原封不动传递给上游。如果 x 小于 0,那反向传播到此为止。
# ReLU层
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
Relu 类有实例变量 mask。这个变量 mask 是由 True/False 构成的 NumPy 数组,它会把正向传播时的输入 x 的元素中小于等于 0 的地方保存为 True,其他地方(大于 0 的元素)保存为 False。
Sigmoid 层 ¶
最终反向传播的输出是 \(\frac{\partial L}{\partial y}y^2\exp{(-x)}\),这个反向传播的值与正向传播的输入 x 和输出 y 相关。简化这个 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
Affine/Softmax 层的实现 ¶
Affine 层 ¶
神经网络的正向传播中进行的矩阵的乘积运算在几何学领域被称为“仿射变换”A。因此,这里将进行仿射变换的处理实现为“Affine 层”。
几何中,仿射变换包括一次线性变换和一次平移,分别对应神经网络的加权和运算与加偏置运算。
回顾一下神经网络的正向传播,是一个加权信号的总和,用到了矩阵的乘法
X = np.random.rand(2) # 输入
W = np.random.rand(2,3) # 权重
B = np.random.rand(3) # 偏置
X.shape # (2,)
W.shape # (2, 3)
B.shape # (3,)
Y = np.dot(X, W) + B
(2,) 是一个 1×2 的哦,但是 (2,3) 是 2×3 的矩阵