作者 | 风雨中的小七

CTR学习笔记系列的第一篇,总结在深度模型称王之前经典LR,FM, FFM模型,这些经典模型后续也作为组件用于各个深度模型。模型分别用自定义Keras Layer和estimator来实现,哈哈一个是旧爱一个是新欢。特征工程依赖feature_column实现,这里做的比较简单在后面的深度模型再好好搞。完整代码在这里https://github.com/DSXiangLi/CTR‍‍‍‍‍‍‍‍‍‍‍‍

问题定义

CTR本质是一个二分类问题,









是用户和广告相关特征,










是每个广告是否被点击,基础模型就是一个简单的Logistics Regression

考虑在之后TF框架里logistics可以简单用activation来表示,我们把核心的部分简化为以下
































LR模型

2010年之前主流的CTR模型通常是最简单的logistics regression,模型可解释性强,工程上部署简单快捷。但最大的问题是依赖于大量的手工特征工程。

刚接触特征工程的同学可能会好奇为什么需要计算组合特征?

最开始我只是简单认为越细粒度的聚合特征Bias越小。接触了因果推理后,我觉得更适合用Simpson Paradox里的Confounder Bias来解释,不同聚合特征之间可能会相悖,例如各个年龄段的男性点击率均低于女性,但整体上男性的点击率高于女性。感兴趣的可以看看这篇博客因果推理的春天系列序 - 数据挖掘中的Confounding, Collidar, Mediation Bias

如果即想简化特征工程,又想加入特征组合,肯定就会想到下面的暴力特征组合方式。这个也被称作POLY2模型

但上述











需要学习














个参数,一方面复杂度高,另一方面对高维稀疏特征会出现大量











是0的情况,模型无法学到样本中未曾出现的特征组合pattern,模型泛化性差。

于是降低复杂度,自动选择有效特征组合,以及模型泛化这三点成为后续主要的改进的方向。

GBDT+LR模型

2014年Facebook提出在GBDT叠加LR的方法,敲开了特征工程模型化的大门。GBDT输出的不是预测概率,而是每一个样本落在每一颗子树哪个叶节点的一个0/1矩阵。在只保留和target相关的有效特征组合的同时,避免了手工特征组合需要的业务理解和人工成本。

相较特征组合,我更喜欢把GBDT输出的特征向量,理解为根据target,对样本进行了聚类/降维,输出的是该样本所属的几个特定人群组合,每一棵子树都对应一种类型的人群组合。

但是!GBDT依旧存在泛化问题,因为所有叶节点的选择都依赖于训练样本,并且GBDT在离散特征上效果比较有限。同时也存在经过GBDT变换得到的特征依旧是高维稀疏特征的问题。

FM模型

2010年Rendall提出的因子分解机模型(FM)为降低计算复杂度,为增加模型泛化能力提供了思路

原理

FM模型将上述暴力特征组合直接求解整个权重矩

















,转化为求解权重矩阵的隐向量













,这一步会大大增加模型泛化能力,因为权重矩阵不再完全依赖于样本中的特定特征组合,而是可以通过特征间的相关关系间接得到。同时隐向量把模型需要学习的参数数量从














降低到





同时FM通过下面的trick,把拟合过程的计算复杂度从











降低到线性复杂度








代码实现-自定义Keras Layer

class FM_Layer(Layer):"""Input:factor_dim: latent vector size input_shape: raw feature sizeactivationoutput:FM layer output"""def __init__(self, factor_dim, activation = None, **kwargs):self.factor_dim = factor_dimself.activation = activations.get(activation) # if None return linear, else return function of identifierself.InputSepc = InputSpec(ndim=2) # Specifies input layer attribute. one Inspec for each inputsuper(FM_Layer,self).__init__(**kwargs)def build(self, input_shape):"""input:tuple of input_shapeoutput:w: linear weightv: latent vectorb: linear Biasfunc:define all the necessary variable here"""assert len(input_shape) >=2input_dim = int(input_shape[-1])self.w = self.add_weight(name = 'w0', shape = (input_dim, 1),initializer = 'glorot_uniform',trainable = True)self.b = self.add_weight(name = 'bias', shape = (1, ),initializer = 'zeros',trainable = True)self.v = self.add_weight(name = 'hidden_vector', shape = (input_dim, self.factor_dim),initializer = 'glorot_uniform',trainable = True)super(FM_Layer, self).build(input_shape)# set self.built=Truedef call(self, x):"""input:x(previous layer output)output:core calculation of the FM layerfunc:core calculcation of layer goes here"""linear_term = K.dot(x, self.w) + self.b# Embedding之和,Embedding内积: (1, input_dim) * (input_dim, factor_dim) = (1, factor_dim)sum_square = K.pow(K.dot(x, self.v),2)square_sum = K.dot(K.pow(x, 2), K.pow(self.v, 2))# (1, factor_dim) -> (1)quad_term = K.mean( (sum_square - square_sum), axis=1, keepdims = True) #output = self.activation((linear_term+quad_term))return outputdef compute_output_shape(self, input_shape):# tf.keras回传input_shape是tf.dimension而不是tuple, 所以要cast成intreturn (int(input_shape[0]), self.output_dim)

FM和MF的关系

Factorizaton Machine 和Matrix Factorization听起来就很像,MF也确实是FM的一个特例。MF是通过对矩阵进行因子分解得到隐向量,但因为只适用于矩阵所以特征只能是二维,常见的是(user_id, item_id)组合。而同样是得到隐向量,FM将矩阵展平把离散特征都做one-hot,因此支持任意数量的输入特征。

FM和Embedding的关系

Embedding最常见于NLP中,把词的高维稀疏特征映射到低维矩阵embedding中,然后用交互函数,例如向量内积来表示词与词之间的相似度。而实际上FM计算的隐向量也是一种Embedding 的拟合方法,并且限制了只用向量内积作为交互函数。上述













得到的就是Embedding向量本身。

FFM

2015年提出的FFM模型在FM的基础上加入了Field的概念

原理

上述FM学到的权重矩阵V是每个特征对应一个隐向量,两特征组合通过隐向量内积的形式来表达。FFM提出同一个特征和不同Field的特征组合应该有不同的隐向量,因此













变成















其中F是特征所属Field的个数。以下数据中country,Data,Ad_type就是Field








FM两特征交互的部分被改写为以下,因此需要学习的参数数量从nk变为nf*k。并且在拟合过程中无法使用上述trick因此复杂度从FM的








上升为











代码实现-自定义model_fn

def model_fn(features, labels, mode, params):"""Field_aware factorization machine for 2 classes classification"""feature_columns, field_dict = build_features()field_dim = len(np.unique(list(field_dict.values())))input = tf.feature_column.input_layer(features, feature_columns)input_dim = input.get_shape().as_list()[-1]with tf.variable_scope('linear'):init = tf.random_normal( shape = (input_dim,2) )w = tf.get_variable('w', dtype = tf.float32, initializer = init, validate_shape = False)b = tf.get_variable('b', shape = [2], dtype= tf.float32)linear_term = tf.add(tf.matmul(input,w), b)tf.summary.histogram( 'linear_term', linear_term )with tf.variable_scope('field_aware_interaction'):init = tf.truncated_normal(shape = (input_dim, field_dim, params['factor_dim']))v = tf.get_variable('v', dtype = tf.float32, initializer = init, validate_shape = False)interaction_term = tf.constant(0, dtype =tf.float32)# iterate over all the combination of featuresfor i in range(input_dim):for j in range(i+1, input_dim):interaction_term += tf.multiply(tf.reduce_mean(tf.multiply(v[i, field_dict[j],: ], v[j, field_dict[i],:])) ,tf.multiply(input[:,i], input[:,j]))interaction_term = tf.reshape(interaction_term, [-1,1])tf.summary.histogram('interaction_term', interaction_term)with tf.variable_scope('output'):y = tf.math.add(interaction_term, linear_term)tf.summary.histogram( 'output', y )if mode == tf.estimator.ModeKeys.PREDICT:predictions = {'predict_class': tf.argmax(tf.nn.softmax(y), axis=1),'prediction_prob': tf.nn.softmax(y)}return tf.estimator.EstimatorSpec(mode = tf.estimator.ModeKeys.PREDICT,predictions = predictions)cross_entropy = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits( labels=labels, logits=y ))if mode == tf.estimator.ModeKeys.TRAIN:optimizer = tf.train.AdamOptimizer(learning_rate = params['learning_rate'])train_op = optimizer.minimize(cross_entropy,global_step = tf.train.get_global_step())return tf.estimator.EstimatorSpec(mode, loss = cross_entropy, train_op = train_op)else:eval_metric_ops = {'accuracy': tf.metrics.accuracy(labels = labels,predictions = tf.argmax(tf.nn.softmax(y), axis=1)),'auc': tf.metrics.auc(labels = labels ,predictions = tf.nn.softmax(y)[:,1]),'pr': tf.metrics.auc(labels = labels,predictions = tf.nn.softmax(y)[:,1],curve = 'PR')}return tf.estimator.EstimatorSpec(mode, loss = cross_entropy, eval_metric_ops = eval_metric_ops)

参考资料

  1. S. Rendle, “Factorization machines,” in Proceedings of IEEE International Conference on Data Mining (ICDM), pp. 995–1000, 2010

  2. Yuchin Juan,Yong Zhuang,Wei-Sheng Chin,Field-aware Factorization Machines for CTR Prediction。

  3. 盘点前深度学习时代阿里、谷歌、Facebook的CTR预估模型

  4. 前深度学习时代CTR预估模型的演化之路:从LR到FFM

  5. 推荐系统召回四模型之:全能的FM模型

  6. 主流CTR预估模型的演化及对比

  7. 深入FFM原理与实践

一起交流

想和你一起学习进步!『NewBeeNLP』目前已经建立了多个不同方向交流群(机器学习 / 深度学习 / 自然语言处理 / 搜索推荐 / 图网络 / 面试交流 / 等),名额有限,赶紧添加下方微信加入一起讨论交流吧!(注意一定要备注信息才能通过)

END -

NLP算法求建议 | 腾讯 VS 美团

2021-04-23

一年级算法工程师的工作总结

2021-04-22

推荐系统技术演进趋势:排序篇

2021-04-21

[211渣硕] 腾讯/阿里/携程 详细NLP算法实习 面经

2021-04-19

CTR学习笔记代码实现1-深度学习的前奏LR-FFM相关推荐

  1. AI Studio 飞桨 零基础入门深度学习笔记4-飞桨开源深度学习平台介绍

    AI Studio 飞桨 零基础入门深度学习笔记4-飞桨开源深度学习平台介绍 深度学习框架 深度学习框架优势 深度学习框架设计思路 飞桨开源深度学习平台 飞桨开源深度学习平台全景 框架和全流程工具 模 ...

  2. 深度学习笔记(1) 深度学习简介

    深度学习笔记(1) 深度学习简介 1. 引言 2. 神经网络 3. 兴起 1. 引言 在机器学习的历史上,一共出现了两种定义: 1956 年,开发了西洋跳棋 AI 程序的 Arthur Samuel ...

  3. 《文哥的学习笔记——推荐系统遇上深度学习》笔记(1~9)

    原地址文哥的学习笔记 本文仅从个人角度进行记录学习,很多内容记录不全面,并且原文提供了代码,建议有需要的读者阅读大佬原文进行学习. 第一篇 FM模型理论和实践: 1.CTR预估(click-throu ...

  4. Udacity 自动驾驶工程师学习笔记(二)——深度学习(1)

    深度学习目录 目录 Lesson01:Neural Netowrks 神经网络 01.神经网络 Neural Network 02.例子:房价 03.Classification Problem 分类 ...

  5. python量化交易学习笔记_Python量化交易学习笔记(45)——深度学习挖短线股5

    前4篇文章分别记录了利用深度学习挖短线股的数据预处理.模型训练.结果预测及策略回测过程,本文记录根据筛选短线股票的过程. 选股流程 1.股票数据下载更新 例如现在是2020年11月23日19:00,我 ...

  6. Python量化交易学习笔记(45)——深度学习挖短线股5

    前4篇文章分别记录了利用深度学习挖短线股的数据预处理.模型训练.结果预测及策略回测过程,本文记录根据筛选短线股票的过程. 选股流程 1.股票数据下载更新 例如现在是2020年11月23日19:00,我 ...

  7. 机器学习处理信号分离_[学习笔记]使用机器学习和深度学习处理信号基础知识...

    参考学习:Signal Generation and Preprocessing 本人只是为了了解信号处理的基础知识而做的学习笔记,涉及深度可能不够,有理解错误的地方请大胆指出,感激不尽 一.信号生成 ...

  8. 基于 OpenVINO™ 的 AI 视觉应用基础课学习笔记(三)深度学习简介

    机器学习与深度学习 机器学习 机器学习(Machine Learning):专门研究计算机怎样模拟或实现人类的学习行为,以获取新知识或技能,重新组织已有的知识结构使之不断改善自身的性能. 是人工智能的 ...

  9. 学习笔记(01):遥感影像深度学习样本制作-计算机视觉工具制作样本

    立即学习:https://edu.csdn.net/course/play/27632/372353?utm_source=blogtoedu 遥感影像深度学习: 1.遥感图像分类------CV中语 ...

最新文章

  1. 生活大爆炸第6季第12集
  2. IT职场最受欢迎的十大晋升秘决
  3. vue 使用fs_node.js中常用的fs文件系统
  4. 程序员离职后躲老家山洞 2 年,敲出 45 万行代码...
  5. netty系列之:Event、Handler和Pipeline
  6. mysql redis geo_利用Redis的Geo功能实现查找附近的位置
  7. RedisTemplate 常用方法、序列化方式、基于 Redis 实现分布式锁
  8. 把实体 转为json 数据格式---jackson 的详细用法_Jackson快速入门
  9. ffmpeg 再编译使用 ffmpeg-gl-transition
  10. Android仿微信语音聊天功能
  11. 简单图形验证码的识别
  12. 论文翻译:《一个包容性设计的具体例子:聋人导向可访问性》
  13. Typora 常用快捷键
  14. 电脑中的耳机插进去没有反应
  15. 支付宝,微信,线上支付流程介绍
  16. hdu4417 Super Mario(树状数组+离线区间操作)
  17. 互联网协议 — Ethernet — 网络数据报文的传输方式
  18. 窗口模式,点按钮防止弹出新弹出页面
  19. ppt如何制作个人简历?
  20. css零到一基础教程006:CSS 颜色

热门文章

  1. SAP License:系统退货处理流程
  2. SAP License:SAP成本收集器两则
  3. 电商Sass平台-商城运营后台原型-仓储管理-订单管理-店铺运营-采购管理-数据分析-交易分析-留存分析-客户管理-用户运营-围栏管理-商品管理-流量分析-电商erp后台管理-用户权限-销量分析
  4. Go语言基础练习题系列1
  5. EZ 2018 06 17 NOIP2018 模拟赛(十九)
  6. [BZOJ3772]精神污染
  7. 程序员如何探索新技术
  8. PNP8550(3.3V DC蜂鸣器) - 原理图系列
  9. 前端开发在uc浏览器上遇到的坑
  10. 视频解码芯片SAA7111A的初始化