(pytorch / mse) 如何改变张量的形状?

Posted

技术标签:

【中文标题】(pytorch / mse) 如何改变张量的形状?【英文标题】:(pytorch / mse) How can I change the shape of tensor? 【发布时间】:2020-10-04 14:12:22 【问题描述】:

问题定义:

我必须使用MSELoss 函数来定义分类问题的损失。因此它一直在说关于张量形状的错误信息。

整个错误信息:

torch.Size([32, 10]) torch.Size([32]) -------------------------------------------------- ------------------------- RuntimeError Traceback(最近调用 最后)在 53 输出 = model.forward(图像) 54 打印(输出.形状,标签.形状) ---> 55 损失 = 标准(输出,标签) 56 损失.backward() 57 优化器.step()

/opt/conda/lib/python3.7/site-packages/torch/nn/modules/module.py 调用(self, *input, **kwargs) 530 结果 = self._slow_forward(*输入,**kwargs) 531 其他: --> 532 结果 = self.forward(*input, **kwargs) 533 for hook in self._forward_hooks.values(): 534 hook_result = hook(自我,输入,结果)

/opt/conda/lib/python3.7/site-packages/torch/nn/modules/loss.py 在 前进(自我,输入,目标) 429 430 def forward(自我,输入,目标): --> 431 返回 F.mse_loss(输入,目标,reduction=self.reduction) 432 第433章

/opt/conda/lib/python3.7/site-packages/torch/nn/functional.py 在 mse_loss(输入,目标,size_average,减少,减少)2213 ret = torch.mean(ret) if reduction == 'mean' else torch.sum(ret) 2214 其他: -> 2215 扩展输入,扩展目标 = torch.broadcast_tensors(输入,目标)2216 ret = torch._C._nn.mse_loss(expanded_input,expanded_target, _Reduction.get_enum(reduction)) 2217 返回ret

/opt/conda/lib/python3.7/site-packages/torch/functional.py 在 广播张量(*张量) 50 [0, 1, 2]]) 51 """ ---> 52 返回 torch._C._VariableFunctions.broadcast_tensors(tensors) 53 54

> RuntimeError: 张量 a (10) 的大小必须与张量的大小匹配 b (32) 在非单一维度 1

如何重塑张量,我应该改变哪个张量(输出或标签)来计算损失?

完整的代码附在下面。

import numpy as np
import torch

# Loading the Fashion-MNIST dataset
from torchvision import datasets, transforms

# Get GPU Device
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

transform = transforms.Compose([transforms.ToTensor(),
                                    transforms.Normalize((0.5,), (0.5,))])
# Download and load the training data
trainset = datasets.FashionMNIST('MNIST_data/', download = True, train = True, transform = transform)
testset = datasets.FashionMNIST('MNIST_data/', download = True, train = False, transform = transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size = 32, shuffle = True, num_workers=4)
testloader = torch.utils.data.DataLoader(testset, batch_size = 32, shuffle = True, num_workers=4)

# Examine a sample
dataiter = iter(trainloader)
images, labels = dataiter.next()

# Define the network architecture
from torch import nn, optim
import torch.nn.functional as F

model = nn.Sequential(nn.Linear(784, 128),
                      nn.ReLU(),
                      nn.Linear(128, 10),
                      nn.LogSoftmax(dim = 1))
model.to(device)

# Define the loss
criterion = nn.MSELoss()

# Define the optimizer
optimizer = optim.Adam(model.parameters(), lr = 0.001)

# Define the epochs
epochs = 5

train_losses, test_losses = [], []

for e in range(epochs):
  running_loss = 0
  for images, labels in trainloader:
    # Flatten Fashion-MNIST images into a 784 long vector
    images = images.to(device)
    labels = labels.to(device)
    images = images.view(images.shape[0], -1)

    # Training pass
    optimizer.zero_grad()
    output = model.forward(images)
    print(output.shape, labels.shape)
    loss = criterion(output, labels)
    loss.backward()
    optimizer.step()

    running_loss += loss.item()
  else:
    test_loss = 0
    accuracy = 0

    # Turn off gradients for validation, saves memory and computation
    with torch.no_grad():
      # Set the model to evaluation mode
      model.eval()

      # Validation pass
      for images, labels in testloader:
        images = images.to(device)
        labels = labels.to(device)
        images = images.view(images.shape[0], -1)
        ps = model(images)
        test_loss += criterion(ps, labels)
        top_p, top_class = ps.topk(1, dim = 1)
        equals = top_class == labels.view(*top_class.shape)
        accuracy += torch.mean(equals.type(torch.FloatTensor))

    model.train()

    print("Epoch: /..".format(e+1, epochs),
          "Training loss: :.3f..".format(running_loss/len(trainloader)),
          "Test loss: :.3f..".format(test_loss/len(testloader)),
          "Test Accuracy: :.3f".format(accuracy/len(testloader)))

【问题讨论】:

把所有的错误日志都放到最后一行 @NatthaphonHongcharoen 感谢您的评论。我附上了错误消息的整行。 【参考方案1】:

从您在出错之前打印的输出中,torch.Size([32, 10]) torch.Size([32])

左边是模型给你的,右边是来自trainloader,通常你用它来做nn.CrossEntropyLoss之类的东西。

从完整的错误日志来看,错误来自这一行

loss = criterion(output, labels)

实现这个工作的方式叫One-hot Encoding,如果是我懒得这么写。

ones = torch.sparse.torch.eye(10).to(device)  # number of class class
labels = ones.index_select(0, labels)

【讨论】:

感谢您的友好解释。但是,它给我带来了另一个困难,说“设备类型为 cuda 的预期对象,但在调用 _th_index_select 时为参数 #1 'self' 获得了设备类型 cpu” 如果来自“labels = ones.index_select(0, labels)”行,则会出现此错误 我编辑了答案,实际上只是将to(device) 放在ones = 之后。看看这是否有效。【参考方案2】:

或者,您可以将损失函数从 nn.MSELoss() 更改为 nn.CrossEntropyLoss()。对于像这样的分类任务,交叉熵损失通常比 MSE 更可取,并且在 PyTorch 的实现中,这个损失函数在后台处理了大量的形状转换,因此您可以为其提供类概率向量和单个类标签。

从根本上说,您的模型会尝试通过计算每个可能的类别的分数(您可以将其称为“置信度分数”)来预测输入所属的类别。因此,如果您有 10 个类,模型的输出将是一个 10 维列表(在 PyTorch 中,张量形状 [10]),预测将是最高分的索引。通常会应用 softmax (https://en.wikipedia.org/wiki/Softmax_function) 函数将这些分数转换为概率分布,因此所有分数将介于 0 和 1 之间,并且所有元素的总和为 1。

然后交叉熵是此任务的损失函数的常见选择:它将预测列表与 one-hot 编码标签进行比较。例如。如果您有 3 个类,则标签看起来像 [1, 0, 0] 代表第一类。这也称为“单热编码”。同时,预测可能看起来像[0.7, 0.1, 0.2]。在 PyTorch 中,nn.CrossEntropyLoss() 期望您的标签以单值张量的形式出现,其值代表类标签,因为实际上不需要在内存中移动长而稀疏的向量。所以这个损失函数完成了你想要做的比较,我猜它的实现比实际创建一个热编码更有效。

【讨论】:

以上是关于(pytorch / mse) 如何改变张量的形状?的主要内容,如果未能解决你的问题,请参考以下文章

在pytorch中连接两个不同形状的火炬张量

如何在pytorch中连接两个不同尺寸的张量

如何将张量逐行乘以 PyTorch 中的向量?

Pytorch张量,如何切换通道位置 - 运行时错误

使用 PyTorch 在 2D 张量上滑动窗口

PyTorch 中的连接张量