c语言sscanf函数的用法是什么
310
2022-09-18
FiBiNet 网络介绍与源码浅析
FiBiNet 网络介绍与源码浅析
前言 (与主题无关, 可以忽略)
2020-09-30: 我知道这有点不太厚道, 文章不写全就发出来, 但最近真的很忙, 同时给自己立了 9 月再写一篇博客的 Flag~ 可是这个月只写了一篇 ???????????? 今晚是 9 月 30 日, 月色很美 … (猜测的, 毕竟明日中秋和国庆一起过; 走路忘了抬头看看夜空, 忧桑~). 虽然下班较早, 但心事重重, 不到最后一刻不动笔. 因此现在先扯一点前言, 后续一定会以全副精力来完成 Flag! 我最近可是看了很多 paper 的, 可以乘着假期总结一番.
2020-10-10: 来更新了… 果然, Flag 这东西真的不能乱立, 看清自己了, 假期还是想玩 ????????????
广而告之
FiBiNet
文章信息
论文标题: FiBiNET: Combining Feature Importance and Bilinear feature Interaction for Click-Through Rate Prediction论文地址:没有找到作者释出的代码, 但是 DeepCTR 给出了实现RecSys, 2019论文作者: Tongwen Huang, Zhiqi Zhang, Junlin Zhang作者单位: 新浪微博
插句题外话, 三作 Junlin Zhang 应该是知乎上的 @张俊林, 当时看到大佬的 推荐系统技术演进趋势:从召回到排序再到重排 很受启发, 向大佬学习.
核心观点
本文提出的 FiBiNet 模型包含两个核心模块, 分别是:
SENET(Squeeze-Excitation network)Bilinear Feature Interaction
其中 SENET 是借鉴计算机视觉中的网络, 可以动态地学习特征的重要性, 对于越重要的特征, 将学习出更大的权重, 并且减小不那么重要的特征的权重; 另外对于特征交叉的问题, 经典的方法主要采用 Inner Product 或者 Hadamard Product 来构造交叉特征, 作者认为这些方法比较简单, 可能无法对交叉特征进行有效的建模, 因此提出了 Bilinear Feature Interaction 方法, 结合了 Inner Product 以及 Hadamard Product 二者, 在两个要交叉的特征间插入一个权重矩阵, 以动态学习到特征间的组合关系.
核心观点介绍
FiBiNet 的网络结构图如下图所示:
网络上半部分为 Deep Part, 主要是 MLP 网络, 不过多介绍; 下半部分 Shallow Part 是 FiBiNet 的核心, 主要对输入特征进行处理. 首先是图的左下部分, 高维的稀疏输入特征经过 Embedding Layer 后映射为低维的稠密向量 embeddings, 此外 embeddings 要经过 SENET 层动态学习特征的重要性, 从而得到 SENET-Like embeddings. 之后 embeddings 和 SENET-Like embeddings 分别输入到 Bilinear-Interaction Layer 中并进行特征交叉, 输出的交叉特征 concatenation 起来后, 再输入到 MLP 中做 CTR 的预估.
其中核心模块为 SENET Layer 以及 Bilinear-Interaction Layer, 下面分别进行介绍.
SENET
SENET 的网络结构图如下:
SENET 主要分为 Squeeze, Excitation, 以及 Re-weight 三个步骤, 其中:
从上面的介绍可以看出, SENET 主要利用两层全连接层来动态学习特征的权重.
Bilinear-Interaction Layer
Bilinear-Interaction Layer 主要用于计算二阶特征交叉, 其计算过程可以使用下图表示:
Combination Layer 与 MLP
源码浅析
原作者的代码没有找到, 发现 DeepCTR 实现了 FiBiNet, 因此下面的源码浅析分析的是 DeepCTR 的实现. 代码地址为: 中的 SENETLayer 中:
SENETLayer 要求的输入为 inputs = [e1, e2, ..., ef], 其中 ei 的 shape 为 [batch_size, 1, embedding_size], 这跟 DeepCTR 处理特征的方式有关, 具体不过多介绍, 注意在其 call 函数中第一步操作为: inputs = concat_func(inputs, axis=1), 这样就将 inputs 转化成了 shape 为 [batch_size, field_size, embedding_size] 的 tensor, 符合我们的直觉.
class SENETLayer(Layer): """SENETLayer used in FiBiNET. Input shape - A list of 3D tensor with shape: ``(batch_size,1,embedding_size)``. Output shape - A list of 3D tensor with shape: ``(batch_size,1,embedding_size)``. Arguments - **reduction_ratio** : Positive integer, dimensionality of the attention network output space. - **seed** : A Python integer to use as random seed. References - [FiBiNET: Combining Feature Importance and Bilinear feature Interaction for Click-Through Rate Prediction]( """ def __init__(self, reduction_ratio=3, seed=1024, **kwargs): self.reduction_ratio = reduction_ratio self.seed = seed super(SENETLayer, self).__init__(**kwargs) def build(self, input_shape): if not isinstance(input_shape, list) or len(input_shape) < 2: raise ValueError('A `AttentionalFM` layer should be called ' 'on a list of at least 2 inputs') self.filed_size = len(input_shape) ## F, 表示 Field 的数量 self.embedding_size = input_shape[0][-1] ## K, 表示 embedding 的大小 reduction_size = max(1, self.filed_size // self.reduction_ratio) ## r, 表示 reduction ratio ## W1, shape 为 (F, F/r) self.W_1 = self.add_weight(shape=( self.filed_size, reduction_size), initializer=glorot_normal(seed=self.seed), name="W_1") ## W2, shape 为 (F/r, F) self.W_2 = self.add_weight(shape=( reduction_size, self.filed_size), initializer=glorot_normal(seed=self.seed), name="W_2") ## tf.tensordot 做的是 element-wise multiplication, ## 具体可以参考我的博客: self.tensordot = tf.keras.layers.Lambda( lambda x: tf.tensordot(x[0], x[1], axes=(-1, 0))) # Be sure to call this somewhere! super(SENETLayer, self).build(input_shape) def call(self, inputs, training=None, **kwargs): ## inputs = [e1, e2, ..., ef] ## 其中 ei 的大小为 [B, 1, K] if K.ndim(inputs[0]) != 3: raise ValueError( "Unexpected inputs dimensions %d, expect to be 3 dimensions" % (K.ndim(inputs))) ## 经 concat_func 处理后, inputs shape 为 [B, F, K] inputs = concat_func(inputs, axis=1) Z = reduce_mean(inputs, axis=-1, ) ## [B, F] A_1 = tf.nn.relu(self.tensordot([Z, self.W_1])) ## [B, F/r] A_2 = tf.nn.relu(self.tensordot([A_1, self.W_2])) ## [B, F] V = tf.multiply(inputs, tf.expand_dims(A_2, axis=2)) ## [B, F, K] ## 这一步和 DeepCTR 对特征的处理有关, 对 V 进行 split, 结果为: ## [v1, v2, ..., vf], 其中 vi 的 shape 为 [B, 1, K] return tf.split(V, self.filed_size, axis=1)
Bilinear-Interaction Layer
该层定义于: 中的 BilinearInteraction 中:
BilinearInteraction 的输入为 inputs = [e1, e2, ..., ef], 其中 ei 的 shape 为 [batch_size, 1, embedding_size], 这跟 DeepCTR 处理特征的方式有关, 具体不过多介绍.
class BilinearInteraction(Layer): """BilinearInteraction Layer used in FiBiNET. Input shape - A list of 3D tensor with shape: ``(batch_size,1,embedding_size)``. Output shape - 3D tensor with shape: ``(batch_size,1,embedding_size)``. Arguments - **str** : String, types of bilinear functions used in this layer. - **seed** : A Python integer to use as random seed. References - [FiBiNET: Combining Feature Importance and Bilinear feature Interaction for Click-Through Rate Prediction]( """ def __init__(self, bilinear_type="interaction", seed=1024, **kwargs): self.bilinear_type = bilinear_type self.seed = seed super(BilinearInteraction, self).__init__(**kwargs) def build(self, input_shape): if not isinstance(input_shape, list) or len(input_shape) < 2: raise ValueError('A `AttentionalFM` layer should be called ' 'on a list of at least 2 inputs') embedding_size = int(input_shape[0][-1]) ## K if self.bilinear_type == "all": ## Field-All Type: W_list 的 shape 为 K * K self.W = self.add_weight(shape=(embedding_size, embedding_size), initializer=glorot_normal(seed=self.seed), name="bilinear_weight") elif self.bilinear_type == "each": ## Field-Each Type: W 的 shape 为 F * K * K self.W_list = [self.add_weight(shape=(embedding_size, embedding_size), initializer=glorot_normal(seed=self.seed), name="bilinear_weight" + str(i)) for i in range(len(input_shape) - 1)] elif self.bilinear_type == "interaction": ## Field-Interaction Type: W_list 的 shape 为 F*(F - 1)/2 * K * K self.W_list = [self.add_weight(shape=(embedding_size, embedding_size), initializer=glorot_normal(seed=self.seed), name="bilinear_weight" + str(i) + '_' + str(j)) for i, j in itertools.combinations(range(len(input_shape)), 2)] else: raise NotImplementedError super(BilinearInteraction, self).build(input_shape) # Be sure to call this somewhere! def call(self, inputs, **kwargs): ## inputs = [e1, p2, ..., ef], ## 其中 ei 的大小为 [B, 1, K] if K.ndim(inputs[0]) != 3: raise ValueError( "Unexpected inputs dimensions %d, expect to be 3 dimensions" % (K.ndim(inputs))) n = len(inputs) ## 这里的 n 就是 field 的个数, 还是用 F 来表示吧 ## 下面的计算, 看着 Bilinear-Interaction Layer 的图示就明白了, 不多说. if self.bilinear_type == "all": vidots = [tf.tensordot(inputs[i], self.W, axes=(-1, 0)) for i in range(n)] p = [tf.multiply(vidots[i], inputs[j]) for i, j in itertools.combinations(range(n), 2)] elif self.bilinear_type == "each": vidots = [tf.tensordot(inputs[i], self.W_list[i], axes=(-1, 0)) for i in range(n - 1)] p = [tf.multiply(vidots[i], inputs[j]) for i, j in itertools.combinations(range(n), 2)] elif self.bilinear_type == "interaction": p = [tf.multiply(tf.tensordot(v[0], w, axes=(-1, 0)), v[1]) for v, w in zip(itertools.combinations(inputs, 2), self.W_list)] else: raise NotImplementedError return concat_func(p)
总结
假期看了两部漫画 《迷域行者》和《一人之下》, 我很快乐~ ????????????
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~