本专栏文章会在本博客和知乎专栏——Sunny.Xia的深度学习同步更新,对于评论博主若未能够及时回复的,可以知乎私信。未经本人允许,请勿转载,谢谢。
一、什么是PNN?
如图所示,相比普通的深度网络,其实多了一层product layer,再送入到深度网络中去(图中为两层隐含层layer1和layer2),最后输出CTR的结果。
Product layer主要包含两部分:
- 线性部分lz
- 非线性部分lp
最终product layer = lz+lp+bias。
第一层隐含层:
第i层隐含层:
这里要注意的是,论文里product layer(lz+lp+b1),实际上已经包含了一层深度网络,该网络的输出维度是D1。可以发现,文中的lz,lp和b1,其实都是一个长度为D1的向量,如下所示。
其中z是F*M的embedding向量,product layer中z的每个圆圈就代表一个M维的embedding向量,共有F个。p是F*1或者是F*M*M的向量,取决于是IPNN还是OPNN。如果是內积IPNN,则p中的每个圆圈表示一个值;如果是外积OPNN,则表示M*M的二维矩阵。
这样应该就可以明白了,论文中实际上是将z和p输送到一个(?,D1)的全连接深度网络,最终得到维度为D1的lz和lp,?取决于z和p的维度大小。
所以网上写PNN的代码,大体上会分为两种方向:
- 如论文中一样,先生成D1个lz、lp,两者再和bias相加后,变为D1维度的embedding,再输送到dnn网络中去。
- 先将z和p向量进行拼接后,直接输入到dnn网络中,网络的第一层输出维度即为D1。
另外,在上述方向上,还衍生出两种变体,不管是IPNN,还是OPNN,本质上是求两两特征向量的交叉关系。对于F个特征field,两两求交需要计算F * (F - 1) / 2次,复杂度直接提升。为了优化时间复杂度,采取的做法是先对所有特征向量,通过加权求和的方式,计算一个叠加特征。再对这个特征进行內积or外积的运算,提高运算效率,但同时也会损失一部分信息,鱼和熊掌不可兼得。
二、实战演练
本文代码地址:https://github.com/ruozhichen/deep_learning (master分支)
tensorflow: 1.14 python: 3.7
代码参见PNN1.py和PNN2.py,分别以两种形式实现Product Layer层,直接python PNN1.py或者python PNN2.py即可执行。
- PNN1.py实现的是论文中提到的优化方法,将两两特征求交简化为提炼出一个向量,然后用这个向量自己跟自己求內积/外积的方式,计算D1次,从而获得lz和lp。
- PNN2.py实现的是两两特征向量计算內积/外积后,再跟原来的特征embedding做拼接,输入到DNN网络中去。
product layer根据內积和外积,可以分为IPNN(Inner Product-based Neural Network)和OPNN(Outer Product-based Neural Network),下面将分别针对每种写法中的IPNN和OPNN进行讲解。
2.1 PNN1.py
Embedding
# ------bulid weights------
feature_embedding = tf.get_variable(name='feature_emb', shape=[feature_size, embedding_size], initializer=tf.glorot_normal_initializer