def gradient(self, x, t): # === 1. 前向传播,计算当前输入下的损失值(开启训练模式) === self.loss(x, t, train_flg=True) # === 2. 从最后一层(通常是 SoftmaxWithLoss)开始反向传播 === dout = 1 # 损失函数的导数对自身为 1,作为反向传播的起点 dout = self.last_layer.backward(dout) # 计算最后一层的反向传播输出 # === 3. 将隐藏层和其他中间层按反向顺序反向传播 === layers = list(self.layers.values()) # 获取所有层的列表 layers.reverse() # 将层顺序反转,便于从后往前传播 for layer in layers: dout = layer.backward(dout) # 依次对每一层执行反向传播 # === 4. 设定梯度字典 grads,用于保存每个参数的梯度 === grads = {} for idx in range(1, self.hidden_layer_num + 2): # 遍历每一层(含输出层) # 获取第 idx 层的 Affine 层的权重和偏置的梯度,并加上权重衰减(L2正则化)项 grads['W' + str(idx)] = self.layers['Affine' + str(idx)].dW + \ self.weight_decay_lambda * self.params['W' + str(idx)] grads['b' + str(idx)] = self.layers['Affine' + str(idx)].db # 如果使用了批归一化(BatchNorm),并且当前不是输出层 if self.use_batchnorm and idx != self.hidden_layer_num + 1: # 提取 BatchNorm 层的缩放参数 gamma 和偏移参数 beta 的梯度 grads['gamma' + str(idx)] = self.layers['BatchNorm' + str(idx)].dgamma grads['beta' + str(idx)] = self.layers['BatchNorm' + str(idx)].dbeta # === 5. 返回包含所有参数梯度的字典,用于优化器更新权重 === return grads
这段代码是一个神经网络中用于反向传播计算梯度的函数 gradient(self, x, t)
,属于某个类(如 MultiLayerNetExtend
)的方法。该方法执行以下步骤:
✅ 1. 前向传播(Forward)
self.loss(x, t, train_flg=True)
-
使用输入
x
和标签t
执行前向传播,并计算损失(包括正则化项)。 -
train_flg=True
表明这是训练过程(例如 BatchNorm 会区分训练和推理模式)。
✅ 2. 反向传播起点
dout = 1
dout = self.last_layer.backward(dout)
-
self.last_layer
通常是损失函数层(比如SoftmaxWithLoss
),backward()
返回对前一层的梯度。 -
这个
1
表示对损失函数的导数(标量)开始反向传播。
✅ 3. 逐层反向传播
layers = list(self.layers.values())
layers.reverse()
for layer in layers:
dout = layer.backward(dout)
-
self.layers
是一个OrderedDict
,按顺序存储所有的网络层。 -
.reverse()
后,按从输出层到输入层的顺序反向传播。 -
每一层都使用
backward()
方法计算梯度并更新dout
。
✅ 4. 收集所有梯度到 grads
字典中
grads = {} for idx in range(1, self.hidden_layer_num+2):
对于每一层(包含隐藏层和输出层):
🧠 权重和偏置项:
grads['W' + str(idx)] = self.layers['Affine' + str(idx)].dW + self.weight_decay_lambda * self.params['W' + str(idx)] grads['b' + str(idx)] = self.layers['Affine' + str(idx)].db
-
从每个
Affine
层中提取梯度:-
dW
:权重的梯度,加上 L2 正则化项(weight_decay_lambda * W
)。 -
db
:偏置项的梯度。
-
🧪 如果使用了 BatchNorm,还要收集 gamma 和 beta 的梯度:
if self.use_batchnorm and idx != self.hidden_layer_num+1: grads['gamma' + str(idx)] = self.layers['BatchNorm' + str(idx)].dgamma grads['beta' + str(idx)] = self.layers['BatchNorm' + str(idx)].dbeta
-
对于除了输出层的各层(因为输出层不使用 BatchNorm):
-
gamma
和beta
是 BatchNorm 层的缩放和平移参数。 -
它们也有各自的反向传播梯度:
dgamma
,dbeta
。
-
✅ 5. 返回梯度字典
return grads
-
grads
是一个包含所有参数梯度的字典,结构如下:
{ 'W1': ..., 'b1': ..., 'gamma1': ..., 'beta1': ..., 'W2': ..., 'b2': ..., ... }
📌 总结
这个函数的作用是:
给定输入
x
和标签t
,通过前向传播计算损失,反向传播得到每层的梯度,并将所有参数的梯度打包进一个字典返回,用于后续的权重更新(如 SGD、Adam)。