Есть ли в Pytorch метод для подсчета количества уникальных значений таким образом, чтобы их можно было распространять обратно? - PullRequest
2 голосов
/ 29 октября 2019

Учитывая следующий тензор (который является результатом работы сети [обратите внимание на grad_fn]):

tensor([121., 241., 125.,   1., 108., 238., 125., 121.,  13., 117., 121., 229.,
        161.,  13.,   0., 202., 161., 121., 121.,   0., 121., 121., 242., 125.],
       grad_fn=<MvBackward>)

, который мы определим как:

xx = torch.tensor([121., 241., 125.,   1., 108., 238., 125., 121.,  13., 117., 121., 229.,
        161.,  13.,   0., 202., 161., 121., 121.,   0., 121., 121., 242., 125.]).requires_grad_(True)

Я хотел быопределить операцию, которая подсчитывает количество вхождений каждого значения таким образом, что операция выведет следующий тензор:

tensor([2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
        0, 7, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
        0, 1, 1])

, то есть есть 2 нуля, 1 один, 2 трети и т. д. общее количество возможных значений установлено в восходящем направлении, но в этом примере это 243

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

Попытка 1

tt = []
for i in range(243):
    tt.append((xx == i).unsqueeze(0))
torch.cat(tt,dim=0).sum(dim=1)

Попытка 2

tvtensor = torch.tensor([i for i in range(243)]).unsqueeze(1).repeat(1,xx.shape[0]).float().requires_grad_(True)
(xx==tvtensor).sum(dim=1)

РЕДАКТИРОВАНИЕ: добавлена ​​попытка

Попытка 3

- На самом деле не ожидал, что это поддержит пропеллер, но решил, что я все равно попробую

ll = torch.zeros((1,243))
for x in xx:
    ll[0,x.long()] += 1

Любая помощь приветствуется

РЕДАКТИРОВАТЬ: В соответствии с просьбой конечной цели этогоэто следующее:

Я использую техникудля расчета структурного сходства между двумя временными последовательностями. Одно реально, а другое генерируется. Техника описана в этой статье (https://link.springer.com/chapter/10.1007/978-3-642-02279-1_33), где временной ряд преобразуется в последовательность кодовых слов, а распределение кодовых слов (аналогично тому, как Bag of Words используется в НЛП) используется для представлениявременные ряды. Две серии считаются похожими, когда два распределения сигналов одинаковы. Вот для чего нужен тензор статистики подсчета.

Желательно, чтобы была возможность построить функцию потерь, которая потребляет этот тензор иизмеряет расстояние между реальным и генерируемым сигналом (евклидова норма на данных во временной области напрямую не работает, и этот подход требует лучших результатов), чтобы он мог соответствующим образом обновить генератор.

Ответы [ 2 ]

2 голосов
/ 29 октября 2019

Вы не сможете сделать это, поскольку unique - это просто недифференцируемая операция.

Кроме того, только floating точечные тензоры могут иметь градиент, поскольку он определен только для области действительных чисел, а не для целых чисел.

Тем не менее, может быть другой, дифференцированный способ сделать то, что вы хотите достичь, но это другой вопрос.

0 голосов
/ 29 октября 2019

Операция «uniquify» недифференцируема, но могут быть способы исправить это, например, написанием пользовательского оператора или умной комбинацией дифференцируемых операторов.

Однако вам необходимоЗадайте себе вопрос: как вы думаете, какой будет градиент такой операции? Или, на более высоком уровне, чего вы пытаетесь достичь с помощью этой операции?

...