目前正在尝试使用以下逻辑为线性回归实现自定义损失函数: *如果模型的输出值大于或等于目标,返回损失为(输出-目标)。 *如果模型的输出值小于目标值,返回损失为(目标 - 输出)^2
import torch.nn as nn
class E_Loss(nn.Module):
def __init__(self, weight=None, size_average=True):
super(E_Loss, self).__init__()
def forward(self, inputs, targets, smooth=1):
inputs = inputs.view(-1)
targets = targets.view(-1)
is_greater = torch.gt(inputs, outputs)
print(is_greater)
if is_greater: #torch.gt(inputs, targets):
loss = (inputs - targets)
else:
loss = np.square(targets - outputs)
return loss
使用我的模型进行训练时,我在 loss.backward() 步骤中遇到此错误: RuntimeError:只能为标量输出隐式创建 grad
假设它需要一个标量输出,我如何重写我的损失函数来产生这个? 重写我的代码而不使用数据加载器会更容易吗?
train_df, test_df = train_test_split(df, test_size=0.4)
train_dataset = FeatureDataset(train_df)
test_dataset = FeatureDataset(test_df)
train_dataloader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_dataloader = DataLoader(test_dataset, batch_size=16, shuffle=False)
#setup dataloader
eloss = E_Loss()
criterion = eloss
model = linearRegression(16, 1)
learningRate = 0.01
optimizer = torch.optim.SGD(model.parameters(), lr=learningRate, weight_decay=0.05)
h_loss = []
epochs = 100
for epoch in range(epochs):
running_loss = 0.0
for i, (x, y) in enumerate(train_dataloader):
optimizer.zero_grad()
#clear gradients after each epoch so it isnt cumulative
outputs = model(x)
#get current output from model for comparison
loss = criterion(outputs, y)
loss.backward()
optimizer.step()
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-39-fb6074e17ffb> in <module>
---> 68 loss.backward()
69 optimizer.step()
70 running_loss += loss.item()
2 frames
/usr/local/lib/python3.8/dist-packages/torch/_tensor.py in backward(self, gradient, retain_graph, create_graph, inputs)
486 inputs=inputs,
487 )
--> 488 torch.autograd.backward(
489 self, gradient, retain_graph, create_graph, inputs=inputs
490 )
/usr/local/lib/python3.8/dist-packages/torch/autograd/__init__.py in backward(tensors, grad_tensors, retain_graph, create_graph, grad_variables, inputs)
188
189 grad_tensors_ = _tensor_or_tensors_to_tuple(grad_tensors, len(tensors))
--> 190 grad_tensors_ = _make_grads(tensors, grad_tensors_, is_grads_batched=False)
191 if retain_graph is None:
192 retain_graph = create_graph
/usr/local/lib/python3.8/dist-packages/torch/autograd/__init__.py in _make_grads(outputs, grads, is_grads_batched)
83 if out.requires_grad:
84 if out.numel() != 1:
---> 85 raise RuntimeError("grad can be implicitly created only for scalar outputs")
86 new_grads.append(torch.ones_like(out, memory_format=torch.preserve_format))
87 else:
RuntimeError: grad can be implicitly created only for scalar outputs
您发布的代码没有任何意义,因为
is_greater = torch.gt(inputs, outputs)
行使用了一个未定义的变量outputs
。torch.gt
是一个元素方面的大于操作,除非 inputs
和 outputs
都是标量,否则在条件语句中使用它的结果是没有意义的。由于您的批量大小是 64,那么您应该得到一个例外RuntimeError: Boolean value of tensor with more than one value is ambiguous
.np.square
。这是模棱两可的,可能会或可能不会工作取决于它是如何在引擎盖下实现的。将 PyTorch 函数与 PyTorch 张量结合使用。张量支持大多数 python 运算符,因此只需使用 x**2
或 x*x
来进行元素平方。您提出的错误表明,尽管存在所有明显的错误,您仍能够运行损失函数代码,但反向传播失败,因为损失函数不是标量值。您发布的代码不适合我,但似乎也没有进行任何形式的均值缩减。假设上述问题得到解决并且它确实运行了,那么我希望您会遇到这样的错误。发生此错误是因为
Tensor.backward
要求张量是标量值,即损失应该是单个数字。大多数情况下,这是通过平均整个批次的损失来实现的。
为了解决损失函数的实现,如果您将描述的函数视为
output - target
的函数,则更容易实现。因为 output >= target
等价于 output - target >= 0
那么在让 x = output - target
之后我们只想要一个函数等于 x
当 x
是非负的并且 x**2
否则。
这可以通过不同的方式实现,但一种简单的方法是认识到
Tensor.relu
可用于将函数分解为正项和负项 x = relu(x) + (-relu(-x))
。使用这个恒等式,很明显你想要的是loss = relu(x) + relu(-x)**2
。解决均值降低问题以及损失函数的工作版本可能是:
class E_loss(nn.Module):
def __init__(self):
super().__init__()
def forward(self, outputs, targets):
x = outputs.flatten() - targets.flatten()
return (x.relu() + ((-x).relu())**2).mean()