Pytorch argsort упорядочен, с дублирующими элементами в тензоре - PullRequest
1 голос
/ 16 мая 2019

У меня есть вектор A = [0,1,2,3,0,0,1,1,2,2,3,3].Мне нужно отсортировать их в возрастающем количестве, чтобы они были упорядочены по списку и из этого извлекать argsort.Чтобы лучше объяснить это, мне нужно отсортировать A так, чтобы он возвращал B = [0,4,5,1,6,7,2,8,9,3,10,11].Тем не менее, когда я использую Pyotrch torch.argsort(A), он возвращает B = [4,5,0,1,6,7,2,8,9,3,10,11].

Я предполагаю, что алгоритм, который делает это, не может контролироваться с моей стороны.Есть ли способ подойти к этому без введения для циклов?Такая операция является частью моей модели NN и приведет к проблемам с производительностью, если не будет выполнена эффективно.Спасибо!

Ответы [ 2 ]

2 голосов
/ 19 мая 2019

Вот чистое решение на основе PyTorch, использующее broadcasting, torch.unique() и torch.nonzero().Это будет большим подспорьем, особенно для реализации / запуска на основе графического процессора, что невозможно, если нам придется переключиться обратно на NumPy, argsort it, а затем перенести обратно на PyTorch (как предлагается в других подходах).

# our input tensor
In [50]: A = torch.tensor([0,1,2,3,0,0,1,1,2,2,3,3])

# construct an intermediate boolean tensor
In [51]: boolean = A[:, None] == torch.unique(A)

In [52]: boolean
Out[52]: 
tensor([[1, 0, 0, 0],
        [0, 1, 0, 0],
        [0, 0, 1, 0],
        [0, 0, 0, 1],
        [1, 0, 0, 0],
        [1, 0, 0, 0],
        [0, 1, 0, 0],
        [0, 1, 0, 0],
        [0, 0, 1, 0],
        [0, 0, 1, 0],
        [0, 0, 0, 1],
        [0, 0, 0, 1]], dtype=torch.uint8)

Получив этот булевский тензор, мы можем найти нужные индексы, проверив позиции, где есть 1 после транспонирования булева тензора.

Это даст нам обоим отсортированные inputи indices.Поскольку нам нужны только индексы, мы можем просто получить их, проиндексировав последний столбец (1 или -1)

In [53]: torch.nonzero(boolean.t())[:, -1]
Out[53]: tensor([ 0,  4,  5,  1,  6,  7,  2,  8,  9,  3, 10, 11])

Вот результат для еще одного примера, представленного OP вкомментарии:

In [55]: A_large = torch.tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9])

In [56]: boolean_large = A_large[:, None] == torch.unique(A_large)

In [57]: torch.nonzero(boolean_large.t())[:, -1]
Out[57]: 
tensor([ 0, 10, 11,  1, 12, 13,  2, 14, 15,  3, 16, 17,  4, 18, 19,  5, 20, 21,
         6, 22, 23,  7, 24, 25,  8, 26, 27,  9, 28, 29])

Примечание : В отличие от решения на основе NumPy, предложенного в других ответах, здесь нам не нужно беспокоиться о том, какой kind алгоритм сортировки мы используемиспользовать, потому что мы вообще не используем сортировку.

1 голос
/ 17 мая 2019

Вот один из способов:

  • сортировка массива numpy с помощью numpy.argsort ()
  • преобразовать результат в тензор, используя torch.from_numpy ()

    import torch import numpy as np A = [0,1,2,3,0,0,1,1,2,2,3,3] x = np.array(A) y = torch.from_numpy(np.argsort(x, kind='mergesort')) print(y)

...