PNN介绍和结构简述
PNN(Product-based Neural Networks)是2016年提出的一种基于向量乘积和多层感知机的推荐排序算法,他将FM和DNN串行结合,即先利用FM的向量乘积形式来表征二阶交叉信息,再输入给DNN这种全连接形式,使得二阶信息叠加非线性能力,期望这种组合能够学到更高阶的交叉信息。
PNN的网络结构如下
PNN网络结构
数据从最下层的input输入到最上层的CTR输出,其中Embedding Layer和Product Layer是FM,L1和L2 Fully Connected是DNN,Product Layer层对FM的内积做了拓展,不仅支持向量内积,还支持向量外积,内外积融合一共三种向量积表征方式。
原始onehot输入经过Embedding Layer转化为隐向量,在Product Layer中计算出一阶特征z和交叉特征p,其中z是所有隐向量和常数1相乘,本质上就是将上一个嵌入层的embedding照搬过来,将所有特征的embedding进行拼接组合成z部分。
p部分是所有特征的两两向量乘积运算,只计算半三角因此一共有**field_num×(field_num-1)**个输出结果,其中field_num是特征域数量,根据乘积的方式不同有三种策略
- 内积 IPNN:一对向量进行内积点乘输出一个标量,因此图中p部分的一个圈代表一个值
- 外积 OPPN:A向量转置和B向量进行矩阵相乘,若隐向量的维度为M,则输出一个M×M的矩阵,为了能使矩阵做信息浓缩输入到下一层,PNN引入了同样是是M×M形状的可学习的权重矩阵W,对应位置的两矩阵做**哈达马积(element-wise乘法)**再求和输出一个标量,因此外积的策略下p部分的一个圈也代表一个值
- 内外积融合 PNN*:将内积的输出向量,和外积的输出向量进行拼接,作为p部分的最终输出,此时输出维度为原来的两倍为field_num×(field_num-1)×2
p部分的结果和z部分再拼接形成了最终DNN的输入,经过两层隐藏层sigmoid输入二分类交叉熵完成模型损失迭代。
PNN和FM,FNN,DeepFM的联系
PNN和FM
若删除PNN的两层DNN,采用内积Product,所有p的标量相加,则PNN退化为FM,本质上PNN是将FM的内积结果不直接相加输出,而是作为中间结果继续灌入多层感知机做训练。
PNN和FNN
FNN也是将FM的结果作为DNN的输入,而FNN是两阶段模型,先训练一个FM得到每个特征的嵌入向量,再将所有嵌入向量拼接输入到全连接层,如果删除PNN的Product Layer,PNN退化为FNN。
PNN和DeepFM
两者都是将FM融入和深度学习的算法策略,PNN是FM和MLP的串行,MLP依赖于FM的输出,而DeepFM是FM和MLP的并行,FM和MLP共享底层联合训练。
PNN的三种形式在PyTorch下的实践
本次实践的数据集和上一篇[特征交叉系列:完全理解FM因子分解机原理和代码实战]一致,采用用户的购买记录流水作为训练数据,用户侧特征是年龄,性别,会员年限等离散特征,商品侧特征采用商品的二级类目,产地,品牌三个离散特征,随机构造负样本,一共有10个特征域,全部是离散特征,对于枚举值过多的特征采用hash分箱,得到一共72个特征。
通过PyTorch构造PNN网络结构如下
class Embedding(nn.Module):
def __init__(self, feat_num, emb_size):
super(Embedding, self).__init__()
self.emb = nn.Embedding(feat_num, emb_size)
nn.init.xavier_normal_(self.emb.weight.data)
def forward(self, x):
# [None, field_num] => [None, field_num, emb_size]
return self.emb(x)
class InnerProductLayer(nn.Module):
def __init__(self, field_num):
super(InnerProductLayer, self).__init__()
self.field_num = field_num
def forward(self, x):
# [None, field_num, emb_size]
p_index = []
q_index =