1. 程式人生 > 其它 >【推薦演算法】Wide & Deep

【推薦演算法】Wide & Deep

Wide & Deep主要解決了FM的以下幾個痛點:

  1. 強化記憶能力。FM這類embedding類模型擁有強大的泛化能力,在embedding的過程中傳入了大量的全域性資訊,對於一些很少出現甚至沒有出現過的特徵組合,也能計算出合理的特徵組合權重。但是,當共現矩陣過於稀疏時,模型會過分泛化,推薦出很多相關性低的內容。Wide & Deep不僅強調了模型的“泛化能力”,還強調了“記憶能力”。具體來說,記憶能力表示一類規則式的推薦,即當出現情況A時,就推薦B。

演算法

如圖,模型由左邊的wide與右邊的deep結合而成,兩者的結果相加後經過一個sigmoid層得到最終的CTR預估值。其中,deep中包含所有特徵,wide中包含人工設計的需要加強記憶能力的特徵交叉(如下載軟體A與展現軟體B),特徵交叉方法使用交叉積,可以看做特徵one-hot表示下的向量內積。

模型輸入

首先定義一個mlp實現deep部分:

class MultiLayerPerceptron(torch.nn.Module):
    def __init__(self, input_dim, embed_dims, dropout):
        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
        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)

為了簡化,我們使用全量物品特徵加入wide部分,並且不手工設計特徵交叉。程式碼中使用LR的實現來實現wide部分(很不嚴謹)。最後,構建完整的DeepFM前向傳播鏈路:

class WideAndDeepModel(torch.nn.Module):
    def __init__(self, field_dims, embed_dim=16, mlp_dims=(16, 16), dropout=0.2):
        super().__init__()
        self.linear = FeaturesLinear(field_dims)
        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.mlp(embed_x.view(-1, self.embed_output_dim))
        return torch.sigmoid(x.squeeze(1))

模型效果

設定:
資料集:ml-100k
優化方法:Adam
學習率:0.003

效果:
收斂epoch: 10
train logloss: 0.52100
val auc: 0.78681
test auc: 0.78500