python - RuntimeError:预期一维目标张量,不支持多目标 Pytorch
问题描述
我最近从 keras 转到了 pytorch,但我仍在努力了解这一切是如何工作的。下面是我使用简单的 MLP 对 mnist 数据集进行分类的代码。就像我以前在 keras 中所做的那样,我将每个 28x28 图像展平为 784 的向量,并且我还为我的标签创建了一个单热表示。在模型中,我希望给定一个 784 的向量,模型会输出一个带有概率的单热向量,但是一旦我的代码到达计算损失,我就会得到以下错误:
RuntimeError: 1D target tensor expected, multi-target not supported
下面是我的代码:
import numpy as np
import matplotlib.pyplot as plt
import torch
import time
from torch import nn, optim
from keras.datasets import mnist
from torch.utils.data import Dataset, DataLoader
RANDOM_SEED = 42
np.random.seed(RANDOM_SEED)
torch.manual_seed(RANDOM_SEED)
# ----------------------------------------------------
class MnistDataset(Dataset):
def __init__(self, data_size=0):
(x, y), (_, _) = mnist.load_data()
x = [i.flatten() for i in x]
x = np.array(x, dtype=np.float32)
if data_size < 0 or data_size > len(y):
assert ("Data size should be between 0 to number of files in the dataset")
if data_size == 0:
data_size = len(y)
self.data_size = data_size
# picking 'data_size' random samples
self.x = x[:data_size]
self.y = y[:data_size]
# scaling between 0-1
self.x = (self.x / 255)
# Creating one-hot representation of target
y_encoded = []
for label in y:
encoded = np.zeros(10)
encoded[label] = 1
y_encoded.append(encoded)
self.y = np.array(y_encoded)
def __len__(self):
return self.data_size
def __getitem__(self, index):
x_sample = self.x[index]
label = self.y[index]
return x_sample, label
# ----------------------------------------------------
num_train_samples = 10000
num_test_samples = 2000
# Each generator returns a single
# sample & its label on each iteration.
mnist_train = MnistDataset(data_size=num_train_samples)
mnist_test = MnistDataset(data_size=num_test_samples)
# Each generator returns a batch of samples on each iteration.
train_loader = DataLoader(mnist_train, batch_size=128, shuffle=True) # 79 batches
test_loader = DataLoader(mnist_test, batch_size=128, shuffle=True) # 16 batches
# ----------------------------------------------------
# Defining the Model Architecture
class MLP(nn.Module):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(28 * 28, 100)
self.act1 = nn.ReLU()
self.fc2 = nn.Linear(100, 50)
self.act2 = nn.ReLU()
self.fc3 = nn.Linear(50, 10)
self.act3 = nn.Sigmoid()
def forward(self, x):
x = self.act1(self.fc1(x))
x = self.act2(self.fc2(x))
output = self.act3(self.fc3(x))
return output
# ----------------------------------------------------
model = MLP()
# Defining optimizer and loss function
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
# ----------------------------------------------------
# Training the model
epochs = 10
print("Training Started...")
for epoch in range(epochs):
for batch_index, (inputs, targets) in enumerate(train_loader):
optimizer.zero_grad() # Zero the gradients
outputs = model(inputs) # Forward pass
loss = criterion(outputs, targets) # Compute the Loss
loss.backward() # Compute the Gradients
optimizer.step() # Update the parameters
# Evaluating the model
total = 0
correct = 0
with torch.no_grad():
for batch_idx, (inputs, targets) in enumerate(test_loader):
outputs = model(inputs)
_, predicted = torch.max(outputs.data, 1)
total += targets.size(0)
correct += predicted.eq(targets.data).cpu().sum()
print('Epoch : {} Test Acc : {}'.format(epoch, (100. * correct / total)))
print("Training Completed Sucessfully")
# ----------------------------------------------------
我还阅读了一些与同一问题相关的其他帖子,其中大多数人说目标的 CrossEntropy 损失必须是一个数字,这完全让我无法理解。有人可以解释一下解决方案吗。谢谢。
解决方案
对于nn.CrossEntropyLoss
,您不需要标签的 one-hot 表示,您只需要传递预测的 logit、形状是(batch_size, n_class)
以及目标向量(batch_size,)
所以只需传入标签索引向量y
而不是 one-hot 向量。
修复了您的代码:
class MnistDataset(Dataset):
def __init__(self, data_size=0):
(x, y), (_, _) = mnist.load_data()
x = [i.flatten() for i in x]
x = np.array(x, dtype=np.float32)
if data_size < 0 or data_size > len(y):
assert ("Data size should be between 0 to number of files in the dataset")
if data_size == 0:
data_size = len(y)
self.data_size = data_size
# picking 'data_size' random samples
self.x = x[:data_size]
self.y = y[:data_size]
# scaling between 0-1
self.x = (self.x / 255)
self.y = y # <--
def __len__(self):
return self.data_size
def __getitem__(self, index):
x_sample = self.x[index]
label = self.y[index]
return x_sample, label
查看 Pytorch 示例以获取更多详细信息: https ://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html
推荐阅读
- javascript - 可以在 Plotly Dash 中动态更新 CSS 吗?
- reactjs - 如何在功能组件中实现 react-slick slickGoTo 方法?
- python - 如何将列表插入到特定位置的列表中?
- python - 如何处理日文字符?
- java - 新项目破坏网格布局
- python - 如果 num1 或 num2 不等于 0
- xml - 输入和保存 XML:literal 值到 protege
- jquery - jQuery addClass/removeClass 几次
- css - 否定全屏选择器不起作用
- node.js - 如何从标准输入管道到 NodeJS 中的 http 请求?