为何我的Sigmoid层阻断了梯度传递?
问题分析与解答
原代码示例
import torch import torch.optim as optim import torch.nn as nn input = torch.tensor([1.,2.], requires_grad=True) sigmoid = nn.Sigmoid() interm = sigmoid(input) optimizer = optim.SGD([input], lr=1, momentum=0.9) for epoch in range(5): optimizer.zero_grad() loss = torch.linalg.vector_norm(interm - torch.tensor([2.,2.])) print(epoch, loss, input, interm) loss.backward(retain_graph=True) optimizer.step() print(interm.grad)
梯度异常+目标无法达成的原因
核心问题:中间结果
interm仅计算一次
你把interm = sigmoid(input)写在了循环外部,这意味着不管优化器怎么更新input,interm始终是初始input=[1.,2.]经过sigmoid计算出的固定值。循环内的loss一直基于这个固定值计算,梯度自然无法传递到更新后的input上,优化过程完全无效。逻辑错误:目标值超出sigmoid输出范围
sigmoid函数的输出永远在(0,1)区间内,你要求interm等于[2.,2.],从数学上根本不可能实现。就算代码修正,优化过程也会朝着不可能的目标无意义迭代,最终loss收敛到固定值(即1与2的差值范数)。冗余操作:
retain_graph=True无必要
这里每次循环都是独立的计算图,不需要保留计算图,去掉该参数不影响运行。另外打印interm.grad意义不大,我们要优化的是input,应该关注input.grad的变化。
修正后的代码示例
import torch import torch.optim as optim import torch.nn as nn input = torch.tensor([1.,2.], requires_grad=True) sigmoid = nn.Sigmoid() optimizer = optim.SGD([input], lr=1, momentum=0.9) # 将目标改为sigmoid可达到的范围,比如[0.9,0.9] target = torch.tensor([0.9,0.9]) for epoch in range(5): optimizer.zero_grad() # 每次循环基于当前input重新计算interm interm = sigmoid(input) loss = torch.linalg.vector_norm(interm - target) print(f"epoch {epoch}: loss={loss.item()}, input={input}, interm={interm}") loss.backward() optimizer.step() # 查看input的梯度变化 print(f"input grad: {input.grad}")
内容的提问来源于stack exchange,提问作者JobHunter69
相关产品推荐
相关产品推荐

