暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

特征交叉模型结构总结与业务应用和思考

播播笔记 2022-04-16
1086
特征交叉系列的模型结构介绍,到这基本告一段落。这篇文章做一个总结,以及对前面一些思考题进行解答,其中一些思考题也是我在具体业务中遇到的一些问题,也分享一些对这些问题的个人观点,也许是不对的,欢迎交流。


目录

  • 1 特征交叉模型总结

  • 2 特征交叉的业务应用和思考

    • 2.1 模型应用和效果分析

      • 2.1.1 deepFM

      • 2.1.2 DCN

      • 2.1.3 DCN-V2

      • 2.1.4 xDeepFM

      • 2.1.5 PNN

    • 2.2 特征交叉思考

      • 2.2.1 DCN如何实现field-wise特征交叉

      • 2.2.2 deepFM特征交叉结果表征方式

      • 2.2.3 自动高阶特征交叉效果一定好吗

      • 2.2.4 人工先验经验的重要性



1 特征交叉模型总结


推荐模型的效果受几方面的因素影响:样本、特征、模型、工程。


样本是最基本的,影响非常大,样本量的大小对模型的训练效果有直接的影响,当样本量非常大时,可以出现大力出奇迹的效果,这时候即使模型非常简单,也可以达到不错的效果。


特征是训练数据的信息表达载体,直接决定了模型可以挖掘到什么信息,决定了模型效果的上限。在前深度学习时代,模型简单,因此想让模型挖掘出有效的信息,对特征工程的依赖强。深度学习在推荐领域的落地,加强了模型对特征的学习能力,但因为DNN处理的特征空间非常高维,在实际学习过程中想要收敛到理想状态,会面临各种各样的难题,因此不能迷信DNN可以在任何情况下都达到理想状态。当给模型提供越多有效经过先验设计的信息,模型在收敛过程越容易接近最优解。


在推荐数据中,特征之间存在关联模式。虽然DNN可以通过隐式方式学习这些模式,但想在实际过程中学到理想状态,是有难度的,绝大多数情况会陷在某个离最优解有段距离的地方,因此通过人工手工交叉设计,或者通过模型结构进行显式特征交叉,可以使模型学习过程更容易,同时也学到更接近最优解的状态,从而提高模型效果。


模型本身对效果的提升,相对样本和特征而言,比较有限。它的作用是尽可能地捕捉和学习样本和特征里包含的信息,本质上是在不断接近效果的上限。


工程上的实时性对模型效果又直接影响,通过提高模型的实时性,可以让模型更灵敏地捕捉到用户行为背后的兴趣变化。


特征交叉的实现方式不同,对模型效果影响的来源维度也不同,手工设计的交叉特征是从特征层影响,直接从源头上影响;通过设计模型结构实现特征交叉,是从模型层面影响,让模型更充分地挖掘特征背后的信息。这个主题介绍的若干模型,这两种方式都有涉及。


往期分享的特征交叉模型结构包括三个系列:


图1 特征交叉模型结构分类


LR系列模型的特征交叉,依赖人工设计,但这个系列的模型LR和W&D在推荐领域有非常重要的地位。LR是前深度学习时代使用最广泛的模型,它原理简单、可解释性强。W&D为后续模型在特征交叉上的优化提供了模型结构的设计思路,即特征交叉结构和DNN结构并行,最后输出层结合这两部分,这种设计思路在特征交叉模型结构的优化上被广泛使用。


FM系列模型,实现了特征的自动交叉,不需要依赖人工设计交叉特征,考虑了特征的field信息,进行field-wise的交叉。这一系列的模型思路相似,在FM的基础上进行两种改进:(1) 在特征交叉中对各个组合项引入差异化,包括FFM、AFM、FwFM;(2) 将FM和DNN结合,包括FNN、PNN、NFM、deepFM。


DCN系列模型,通过模型结构设计,实现特征的高阶显式自动交叉,提高了特征交叉的表达上限。DCN系列模型中,DCN、DCN-V2实现了bit-wise的特征交叉,xDeepFM实现了field-wise的特征交叉。


表1 三种系列模型特征交叉结构对比

模型

优点

缺点

LR系列

模型简单,可解释性强

依赖人工设计,对特征工程要求高

FM系列

特征显式自动交叉,不需要依赖人工设计

一般交叉到2阶为止,高阶交叉复杂度高

DCN系列

特征高阶显式自动交叉

模型复杂度高


表2 模型特征交叉结构特点和复杂度(复杂度仅针对特征交叉结构)

模型

优点

缺点

空间复杂度

时间复杂度

LR

模型简单、可解释性强

需人工设计交叉组合

O(N)

O(N)

W&D

特征交叉和DNN结合

需人工设计交叉组合

O(N)

O(N)

FM

自动交叉,field-wise

一般到2阶交叉为止

O(ND)

O(ND)

FFM

充分考虑域和域之间的差异性

空间复杂度高,一般到2阶为止

O(FND)

O(DNN)

AFM

采用attention机制学习每个组合项的重要度

特征组合稀疏性问题

O(ND)

O(NND)

FwFM

考虑隐向量基于域的差异性,参数量比FFM小

一般到2阶为止

O(ND+FF)

O(DNN)

FNN

FM作为DNN输入,发挥FM优势

分段训练(非end-to-end);FM作为底层输入,作用被削弱;FNN的模型能力受FM能力限制

O(ND)

O(ND)

PNN

end-to-end结合显式交叉和DNN结构

内积/外积交叉计算复杂度高;显式交叉作为DNN输入导致低阶交叉重要度降低

内积形式O(NNH)

内积形式

O(NND+NNH)

NFM

结合FM和DNN,保留了低阶交叉信息;用向量而非标量表达二阶交叉

二阶交叉作为DNN输入,交叉特征隐式化

O(ND)

O(ND)

deepFM

结合FM和dnn,field-wise

交叉到2阶为止

O(FD)

O(FD)

DCN

高阶显式交叉

bit-wise

O(2NL)

O(LNN)

DCN-V2

高阶显式交叉,交叉项feature map有差别加权组合,可引入非线性优化

bit-wise,参数量增加

O(LNN)

O(LNNN)

xDeepFM

高阶显式交叉,field-wise

时间复杂度高

O(2LHDF)

O(FHHDL)

N为输入特征  维度(  为onehot或者Dense embedding形式,依据不同模型的特征交叉部分的输入而定),F为特征field数量,H为隐层field数量(神经元数量),D为每维特征的维度,L为特征交叉结构网络层数。具体每种模型的复杂度如何得来,可详细查看每个系列中模型的介绍。


2 特征交叉的业务应用和思考


DNN结构通过全连接层和激活函数,实现了特征的隐式高阶交叉。理论上DNN结构可以学到特征之间的交叉模式,但DNN在高维空间收敛到最优解在实际过程中实现起来有难度,因此在模型中输入先验的特征交叉信息,或者通过网络结构的设计使特征显式自动交叉,可以降低模型的学习难度,从而达到更好的效果。


我在实际业务中尝试过多种模型,其中有一些有显著效果,有一些有不显著效果。


2.1 模型应用和效果分析


2.1.1 DeepFM

DeepFM优化W&D,有明显效果,且为后续优化提供了一个比较强的base。


2.1.2 DCN


DCN对比DeepFM在某些业务有明显效果,在某些业务效果不明显。从效果说明了deepFM中FM这个结构很强。DCN效果不明显,有两方面的思考:


  • (1) bit-wise的交叉和field-wise对比,由于没有考虑到field信息,效果打折,这里有兴趣的朋友可以试一试,把DCN的交叉结构层数设为1,其它部分DCN和deepFM两个模型保持一致,再对比效果;


  • (2) 通过增加模型层数,使其学习高阶特征交叉,是预期想达到的理想状态,但是同时带来模型复杂度的提高,以及模型学习难度的提高,在实际过程中,模型是否能学到期望的效果,是存疑的,这点也不太好验证,目前我没有想到一个比较好的验证方式,或许可以试试不同的特征交叉层数。


2.1.3 DCN-V2


DCN-V2对比DCN/deepFM有明显提升,但需要比较好的工程支持,否则容易由于模型空间复杂度和时间复杂度过高,线上推理超时,无法满足服务部署要求。

DCN-V2的效果,个人认为属于大力出奇迹的这种,通过大量增加模型参数(相比DNN侧),来提高模型表达能力,达到提高模型表达能力的效果。


2.1.4 xDeepFM


从离线指标看,对比deepFM有微弱提升,由于线上服务耗时问题,没有部署线上。个人觉得需要看业务,也许有的业务会和DCN一样有提升,但这部分提升,个人也认为是大力出奇迹的这种。


2.1.5 PNN


在具体业务中使用PNN落地,仅使用PNN的交叉部分,用于替换deepFM中的FM部分,对交叉后的向量进行线性组合,得到交叉特征表征。相比deepFM,有不显著的提升。这里的提升,主要来源于通过引入矩阵参数对交叉项组合,一定程度提高了信息量,但这个提升有限,进一步说明了FM对特征交叉的强大性。


2.2 特征交叉思考


在特征交叉这个主题的系列分享中,遗留了一些问题,在这里解答部分,没有解答的会在后续相关主题中继续。


2.2.1 DCN如何实现field-wise特征交叉


DCN模型实现的是bit-wise的特征交叉,忽略了特征的field信息,是否可以借鉴DCN的bit-wise交叉的思路,实现field-wise的交叉呢?


应该是可以的,对于输入从N维的特征  变为F个field的D维特征([F, D]),仍然采用DCN的特征交叉原理,即  ,只是其中参数的维度进行调整,  转置并维度扩充为[D, F, 1],  维度扩充为[D, 1, F],  则完成了field-wise的交叉,  为F*1或者F*F的矩阵,两者的区别类似DCN和DCN-V2的区别,F*F表示对feature map每行交叉项进行线性加权组合时,参数不共享,F*1则表示参数共享。


我在具体业务落地时,和deepFM相比有一定效果,但效果不如DCN-V2,还是那句话,DCN-V2属于大力出奇迹这类效果。


代码1 DCN field-wise特征交叉

    def dcn_cross_layer_field_vector(params, input_layer, mode, layer_dropout=1):
    '''
    cross net module: field-wise cross, w use vector
    x_{l+1} = x_0*(tf.matmul(W_l, x_l) + b_l) + x_l
    '''
        layer_name = 'cross_layers_field_v'


    field_num = input_layer.shape[1].value # return the F number input_layer [B, F, D]
    ebd_dim = input_layer.shape[
    2].value # the embedding size of each field, in this model, the size of all fields is same
    output_size = params.cross_layers['out_dim']
    layer_num = params.cross_layers['layer_num']


    kernel_initializer = tf.glorot_uniform_initializer()
    bias_initializer = tf.zeros_initializer()


    embedding_layer_0 = tf.transpose(input_layer, [0, 2, 1]) # [B, D, F]
    embedding_layer_extend_0 = tf.expand_dims(embedding_layer_0, axis=3) # [B, D, F, 1]
    embedding_layer_l = embedding_layer_0 # [B, D, F]


    tf.logging.warning("{} input shape: {}".format(layer_name, input_layer.shape))


    # process cross net
    for i in range(layer_num):
    index = i + 1
    embedding_layer_extend_l = tf.expand_dims(embedding_layer_l, axis=2) # [B, D, 1, F]


    kernel = tf.get_variable(
    name="{0}_kernel_{1}".format(layer_name, index),
    shape=[field_num, 1],
    dtype=tf.float32,
    initializer=kernel_initializer,
    ) # [F, 1]
    bias = tf.get_variable(
    name="{0}_bias_{1}".format(layer_name, index),
    shape=[ebd_dim, field_num],
    dtype=tf.float32,
    initializer=bias_initializer,
    ) # [D, F]
    embedding_layer_m_0_l = tf.matmul(
    embedding_layer_extend_0, # [B, D, F, 1]
    embedding_layer_extend_l, # [B, D, 1, F]
    name="{0}_m_0_l_{1}".format(layer_name, index),
    ) # tf.matmul(x_l, W_l) [B, D, F, F]
    embedding_layer_m_0_l_w = tf.matmul(
    embedding_layer_m_0_l, # [B, D, F, F]
    kernel, # [F, 1]
    name="{0}_m_0_l_w_{1}".format(layer_name, index),
    ) # [B, D, F, 1]


    # for matrix: embedding_layer_l = tf.add(tf.add(tf.reduce_sum(embedding_layer_m_0_l_w, axis=2, keepdims=False), bias), embedding_layer_l) # 【B, D, F】
    embedding_layer_l = tf.add(tf.add(tf.squeeze(embedding_layer_m_0_l_w, axis=[3]), bias),
    embedding_layer_l) # [B, D, F]
    if layer_dropout < 1.0:
    embedding_layer_l = tf.layers.dropout(embedding_layer_l, rate=(1 - layer_dropout),
    training=(mode == tf.estimator.ModeKeys.TRAIN),
    name="{0}_layer_{1}_dropout".format(layer_name, index),
    )


    # process output
    embedding_layer_l = tf.squeeze(tf.concat(tf.split(embedding_layer_l, field_num, axis=2), axis=1),
    axis=[2]) # [B, F*D]


    # concate 输出
    output_w = tf.get_variable(
    "{0}_output_w".format(layer_name),
    shape=[field_num * ebd_dim, output_size],
    dtype=tf.float32,
    initializer=kernel_initializer,
    )
    output_layer = tf.matmul(embedding_layer_l, output_w, name="{0}_output".format(layer_name)) # [B, Output]

        return output_layer


    2.2.2 deepFM特征交叉结果表征方式


    deepFM的特征交叉,可以在D和F两个维度求和,从而得到不同维度的表征,两种表征方式可能存在信息量不等价问题。在D这个维度求和相当于对F个field特征两两内积,得到F*(F-1)/2维的向量表征,而采用计算优化方式,相当于在field维度求和,则得到D维向量表征。


    具体问题在《模型结构之特征交叉(2)-FM系列(2.2)-AFM,DeepFM等(附代码)》有详细说明,其中附了在field维度求和的代码,当时写该篇分享时还没有验证,对两种表征方式没有明确结论,只是猜想用D维表征特征交叉结果,不会有明显效果。


    后来做了一些其它改进,加了一些交叉项,也就是使用内积求和方式,得到f维(指定f种交叉)的向量表征,有明显效果提升;而使用优化方式,最终得到D维向量表征,对比base没有明显变化。因此推测内积形式得到的F*(F-1)/2维的向量表征,具备更强的信息量。F*(F-1)/2维的结果表征,相当于对交叉操作先按位乘然后sum pooling,结果再concat,而D维的结果表征,相当于交叉操作先按位乘,再sum pooling;两者对比,在每个交叉项内sum pooling后concat,比对所有交叉项之间sum pooling,信息表达能力更强,也就是在项内sum pooling使信息表达更合理


    关于这个点,可能我的想法也不对,欢迎朋友一起来讨论。


    2.2.3 自动高阶特征交叉效果一定好吗


    在理想情况下,特征自动高阶交叉,其信息表达能力肯定强于手工低阶交叉的表达能力,但在具体业务场景和实际模型训练过程,可能不一定。我在尝试特征自动高阶交叉时,便遇到了这个问题。


    分析可能的原因有两点:

    • (1) 模型自动高阶特征交叉时,模型复杂度提高,导致模型学习难度增加,在实际收敛过程,不一定能收敛到预期的效果;这点可以通过拉长时间和加大数据量解决,但不好论证;

    • (2) 模型自动交叉项中的某些项带偏了,这些项实际上可能没有交叉性,但在少量数据上表现出强交叉性,而在大多数数据上没有,但模型被这少量数据带偏后纠不回来了;关于这点,也比较难论证且存疑,因为默认模型是学数据分布的某个函数,如果某些交叉项在大多数数据上没有,那模型就不应该学到,学偏后是否能纠回来,默认是可以的。

    2.2.4 人工先验经验的重要性


    我在特征交叉的优化上,让模型显式自动高阶特征交叉,某些模型的效果不及预期,而通过人工对业务的分析,加入一些手工交叉特征,效果非常明显,再次论证了人工先验经验的重要性,以及算法工程师的必要性。


    神经网络理想状态下很强大,可以拟合任何函数,但很多时候会因为它理论的强大忽略一点:它的学习是有难度的。算法工程师不断挖掘先验知识,输入到模型,可以非常有效降低模型学习难度,使模型更接近预期的理想状态。


    模型不是万能的,一个好的算法工程师,其作用之一是让模型效果不断接近它的天花板。



    下一篇将分享多目标、激活函数或者其它


    以及朋友们有什么想要一起探讨的,可以在评论区告诉我,共同学习一起进步呀~


    推荐系列文章:

    推荐模型结构-特征交叉

    基础知识类

    工具类


    微信最近对公众号的推送算法改版较大,为了更好地找到我,动动手对这个公众号置顶呀~


    公众号的内容会同时在知乎专栏更新,有兴趣的朋友可以在知乎找我玩(知乎账号:婷播播),知乎专栏:推荐学习笔记


    生活的思考和记录会在另一个公众号更新,有兴趣的朋友也可以动手关注一下


    文章转载自播播笔记,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

    评论