深度因式分解机
深度因式分解机
Deep Factorization Machines
学习有效的特征组合对于点击率预测任务的成功至关重要。因子分解机以线性范式对特征交互进行建模(例如,双线性交互)。对于实际数据来说,这通常是不够的,因为在实际数据中,固有特征交叉结构通常非常复杂和非线性。更糟糕的是,二阶特征交互在实际的分解机中通常被使用。从理论上讲,用因子分解机对高阶特征组合进行建模是可行的,但由于数值不稳定和计算复杂度高,通常不采用这种方法。
一个有效的解决方案是使用深度神经网络。深度神经网络在特征表示学习方面具有强大的功能,并且有潜力学习复杂的特征交互。因此,将深度神经网络集成到因子分解机中是很自然的。向因子分解机中添加非线性变换层,使其能够同时对低阶特征组合和高阶特征组合进行建模。此外,输入的非线性固有结构也可以用深度神经网络捕捉。在这一部分中,将介绍一个典型的模型,将FM和deep神经网络结合起来,命名为DeepFM(DeepFM)[Guo et al.,2017]。
1. Model Architectures
DeepFM由一个FM组件和一个deep组件组成,集成在一个并行结构中。FM组件与用于建模低阶特征交互作用的双向因式分解机相同。deep组件是一个多层感知器,用于捕获高阶特征交互和非线性。这两个组件共享相同的输入/嵌入,输出总结为最终预测。值得一提的是,DeepFM与深度广度Wide&Deep架构的理论相似,既能存储又能扩展。DeepFM相对于Wide&Deep模型的优势在于,通过自动识别特征组合来减少手工构建特征工程的工作量。
值得注意的是,深度调频并不仅仅是将深度调频与神经网络相结合。还可以在特征交互上添加非线性层[He&Chua,2017]。
from d2l import mxnet as d2l
from mxnet import init, gluon, np, npx
from mxnet.gluon import nn
import os
import sys
npx.set_np()
2. Implemenation of DeepFM
DeepFM的实现与FM类似。使用功能块保持激活功能不变。Dropout也用于正则化模型。MLP的神经元数目可以通过MLP_dims超参数进行调整。
class DeepFM(nn.Block):
def __init__(self, field_dims, num_factors, mlp_dims, drop_rate=0.1):
super(DeepFM, self).__init__()
num_inputs = int(sum(field_dims))
self.embedding = nn.Embedding(num_inputs, num_factors)
self.fc = nn.Embedding(num_inputs, 1)
self.linear_layer = nn.Dense(1, use_bias=True)
input_dim = self.embed_output_dim = len(field_dims) * num_factors
self.mlp = nn.Sequential()
for dim in mlp_dims:
self.mlp.add(nn.Dense(dim, 'relu', True, in_units=input_dim))
self.mlp.add(nn.Dropout(rate=drop_rate))
input_dim = dim
self.mlp.add(nn.Dense(in_units=input_dim, units=1))
def forward(self, x):
embed_x = self.embedding(x)
square_of_sum = np.sum(embed_x, axis=1) ** 2
sum_of_square = np.sum(embed_x ** 2, axis=1)
inputs = np.reshape(embed_x, (-1, self.embed_output_dim))
x = self.linear_layer(self.fc(x).sum(1)) \
+ 0.5 * (square_of_sum - sum_of_square).sum(1, keepdims=True) \
+ self.mlp(inputs)
x = npx.sigmoid(x)
return x
3. Training and Evaluating the Model
数据加载过程与FM相同。将DeepFM的MLP组件设置为一个具有金字塔结构的三层密集网络(30-20-10)。所有其超参数与FM相同。
batch_size = 2048
data_dir = d2l.download_extract('ctr')
train_data = d2l.CTRDataset(os.path.join(data_dir, 'train.csv'))
test_data = d2l.CTRDataset(os.path.join(data_dir, 'test.csv'),
feat_mapper=train_data.feat_mapper,
defaults=train_data.defaults)
field_dims = train_data.field_dims
num_workers = 0 if sys.platform.startswith('win') else 4
train_iter = gluon.data.DataLoader(train_data, shuffle=True,
last_batch='rollover',
batch_size=batch_size,
num_workers=num_workers)
test_iter = gluon.data.DataLoader(test_data, shuffle=False,
last_batch='rollover',
batch_size=batch_size,
num_workers=num_workers)
ctx = d2l.try_all_gpus()
net = DeepFM(field_dims, num_factors=10, mlp_dims=[30, 20, 10])
net.initialize(init.Xavier(), ctx=ctx)
lr, num_epochs, optimizer = 0.01, 30, 'adam'
trainer = gluon.Trainer(net.collect_params(), optimizer,
{'learning_rate': lr})
loss = gluon.loss.SigmoidBinaryCrossEntropyLoss()
d2l.train_ch13(net, train_iter, test_iter, loss, trainer, num_epochs, ctx)
loss 0.510, train acc 0.845, test acc 0.860
123302.7 examples/sec on [gpu(0), gpu(1)]
与FM相比,DeepFM收敛速度更快,性能更好。
4. Summary
- Integrating neural networks to FM enables it to model complex and high-order interactions.
- DeepFM outperforms the original FM on the advertising dataset.