跳转至

误差反向传播

707 个字 75 行代码 预计阅读时间 4 分钟

高效计算权重参数的梯度的方法——误差反向传播

链式法则

传递这个局部导数的原理,是基于链式法则(chain rule)的

image-20260309145201500

局部导数 \(\frac{\partial y}{\partial x}\) 乘以上游传来的值 \(E\),然后传递给前面的节点。这就是反向传播的计算顺序。实现的原理是链式法则

\(z=(x+y)^2\)

可以写成两个式子,反向传播图如下所示 $$ z=t^2\ t=x+y $$

image-20260309145310270

反向传播

加法节点的反向传播

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

image-20260309150043717

乘法节点的反向传播

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

image-20260309150357474

加法的反向传播只是将上游的值传给下游,并不需要正向传播的输入信号。但是,乘法的反向传播需要正向传播时的输入信号值

简单层的实现

### 乘法层的实现

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

用前面苹果的例子

image-20260309151008007

# 买苹果
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)

\[ y= \begin{cases} x&(x\gt0)\\ 0&(x\leq0) \end{cases} \]

可求得导数

\[ \frac{\partial y}{\partial x}= \begin{cases} 1&(x\gt0)\\ 0&(x\leq0) \end{cases} \]

也就是说,如果正向传播输入 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

\[ y=\frac{1}{1+\exp{(-x)}} \]

最终反向传播的输出是 \(\frac{\partial L}{\partial y}y^2\exp{(-x)}\),这个反向传播的值与正向传播的输入 x 和输出 y 相关。简化这个 sigmoid 层表示为

image-20260309160548814

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 的矩阵