본문 바로가기

Machine Learning Tasks/Recommender Systems

RecSys - DeepFM

반응형

RecSys - Factorization Machines (1)

ResSys - Factorization Machines (2)

RecSys - Field-aware Factorization Machines


유저가 추천된 아이템에 대하여 클릭할 확률을 예측하는 CTR (Click Through Rate) prediction은 온라인 광고, 유튜브 등의 모바일 어플리케이션에 유용하게 탑재되는 알고리즘으로 수많은 데이터가 존재하는 상황에서 플랫폼의 수익성 증대, 유저 관리 측면에서 매우 중요합니다. 지난 포스트에서 살펴본 FM (Factorization Machine)이나 FFM (Field-aware Factorization Machine)에서는 희박하고 (sparse) 고차원 (high-dimensional) 데이터에 대해 피쳐간의 상호작용 (feature interaction)을 학습함으로써 CTR prediction을 수행했습니다. 하지만 FM에서 보았다시피 이론상으로 feature간의 고차 상호작용 (high-order interaction) 학습이 가능하나 높은 복잡도로 인해 주로 feature의 2차 상호작용만 학습하게됩니다. 예를 들어 남자 청소년이 RPG 게임을 좋아한다는 현상이 있으면 이는 성별/나이대/게임종류 세 가지 feature의 3차 상호작용을 모델링해야하나 이를 직관적으로 알기도 힘들 뿐더러 일일히 모델링할 수도 없습니다.

이번 포스트에서 살펴볼 DeepFM은 저차원 (2차 상호작용) / 고차원 (3차 이상 상호작용)을 기존의 FM과 DNN (Deep Neural Networks)을 통해 모델링하여 CTR prediction 성능을 높인 모델입니다. 특히, 기존 FM의 feature 임베딩을 FM / DNN 부분이 공유하도록 함으로써 복잡한 feature engineering 필요없이 end-to-end 방식으로 low/high-order feature interaction을 학습합니다.

DeepFM

전체 구성도는 Figure 1과 같습니다. 각 feature 필드에 대해 임베딩을 통해 dense vecetor로 피쳐를 표현하고 이를 FM 모듈과 DNN 모듈이 공유하는 형태로 구성되어 있습니다.

데이터 $(x, y)$가 $d$차원의 $x=[x_{field_1}, ..., x_{field_m}]$로 이루어져있고 1차 feature 중요도를 $w_i$, 다른 feature와의 상호작용을 위한 잠재벡터를 $V_i$라 한다면 DeepFM의 예측은 다음과 같이 구성됩니다.

$\hat{y}(x) = sigmoid(y_{FM}(x)+y_{DNN}(x))$

FM component

FM 모듈은 Factorization Machine 부분으로 다음과 같고 feature $i, j$가 데이터 상에서 모두 0이 아닐 때 우측 항이 해당 조합에 대해 적용되며 구성은 Figure 2와 같습니다.

$y_{FM}(x) = <w,x> + \sum_{i=1}^d \sum_{j=i+1}^d <V_i, V_j>x_i \times x_j $

Deep component

High-order feature interaction을 학습하기 위한 deep 모듈은 feed-forward network로 구성됩니다. DNN이 주로 사용되는 이미지나 음성과 달리 추천시스템에서의 데이터는 희박한 고차원 데이터이므로 DNN 적용 전에 각 feature를 임베딩하여 저차원 dense vector 형태로 만들어줍니다. 임베딩 형태는 Figure 3과 같고 $k$는 임베딩 차원으로 각 feature 필드의 크기가 다르더라도 같은 차원으로 임베딩됩니다. 여기서 각 feature의 잠재 벡터 $V_i$가 입력으로 사용되어 DNN에 들어가기위한 입력은 다음과 같습니다.

$a^0 = [e_1, ..., e_m], e_i=V_{field_i}\times x_{field_i}$

주목할 점은 FM 모듈과 입력을 공유하여 별도의 feature 엔지니어링이 필요하지 않다는 점입니다. Deep 모듈의 구성도는 Figure 4와 같습니다. 또한 DNN의 layer를 거치는 forward 프로세스는 다음과 같고 과적합 방지를 위해 dropout을 적용합니다. ($\sigma$는 non-linear 활성화 함수입니다.)

$a^l = \sigma (W^l \times a^{l-1}+b^l)$

 

Pytorch implementation

FM 모듈은 지난 포스트에서 구성한 것으로 갈음하고 deep 모듈만 구현해보도록 하겠습니다. 먼저 MLP를 구현하면 다음과 같습니다. 입력 인자의 embed_dims는 리스트나 튜플로 MLP 각 층의 차원을 나타냅니다.

class MultiLayerPerceptron(torch.nn.Module):

    def __init__(self, input_dim, embed_dims, dropout, output_layer=True):
        super().__init__()
        layers = list()
        for embed_dim in embed_dims:
            layers.append(torch.nn.Linear(input_dim, embed_dim))
            layers.append(torch.nn.BatchNorm1d(embed_dim))
            layers.append(torch.nn.ReLU())
            layers.append(torch.nn.Dropout(p=dropout))
            input_dim = embed_dim
        if output_layer:
            layers.append(torch.nn.Linear(input_dim, 1))
        self.mlp = torch.nn.Sequential(*layers)

    def forward(self, x):
        """
        :param x: Float tensor of size ``(batch_size, embed_dim)``
        """
        return self.mlp(x)

이후에는 deep 모듈과 FM 모듈을 합치는 최종 모델을 구성합니다. 주의할 점은 MLP 모듈의 입력은 [batch size, embed_dim*number of fields]가 된다는 점입니다.

class DeepFactorizationMachineModel(torch.nn.Module):

    def __init__(self, field_dims, embed_dim, mlp_dims, dropout):
        super().__init__()
        self.linear = FeaturesLinear(field_dims)
        self.fm = FactorizationMachine(reduce_sum=True)
        self.embedding = FeaturesEmbedding(field_dims, embed_dim)
        self.embed_output_dim = len(field_dims) * embed_dim
        self.mlp = MultiLayerPerceptron(self.embed_output_dim, mlp_dims, dropout)

    def forward(self, x):
        """
        :param x: Long tensor of size ``(batch_size, num_fields)``
        """
        embed_x = self.embedding(x)
        x = self.linear(x) + self.fm(embed_x) + self.mlp(embed_x.view(-1, self.embed_output_dim))
        return torch.sigmoid(x.squeeze(1))

 

참조

반응형