PyTorch:损失保持不变



我在 PyTorch 中用我自己实现的损失函数focal_loss_fixed编写了一段代码。但是我的损失值在每个时期之后都保持不变。看起来权重没有更新。这是我的代码片段:

optimizer = optim.SGD(net.parameters(),
lr=lr,
momentum=0.9,
weight_decay=0.0005)

for epoch in T(range(20)):
net.train()
epoch_loss = 0
for n in range(len(x_train)//batch_size):
(imgs, true_masks) = data_gen_small(x_train, y_train, iter_num=n, batch_size=batch_size)
temp = []
for tt in true_masks:
temp.append(tt.reshape(128, 128, 1))
true_masks = np.copy(np.array(temp))
del temp
imgs = np.swapaxes(imgs, 1,3)
imgs = torch.from_numpy(imgs).float().cuda()
true_masks = torch.from_numpy(true_masks).float().cuda()
masks_pred = net(imgs)
masks_probs = F.sigmoid(masks_pred)
masks_probs_flat = masks_probs.view(-1)
true_masks_flat = true_masks.view(-1)
print((focal_loss_fixed(tf.convert_to_tensor(true_masks_flat.data.cpu().numpy()), tf.convert_to_tensor(masks_probs_flat.data.cpu().numpy()))))
loss = torch.from_numpy(np.array(focal_loss_fixed(tf.convert_to_tensor(true_masks_flat.data.cpu().numpy()), tf.convert_to_tensor(masks_probs_flat.data.cpu().numpy())))).float().cuda()
loss = Variable(loss.data, requires_grad=True)
epoch_loss *= (n/(n+1))
epoch_loss += loss.item()*(1/(n+1))
print('Step: {0:.2f}% --- loss: {1:.6f}'.format(n * batch_size* 100.0 / len(x_train), epoch_loss), end='r')
optimizer.zero_grad()
loss.backward()
optimizer.step()
print('Epoch finished ! Loss: {}'.format(epoch_loss))

这是我的"focal_loss_fixed"功能:

def focal_loss_fixed(true_data, pred_data):
gamma=2.
alpha=.25
eps = 1e-7
# print(type(y_true), type(y_pred))
pred_data = K.clip(pred_data,eps,1-eps)
pt_1 = tf.where(tf.equal(true_data, 1), pred_data, tf.ones_like(pred_data))
pt_0 = tf.where(tf.equal(true_data, 0), pred_data, tf.zeros_like(pred_data))
with tf.Session() as sess:
return sess.run(-K.sum(alpha * K.pow(1. - pt_1, gamma) * K.log(pt_1))-K.sum((1-alpha) * K.pow( pt_0, gamma) * K.log(1. - pt_0)))

在每个纪元之后,损失值保持不变(5589.60328(。怎么了?

在计算损失时,你调用focal_loss_fixed()它使用TensorFlow来计算损失值。focal_loss_fixed()创建一个图并在会话中运行它以获取值,此时 PyTorch 不知道导致损失的操作顺序,因为它们是由 TensorFlow 后端计算的。那么,PyTorch 在loss中看到的所有内容很可能都是一个常量,就好像你写的那样

loss = 3

因此,梯度将为零,并且参数将永远不会更新。我建议你使用 PyTorch 运算重写你的损失函数,以便可以计算相对于其输入的梯度。

我认为问题在于你的重量衰减。

从本质上讲,你不是将权重减少x,而是将权重乘以x,这意味着你瞬间只做非常小的增量,导致(看似(停滞损失函数。

有关这方面的更多解释可以在 PyTorch 论坛(例如,这里或这里(中找到。
不幸的是,仅 SGD 的来源也没有告诉您太多有关其实施的信息。 只需将其设置为更大的值应该会带来更好的更新。你可以从完全省略它开始,然后迭代地减少它(从1.0开始(,直到你得到更不错的结果。

最新更新