Векторизованная реализация факторизации на местах - PullRequest
2 голосов
/ 03 июля 2019

Я хотел бы реализовать модель факторизации с учетом поля (FFM) векторизованным способом. В FFM прогноз делается следующим уравнением

$ \sum_{j_1=1}^n \sum_{j_2=j_1+1}^n (\textbf{w}_{j_1, f_2}, \textbf{w}_{j_2, f_1}) x_{j_1} x_{j_2} $

где w - вложения, которые зависят от объекта и поля другого объекта. Для получения дополнительной информации см. Уравнение (4) в FFM .

Для этого я определил следующий параметр:

import torch

W = torch.nn.Parameter(torch.Tensor(n_features, n_fields, n_factors), requires_grad=True)

Теперь, учитывая вход x размера (batch_size, n_features), я хочу иметь возможность вычислить предыдущее уравнение. Вот моя текущая (не векторизованная) реализация:

total_inter = torch.zeros(x.shape[0])
for i in range(n_features):
    for j in range(i + 1, n_features):
        temp1 = torch.mm(
            x[:, i].unsqueeze(1),
            W[i, feature2field[j], :].unsqueeze(0))
        temp2 = torch.mm(
            x[:, j].unsqueeze(1),
            W[j, feature2field[i], :].unsqueeze(0))
        total_inter += torch.sum(temp1 * temp2, dim=1)

Неудивительно, что эта реализация ужасно медленная, поскольку n_features может легко достигать 1000! Однако обратите внимание, что большинство записей x равно 0. Все входные данные приветствуются!

Изменить:

Если это может помочь каким-либо образом, вот некоторые реализации этой модели в PyTorch:

К сожалению, я не могу понять, как именно они это сделали.

1 Ответ

2 голосов
/ 10 июля 2019
  1. Что-то, что может потенциально помочь вам ускорить умножение, использует pytorch разреженные тензоры .

  2. Также может сработатьследующее: Создайте n массивов, по одному для каждого объекта i , который будет содержать соответствующие коэффициенты поля в каждой строке.например, для функции i = 0

[ W[0, feature2field[0], :],
  W[0, feature2field[1], :],
  W[0, feature2field[n], :]]

Затем вычислите умножение этих массивов, назовем их F, с X

R[i] = F[i] * X

Итак, каждый элемент в Rбудет содержать результат умножения массива F [i] на X.

Далее вы умножите каждый R [i] на его транспонирование

R[i] = R[i] * R[i].T

Теперь вы можетевыполните суммирование в цикле, как раньше

for i in range(n_features):
    total_inter += torch.sum(R[i], dim=1)

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

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

Кроме того, хотя незначительные, тем не менее, пожалуйста, переместите 1-ю операцию отжиматьза пределами вложенного цикла for.

Надеюсь, это поможет.

...