PyTorch自定义损失功能 [英] PyTorch custom loss function

查看:293
本文介绍了PyTorch自定义损失功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

应如何实现自定义损失功能?使用以下代码会导致错误:

  import torch 
import torch.nn as nn
import torchvision
导入torchvision.transforms转换为
导入numpy为np
导入matplotlib.pyplot为plt
导入torch.utils.data为data_utils
导入torch.nn为nn
torch.nn.function as F

num_epochs = 20

x1 = np.array([0,0])
x2 = np。 array([0,1])$ ​​b $ b x3 = np.array([1,0])
x4 = np.array([1,1])$ ​​b
$ b num_epochs = 200

class cus2(torch.nn.Module):

def __init __(self):
super(cus2,self).__ init __()

def forward(自身,输出,标签):
#重塑标签以给出长度为batch_size * seq_len的平面向量
labels = labels.view(-1)

#屏蔽掉'PAD'令牌
mask =(labels> = 0).float()

#令牌的数量是掩码$ b $中元素的总和b num_tokens = int(torch.sum(m ask).data [0])

#选择与标签相对应的值并乘以掩码
输出=输出[range(outputs.shape [0]),标签] *掩码

#所有非'PAD'令牌的交叉熵损失
return -torch.sum(输出)/ num_tokens


x = torch.tensor([ x1,x2,x3,x4])。float()

y = torch.tensor([0,1,1,0])。long()

train = data_utils.TensorDataset(x,y)
train_loader = data_utils.DataLoader(train,batch_size = 2,shuffle = True)

设备='cpu'

input_size = 2
hidden_​​size = 100
num_classes = 2

learning_rate = .0001

class NeuralNet(nn.Module):
def __init__ (self,input_size,hidden_​​size,num_classes):
super(NeuralNet,self).__ init __()
self.fc1 = nn.Linear(input_size,hidden_​​size)
self.relu = nn。 ReLU()
self.fc2 = nn.Linear(hidden_​​size,num_classes)

def forward(self,x):
out = self.fc1(x)
out = self.relu(out)
out = self.fc2(out)
返回

(0,1):

模型= NeuralNet(input_size,hidden_​​size,num_classes).to(设备)

准则= nn.CrossEntropyLoss()
#准则= Regress_Loss()
#标准= cus2()
优化程序= torch.optim.Adam(model.parameters(),lr = learning_rate)

total_step = len(train_loader)
代表范围内的时期(num_epochs):
代表i,(images,标签)枚举(train_loader):
images = images.reshape(-1,2).to(device)
标签= labels.to(设备)

输出=模型(图像)
损失=标准(输出,标签)

Optimizer.zero_grad( )
loss.backward()
Optimizer.step()
#打印(损失)

输出=模型(x)

print(outputs.data.max(1)[1])$ ​​b $ b

对训练数据做出完美的预测:

  tensor([0,1,1,0 ])

使用来自



是在上述代码中以 cus2

实施

注释代码#条件= cus2() 使用此损失函数将返回:

  tensor([0,0,0,0]) 

还返回警告:


UserWarning:无效的索引0维张量这将是
PyTorch 0.5中的错误。使用tensor.item()将0维张量转换为Python
数字


我没有实现自定义损失函数正确吗?

解决方案

除以下内容外,您的损失函数在编程上是正确的:

 #令牌数是掩码
中元素的总和num_tokens = int(torch.sum(mask).data [0])

当您执行 torch.sum 时,它将返回0维张量,因此警告无法索引。要解决此问题,请按照建议执行 int(torch.sum(mask).item()) int(torch.sum(mask))也可以。



现在,您是否要使用自定义损失来模拟CE损失?如果是,那么您就错过了 log_softmax



要修复该问题,请添加 outputs =火炬语句4之前的.nn.functional.log_softmax(outputs,dim = 1)。请注意,如果您已附加教程,则 log_softmax 在前向呼叫中已经完成。你也可以那样做。



此外,我注意到学习速度很慢,即使有CE丧失,结果也不一致。在习俗和CE丢失的情况下,将学习率提高到1e-3对我来说效果很好。


How should a custom loss function be implemented ? Using below code is causing error :

import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms
import numpy as np
import matplotlib.pyplot as plt
import torch.utils.data as data_utils
import torch.nn as nn
import torch.nn.functional as F

num_epochs = 20

x1 = np.array([0,0])
x2 = np.array([0,1])
x3 = np.array([1,0])
x4 = np.array([1,1])

num_epochs = 200

class cus2(torch.nn.Module):

    def __init__(self):
        super(cus2,self).__init__()

    def forward(self, outputs, labels):
        # reshape labels to give a flat vector of length batch_size*seq_len
        labels = labels.view(-1)  

        # mask out 'PAD' tokens
        mask = (labels >= 0).float()

        # the number of tokens is the sum of elements in mask
        num_tokens = int(torch.sum(mask).data[0])

        # pick the values corresponding to labels and multiply by mask
        outputs = outputs[range(outputs.shape[0]), labels]*mask

        # cross entropy loss for all non 'PAD' tokens
        return -torch.sum(outputs)/num_tokens


x = torch.tensor([x1,x2,x3,x4]).float()

y = torch.tensor([0,1,1,0]).long()

train = data_utils.TensorDataset(x,y)
train_loader = data_utils.DataLoader(train , batch_size=2 , shuffle=True)

device = 'cpu'

input_size = 2
hidden_size = 100 
num_classes = 2

learning_rate = .0001

class NeuralNet(nn.Module) : 
    def __init__(self, input_size, hidden_size, num_classes) : 
        super(NeuralNet, self).__init__()
        self.fc1 = nn.Linear(input_size , hidden_size)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(hidden_size , num_classes)

    def forward(self, x) : 
        out = self.fc1(x)
        out = self.relu(out)
        out = self.fc2(out)
        return out

for i in range(0 , 1) :

        model = NeuralNet(input_size, hidden_size, num_classes).to(device)

        criterion = nn.CrossEntropyLoss()
#         criterion = Regress_Loss()
#         criterion = cus2()
        optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

        total_step = len(train_loader)
        for epoch in range(num_epochs) : 
            for i,(images , labels) in enumerate(train_loader) : 
                images = images.reshape(-1 , 2).to(device)
                labels = labels.to(device)

                outputs = model(images)
                loss = criterion(outputs , labels)

                optimizer.zero_grad()
                loss.backward()
                optimizer.step()
#                 print(loss)

        outputs = model(x)

        print(outputs.data.max(1)[1])

makes perfect predictions on training data :

tensor([0, 1, 1, 0])

Using a custom loss function from https://cs230-stanford.github.io/pytorch-nlp.html#writing-a-custom-loss-function :

is implemented in above code as cus2

Un-commenting code # criterion = cus2() to use this loss function returns :

tensor([0, 0, 0, 0])

A warning is also returned :

UserWarning: invalid index of a 0-dim tensor. This will be an error in PyTorch 0.5. Use tensor.item() to convert a 0-dim tensor to a Python number

I've not implemented the custom loss function correctly ?

解决方案

Your loss function is programmatically correct except for below:

    # the number of tokens is the sum of elements in mask
    num_tokens = int(torch.sum(mask).data[0])

When you do torch.sum it returns a 0-dimensional tensor and hence the warning that it can't be indexed. To fix this do int(torch.sum(mask).item()) as suggested or int(torch.sum(mask)) will work too.

Now, are you trying to emulate the CE loss using the custom loss? If yes, then you are missing the log_softmax

To fix that add outputs = torch.nn.functional.log_softmax(outputs, dim=1) before statement 4. Note that in case of tutorial that you have attached, log_softmax is already done in the forward call. You can do that too.

Also, I noticed that the learning rate is slow and even with CE loss, results are not consistent. Increasing the learning rate to 1e-3 works well for me in case of custom as well as CE loss.

这篇关于PyTorch自定义损失功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆