以下是神经网络前向传播和部分实现的反向传播过程:
import numpy as npdef sigmoid(z): return 1 / (1 + np.exp(-z))X_train = np.asarray([[1,1], [0,0]]).TY_train = np.asarray([[1], [0]]).Thidden_size = 2output_size = 1learning_rate = 0.1 forward propagationw1 = np.random.randn(hidden_size, 2) * 0.1b1 = np.zeros((hidden_size, 1))w2 = np.random.randn(output_size, hidden_size) * 0.1b2 = np.zeros((output_size, 1))Z1 = np.dot(w1, X_train) + b1A1 = sigmoid(Z1)Z2 = np.dot(w2, A1) + b2A2 = sigmoid(Z2)derivativeA2 = A2 * (1 - A2)derivativeA1 = A1 * (1 - A1) first steps of back propagationerror = (A2 - Y_train)dA2 = error / derivativeA2dZ2 = np.multiply(dA2, derivativeA2)
以下代码的直觉是什么:
error = (A2 - Y_train)dA2 = error / derivativeA2dZ2 = np.multiply(dA2, derivativeA2)
我理解的是,error是当前预测值A2
与实际值Y_train
之间的差异。
但是,为什么要将这个误差除以A2
的导数,然后将error / derivativeA2
的结果乘以derivativeA2
?这背后的直觉是什么?
回答:
这些表达式确实令人困惑:
derivativeA2 = A2 * (1 - A2)error = (A2 - Y_train)dA2 = error / derivativeA2
…因为error
本身并没有意义。此时,目标是计算交叉熵损失的导数,其公式如下:
dA2 = (A2 - Y_train) / (A2 * (1 - A2))
请参见这些讲义(公式6)以了解推导过程。恰好前面的操作是sigmoid
,其导数是A2 * (1 - A2)
。这就是为什么这个表达式再次被用来计算dZ2
(公式7)。
但如果您使用不同的损失函数(例如,L2)或不同的压缩层,那么A2 * (1 - A2)
不会被重复使用。这些是在计算图中的不同节点。