前言
上篇文章中我们引入了推荐系统中特征交叉的概念,以及介绍了一些常见的特征交叉方法,这篇文章我们将详细地讨论一下推荐系统中特征交叉地模型,他们的特点,以及他们为什么会这样。本文中介绍的模型有Wide & Deep,deepFM,NFM,以及AFM和相应地拓展。
Wide & Deep
 
 首先附上Wide&deep的模型结构,看起来很简单,左边时一个线性模型,右边时一个DNN模型。该模型采用线性部分提升模型的记忆能力,同时采用DNN部分提升模型的泛化能力。
与DNN部分相比,Wide部分更是这个模型的核心。它是一个使用L1正则化的FTLR模型,该模型之前被广泛地应用于推荐系统中,主要的一个特点就是稀疏化,模型的特征都是0,1。同时采用L1正则化训练,可以将最后参数W中0的取值尽可能地多(关于逻辑回归中L1正则,L2正则中w参数地变化大家应该都了解吧)。第二个特点就是特征高度交叉,交叉的方式与我上篇文章中第一种交叉方式相同。
 与wide部分的结构相比,wide部分采用的特征也十分重要,谷歌在这篇论文中wide部分的特征是怎么选取的呢?下面这张图片是谷歌在他们系统中使用的模型(以谷歌商店APP推荐为例):
 左边是DNN部分,其中**User Installed App(用户已经安装APP)和Impression App(曝光APP)**产生的Cross Product Transformation就是wide部分(这里其实还是有点误导,大家可以认为曝光APP其实就是我们常说的target app(即目标item)。在训练过程中,如果target后来被安装了,那么label为1,没有被安装则label为0)。Cross Product Transformation其实就是将用户已经安装的app和待预测的app进行交叉。由于app的数量很多,交叉起来会直接爆炸,因此采用了FTLR来过滤一些稀疏特征。
为了防止大家对交叉和训练的方式有疑惑,我这里详细介绍一下:
 假如FTLR中只有app交叉特征,app总数量为26个(用A-Z表示),那么FTLR中W的维度为676(26x26)。如果某个用户已经安装的app为(A,B),待预测的app为(E),那么交叉得到的特征为(A&E,B&E)两个特征,这时候我们找出这两个特征对应的w进行梯度下降。模型训练完成后我们只需要保存每个特征(676维)和对应的w值。线上通过特征交叉我们可以得分相应的特征,直接取w进行相加就可以得到wide侧的值了(或许再加上一个sigmoid)。
总结与展望:wide&deep在DNN的基础上引入了wide侧进行联合优化,在DNN的高拟合基础上增加了模型的记忆能力。wide侧的模型是一个使用L1正则化的FTLR模型,主要用于记忆用户已安装app和target app之间的关联。
看完这个wide侧之后,我想了又想,虎躯一震,觉得将FTLR变为DNN不就是YoutubeDNN的核心部分吗,都是通过挖掘用户已经产生行为的item和target Item之间的关联来优化目标,只是者采用了相对古老的FTLR,一种采用了相对比较新的embedding。
DeepFM
如果说选择一个深度模型做推荐的话,DeepFM真的就是强烈推荐了。话不多说,我们直接看DeepFM的模型结构。
 
 模型左侧是FM,模型右侧是DNN。FM模型的结构很简单,我在之前的文章也介绍过了,大家感兴趣的话可以看:。除了这个模型优美的结构之外,还有一些有意思的地方。
 我之前在脉脉上看到一个问题:**deepFM和wide&deep模型中DNN模块有什么不一样的地方。**这个问题看的我虎躯一震。之前根本没有注意到这个问题。其实就我的感觉其实这里涉及一个DNN模型的转化,目前推荐模型中现在很少会直接将连续值输入到模型中(直接category类的一直是one-hot)。
 上图的wide&deep模型将用户的年纪,安装的App数量等特征直接输入到了模型之中(可能经过归一化),但是DeepFM模型中所有Field都进行了embedding,目前我所接触到的推荐模型中,也全都是将数值型进行了embedding。举个例子,用户年龄0-100,我们可以划为[0-7,7-14,14-19,19-25,25-35,35-50,50-60,60-75,75-10,其余]9个区间再加一个填充值(防止用户年龄缺失)。如果某个用户的年纪是22,那么我们可以将该用户进行embedding,结果是[0,0,0,1,0,0,0,0,0,0]。然后按照下面的方法就可以直接得到用户在年龄这个Field的embedding。但是更常见的做法是,将年龄为22的用户该特征的映射为4,年龄为10岁映射为1,然后直接查表进行embedding。
  至于为什么大家现在都全部embedding,而不输入数值,我没有找到具体的解释,如果有大佬了解的话可以介绍下。
至于为什么大家现在都全部embedding,而不输入数值,我没有找到具体的解释,如果有大佬了解的话可以介绍下。
总结:DeepFM模型是将全部的特征分别进行FM和DNN,并且两边模型中的特征embedding都是共享的。不过在我看来,没必要将所有的特征都输入到FM和DNN中,两者如果可以进行特征分配可能会好一些,让更需要交叉的特征输入放入FM侧。
NFM
FM终究是一阶的交叉,如果要进行二阶三阶甚至更高阶的交叉的话是无法做到的。如果可以放入DNN中进行更高阶的交叉可能会有更好的效果。NFM就是一个这样的模型。
 
 从上图中好像并没有看到FM的结构,只是有个奇怪的Bi-interaction Pooling。这是一个什么东西呢?
     
      
       
        
         
          f
         
         
          
           B
          
          
           i
          
         
        
        
         (
        
        
         
          V
         
         
          x
         
        
        
         )
        
        
         =
        
        
         
          ∑
         
         
          
           i
          
          
           =
          
          
           1
          
         
         
          n
         
        
        
         
          ∑
         
         
          
           j
          
          
           =
          
          
           i
          
          
           +
          
          
           1
          
         
         
          n
         
        
        
         
          x
         
         
          i
         
        
        
         
          v
         
         
          i
         
        
        
         ∗
        
        
         
          x
         
         
          j
         
        
        
         
          v
         
         
          j
         
        
       
       
        f_{Bi}(V_x)=\sum_{i=1}^{n}\sum_{j=i+1}^{n}x_iv_i*x_jv_j
       
      
     fBi(Vx)=i=1∑nj=i+1∑nxivi∗xjvj
 其中
    
     
      
       
        (
       
       
        
         V
        
        
         i
        
       
       
        ∗
       
       
        
         V
        
        
         j
        
       
       
        
         )
        
        
         k
        
       
       
        =
       
       
        
         v
        
        
         
          (
         
         
          i
         
         
          k
         
         
          )
         
        
       
       
        
         v
        
        
         
          (
         
         
          j
         
         
          k
         
         
          )
         
        
       
      
      
       (V_i*V_j)_k=v_{(ik)} v_{(jk)}
      
     
    (Vi∗Vj)k=v(ik)v(jk)。
 我们把FM模型拿出来看看:
 
     
      
       
        
         F
        
        
         M
        
        
         :
        
        
         y
        
        
         =
        
        
         
          w
         
         
          0
         
        
        
         +
        
        
         
          ∑
         
         
          
           i
          
          
           =
          
          
           1
          
         
         
          n
         
        
        
         
          w
         
         
          i
         
        
        
         
          x
         
         
          i
         
        
        
         +
        
        
         
          ∑
         
         
          
           i
          
          
           =
          
          
           1
          
         
         
          n
         
        
        
         
          ∑
         
         
          
           j
          
          
           =
          
          
           i
          
          
           +
          
          
           1
          
         
         
          n
         
        
        
         <
        
        
         
          v
         
         
          i
         
        
        
         ,
        
        
         
          v
         
         
          j
         
        
        
         >
        
        
         
          x
         
         
          i
         
        
        
         
          x
         
         
          j
         
        
       
       
        FM:y=w_0+\sum_{i=1}^{n}w_ix_i+\sum_{i=1}^{n}\sum_{j=i+1}^{n}<v_i,v_j>x_ix_j
       
      
     FM:y=w0+i=1∑nwixi+i=1∑nj=i+1∑n<vi,vj>xixj
 可以发现
    
     
      
       
        
         v
        
        
         i
        
       
       
        ,
       
       
        
         v
        
        
         j
        
       
      
      
       v_i,v_j
      
     
    vi,vj的向量乘法变成了点乘法,最终导致
    
     
      
       
        
         f
        
        
         
          B
         
         
          i
         
        
       
       
        (
       
       
        
         V
        
        
         x
        
       
       
        )
       
      
      
       f_{Bi}(V_x)
      
     
    fBi(Vx)不再像FM结果那样是一个数值,从而变成了一个
    
     
      
       
        k
       
      
      
       k
      
     
    k维的向量。用一句话表示就是Bi-interaction Pooling是在特征embedding后的每一个维度上进行了一次特征交叉。
 讲述完最核心的部分之后,我们发现input Feature vector那里和上面我们介绍的deepFM的特征输入好像有点不一样,出现了一个0.2的数值型。那么它是怎么转化成上面的
    
     
      
       
        
         v
        
        
         7
        
       
      
      
       v_7
      
     
    v7呢?其实是这样的,我们在对用户爱好进行embedding的时候,可能将爱好足球和游戏进行了embdeding,但是一个用户有多个爱好,对每个爱好的喜爱程度也不一样,这时候就会出现一个爱好得分,比如足球:0.2。这样将0.2乘以足球的embedding就是用户爱好足球的embedding。
以上就是NFM的核心部分了,论文模型也比较简单。论文说NFM的方式实现了更加维度的交叉,其实我内心是有点拒绝的,因此我认为特征与特征的交叉从始至终都只发生在Bi-interaction Pooling阶段。在这个阶段我们得到了一个在特征embedding后的每一个维度上进行了一次特征交叉的k维的embedding。所有特征的交叉都通过sum累计到了这个k维embedding中,后续将这个embedding输入到DNN模型中,也只是这个embedding内部的交叉,特征之间的差异信息已经全部通过sum全部掩盖了。当然我只是我从直观上来说,可能DNN大力出奇迹,真的学习到了多层交叉呢。
在我内心,其实还有一个别的Bi-interaction Pooling方法:
 
 这个是常规的FM方法,正常情况下我们将m(m-1)/2个向量乘相加起来,但是如果我们不想加,直接再后面再加两层DNN网络的话,是不是可以将特征继续实现更高维度的交叉?我个人感觉从直观上来说是要比NFM说的高维度交叉更加合理的,可能计算的复杂度会高上不少。
总结:本文主要介绍了推荐系统中wide&deep,deepFM和NFM模型,重点在于介绍各个模型中的特征交叉,wide&deep中特征交叉部分主要使用带L1正则化的FTLR实现,DeepFM主要是使用FM进行实现特征交叉,而NFM采用了Bi-interaction Pooling方法将原本输出为数值的FM变为输出为一个k维的embedding,然后放入DNN中进行更高维度的交叉。此外,由于论文是各个不同的研究机构在不同时间发表的,在特征的处理或者说embedding方便有着一些区别。










