FNN 网络介绍与源码浅析

前言

周五晚上分享 paper !!! 感动自己一把~ ???? 感觉本周看的 Paper 还挺多的, 打算尽可能都做下记录, 方便日后查阅.

广而告之

可以在微信中搜索 “珍妮的算法之路” 或者 “world4458” 关注我的微信公众号;另外可以看看知乎专栏 ​​PoorMemory-机器学习​​, 以后文章也会发在知乎专栏中;

文章信息

核心观点

本文主要介绍了两个网络 FNN (FM supported NN) 以及 SNN (sampling-based NN), 我重点看了下 FNN 而不关心 SNN. FNN 的核心是在设计 Embedding Layer 时, 使用的参数量和 FM 一致, 这样的话, 可以通过预训练 FM, 然后使用 FM 的参数来初始化 Embedding Layer. 由于存在预训练的过程,
所以降低了整个网络的训练过程中的开销, 模型可以更快的收敛. 在 ​​​xDeepFM​​​ 论文中有提到 FNN 的不足: FNN (PNN 亦如此) 只关注于高阶的特征交叉, 而忽视了低阶的交叉特征. (​​Wide & Deep​​​ 与 ​​DeepFM​​ 通过引入线性层(shallow component), 和 DNN (deep component) 结合来解决低阶交叉特征被忽视的问题.)

核心观点介绍

FNN 的网络结构图如下:



FNN 网络介绍与源码浅析_tensorflow

可以发现, 主要还是经典的 Embedding + MLP 结构. 其核心在于设计 Embedding Layer 时, 按照 FM 的思路来设置. 回忆 FM 的公式是:

FNN 网络介绍与源码浅析_机器学习_02

那么 FNN 在设计 Embedding 时, 设置每个 Field 对应的 Embedding 权重为 FNN 网络介绍与源码浅析_深度学习_03, 其中 FNN 网络介绍与源码浅析_tensorflow_04FNN 网络介绍与源码浅析_tensorflow_05 是第 FNN 网络介绍与源码浅析_tensorflow_06 个 Field 下的特征的起始和结束索引值. 注意到每个特征的 emb FNN 网络介绍与源码浅析_python_07 大小为 FNN 网络介绍与源码浅析_机器学习_08, 它表示为:

FNN 网络介绍与源码浅析_tensorflow_09

它可以看成由两部分组成, 其中 FNN 网络介绍与源码浅析_tensorflow_10 正好和 FM 中的一阶特征对应的权重对应起来, 而 FNN 网络介绍与源码浅析_tensorflow_11 和 FM 中每个特征对应的隐向量对应起来了. 这样的话. 另外注意到网络结构图中还有一个 FNN 网络介绍与源码浅析_机器学习_12, 可以认为是偏置. 这样的, Embedding Layer 中的权重和 FM 中的权重参数一致, 因此可以使用预训练的 FM 中的权重来初始化网络的 Embedding Layer.

在 ​​https://github.com/Atomu2014/product-nets/blob/master/python/models.py​​​ 中实现了 FNN: (这个代码是 PNN 的作者实现的, 有的细节可以查看 ​​Product-based Neural Network (PNN) 介绍与源码浅析​​, 哈哈, 随时随地打广告 ???? ???? ????, 原作者的代码基于 Theano 实现, 不太想看~~)

核心代码如下, 非常简单:

## num_inputs 是 Field 的个数
for i in range(num_inputs):
init_vars.append(('embed_%d' % i, [field_sizes[i], embed_size], 'xavier', dtype))
node_in = num_inputs * embed_size
for i in range(len(layer_sizes)):
init_vars.append(('w%d' % i, [node_in, layer_sizes[i]], 'xavier', dtype))
init_vars.append(('b%d' % i, [layer_sizes[i]], 'zero', dtype))
node_in = layer_sizes[i]

## xw 就是 W * x, 得到每个特征对应的 Embedding, 然后 Concat 起来
## 最后输入到 MLP 中
w0 = [self.vars['embed_%d' % i] for i in range(num_inputs)]
xw = tf.concat([tf.sparse_tensor_dense_matmul(self.X[i], w0[i]) for i in range(num_inputs)], 1)
l = xw

for i in range(len(layer_sizes)):
wi = self.vars['w%d' % i]
bi = self.vars['b%d' % i]
print(l.shape, wi.shape, bi.shape)
l = tf.nn.dropout(
utils.activate(
tf.matmul(l, wi) + bi,
layer_acts[i]),
self.layer_keeps[i])

l = tf.squeeze(l)
self.y_prob = tf.sigmoid(l)

结论

夜里 12:06, 收摊喽~~ ????