代码之家  ›  专栏  ›  技术社区  ›  blue-sky

pytorch自定义丢失功能

  •  2
  • blue-sky  · 技术社区  · 6 年前

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

    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])
    

    对培训数据做出完美预测:

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

    使用自定义丢失函数 https://cs230-stanford.github.io/pytorch-nlp.html#writing-a-custom-loss-function :

    enter image description here

    在上述代码中实现为 cus2

    取消注释代码 # criterion = cus2() 要使用此loss函数返回:

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

    同时返回警告:

    用户警告:0-dim张量的索引无效。这将是一个错误 火炬0.5。使用tensor.item()将0-dim张量转换为python 数

    我没有正确实现自定义丢失功能?

    1 回复  |  直到 6 年前
        1
  •  1
  •   Umang Gupta    6 年前

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

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

    当你这样做的时候 torch.sum 它返回一个0维张量,因此警告它不能被索引。解决这个问题 int(torch.sum(mask).item()) 如建议或 int(torch.sum(mask)) 也会工作。

    现在,您是否尝试使用自定义丢失来模拟CE丢失?如果是的话,那么你就错过了 log_softmax

    修复添加 outputs = torch.nn.functional.log_softmax(outputs, dim=1) 在语句4之前。请注意,在附加教程的情况下, 对数最大值 已在转接呼叫中完成。你也可以这样做。

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