web-dev-qa-db-fra.com

Création d'un vecteur chaud à partir d'indices donnés comme tenseur

J'ai un tenseur de taille 4 x 6 où 4 est la taille du lot et 6 est la longueur de la séquence. Chaque élément des vecteurs de séquence est un indice (0 à n). Je veux créer un 4 x 6 x n tenseur où les vecteurs en 3ème dimension seront un encodage à chaud de l'index ce qui signifie que je veux mettre 1 dans l'index spécifié et le reste des valeurs sera nul.

Par exemple, j'ai le tenseur suivant:

[[5, 3, 2, 11, 15, 15],
[1, 4, 6, 7, 3, 3],
[2, 4, 7, 8, 9, 10],
[11, 12, 15, 2, 5, 7]]

Ici, toutes les valeurs sont entre (0 à n) où n = 15. Donc, je veux convertir le tenseur en 4 X 6 X 16 tenseur où la troisième dimension représentera un vecteur d'encodage à chaud.

Comment puis-je faire cela en utilisant les fonctionnalités de PyTorch? En ce moment, je fais cela avec boucle mais je veux éviter de boucler!

13
Wasi Ahmad

NOUVELLE RÉPONSE Depuis PyTorch 1.1, il y a un one_hot fonction dans torch.nn.functional. Étant donné n'importe quel tenseur d'index indices et un index maximal n, vous pouvez créer une version one_hot comme suit:

n = 5
indices = torch.randint(0,n, size=(4,7))
one_hot = torch.nn.functional.one_hot(indices, n) # size=(4,7,n)

Réponse très ancienne

Pour le moment, le découpage et l'indexation peuvent être un peu pénibles dans PyTorch d'après mon expérience. Je suppose que vous ne voulez pas convertir vos tenseurs en tableaux numpy. La façon la plus élégante à laquelle je peux penser en ce moment est d'utiliser des tenseurs clairsemés, puis de les convertir en un tenseur dense. Cela fonctionnerait comme suit:

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)

Remarque: PyTorch fait actuellement l'objet de travaux qui ajouteront la diffusion de style numpy et d'autres fonctionnalités dans les deux ou trois prochaines semaines et d'autres fonctionnalités. Il est donc possible, de meilleures solutions seront disponibles dans un proche avenir.

J'espère que ça vous aide un peu.

13
mexmex

La façon la plus simple que j'ai trouvée. Où x est une liste de nombres et class_count est le nombre de classes que vous avez.

def one_hot(x, class_count):
    return torch.eye(class_count)[x,:]

Utilisez-le comme ceci:

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.]])


8
ege ozsoy

Cela peut être fait dans PyTorch en utilisant la méthode in situ scatter_ Pour tout objet Tensor.

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)

Pour num_classes=3 (Les indices doivent varier de [0,3)), Cela vous donnera

(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]

Notez que labels doit être un torch.LongTensor.

Référence de la documentation PyTorch: torch.Tensor.scatter _

3
activatedgeek