我对Pytorch如何处理one-Hot向量感到非常困惑。在本教程中,神经网络将生成一个one-Hot向量作为其输出。据我了解,教程中神经网络的示意结构应该是这样的:
但是,标签
不是单热向量格式。我得到以下size
print(labels.size())
print(outputs.size())
output>>> torch.Size([4])
output>>> torch.Size([4, 10])
奇迹般地,如果他们将输出
和标签
传递给标准=CrossEntropyLoss()
,则根本没有错误。
loss = criterion(outputs, labels) # How come it has no error?
也许pytorch会自动将标签
转换为one-Hot向量形式。所以,我尝试在将标签传递给损失函数之前将其转换为one-Hot向量。
def to_one_hot_vector(num_class, label):
b = np.zeros((label.shape[0], num_class))
b[np.arange(label.shape[0]), label] = 1
return b
labels_one_hot = to_one_hot_vector(10,labels)
labels_one_hot = torch.Tensor(labels_one_hot)
labels_one_hot = labels_one_hot.type(torch.LongTensor)
loss = criterion(outputs, labels_one_hot) # Now it gives me error
但是,我得到了以下错误
RuntimeError: /opt/pytorch/pytorch/aten/src/THCUNN/generic/ClassNLLCriterion.cu:15不支持多目标
那么,Pytorch
不支持one-热向量吗?Pytorch
如何计算两个张量输出=[1,00]、[0,0,1]
和标签=[0,2]
的交叉熵
?目前对我来说根本没有意义。
PyTorch在其CrossEntropyLoss
的留档中声明
该标准期望类索引(0到C-1)作为大小小批量1D张量的每个值的目标
换句话说,它在CEL
中概念上内置了您的to_one_hot_vector
函数,并且不会公开one-HotAPI。请注意,与存储类标签相比,one-Hot向量的内存效率很低。
如果您被赋予one-Hot向量并且需要转到类标签格式(例如与CEL
兼容),您可以使用argmax
,如下所示:
import torch
labels = torch.tensor([1, 2, 3, 5])
one_hot = torch.zeros(4, 6)
one_hot[torch.arange(4), labels] = 1
reverted = torch.argmax(one_hot, dim=1)
assert (labels == reverted).all().item()
此代码将帮助您同时使用一个热编码和多个热编码:
import torch
batch_size=10
n_classes=5
target = torch.randint(high=5, size=(1,10)) # set size (2,10) for MHE
print(target)
y = torch.zeros(batch_size, n_classes)
y[range(y.shape[0]), target]=1
y
OHE中的输出
tensor([[4, 3, 2, 2, 4, 1, 1, 1, 4, 2]])
tensor([[0., 0., 0., 0., 1.],
[0., 0., 0., 1., 0.],
[0., 0., 1., 0., 0.],
[0., 0., 1., 0., 0.],
[0., 0., 0., 0., 1.],
[0., 1., 0., 0., 0.],
[0., 1., 0., 0., 0.],
[0., 1., 0., 0., 0.],
[0., 0., 0., 0., 1.],
[0., 0., 1., 0., 0.]])
当我设置target=torch. randint(高=5,大小=(2,10))
时,MHE的输出
tensor([[3, 2, 4, 4, 2, 4, 0, 4, 4, 1],
[4, 1, 1, 3, 2, 2, 4, 2, 4, 3]])
tensor([[0., 0., 0., 1., 1.],
[0., 1., 1., 0., 0.],
[0., 1., 0., 0., 1.],
[0., 0., 0., 1., 1.],
[0., 0., 1., 0., 0.],
[0., 0., 1., 0., 1.],
[1., 0., 0., 0., 1.],
[0., 0., 1., 0., 1.],
[0., 0., 0., 0., 1.],
[0., 1., 0., 1., 0.]])
如果您需要多个OHE:
torch.nn.functional.one_hot(target)
tensor([[[0, 0, 0, 1, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 1],
[0, 0, 0, 0, 1],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 1],
[1, 0, 0, 0, 0],
[0, 0, 0, 0, 1],
[0, 0, 0, 0, 1],
[0, 1, 0, 0, 0]],
[[0, 0, 0, 0, 1],
[0, 1, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 0, 1, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 1],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 1],
[0, 0, 0, 1, 0]]])
正如@Jatentaki明确指出的那样,您可以使用torch. argmax(one_hot,dim=1)
将one-Hot编码向量转换为数字。
但是,如果您仍然想在PyTorch中使用one-Hot编码输出训练您的网络,您可以使用nn. LogSoftmax
以及NLLLOSS
:
import torch
from torch import nn
output_onehot = nn.LogSoftmax(dim=1)(torch.randn(3, 5)) # m = 3 samples, each has n = 5 features
target = torch.tensor([1, 0, 4]) # target values for each sample
nn.NLLLoss()(output_onehot, target)
print(output_onehot)
print(target)
# You can get the probabilities using the exponential function:
print("Probabilities:", torch.exp(output_onehot))
输出将是这样的:
tensor([[-0.5413, -2.4461, -2.0110, -1.9964, -2.7851],
[-2.3376, -1.6985, -1.8472, -3.0975, -0.6585],
[-3.2820, -0.7160, -1.5297, -1.5636, -3.0412]])
tensor([1, 0, 4])
Probabilities: tensor([[0.5820, 0.0866, 0.1339, 0.1358, 0.0617],
[0.0966, 0.1830, 0.1577, 0.0452, 0.5176],
[0.0376, 0.4887, 0.2166, 0.2094, 0.0478]])