(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) 如何改变张量的形状?的主要内容,如果未能解决你的问题,请参考以下文章