精华内容
下载资源
问答
  • CTR预估算法之FM, FFM, DeepFM及实践

    万次阅读 多人点赞 2017-12-29 16:55:36
    CTR预估综述 Factorization Machines(FM) 算法原理 代码实现 Field-aware Factorization Machines(FFM) 算法原理 代码实现 Deep FM 算法原理 代码实现 参考文献 CTR预估综述 点击率(Click ...

    目录

    CTR预估综述

    点击率(Click through rate)是点击特定链接的用户与查看页面,电子邮件或广告的总用户数量之比。 它通常用于衡量某个网站的在线广告活动是否成功,以及电子邮件活动的有效性。
    点击率是广告点击次数除以总展示次数(广告投放次数)

    此处输入图片的描述

    目前,CTR的数值平均接近0.2%0.2\%0.3%0.3\%,超过2%2\%被认为是非常成功的。

    常用的CTR预估算法有FM, FFM, DeepFM。

    Factorization Machines(FM)

    FM的paper地址如下:https://www.csie.ntu.edu.tw/~b97053/paper/Rendle2010FM.pdf
    FM主要目标是:解决数据稀疏的情况下,特征怎样组合的问题
    根据paper的描述,FM有一下三个优点:

    1. 可以在非常稀疏的数据中进行合理的参数估计
    2. FM模型的时间复杂度是线性的
    3. FM是一个通用模型,它可以用于任何特征为实值的情况

    算法原理

    在一般的线性模型中,是各个特征独立考虑的,没有考虑到特征与特征之间的相互关系。但实际上,大量的特征之间是有关联的。
    一般的线性模型为:

    y=w0+i=1nwixiy = w_0 + \sum_{i=1}^nw_ix_i

    从上面的式子中看出,一般的线性模型没有考虑特征之间的关联。为了表述特征间的相关性,我们采用多项式模型。在多项式模型中,特征xix_ixjx_j的组合用xixjx_ix_j表示。为了简单起见,我们讨论二阶多项式模型。

    y=w0+i=1nwixi+i=1nj=i+1nwijxixjy = w_0 + \sum_{i=1}^nw_ix_i + \sum_{i=1}^{n}\sum_{j=i+1}^nw_{ij}x_ix_j

    该多项是模型与线性模型相比,多了特征组合的部分,特征组合部分的参数有n(n1)2\frac{n(n-1)}{2}个。如果特征非常稀疏且维度很高的话,时间复杂度将大大增加。
    为了降低时间复杂度,对每一个特征,引入辅助向量lantent vector Vi=[vi1,vi2,...,vik]TV_i=[v_{i1},v_{i2},...,v_{ik}]^T, 模型修改如下:

    y=w0+i=1nwixi+i=1nj=i+1n<Vi,Vj>xixjy = w_0 + \sum_{i=1}^nw_ix_i + \sum_{i=1}^{n}\sum_{j=i+1}^n<V_i,V_j> x_ix_j

    以上就是FM模型的表达式kk是超参数,即lantent vector的维度,一般取30或40,也可以取其他数 具体情况具体分析。上式如果要计算的话,时间复杂度是O(kn2)O(kn^2), 可以通过如下方式化简。对于FM的交叉项

    i=1nj=i+1n<Vi,Vj>xixj\sum_{i=1}^{n}\sum_{j=i+1}^n<V_i,V_j> x_ix_j

    =12i=1nj=1n<Vi,Vj>xixj12i=1n<Vi,Vi>xixi=\frac{1}{2}\sum_{i=1}^{n}\sum_{j=1}^n<V_i,V_j> x_ix_j -\frac{1}{2}\sum_{i=1}^n<V_i,V_i>x_ix_i

    =12(i=1nj=1nf=1kvifvjfxixji=1nf=1kvifvifxixi)=\frac{1}{2}(\sum_{i=1}^n\sum_{j=1}^{n}\sum_{f=1}^kv_{if}v_{jf}x_ix_j - \sum_{i=1}^{n}\sum_{f=1}^kv_{if}v_{if}x_ix_i)

    =12f=1k((i=1nvifxi)(j=1nvjfxj)i=1nvif2xi2)=\frac{1}{2}\sum_{f=1}^{k}((\sum_{i=1}^nv_{if}x_i)(\sum_{j=1}^nv_{jf}x_j) - \sum_{i=1}^nv_{if}^2x_i^2)

    =12f=1k((i=1nvifxi)2i=1nvif2xi2))=\frac{1}{2}\sum_{f=1}^{k}((\sum_{i=1}^nv_{if}x_i)^2 - \sum_{i=1}^nv_{if}^2x_i^2))

    通过对每个特征引入lantent vector ViV_i, 并对表达式进行化简,可以把时间复杂度降低到O(kn)O(kn)

    代码实现

    我们利用kaggle上的CTR预测比赛中数据测试了算法,由于代码过于冗长,此处仅给出FM类的代码,包括add palceholders, inference等模块。详细代码参考github,https://github.com/Johnson0722/CTR_Prediction/tree/master

    class FM(object):
        """
        Factorization Machine with FTRL optimization
        """
        def __init__(self, config):
            """
            :param config: configuration of hyperparameters
            type of dict
            """
            # number of latent factors
            self.k = config['k']
            self.lr = config['lr']
            self.batch_size = config['batch_size']
            self.reg_l1 = config['reg_l1']
            self.reg_l2 = config['reg_l2']
            # num of features
            self.p = feature_length
    
        def add_placeholders(self):
            self.X = tf.sparse_placeholder('float32', [None, self.p])
            self.y = tf.placeholder('int64', [None,])
            self.keep_prob = tf.placeholder('float32')
    
        def inference(self):
            """
            forward propagation
            :return: labels for each sample
            """
            with tf.variable_scope('linear_layer'):
                b = tf.get_variable('bias', shape=[2],
                                    initializer=tf.zeros_initializer())
                w1 = tf.get_variable('w1', shape=[self.p, 2],
                                     initializer=tf.truncated_normal_initializer(mean=0,stddev=1e-2))
                # shape of [None, 2]
                self.linear_terms = tf.add(tf.sparse_tensor_dense_matmul  (self.X, w1), b)
    
            with tf.variable_scope('interaction_layer'):
                v = tf.get_variable('v', shape=[self.p, self.k],
                                    initializer=tf.truncated_normal_initializer(mean=0, stddev=0.01))
                # shape of [None, 1]
                self.interaction_terms = tf.multiply(0.5,
                                                     tf.reduce_mean(
                                                         tf.subtract(
                                                             tf.pow(tf.sparse_tensor_dense_matmul(self.X, v), 2),
                                                             tf.sparse_tensor_dense_matmul(tf.pow(self.X, 2), tf.pow(v, 2))),
                                                         1, keep_dims=True))
            # shape of [None, 2]
            self.y_out = tf.add(self.linear_terms, self.interaction_terms)
            self.y_out_prob = tf.nn.softmax(self.y_out)
    
        def add_loss(self):
            cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=self.y, logits=self.y_out)
            mean_loss = tf.reduce_mean(cross_entropy)
            self.loss = mean_loss
            tf.summary.scalar('loss', self.loss)
    
        def add_accuracy(self):
            # accuracy
            self.correct_prediction = tf.equal(tf.cast(tf.argmax(model.y_out,1), tf.int64), model.y)
            self.accuracy = tf.reduce_mean(tf.cast(self.correct_prediction, tf.float32))
            # add summary to accuracy
            tf.summary.scalar('accuracy', self.accuracy)
    
        def train(self):
            # Applies exponential decay to learning rate
            self.global_step = tf.Variable(0, trainable=False)
            # define optimizer
            optimizer = tf.train.FtrlOptimizer(self.lr, l1_regularization_strength=self.reg_l1,
                                               l2_regularization_strength=self.reg_l2)
            extra_update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
            with tf.control_dependencies(extra_update_ops):
                self.train_op = optimizer.minimize(self.loss, global_step=self.global_step)
    
        def build_graph(self):
            """build graph for model"""
            self.add_placeholders()
            self.inference()
            self.add_loss()
            self.add_accuracy()
            self.train()
    
    

    Field-aware Factorization Machines(FFM)

    FFM的论文地址:https://www.csie.ntu.edu.tw/~cjlin/papers/ffm.pdf
    FFM(Field-aware Factorization Machine)最初的概念来自Yu-Chin Juan(阮毓钦,毕业于中国台湾大学,现在美国Criteo工作)与其比赛队员,提出了FM的升级版模型。通过引入field的概念3,FFM把相同性质的特征归于同一个field。
    在FFM中,每一维特征 xix_i,针对其它特征的每一种field fjf_j,都会学习一个隐向量Vi,fjV_{i,f_j}。因此,隐向量不仅与特征相关,也与field相关。这也是FFM中“Field-aware”的由来。

    算法原理

    设样本一共有nn个特征, ff 个field,那么FFM的二次项有nfnf个隐向量。而在FM模型中,每一维特征的隐向量只有一个。FM可以看作FFM的特例,是把所有特征都归属到一个field时的FFM模型。根据FFM的field敏感特性,可以导出其模型方程。

    y=w0+i=1nwixi+i=1nj=i+1n<Vi,fj,Vj,fi>xixjy = w_0 + \sum_{i=1}^nw_ix_i+\sum_{i=1}^n\sum_{j=i+1}^n<V_{i,f_j},V_{j,f_i}>x_ix_j

    其中,fjf_j是第jj的特征所属的字段。如果隐向量的长度为 kk,那么FFM的二次参数有 nfknfk 个,远多于FM模型的 nknk 个。此外,由于隐向量与field相关,FFM二次项并不能够化简,时间复杂度是 O(kn2)O(kn^2)
    需要注意的是由于FFM中的latent vector只需要学习特定的field,所以通常:

    KFFM<<KFMK_{FFM}<<K_{FM}

    下面以一个例子简单说明FFM的特征组合方式[9]。输入记录如下

    Clicked Publisher§ Advertiser(A) Gender(G)
    Yes ESPN Nike Male

    对于FM模型来说,其交叉项为:

    ϕFMV,x=<VESPN,VNike>+<VESPN,VMale>+<VNike,VMale>\phi_{FM}(V,x) = <V_{ESPN},V_{Nike}>+<V_{ESPN},V_{Male}>+<V_{Nike},V_{Male}>,

    因为在FM中,每个特征只有一个latent vecotr,这个latent可以用来学习和其他特征之间的关系。
    但是在FFM中,每一个特征有好几个latent vector,取决于其他特征的字段。在这个例子中,FFM的特征交叉项

    ϕFFMV,x=<VESPN,A,VNike,P>+<VESPN,G,VMale,P>+<VNike,G,VMale,A>\phi_{FFM}(V,x) = <V_{ESPN,A},V_{Nike,P}>+<V_{ESPN,G},V_{Male,P}>+<V_{Nike,G},V_{Male,A}>

    简单来讲,就是说在做latent vector的inner product的时候,必须考虑到其他特征所属的字段。例如
    <VESPN,A,VNike,P><V_{ESPN,A},V_{Nike,P}>中,因为NikeNike在字段A中,所以ESPNESPN的这个特征必须考虑到字段AA,以区分其他字段。<VESPN,G,VMale,P><V_{ESPN,G},V_{Male,P}>中因为其交叉的特征MaleMale属于字段GG,所以使用了VESPN,GV_{ESPN,G}这个latent vector。这样,每个特征都有ff个latent vector

    代码实现

    同样的,这里只给出FFM类的代码,详细代码见github,https://github.com/Johnson0722/CTR_Prediction/tree/master

    class FFM(object):
        """
        Field-aware Factorization Machine
        """
        def __init__(self, config):
            """
            :param config: configuration of hyperparameters
            type of dict
            """
            # number of latent factors
            self.k = config['k']
            # num of fields
            self.f = config['f']
            # num of features
            self.p = feature_length
            self.lr = config['lr']
            self.batch_size = config['batch_size']
            self.reg_l1 = config['reg_l1']
            self.reg_l2 = config['reg_l2']
            self.feature2field = config['feature2field']
    
        def add_placeholders(self):
            self.X = tf.placeholder('float32', [self.batch_size, self.p])
            self.y = tf.placeholder('int64', [None,])
            self.keep_prob = tf.placeholder('float32')
    
        def inference(self):
            """
            forward propagation
            :return: labels for each sample
            """
            with tf.variable_scope('linear_layer'):
                b = tf.get_variable('bias', shape=[2],
                                    initializer=tf.zeros_initializer())
                w1 = tf.get_variable('w1', shape=[self.p, 2],
                                     initializer=tf.truncated_normal_initializer(mean=0,stddev=1e-2))
                # shape of [None, 2]
                self.linear_terms = tf.add(tf.matmul(self.X, w1), b)
    
            with tf.variable_scope('field_aware_interaction_layer'):
                v = tf.get_variable('v', shape=[self.p, self.f, self.k], dtype='float32',
                                    initializer=tf.truncated_normal_initializer(mean=0, stddev=0.01))
                # shape of [None, 1]
                self.field_aware_interaction_terms = tf.constant(0, dtype='float32')
                # build dict to find f, key of feature,value of field
                for i in range(self.p):
                    for j in range(i+1,self.p):
                        self.field_aware_interaction_terms += tf.multiply(
                            tf.reduce_sum(tf.multiply(v[i,self.feature2field[i]], v[j,self.feature2field[j]])),
                            tf.multiply(self.X[:,i], self.X[:,j])
                        )
            # shape of [None, 2]
            self.y_out = tf.add(self.linear_terms, self.field_aware_interaction_terms)
            self.y_out_prob = tf.nn.softmax(self.y_out)
    
        def add_loss(self):
                cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=self.y, logits=self.y_out)
                mean_loss = tf.reduce_mean(cross_entropy)
                self.loss = mean_loss
                tf.summary.scalar('loss', self.loss)
    
        def add_accuracy(self):
            # accuracy
            self.correct_prediction = tf.equal(tf.cast(tf.argmax(model.y_out,1), tf.int64), model.y)
            self.accuracy = tf.reduce_mean(tf.cast(self.correct_prediction, tf.float32))
            # add summary to accuracy
            tf.summary.scalar('accuracy', self.accuracy)
    
        def train(self):
            # Applies exponential decay to learning rate
            self.global_step = tf.Variable(0, trainable=False)
            # define optimizer
            optimizer = tf.train.AdagradDAOptimizer(self.lr, global_step=self.global_step)
            extra_update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
            with tf.control_dependencies(extra_update_ops):
                self.train_op = optimizer.minimize(self.loss, global_step=self.global_step)
    
        def build_graph(self):
            """build graph for model"""
            self.add_placeholders()
            self.inference()
            self.add_loss()
            self.add_accuracy()
            self.train()
    
    

    Deep FM

    论文地址:https://arxiv.org/pdf/1703.04247.pdf

    对于一个基于CTR预估的推荐系统,最重要的是学习到用户点击行为背后隐含的特征组合。在不同的推荐场景中,低阶组合特征或者高阶组合特征可能都会对最终的CTR产生影响5
    人工方式的特征工程,通常有两个问题:一个是特征爆炸。以通常使用的Poly-2模型为例,该模型采用直接对2阶特征组合建模来学习它们的权重,这种方式构造的特征数量跟特征个数乘积相关,例如:加入某类特征有1万个可能的取值(如APP),另一类特征也有1万个可能的取值(如用户),那么理论上这两个特征组合就会产生1亿个可能的特征项,引起特征爆炸的问题;如果要考虑更高阶的特征,如3阶特征,则会引入更高的特征维度,比如第三个特征也有1万个(如用户最近一次下载记录),则三个特征的组合可能产生10000亿个可能的特征项,这样高阶特征基本上无法有效学习。另一个问题是大量重要的特征组合都隐藏在数据中,无法被专家识别和设计 (关于这个的一个有名的例子是啤酒和尿片的故事)。依赖人工方式进行特征设计,存在大量有效的特征组合无法被专家识别的问题。实现特征的自动组合的挖掘,就成为推荐系统技术的一个热点研究方向,深度学习作为一种先进的非线性模型技术在特征组合挖掘方面具有很大的优势。
    针对上述两个问题,广度模型深度模型提供了不同的解决思路。其中广度模型包括FM/FFM等大规模低秩(Low-Rank)模型,FM/FFM通过对特征的低秩展开,为每个特征构建隐式向量,并通过隐式向量的点乘结果来建模两个特征的组合关系实现对二阶特征组合的自动学习。作为另外一种模型,Poly-2模型则直接对2阶特征组合建模来学习它们的权重。FM/FFM相比于Poly-2模型,优势为以下两点。第一,FM/FFM模型所需要的参数个数远少于Poly-2模型:FM/FFM模型为每个特征构建一个隐式向量,所需要的参数个数为O(km),其中k为隐式向量维度,m为特征个数;Poly-2模型为每个2阶特征组合设定一个参数来表示这个2阶特征组合的权重,所需要的参数个数为O(m^2)。第二,相比于Poly-2模型,FM/FFM模型能更有效地学习参数:当一个2阶特征组合没有出现在训练集时,Poly-2模型则无法学习该特征组合的权重;但是FM/FFM却依然可以学习,因为该特征组合的权重是由这2个特征的隐式向量点乘得到的,而这2个特征的隐式向量可以由别的特征组合学习得到。总体来说,FM/FFM是一种非常有效地对二阶特征组合进行自动学习的模型。
    深度学习是通过神经网络结构和非线性激活函数,自动学习特征之间复杂的组合关系。目前在APP推荐领域中比较流行的深度模型有FNN/PNN/Wide&Deep;FNN模型是用FM模型来对Embedding层进行初始化的全连接神经网络。PNN模型则是在Embedding层和全连接层之间引入了内积/外积层,来学习特征之间的交互关系。Wide&Deep模型由谷歌提出,将LR和DNN联合训练,在Google Play取得了线上效果的提升。
    但目前的广度模型和深度模型都有各自的局限。广度模型(LR/FM/FFM)一般只能学习1阶和2阶特征组合;而深度模型(FNN/PNN)一般学习的是高阶特征组合。在之前的举例中可以看到无论是低阶特征组合还是高阶特征组合,对推荐效果都是非常重要的。Wide&Deep模型依然需要人工特征工程来为Wide模型选取输入特征。
    DeepFM模型结合了广度和深度模型的有点,联合训练FM模型和DNN模型,来同时学习低阶特征组合和高阶特征组合。此外,DeepFM模型的Deep component和FM component从Embedding层共享数据输入,这样做的好处是Embedding层的隐式向量在(残差反向传播)训练时可以同时接受到Deep component和FM component的信息,从而使Embedding层的信息表达更加准确而最终提升推荐效果。DeepFM相对于现有的广度模型、深度模型以及Wide&Deep; DeepFM模型的优势在于:

    • DeepFM模型同时对低阶特征组合和高阶特征组合建模,从而能够学习到各阶特征之间的组合关系
    • DeepFM模型是一个端到端的模型,不需要任何的人工特征工程

    算法原理

    首先给出DeepFM的系统框图
    此处输入图片的描述

    DeepFM包含两部分,左边的FM部分和右边的DNN部分。这两部分共享相同的输入。对于给定的特征ii, wiw_i用于表示一阶特征的重要性,特征ii的隐向量(latent vector)ViV_i用户表示和其他特征的相互影响。在FM部分,ViV_i用于表征二阶特征,同时在神经网络部分用于构建高阶特征。对于当前模型,所有的参数共同参与训练。DeepFM的预测结果可以写为

    y=sigmoid(yFM+yDNN)y = sigmoid(y_{FM}+y_{DNN})

    y(0,1)y\in(0,1)是预测的CTR,yFMy_{FM}是FM部分得到的结果,yDNNDNNy_{DNN}是DNN部分的结果
    对于FM部分, 其计算公式和模型如下。详细可以看第一节,这里不在赘述

    yFM=w0+i=1nwixi+i=1nj=i+1n<Vi,Vj>xixjy_{FM} = w_0 + \sum_{i=1}^nw_ix_i + \sum_{i=1}^{n}\sum_{j=i+1}^n<V_i,V_j> x_ix_j

    此处输入图片的描述

    对于神经网络DNN部分,其模型如下所示:

    此处输入图片的描述

    深度部分是一个前馈神经网络,可以学习高阶的特征组合。需要注意的是原始的输入的数据是很多个字段的高维稀疏数据。因此引入一个embedding layer将输入向量压缩到低维稠密向量。
    embedding layer的结构如下图所示,
    此处输入图片的描述

    embedding layer有两个有趣的特性:

    • 输入数据的每个字段的特征经过embedding之后,都为kk维(lantent vector的维度),所以embedding后的特征维度是 ×k字段数×k
    • 在FM里得到的隐变量VV现在作为了嵌入层网络的权重,FM模型作为整个模型的一部分与其他深度学习模型一起参与整体的学习, 实现端到端的训练。

    将embedding layer表征如下:

    a(0)=[e1,e2,...,em]a^{(0)}=[e_1,e_2,...,e_m]

    eie_i是第ii个字段的embedding,mm是字段的个数。a(0)a^{(0)}是输入神经网络的向量,然后通过如下方式前向传播:

    al+1=σ(W(l)a(l)+b(l))a^{l+1} = \sigma(W^{(l)}a^{(l)} + b^{(l)})

    需要指出的是,FM部分与深度部分共享相同的embedding带来了两个好处:

    • 从原始数据中同时学习到了低维与高维特征
    • 不再需要特征工程。而Wide&Deep Model需要

    关于DNN网络结构的设计,文中给出的结果是,对于hidden layer, 使用三层200-200-200的结构设计。使用relu函数作为激活函数,增加了dropout。当然,关于超参数的调试,这个还要具体情况具体分析,只有手动取调试才知道哪些参数组合更好

    代码实现

    同样的,这里只给出FFM类的代码,详细代码见github,https://github.com/Johnson0722/CTR_Prediction/tree/master

    class DeepFM(object):
        """
        Deep FM with FTRL optimization
        """
        def __init__(self, config):
            """
            :param config: configuration of hyperparameters
            type of dict
            """
            # number of latent factors
            self.k = config['k']
            self.lr = config['lr']
            self.batch_size = config['batch_size']
            self.reg_l1 = config['reg_l1']
            self.reg_l2 = config['reg_l2']
            # num of features
            self.p = feature_length
            # num of fields
            self.field_cnt = field_cnt
    
        def add_placeholders(self):
            self.X = tf.placeholder('float32', [None, self.p])
            self.y = tf.placeholder('int64', [None,])
            # index of none-zero features
            self.feature_inds = tf.placeholder('int64', [None,field_cnt])
            self.keep_prob = tf.placeholder('float32')
    
        def inference(self):
            """
            forward propagation
            :return: labels for each sample
            """
            v = tf.Variable(tf.truncated_normal(shape=[self.p, self.k], mean=0, stddev=0.01),dtype='float32')
    
            # Factorization Machine
            with tf.variable_scope('FM'):
                b = tf.get_variable('bias', shape=[2],
                                    initializer=tf.zeros_initializer())
                w1 = tf.get_variable('w1', shape=[self.p, 2],
                                     initializer=tf.truncated_normal_initializer(mean=0,stddev=1e-2))
                # shape of [None, 2]
                self.linear_terms = tf.add(tf.matmul(self.X, w1), b)
    
                # shape of [None, 1]
                self.interaction_terms = tf.multiply(0.5,
                                                     tf.reduce_mean(
                                                         tf.subtract(
                                                             tf.pow(tf.matmul(self.X, v), 2),
                                                             tf.matmul(tf.pow(self.X, 2), tf.pow(v, 2))),
                                                         1, keep_dims=True))
                # shape of [None, 2]
                self.y_fm = tf.add(self.linear_terms, self.interaction_terms)
    
            # three-hidden-layer neural network, network shape of (200-200-200)
            with tf.variable_scope('DNN',reuse=False):
                # embedding layer
                y_embedding_input = tf.reshape(tf.gather(v, self.feature_inds), [-1, self.field_cnt*self.k])
                # first hidden layer
                w1 = tf.get_variable('w1_dnn', shape=[self.field_cnt*self.k, 200],
                                     initializer=tf.truncated_normal_initializer(mean=0,stddev=1e-2))
                b1 = tf.get_variable('b1_dnn', shape=[200],
                                     initializer=tf.constant_initializer(0.001))
                y_hidden_l1 = tf.nn.relu(tf.matmul(y_embedding_input, w1) + b1)
                # second hidden layer
                w2 = tf.get_variable('w2', shape=[200, 200],
                                     initializer=tf.truncated_normal_initializer(mean=0,stddev=1e-2))
                b2 = tf.get_variable('b2', shape=[200],
                                     initializer=tf.constant_initializer(0.001))
                y_hidden_l2 = tf.nn.relu(tf.matmul(y_hidden_l1, w2) + b2)
                # third hidden layer
                w3 = tf.get_variable('w1', shape=[200, 200],
                                     initializer=tf.truncated_normal_initializer(mean=0,stddev=1e-2))
                b3 = tf.get_variable('b1', shape=[200],
                                     initializer=tf.constant_initializer(0.001))
                y_hidden_l3 = tf.nn.relu(tf.matmul(y_hidden_l2, w3) + b3)
                # output layer
                w_out = tf.get_variable('w_out', shape=[200, 2],
                                     initializer=tf.truncated_normal_initializer(mean=0,stddev=1e-2))
                b_out = tf.get_variable('b_out', shape=[2],
                                     initializer=tf.constant_initializer(0.001))
                self.y_dnn = tf.nn.relu(tf.matmul(y_hidden_l3, w_out) + b_out)
            # add FM output and DNN output
            self.y_out = tf.add(self.y_fm, self.y_dnn)
            self.y_out_prob = tf.nn.softmax(self.y_out)
    
        def add_loss(self):
            cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=self.y, logits=self.y_out)
            mean_loss = tf.reduce_mean(cross_entropy)
            self.loss = mean_loss
            tf.summary.scalar('loss', self.loss)
    
        def add_accuracy(self):
            # accuracy
            self.correct_prediction = tf.equal(tf.cast(tf.argmax(model.y_out,1), tf.int64), model.y)
            self.accuracy = tf.reduce_mean(tf.cast(self.correct_prediction, tf.float32))
            # add summary to accuracy# CTR预估算法之FM, FFM, DeepFM及实践# CTR预估算法之FM, FFM, DeepFM及实践c
    
       tf.summary.scalar('accuracy', self.accuracy)
    
        def train(self):
            # Applies exponential decay to learning rate
            self.global_step = tf.Variable(0, trainable=False)
            # define optimizer
            optimizer = tf.train.FtrlOptimizer(self.lr, l1_regularization_strength=self.reg_l1,
                                               l2_regularization_strength=self.reg_l2)
            extra_update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
            with tf.control_dependencies(extra_update_ops):
                self.train_op = optimizer.minimize(self.loss, global_step=self.global_step)
    
        def build_graph(self):
            """build graph for model"""
            self.add_placeholders()
            self.inference()
            self.add_loss()
            self.add_accuracy()
            self.train()
    
    

    参考文献

    1.https://en.wikipedia.org/wiki/Click-through_rate
    2.http://blog.csdn.net/g11d111/article/details/77430095
    3.https://tech.meituan.com/deep-understanding-of-ffm-principles-and-practices.html
    4.http://www.csie.ntu.edu.tw/~r01922136/slides/ffm.pdf
    5.http://baijiahao.baidu.com/s?id=1579855367208283187&wfr=spider&for=pc

    活动推广

    在这里插入图片描述

    展开全文
  • CTR预估

    2018-07-30 16:42:30
    CTR CTR又称广告点击率,英文名(click through rate) Ref CTR预估基本知识

    CTR

    CTR又称广告点击率,英文名(click through rate)

    对数损失函数(Logarithmic Loss Function)的原理和 Python 实现

    Ref

    CTR预估基本知识

    展开全文
  • ctr预估

    2021-02-01 09:32:57
    背景 ...为了提升检索的效率,通常分为两阶段来检索。召回/候选生成(Matching/Candidate Generation)阶段...推荐系统中CTR预估的重要性不言而喻,其中个性化是提升CTR模型效果的关键。本文介绍一种全新的排序模型,主

    背景

    以电商场景优化用户点击为例,推荐系统的任务是从海量的候选商品中选出用户最感兴趣且最可能点击的商品。为了提升检索的效率,通常分为两阶段来检索。召回/候选生成(Matching/Candidate Generation)阶段根据U2I相关性从整个候选集中筛选出少量的候选商品(比如1000个),常用协同过滤方法。排序(Ranking)阶段根据排序模型预估这小部分候选商品的CTR,排序后展示给用户。

    推荐系统中CTR预估的重要性不言而喻,其中个性化是提升CTR模型效果的关键。本文介绍一种全新的排序模型,主要的思想是融合Match中的协同过滤思想,在Rank模型中表征U2I的相关性,从而提升模型的个性化能力,并取得不俗的效果。

    搜索场景中用户通过输入搜索词显式地表达用户的意图,而推荐场景中没有这种显式获取用户意图的方式。用户的意图往往隐藏在用户行为序列中,可以说用户行为序列就是推荐中的query。因此,对用户行为序列进行建模来抽取其中的用户意图就非常重要。DIN[1]以及DIEN[2]等后续工作关注用户兴趣的表征以提升模型效果,而我们的工作在此基础上又往前走了一步,关注U2I相关性的表征。U2I相关性可以直接衡量用户对目标商品的偏好强度。可以理解成从用户特征(用户兴趣表征)到U2I交叉特征(U2I相关性表征)的升级。

    表征U2I相关性很容易想到召回中的协同过滤(CF)。I2I CF是工业界最常见的方法,预计算I2I的相似度,然后根据用户的行为和I2I相似度间接得到U2I相关性。因子分解(factorization)的方法更加直接,通过用户表征和商品表征的内积直接得到U2I相关性,这里暂且称这种方法为U2I CF。最近有一些深度学习的方法进入到相关领域:比如I2I CF中有NAIS[7],用attention机制区分用户行为的重要性,和DIN[1]的做法相似;U2I CF中有DNN4YouTube[3],把召回建模成大规模多分类问题,也就是常说的DeepMatch。DeepMatch可以看做factorization技术的非线性泛化。我们根据协同过滤中的U2I CF和I2I CF分别构建了两个子网络来表征U2I相关性。

    模型介绍

    DMR(Deep Match to Rank)模型的网络结构如图所示。仅仅依靠MLP隐式的特征交叉很难捕捉到U2I的相关性。对于输入到MLP中的U2I交叉特征,除了手工构建的U2I交叉特征,我们通过User-to-Item子网络和Item-to-Item子网络来表征U2I相关性,进一步提升模型的表达能力。

    图片

    User-to-Item网络

    受factorization方法的启发,我们用user representation和item representation的内积来表征U2I相关性,这可以看做是一种显式的特征交叉。user representation根据用户行为特征得到,一种简单的方法是做average pooling,即把每个行为特征看得同等重要。我们考虑到行为时间等context特征对行为重要性的区分度,采用attention机制,以位置编码(positional encoding,参考Transformer[4])等context特征作为query去适应性地学习每个行为的权重。其中位置编码行为序列按时间顺序排列后的编号,表达行为时间的远近。公式如下:

    图片

    其中pt∈Rdppt∈Rdp是第tt个position embedding,et∈Rdeet∈Rde是第tt个用户行为的特征向量,Wp∈Rdh×dpWp∈Rdh×dp,We∈Rdh×deWe∈Rdh×de,b∈Rdhb∈Rdh and z∈Rdhz∈Rdh是学习参数,αtαt是第tt个用户行为的归一化权重。通过weighted sum pooling,得到定长的特征向量,然后通过全连接层进行非线性变化得到user representation,以匹配item representation的维度dvdv。最终的user representation u∈Rdvu∈Rdv可以定义为:

    图片

    其中函数g(⋅)g(⋅)代表非线性变换,输入维度dede,输出维度dvdv, htht是第tt个用户行为的带权的特征向量。
    目标item representation直接通过embedding lookup得到,这个embedding矩阵V′V′是单独的一个矩阵,用于输出端,和输入端的item使用的embedding矩阵VV不同(类似于word2vec[6]中一个单词有输入和输出两种表征)。有了user representation和item representation,我们用内积来表征U2I相关性:

    图片

    我们希望rr越大代表相关性越强,从而对CTR预测有正向的效果。然后从反向传播的角度考虑,仅仅通过点击label的监督很难学出这样的效果。另外,embedding矩阵V′V′的学习完全依赖于唯一的相关性单元rr。基于以上两点,我们提出了DeepMatch网络(即图中最后侧的Auxiliary Match Network),引入用户行为作为label监督User-to-Item网络的学习。

    DeepMatch网络的任务是根据前T−1T−1个行为预测第TT个行为,是一个大规模多分类任务,有多少候选商品就有多个分类。根据上述用户表征的形式,我们可以获得前T−1T−1个用户行为对应的user representation,记作uT−1∈RdvuT−1∈Rdv。用户在发生这T−1T−1个行为后,下一个点击商品jj的概率可以用softmax函数来定义:

    图片

    其中v′j∈Rdvvj′∈Rdv第jj个商品的(输出)表征。目标商品的输出表征 V′∈RK×dvV′∈RK×dv实际上就是softmax层的参数。以交叉熵为损失函数,我们有以下损失:

    图片

    其中yij∈{0,1}yji∈{0,1}代表第II个样本的第jj个商品的label,pijpji是相应的预测结果,KK是不同的分类数,也就是商品数。yij=1yji=1当且仅当商品jj是用户行为序列中的第TT个行为。考虑到softmax的计算量太大,正比于商品总数KK,采用negative sampling的方法来简化计算,损失变为如下形式:

    图片

    其中σ(⋅)σ(⋅)是sigmoid 函数, v′ovo′是正样本, v′jvj′是负样本, kk是采用的负样本数,远小于总体商品总数KK。DeepMatch的loss会加到MLP最终的分类loss上。DeepMatch网络会促使更大的内积rr代表更强的相关性,从而帮助模型的训练。实际上,User-to-Item Network是Ranking模型和Matching模型以统一的方式进行联合训练。这和简单地将召回阶段的match_type、match_score等特征加入到排序模型中不同。召回阶段通常是多路召回,不同召回方式的分数不在同一个metric下,无法直接比较(比如swing和DeepMatch的分数不能直接比较)。DMR通过User-to-Item网络能够针对任意给定的目标商品表征U2I相关性,且可以相互比较。

    Item-to-Item网络

    User-to-Item网络通过内积直接表征U2I相关性,而Item-to-Item网络通过计算I2I相似度间接表征U2I相关性。回忆一下DIN[1]等模型中的target attention,即以目标商品为query对用户行为序列做attention,区分出行为的重要程度。我们可以把它理解成一个I2I的相似度计算,和目标商品更相似的用户行为商品获得更高的权重,从而主导pooling后的特征向量。基于这样的理解,我们将所有的权重(softmax归一化之前)求和就得到了另一种U2I相关性表达。公式如下:

    Item-to-Item网络使用additive attention[5]形式计算,区别于User-to-Item的内积形式,可以让增强表征能力。

    除了U2I相关性表征,Item-to-Item网络也将target attention后的用户表征输入到MLP中。DMR如果没有U2I相关性表征以及positional encoding,则和DIN[1]模型基本相同。

    实验

    我们在阿里妈妈的公开数据集,以及1688为你推荐的生产数据集上做了一系列实验,验证模型整体的效果并且探索某个模块对模型的影响。

    离线实验

    图片

    线上实验

    我们在1688为你推荐上线DMR模型,对比模型是DIN[1](我们上一个版本的CTR模型),CTR相对提升5.5%,DPV相对提升12.8%,目前已经全量。

    成果和展望

    最初产生融合Matching和Ranking的想法是在4月份的时候,通过实验不断完善,在8月份拿到不错的线上效果,9月份论文投稿(Deep Match to Rank Model for Personalized Click-Through Rate Prediction),11月被AAAI-20录用(Oral)。背后是点滴的积累和团队的帮助。

    DMR提供了一个Matching和Ranking联合训练的框架,U2I相关性表征的模块可以很容易嵌到现有的CTR模型中,相当于在你原来的模型上加了一些有效的特征。我们后续的CTR模型迭代会基于DMR的框架不断加入新的改进。

    参考资料

    [1] Deep Interest Network for Click-Through Rate Prediction - KDD18
    [2] Deep Interest Evolution Network for Click-Through Rate Prediction - AAAI19
    [3] Deep Neural Networks for YouTube Recommendations - ResSys16
    [4] Attention Is All You Need - NIPS17
    [5] Neural Machine Translation by Jointly Learning to Align and Translate - ICLR15
    [6] Distributed Representations of Words and Phrases and their Compositionality - NIPS13
    [7] NAIS - Neural Attentive Item Similarity Model for Recommendation - TKDE18

    展开全文
  • 基于深度学习的CTR预估,从FM推演各深度学习CTR预估模型
  • 欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~作者:辛俊波 | 腾讯 应用研究员一、前言深度学习凭借其强大的表达能力和灵活的网络结构在NLP、...本文就近几年CTR预估领域中学术界的经典方法进行探究, ...

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~

    作者:辛俊波 | 腾讯 应用研究员

    一、前言

    深度学习凭借其强大的表达能力和灵活的网络结构在NLP、图像、语音等众多领域取得了重大突破。在广告领域,预测用户点击率(Click Through Rate,简称CTR)领域近年也有大量关于深度学习方面的研究,仅这两年就出现了不少于二十多种方法。本文就近几年CTR预估领域中学术界的经典方法进行探究, 并比较各自之间模型设计的初衷和各自优缺点。通过十种不同CTR深度模型的比较,不同的模型本质上都可以由基础的底层组件组成。

    本文中出现的变量定义:

    ​ • n: 特征个数,所有特征one-hot后 连接起来的整体规模大小

    ​ • f: 特征field个数,表示特征类别有多少个

    ​ • k: embedding层维度,在FM中是隐向量维度

    ​ • H1: 深度网络中第一个隐层节点个数,第二层H2,以此类推。

    二、深度学习模型

    1. Factorization-machine(FM)

    ​ FM模型可以看成是线性部分的LR,还有非线性的特征组合xixj交叉而成,表示如下:

    1460000016742051

    其中vi是第i维特征的隐向量,长度k<

    1460000016742052?w=1304&h=644图1 FM模型结构

    FM = LR+ embedding

    待学习的参数如下:

    (1)LR部分: 1+n

    (2)embedding 部分:n*k

    FM下文中将作为各种网络模型的基础组件

    2. Deep Neural Network(DNN)

    图2是经典的DNN网络, 结构上看就是传统的多层感知机(MultiLayer Perceptron,简称MLP)。在MLP网络中,输入是原始的特征n维特征空间,假设第一层隐层节点数为H1,第二层为H2,以此类推。在第一层网络中,需要学习的参数就是n*H1。对于大多数CTR模型来说,特征体系都极其庞大而且稀疏,典型的特征数量级n从百万级到千万级到亿级甚至更高,这么大规模的n作为网络输入在ctr预估的工业界场景中是不可接受的。下面要讲到的大多数深度学习CTR网络结构,都围绕着如何将DNN的高维离散输入,通过embedding层变成低维稠密的输入工作来展开。

    1460000016742053?w=560&h=279图2 DNN模型结构

    DNN待学习参数: nH1+H1H2+H2H3+H3o(o为输出层大小,在ctr预估中为1)

    DNN(后文称MLP)也将作为下文各种模型的基础组件之一

    3. Factorisation-machine supported Neural Networks (FNN)

    在上述的DNN中,网络的原始输入是全部原始特征,维度为n,通常都是百万级以上。然而特征维度n虽然空间巨大,但如果归属到每个特征所属的field(维度为f),通常f维度会小很多。如果有办法将每个特征用其所属的field来表示,原始输入将大大减少不少。Factorisation-machine supported Neural Networks,简称FNN就是基于这种思想提出来的。

    1460000016742054?w=1330&h=928图3 FNN模型结构

    FNN假设每个field有且只有一个值为1,其他均为0。x为原始输入的特征,它是大规模离散稀疏的。它可以分成n个field,每一个field中,只有一个值为1,其余都为0(即one hot)。field i的输入可以表示成 x[start_i: end_i], W0i

    为field i的embedding矩阵。Zi 为embedding后的向量,是一个k维的向量,它由一次项wi ,二次项vi=(vi1,vi2,…vik) 组成,其中k是FM中二次项的向量的维度。而后面的l1,l2则为神经网络的全连接层的表示。

    除此之外,FNN还具有以下几个特点:

    Ø FM参数需要预训练

    ​ FM部分的embedding需要预先进行训练,所以FNN不是一个end-to-end模型。在其他论文中,有试过不用FM初始化embedding, 而用随机初始化的方法,要么收敛速度很慢,要么无法收敛。有兴趣的同学可以实验验证下。

    Ø 无法拟合低阶特征

    ​ FM得到的embedding向量直接concat连接之后作为MLP的输入去学习高阶特征表达,最终的DNN输出作为ctr预估值。因此,FNN对低阶信息的表达比较有限。

    Ø 每个field只有一个非零值的强假设

    ​ FNN假设每个fileld只有一个值为非零值,如果是稠密原始输入,则FNN失去意义。对于一个fileld有几个非零值的情况,例如用户标签可能有多个,一般可以做average/sum/max等处理。

    FNN = LR + DEEP = LR + embedding + MLP

    (1)LR部分: 1+n

    (2)embedding部分: n*k

    (3)MLP部分: fkH1+H1*H2+H2

    ​ 可以看到,对比DNN,在进入MLP部分之前,网络的输入由n降到了f*k(f为field个数,几十到几百之间,k为隐向量维度,一般0~100)

    4. Product-based Neural Network(PNN)

    FNN的embedding层直接concat连接后输出到MLP中去学习高阶特征。PNN,全称为Product-based Neural Network,认为在embedding输入到MLP之后学习的交叉特征表达并不充分,提出了一种product layer的思想,既基于乘法的运算来体现体征交叉的DNN网络结构,如图4所示。

    1460000016742055?w=1268&h=791图3 PNN模型结构

    ​ 对比FNN网络,PNN的区别在于中间多了一层Product Layer层。Product Layer层由两部分组成,左边z为embedding层的线性部分,右边为embedding层的特征交叉部分。除了Product layer不同,PNN和FNN的MLP结构是一样的。这种product思想来源于,在ctr预估中,认为特征之间的关系更多是一种and“且”的关系,而非add"加”的关系。例如,性别为男且喜欢游戏的人群,比起性别男和喜欢游戏的人群,前者的组合比后者更能体现特征交叉的意义。根据product的方式不同,可以分为inner product(IPNN)和outer product(OPNN),如图5所示。

    1460000016742056?w=1128&h=571图5 PNN(左图:IPNN;右图:OPNN)

    Product layer的输出为

    1460000016742057

    PNN = FM + product + MLP

    Ø Inner Product-based Neural Network

    ​ IPNN的叉项使用了内积g(fi, fj) = 。f个filed,两两求内积共计交叉项p部分的参数共f(f-1)/2(f为特征的field个数,原始论文里用的N)个,线性部分z部分参数共fk个。需要学习的参数为:

    ​ (1)FM部分: 1+ n + n*k

    ​ (2)product部分: (fk + f(f-1)/2)*H1

    ​ (3)MLP部分:H1H2+H21

    Ø Outer Product-based Neural Network

    ​ OPNN用矩阵乘法来表示特征的交叉, g(fi, fj)=fifit。f个field两两求矩阵乘法,交叉项p共f(f-1)/2kk个参数。线性部分z部分参数共fk个。需要学习的参数为:

    ​ (1)FM部分: 1+ n + n*k

    ​ (2)product部分: (fk + f(f-1)/2kk)*H1

    ​ (3)MLP部分:H1H2+H21

    5. Wide & Deep Learning(Wide&Deep)

    前面介绍的两种变体DNN结构FNN和PNN,都在embedding层对输入做处理后输入MLP,让神经网络充分学习特征的高阶表达,deep部分是有了,对高阶的特征学习表达较强,但wide部分的表达是缺失的, 模型对于低阶特征的表达却比较有限。google在2016年提出了大名鼎鼎的wide&Deep的结构正是解决了这样的问题。Wide&deep结合了wide模型的优点和deep模型的优点,网络结构如图6所示,wide部分是LR模型,Deep部分是DNN模型。

    1460000016742058图6 Wide&Deep 模型结构

    在这个经典的wide&deep模型中,google提出了两个概念,generalization(泛化性)和memory(记忆性)

    Ø Memory(记忆性)

    wide部分长处在于学习样本中的高频部分,优点是模型的记忆性好,对于样本中出现过的高频低阶特征能够用少量参数学习;缺点是模型的泛化能力差,例如对于没有见过的ID类特征,模型学习能力较差。

    Ø Generalization(泛化性)

    deep部分长处在于学习样本中的长尾部分,优点是泛化能力强,对于少量出现过的样本甚至没有出现过的样本都能做出预测(非零的embedding向量);缺点是模型对于低阶特征的学习需要用较多参才能等同wide部分效果,而且泛化能力强某种程度上也可能导致过拟合出现bad case.

    除此之外,wide&deep模型还有如下特点

    Ø 人工特征工程

    LR部分的特征,仍然需要人工设计才能保证一个不错的效果。因为LR部分是直接作为最终预测的一部分,如果作为wide部分的LR特征工程做的不够完善,将影响整个wide&deep的模型精度

    Ø 联合训练

    模型是end-to-end结构,wide部分和deep部分是联合训练的

    Ø embedding层deep部分单独占有

    LR部分直接作为最后输出,因此embedding层是deep部分独有的。

    wide&deep = LR + embedding + MLP

    ​ (1)LR部分: 1+n

    ​ (2)embedding部分:n*k

    ​ (3)MLP部分: fkH1 + H1H2 + H21

    6. Factorization-Machine based Neural Network (deepFM)

    google提出的wide&deep框架固然强大,但由于wide部分是个LR模型,仍然需要人工特征工程。但wide&deep给整个学术界和工业界提供了一种框架思想。基于这种思想,华为诺亚方舟团队结合FM相比LR的特征交叉的功能,将wide&deep部分的LR部分替换成FM来避免人工特征工程,于是有了deepFM,网络结构如图6所示。

    1460000016742059?w=1444&h=704图7 DeepFM模型结构

    比起wide&deep的LR部分,deeFM采用FM作为wide部分的输出,FM部分如图8所示。

    1460000016742060?w=523&h=285

    1460000016742061图8 deepFM模型中的FM部分结构

    除此之外,deepFM还有如下特点:

    Ø 低阶特征表达

    wide部分取代WDL的LR,比FNN和PNN相比能捕捉低阶特征信息

    Ø embedding层共享

    wide&deep部分的embedding层得需要针对deep部分单独设计;而在deepFM中,FM和DEEP部分共享embedding层,FM训练得到的参数既作为wide部分的输出,也作为DNN部分的输入。

    Ø end-end训练

    embedding和网络权重联合训练,无需预训练和单独训练

    deepFM = FM + embedding + DNN

    (1)FM部分: 1+n

    (2)embedding部分:n*k

    (3)DNN部分: fkH1 + H1*H2+H1

    通过embedding层后,FM部分直接输出没有参数需要学习,进入DNN部分的参数维度从原始n维降到f*k维。

    7. Neural Factorization Machines (NFM)

    ​ 前面的deepFM在embedding层后把FM部分直接concat起来(f*k维,f个field,每个filed是k维向量)作为DNN的输入。Neural Factorization Machines,简称NFM,提出了一种更加简单粗暴的方法,在embedding层后,做了一个叫做BI-interaction的操作,让各个field做element-wise后sum起来去做特征交叉,MLP的输入规模直接压缩到k维,和特征的原始维度n和特征field维度f没有任何关系。网络结构如图9所示。

    1460000016742062?w=906&h=950图9 NFM模型结构

    这里论文只画出了其中的deep部分, wide部分在这里省略没有画出来。Bi-interaction听名字很高大上,其实操作很简单:就是让f个field两两element-wise相乘后,得到f*(f-1)/2个向量,然后直接sum起来,最后得到一个k维的向量。所以该层没有任何参数需要学习。

    NFM = FM + embedding + MLP

    需要学习的参数有:

    (1)FM部分: 1+n

    (2)embedding部分:n*k

    (3)MLP部分: kH1 + H1H2+…+Hl*1

    NFM在embedding做了bi-interaction操作来做特征的交叉处理,优点是网络参数从n直接压缩到k(比FNN和deepFM的f*k还少),降低了网络复杂度,能够加速网络的训练得到模型;但同时这种方法也可能带来较大的信息损失。

    8. Attention Neural Factorization Machines (AFM)

    ​ 前面提到的各种网络结构中的FM在做特征交叉时,让不同特征的向量直接做交叉,基于的假设是各个特征交叉对ctr结果预估的贡献度是一样的。这种假设其实是不合理的, 不同特征在做交叉时,对ctr预估结果的贡献度是不一样的。Attention Neural Factorization Machines,简称NFM模型,利用了近年来在图像、NLP、语音等领域大获成功的attention机制,在前面讲到的NFM基础上,引入了attention机制来解决这个问题。AFM的网络结构如图10所示。和NFM一样,这里也省略了wide部分,只画出了deep部分结构。

    1460000016742063图10 AFM模型结构

    AFM的embedding层后和NFM一样,先让f个field的特征做了element-wise product后,得到f*(f-1)/2个交叉项。和NFM直接把这些交叉项sum起来不同,AFM引入了一个Attention Net,认为这些交叉特征项每个对结果的贡献是不同的,例如xi和xj的权重重要度,用aij来表示。从这个角度来看,其实AFM其实就是个加权累加的过程。Attention Net部分的权重aij不是直接学习,而是通过如下公式表示

    1460000016742064?w=618&h=184

    1460000016742065?w=466&h=62

    这里t表示attention net中的隐层维度,k和前面一样,为embedding层的维度。所以这里需要学习的参数有3个,W, b, h,参数个数共tk+2t个。得到aij权重后,对各个特征两两点积加权累加后,得到一个k维的向量,引入一个简单的参数向量pT,维度为k进行学习,和wide部分一起得到最终的AFM输出。

    1460000016742066

    总结AFM的网络结构来说,有如下特点:

    Ø Attention Network

    AFM的亮点所在,通过一个attention net生成一个关于特征交叉项的权重,然后将FM原来的二次项直接累加,变成加权累加。本质上是一个加权平均,学习xjxj的交叉特征重要性

    Ø Deep Network

    没有deep,卒。

    Attention net学习得到的交叉项直接学些个pt参数就输出了,少了DNN部分的表达,对高阶特征部分的进一步学习可能存在瓶颈。另外,FFM其实也引入了field的概念去学习filed和featrue之间的权重。没有了deep 部分的AFM,和优化的FFM上限应该比较接近。

    AFM = FM + embedding + attention + MLP(一层)

    需要学习的参数有:

    (1)FM部分参数:1+n

    (2)Embedding部分参数: n*k

    (3)Attention Network部分参数: kt+t2

    (4)MLP部分参数:k*1

    9. Deep&CrossNetwork(DCN)

    在ctr预估中,特征交叉是很重要的一步,但目前的网络结构,最多都只学到二级交叉。LR模型采用原始人工交叉特征,FM自动学习xi和xj的二阶交叉特征,而PNN用product方式做二阶交叉,NFM和AFM也都采用了Bi-interaction的方式学习特征的二阶交叉。对于更高阶的特征交叉,只有让deep去学习了。为解决这个问题,google在2017年提出了Deep&Cross Network,简称DCN的模型,可以任意组合特征,而且不增加网络参数。图11为DCN的结构。

    1460000016742067图10 DCN模型结构

    整个网络分4部分组成:

    (1)Embedding and stacking layer

    之所以不把embedding和stacking分开来看,是因为很多时候,embedding和stacking过程是分不开的。前面讲到的各种 XX-based FM 网络结构,利用FM学到的v向量可以很好的作为embedding。而在很多实际的业务结构,可能已经有了提取到的embedding特征信息,例如图像的特征embedding,text的特征embedding,item的embedding等,还有其他连续值信息,例如年龄,收入水平等,这些embedding向量stack在一起后,一起作为后续网络结构的输入。当然,这部分也可以用前面讲到的FM来做embedding。为了和原始论文保持一致,这里我们假设X0向量维度为d(上文的网络结构中为k),这一层的做法就是简答的把各种embedding向量concat起来。

    1460000016742068?w=598&h=96

    (2)Deep layer netwok

    在embedding and stacking layer之后,网络分成了两路,一路是传统的DNN结构。表示如下

    1460000016742069?w=414&h=88

    为简化理解,假设每一层网络的参数有m个,一共有Ld层,输入层由于和上一层连接,有dm个参数(d为x0向量维度),后续的Ld-1层,每层需要m(m+1)个参数,所以一共需要学习的参数有 dm+m(m+1)*(Ld-1)。最后的输出也是个m维向量Hl2

    (3)Cross layer network

    ​ Embedding and stacking layer输入后的另一路就是DCN的重点工作了。假设网络有L1层,每一层和前一层的关系可以用如下关系表示

    1460000016742070

    可以看到f是待拟合的函数,xl即为上一层的网络输入。需要学习的参数为wl和bl,因为xl维度为d, 当前层网络输入xl+1也为d维,待学习的参数wl和bl也都是d维度向量。因此,每一层都有2*d的参数(w和b)需要学习,网络结构如下。

    1460000016742071

    经过Lc层的cross layer network后,在该layer最后一层Lc层的输出为Lc2的d维向量

    (4)Combination Output Layer

    经过crossnetwork的输出XL1(d维)和deep network之后的向量输入(m维)直接做concat,变为一个d+m的向量,最后套一个LR模型,需要学习参数为1+d+m。

    总结起来,DCN引入的crossnetwork理论上可以表达任意高阶组合,同时每一层保留低阶组合,参数的向量化也控制了模型的复杂度。

    DCN = embedding + cross + deep + LR

    待学习参数有:

    (1)embedding部分参数: 根据情况而定

    (2)cross部分参数:2dLc(Lc为cross网路层数)

    (3)deep部分参数:d(m+1)+m(m+1)*(Ld-1)(Ld为深度网络层数,m为每层网络参数)

    (4)LR 部分参数:1+d+m

    10. Deep Interest Network (DIN)

    ​ 最后介绍阿里在2017年提出的Deep Interest Network,简称DIN模型。与上面的FNN,PNN等引入低阶代数范式不同,DIN的核心是基于数据的内在特点,引入了更高阶的学习范式。用户的兴趣是多种多样的,从数学的角度来看,用户的兴趣在兴趣空间是一个多峰分布。在预测ctr时,用户embedding表示的兴趣维度,很多是和当前item是否点击无关的,只和用户兴趣中的局部信息有关。因此,受attention机制启发,DIN在embedding层后做了一个action unit的操作,对用户的兴趣分布进行学习后再输入到DNN中去,网络结构如图12所示

    1460000016742072?w=1163&h=660图12 DIN模型结构

    DIN把用户特征、用户历史行为特征进行embedding操作,视为对用户兴趣的表示,之后通过attention network,对每个兴趣表示赋予不同的权值。

    • Vu:表示用户最终向量

    • Vi:表示用户兴趣向量(shop_id, good_id..)

    • Va:表示广告表示向量

    • Wi: 对于候选广告,attention机制中该兴趣的权重

    1460000016742073

    可以看到,对于用户的每个兴趣向量Vi,都会通过学习该兴趣的权重Vi, 来作为最终的用户表示。

    三、写在最后

    前面介绍了10中深度学习模型的网络结构,总结起来可以用如下的所表示

    1460000016742074?w=1210&h=720

    各种CTR深度模型看似结构各异,其实大多数可以用如下的通用范式来表达,

    Ø input->embedding

    把大规模的稀疏特征ID用embedding操作映射为低维稠密的embedding向量

    Ø embedding层向量

    concat, sum, average pooling等操作,大部分CTR模型在该层做改造

    Ø embedding->output

    通用的DNN全连接框架,输入规模从n维降为k*f维度甚至更低。

    1460000016742075?w=720&h=547图3 通用深度学习模型结构

    其中,embedding vector这层的融合是深度学习模型改造最多的地方,该层是进入深度学习模型的输入层,embedding融合的质量将影响DNN模型学习的好坏。个人总结大体有以下4种操作,当然后续可能会有越来越多其他的变形结构。

    1460000016742076?w=972&h=417图14 embedding层融合方式

    另外,DNN部分,业界也有很多或state-of-art或很tricky的方法,都可以在里面进行尝试,例如dropout,在NFM的Bi-interaction中可以尝试以一定概率dropout掉交叉特征增前模型的泛化能力等。

    写在最后

    ​ ctr预估领域不像图像、语音等领域具有连续、稠密的数据以及空间、时间等的良好局部相关性,ctr预估中的大多数输入都是离散而且高维的,特征也分散在少量不同的field上。要解决这样的一个深度学习模型,面临的第一个问题是怎么把输入向量用一个embedding层降维策划那个稠密连续的向量,如本文介绍的用FM去做预训练,或者和模型一起联合训练,或者其他数据源提取的embedding特征向量去做concat。其次,在宽和深的大战中,在google在提出了wide&deep的模型框架后,这套体系基本已成为业内的基本框架。无论wide部分或者deep怎么改造,其实本质上还是一些常见组件的结合,或者改造wide,或者改造deep,或者在wide和deep的结合过程中进行改造。

    ctr预估领域方法变化层出不穷,但万变不离其宗,各种模型本质上还是基础组件的组合,如何结合自己的业务、数据、应用场景去挑选合适的模型应用,可能才是真正的难点所在。

    四、参考文献

    [1]Factorization Machines

    [2]Wide & Deep Learning for Recommender Systems

    [3]Deep Learning over Multi-Field Categorical Data: A Case Study on User Response Prediction

    [4]Product-based Neural Networks for User Response Prediction

    [5]DeepFM: A Factorization-Machine based Neural Network for CTR Prediction

    [6]Neural Factorization Machines for Sparse Predictive Analytics

    [7] Attentional Factorization Machines: Learning the Weight of Feature Interactions via Attention Networks

    [8]Deep & Cross Network for Ad Click Predictions

    [9]Deep Interest Network for Click-Through Rate Prediction

    此文已由作者授权腾讯云+社区发布,更多原文请点击

    搜索关注公众号「云加社区」,第一时间获取技术干货,关注后回复1024 送你一份技术课程大礼包!

    海量技术实践经验,尽在云加社区!

    展开全文
  • CTR预估模型讲义pdf

    2020-10-18 22:29:01
    CTR预估模型讲义pdf
  • CTR预估神器deepFM

    2019-07-26 17:44:04
    deepfm CTR预估 解决高维稀疏矩阵训练深度网络带来的问题
  • 深度学习在CTR预估的应用的PPT,目录如下: 1、当深度学习遇到CTR预估 2、传统主流CTR预估方法 3、深度学习基础模型 4、深度学习CTR预估模型 5、互联网公司深度学习CTR案例
  • 特征工程与CTR预估

    千次阅读 多人点赞 2021-05-09 10:11:36
    特征工程与CTR预估缺失值如何处理缺失值判断缺失值删除缺失值填充连续特征归一化连续特征离散化自定义分箱等距分箱等频分箱离散特征OneHot编码ID特征Embedding特征构造方法理解AUC指标课后练习 点击率(Click-...
  • kaggle CTR预估

    2017-05-18 10:54:00
    参考涛哥之前做过的CTR预估project,学习下CTR预估的相关知识:http://blog.csdn.net/hero_fantao/article/category/6877765 目标:本周末完成CTR预估项目 转载于:...
  • CTR预估模型原文汇总

    2018-12-08 23:59:51
    CTR预估相关模型原文汇总,其中包括DeepFM、AFM、DIN、DIEN、FM、FFM、FNN、NFM、Wide&Deep;、PNN等模型。
  • CTR预估:点击率预估

    2019-08-26 21:08:26
    找到了一篇比较直白的解释: CTR预估解析
  • CTR注:点击率预估的数据通常是正样本远少于负样本,因此性能评估一般使用准确率/召回率或AUC;点击率的场景每天都在变化,因此要求模型更新快,所以模型不能太复杂,实际应用中,logistic回归通常就能满足工业需求...
  • 深度CTR预估

    2020-09-23 20:06:02
    传统CTR预估一般是特征工程+LR/FM的组合,这种通过大量特征工程来提高预测效果的工作费时费力,且构造过程不具有通用性。此外,传统的人工特征工程很难处理开放式的特征(如用户ID),而这些特征往往能够为模型提供...
  • CTR预估】简单介绍

    2020-10-12 17:24:19
    目录一、关于CTR预估什么是CTR预估为什么要进行CTR评估如何进行CTR预估什么是FM 一、关于CTR预估 什么是CTR预估 CTR(Click-Through-Rate)为点击率 广告平台关注的指标,ECPM(earning cost per mille) 用该指标...
  • CTR预估的几种方式

    万次阅读 2017-12-11 20:46:55
    1.CTR预估CTR预估是计算广告中最核心的算法之一,那么CTR预估是指什么呢?简单来说,CTR预估是对每次广告的点击情况做出预测,预测用户是点击还是不点击。具体定义可以参考 CTR. CTR预估和很多因素相关,比如历史...
  • CTR预估模型:神经网络模型讲义pdf
  • 文 | Ruhjkg@知乎编 | 小鹿鹿lulu本文已获作者授权,禁止二次转载前言CTR(click through rate)预估模型是广告推荐领域的核心问题。早期主要是使用LR(线性...
  • CTR预估的常用方法

    2019-07-09 19:29:00
    CTR预估模型就是综合考虑各种因素、特征,在大量历史数据上训练得到的模型。 CTR预估的训练样本一般从历史log、离线特征库获得。 样本标签相对容易,用户点击标记为1,没有点击标记为0。特征则会考虑很多,例如...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,709
精华内容 683
关键字:

ctr预估