Pytorch 从作为张量给出的索引创建一个热向量

Pytorch 从作为张量给出的索引创建一个热向量,pytorch,Pytorch,我有一个大小为4x6的张量,其中4是批量大小,6是序列长度。序列向量的每个元素都是一些索引(0到n)。我想创建一个4x6xn张量,其中第三维的向量将是索引的一个热编码,这意味着我想在指定的索引中放入1,其余的值将为零 例如,我有以下张量: [[5, 3, 2, 11, 15, 15], [1, 4, 6, 7, 3, 3], [2, 4, 7, 8, 9, 10], [11, 12, 15, 2, 5, 7]] 这里,所有的值都在(0到n)之间,其中n=15。所以,我想把张量转换成一个4x6x

我有一个大小为4x6的张量,其中4是批量大小,6是序列长度。序列向量的每个元素都是一些索引(0到n)。我想创建一个
4x6xn
张量,其中第三维的向量将是索引的一个热编码,这意味着我想在指定的索引中放入1,其余的值将为零

例如,我有以下张量:

[[5, 3, 2, 11, 15, 15],
[1, 4, 6, 7, 3, 3],
[2, 4, 7, 8, 9, 10],
[11, 12, 15, 2, 5, 7]]
这里,所有的值都在(0到n)之间,其中n=15。所以,我想把张量转换成一个
4x6x16
张量,其中第三维表示一个热编码向量


如何使用PyTorch功能实现这一点?现在,我正在使用循环进行此操作,但我希望避免循环

新答案 从PyTorch 1.1开始,在
torch.nn.functional
中有一个
one\u hot
函数。给定索引的任何张量
索引
和最大索引
n
,您可以创建一个单热版本,如下所示:

n = 5
indices = torch.randint(0,n, size=(4,7))
one_hot = torch.nn.functional.one_hot(indices, n) # size=(4,7,n)
from torch.sparse import FloatTensor as STensor

batch_size = 4
seq_length = 6
feat_dim = 16

batch_idx = torch.LongTensor([i for i in range(batch_size) for s in range(seq_length)])
seq_idx = torch.LongTensor(list(range(seq_length))*batch_size)
feat_idx = torch.LongTensor([[5, 3, 2, 11, 15, 15], [1, 4, 6, 7, 3, 3],                            
                             [2, 4, 7, 8, 9, 10], [11, 12, 15, 2, 5, 7]]).view(24,)

my_stack = torch.stack([batch_idx, seq_idx, feat_idx]) # indices must be nDim * nEntries
my_final_array = STensor(my_stack, torch.ones(batch_size * seq_length), 
                         torch.Size([batch_size, seq_length, feat_dim])).to_dense()    

print(my_final_array)
非常古老的答案

目前,根据我的经验,切片和索引对PyTorch来说可能有点痛苦。我假设你不想把张量转换成numpy数组。目前我能想到的最优雅的方法是使用稀疏张量,然后转换成稠密张量。其工作如下:

n = 5
indices = torch.randint(0,n, size=(4,7))
one_hot = torch.nn.functional.one_hot(indices, n) # size=(4,7,n)
from torch.sparse import FloatTensor as STensor

batch_size = 4
seq_length = 6
feat_dim = 16

batch_idx = torch.LongTensor([i for i in range(batch_size) for s in range(seq_length)])
seq_idx = torch.LongTensor(list(range(seq_length))*batch_size)
feat_idx = torch.LongTensor([[5, 3, 2, 11, 15, 15], [1, 4, 6, 7, 3, 3],                            
                             [2, 4, 7, 8, 9, 10], [11, 12, 15, 2, 5, 7]]).view(24,)

my_stack = torch.stack([batch_idx, seq_idx, feat_idx]) # indices must be nDim * nEntries
my_final_array = STensor(my_stack, torch.ones(batch_size * seq_length), 
                         torch.Size([batch_size, seq_length, feat_dim])).to_dense()    

print(my_final_array)
注:PyTorch目前正在进行一些工作,将在未来两三周内添加numpy风格的广播和其他功能以及其他功能。因此,在不久的将来,可能会有更好的解决方案


希望这对你有所帮助

这可以在
PyTorch
中对任何
Tensor
对象使用就地
scatter
方法来完成

labels = torch.LongTensor([[[2,1,0]], [[0,1,0]]]).permute(0,2,1) # Let this be your current batch
batch_size, k, _ = labels.size()
labels_one_hot = torch.FloatTensor(batch_size, k, num_classes).zero_()
labels_one_hot.scatter_(2, labels, 1)
对于
num_classes=3
(索引应在
[0,3)
之间变化),这将为您提供

(0 ,.,.) = 
  0  0  1
  0  1  0
  1  0  0
(1 ,.,.) = 
  1  0  0
  0  1  0
  1  0  0
[torch.FloatTensor of size 2x3x3]
请注意,
标签
应为
火炬.长传感器


PyTorch Docs Reference:

这是我找到的最简单的方法。其中x是一个数字列表,class_count是您拥有的类的数量

def one_hot(x, class_count):
    return torch.eye(class_count)[x,:]
像这样使用它:

x = [0,2,5,4]
class_count = 8
one_hot(x,class_count)
tensor([[1., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 1., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 1., 0., 0.],
        [0., 0., 0., 0., 1., 0., 0., 0.]])



labels
而不是
X
?@ramin它应该是labels而不是X。我提交了一个编辑。这也是一个更快的方法。