web-dev-qa-db-fra.com

Comment récupérer efficacement les indices de valeurs maximales dans un tenseur de torche?

Supposons avoir un tenseur de torche, par exemple de la forme suivante:

x = torch.Rand(20, 1, 120, 120)

Ce que je voudrais maintenant, c'est obtenir les indices des valeurs maximales de chaque matrice 120x120. Pour simplifier le problème, je voudrais d'abord x.squeeze() travailler avec la forme [20, 120, 120]. Je voudrais alors obtenir le tenseur de torche qui est une liste d'indices de forme [20, 2].

Comment puis-je faire ça rapidement?

7
Chris

Si je vous comprends bien, vous ne voulez pas les valeurs, mais les indices. Malheureusement, il n'y a pas de solution prête à l'emploi. Il existe une fonction argmax(), mais je ne vois pas comment l'obtenir pour faire exactement ce que vous voulez.

Voici donc une petite solution de contournement, l'efficacité devrait également être correcte car nous ne faisons que diviser les tenseurs:

n = torch.tensor(4)
d = torch.tensor(4)
x = torch.Rand(n, 1, d, d)
m = x.view(n, -1).argmax(1)
# since argmax() does only return the index of the flattened
# matrix block we have to calculate the indices by ourself 
# by using / and % (// would also work, but as we are dealing with
# type torch.long / works as well
indices = torch.cat(((m / d).view(-1, 1), (m % d).view(-1, 1)), dim=1)
print(x)
print(indices)

n représente votre première dimension et d les deux dernières dimensions. Je prends de plus petits nombres ici pour montrer le résultat. Mais bien sûr, cela fonctionnera également pour n=20 et d=120:

n = torch.tensor(20)
d = torch.tensor(120)
x = torch.Rand(n, 1, d, d)
m = x.view(n, -1).argmax(1)
indices = torch.cat(((m / d).view(-1, 1), (m % d).view(-1, 1)), dim=1)
#print(x)
print(indices)

Voici la sortie pour n=4 et d=4:

tensor([[[[0.3699, 0.3584, 0.4940, 0.8618],
          [0.6767, 0.7439, 0.5984, 0.5499],
          [0.8465, 0.7276, 0.3078, 0.3882],
          [0.1001, 0.0705, 0.2007, 0.4051]]],


        [[[0.7520, 0.4528, 0.0525, 0.9253],
          [0.6946, 0.0318, 0.5650, 0.7385],
          [0.0671, 0.6493, 0.3243, 0.2383],
          [0.6119, 0.7762, 0.9687, 0.0896]]],


        [[[0.3504, 0.7431, 0.8336, 0.0336],
          [0.8208, 0.9051, 0.1681, 0.8722],
          [0.5751, 0.7903, 0.0046, 0.1471],
          [0.4875, 0.1592, 0.2783, 0.6338]]],


        [[[0.9398, 0.7589, 0.6645, 0.8017],
          [0.9469, 0.2822, 0.9042, 0.2516],
          [0.2576, 0.3852, 0.7349, 0.2806],
          [0.7062, 0.1214, 0.0922, 0.1385]]]])
tensor([[0, 3],
        [3, 2],
        [1, 1],
        [1, 0]])

J'espère que c'est ce que vous vouliez obtenir! :)

Modifier:

Voici un peu modifié qui pourrait être un peu plus rapide (pas beaucoup je suppose :), mais c'est un peu plus simple et plus joli:

Au lieu de cela comme avant:

m = x.view(n, -1).argmax(1)
indices = torch.cat(((m // d).view(-1, 1), (m % d).view(-1, 1)), dim=1)

Le remodelage nécessaire déjà effectué sur les valeurs argmax:

m = x.view(n, -1).argmax(1).view(-1, 1)
indices = torch.cat((m // d, m % d), dim=1)

Mais comme mentionné dans les commentaires. Je ne pense pas qu'il soit possible d'en tirer beaucoup plus.

Une chose que vous pourriez faire, s'il est vraiment important pour vous d'obtenir la dernière amélioration possible des performances, implémente cette fonction ci-dessus comme une extension de bas niveau (comme en C++ ) pour pytorch.

Cela vous donnerait juste une fonction que vous pouvez appeler pour cela et éviterait le code lent python.

https://pytorch.org/tutorials/advanced/cpp_extension.html

3
blue-phoenox