背景

这一篇我们从基础的深度ctr模型谈起。我很喜欢Wide&Deep的框架感觉之后很多改进都可以纳入这个框架中。Wide负责样本中出现的频繁项挖掘,Deep负责样本中未出现的特征泛化。而后续的改进要么用不同的IFC让Deep更有效的提取特征交互信息,要么是让Wide更好的记忆样本信息

以下代码针对Dense输入感觉更容易理解模型结构,其他针对spare输入的模型和完整代码
https://github.com/DSXiangLi/CTR

Embedding + MLP

点击率模型最初在深度学习上的尝试是从简单的MLP开始的。把高维稀疏的离散特征做Embedding处理,然后把Embedding拼接作为MLP的输入,经过多层全联接神经网络的非线性变换得到对点击率的预测。

不知道你是否也像我一样困惑过,这个Embedding+MLP究竟学到了什么信息?MLP的Embedding和FM的Embedding学到的是同样的特征交互信息么?最近从大神那里听到一个蛮有说服力的观点,当然keep skeptical,欢迎一起讨论~

mlp可以学到所有特征低阶和高阶的信息表达,但依赖庞大的搜索空间。在样本有限,参数也有限的情况下往往只能学到有限的信息。因此才依赖于基于业务理解的特征工程来帮助mlp在有限的空间下学到更多有效的特征交互信息。FM的向量内积只是二阶特征工程的一种方法。之后针对deep的很多改进也是在探索如何把特征工程的业务经验用于更好的提取特征交互信息

代码实现

def build_features(numeric_handle):
f_sparse = []
f_dense = [] for col, config in EMB_CONFIGS.items():
ind = tf.feature_column.categorical_column_with_hash_bucket(col, hash_bucket_size = config['hash_size'])
one_hot = tf.feature_column.indicator_column(ind)
f_sparse.append(one_hot) # Method1 for numeric feature
if numeric_handle == 'bucketize':
# Method1 'onehot': bucket to one hot
for col, config in BUCKET_CONFIGS.items():
num = tf.feature_column.numeric_column( col )
bucket = tf.feature_column.bucketized_column( num, boundaries=config )
f_sparse.append(bucket)
else :
# Method2 'dense': concatenate with embedding
for col, config in BUCKET_CONFIGS.items():
num = tf.feature_column.numeric_column( col )
f_dense.append(num)
return f_sparse, f_dense @tf_estimator_model
def model_fn(features, labels, mode, params):
sparse_columns, dense_columns = build_features(params['numeric_handle']) with tf.variable_scope('EmbeddingInput'):
embedding_input = []
for f_sparse in sparse_columns:
sparse_input = tf.feature_column.input_layer(features, f_sparse) input_dim = sparse_input.get_shape().as_list()[-1] init = tf.random_normal(shape = [input_dim, params['embedding_dim']]) weight = tf.get_variable('w_{}'.format(f_sparse.name), dtype = tf.float32, initializer = init) embedding_input.append( tf.matmul(sparse_input, weight) ) dense = tf.concat(embedding_input, axis=1, name = 'embedding_concat') # if treat numeric feature as dense feature, then concatenate with embedding. else concatenate wtih sparse input
if params['numeric_handle'] == 'dense':
numeric_input = tf.feature_column.input_layer(features, dense_columns) numeric_input = tf.layers.batch_normalization(numeric_input, center = True, scale = True, trainable =True,
training = (mode == tf.estimator.ModeKeys.TRAIN))
dense = tf.concat([dense, numeric_input], axis = 1, name ='numeric_concat') with tf.variable_scope('MLP'):
for i, unit in enumerate(params['hidden_units']):
dense = tf.layers.dense(dense, units = unit, activation = 'relu', name = 'Dense_{}'.format(i))
if mode == tf.estimator.ModeKeys.TRAIN:
dense = tf.layers.dropout(dense, rate = params['dropout_rate'], training = (mode==tf.estimator.ModeKeys.TRAIN)) with tf.variable_scope('output'):
y = tf.layers.dense(dense, units=1, name = 'output') return y

Wide&Deep

Wide&Deep是在上述MLP的基础上加入了Wide部分。作者认为Deep的部分负责generalization既样本中未出现模式的泛化和模糊查询,就是上面的Embedding+MLP。wide负责memorization既样本中已有模式的记忆,是对离散特征和特征组合做Logistics Regression。Deep和Wide一起进行联合训练。

这样说可能不完全准确,作者在文中也提到wide部分只是用来锦上添花,来帮助Deep增加那些在样本中频繁出现的模式在预测目标上的区分度。所以wide不需要是一个full-size模型,而更多需要业务上判断比较核心的特征和交叉特征。

连续特征的处理

ctr模型大多是在探讨稀疏离散特征的处理,那连续特征应该怎么处理呢?有几种处理方式

  1. 连续特征离散化处理,之后可以做embedding/onehot/cross
  2. 连续特征不做处理,直接和其他离散特征embedding后的vector拼接作为输入。这里要考虑对连续特征进行归一化处理, 不然会收敛的很慢。上面MLP尝试了BatchNorm,Wide&Deep则直接在feature_column里面做了归一化。
  3. 既作为连续特征输入,同时也做离散化和其他离散特征进行交互

连续特征离散化的优缺点
缺点

  1. 信息丢失,丢失多少信息要看桶分的咋样
  2. 平滑度下降,处于分桶边界的特征变动可能带来预测值比较大的波动

优点

  1. 加入非线性,多数情况下连续特征和目标之间都不是线性关系,而是在到达某个阈值对用户存在0/1的影响
  2. 更稳健,可有效避免连续特征中的极值/长尾问题
  3. 特征交互,做离散特征处理后方便进一步做cross特征
  4. 省事...,不需要再考虑啥正不正态要不要做归一化之类的

代码实现

def znorm(mean, std):
def znorm_helper(col):
return (col-mean)/std
return znorm_helper def build_features():
f_onehot = []
f_embedding = []
f_numeric = [] # categorical features
for col, config in EMB_CONFIGS.items():
ind = tf.feature_column.categorical_column_with_hash_bucket(col, hash_bucket_size = config['hash_size'])
f_onehot.append( tf.feature_column.indicator_column(ind))
f_embedding.append( tf.feature_column.embedding_column(ind, dimension = config['emb_size']) ) # numeric features: both in numeric feature and bucketized to discrete feature
for col, config in BUCKET_CONFIGS.items():
num = tf.feature_column.numeric_column(col,
normalizer_fn = znorm(NORM_CONFIGS[col]['mean'],NORM_CONFIGS[col]['std'] ))
f_numeric.append(num)
bucket = tf.feature_column.bucketized_column( num, boundaries=config )
f_onehot.append(bucket) # crossed features
for col1,col2 in combinations(f_onehot,2):
# if col is indicator of hashed bucuket, use raw feature directly
if col1.parents[0].name in EMB_CONFIGS.keys():
col1 = col1.parents[0].name
if col2.parents[0].name in EMB_CONFIGS.keys():
col2 = col2.parents[0].name crossed = tf.feature_column.crossed_column([col1, col2], hash_bucket_size = 20)
f_onehot.append(tf.feature_column.indicator_column(crossed)) f_dense = f_embedding + f_numeric #f_dense = f_embedding + f_numeric + f_onehot
f_sparse = f_onehot #f_sparse = f_onehot + f_numeric return f_sparse, f_dense def build_estimator(model_dir):
sparse_feature, dense_feature= build_features() run_config = tf.estimator.RunConfig(
save_summary_steps=50,
log_step_count_steps=50,
keep_checkpoint_max = 3,
save_checkpoints_steps =50
) dnn_optimizer = tf.train.ProximalAdagradOptimizer(
learning_rate= 0.001,
l1_regularization_strength=0.001,
l2_regularization_strength=0.001
) estimator = tf.estimator.DNNLinearCombinedClassifier(
model_dir=model_dir,
linear_feature_columns=sparse_feature,
dnn_feature_columns=dense_feature,
dnn_optimizer = dnn_optimizer,
dnn_dropout = 0.1,
batch_norm = False,
dnn_hidden_units = [48,32,16],
config=run_config ) return estimator

CTR学习笔记&代码实现系列

https://github.com/DSXiangLi/CTR

CTR学习笔记&代码实现1-深度学习的前奏LR->FFM

参考材料

  1. Weinan Zhang, Tianming Du, and Jun Wang. Deep learning over multi-field categorical data - - A case study on user response prediction. In ECIR, 2016.
  2. Cheng H T, Koc L, Harmsen J, et al. Wide & deep learning for recommender systems[C]//Proceedings of the 1st Workshop on Deep Learning for Recommender Systems. ACM, 2016: 7-10
  3. https://www.jiqizhixin.com/articles/2018-07-16-17
  4. https://cloud.tencent.com/developer/article/1063010
  5. https://github.com/shenweichen/DeepCTR

CTR学习笔记&代码实现2-深度ctr模型 MLP->Wide&Deep的更多相关文章

  1. CTR学习笔记&代码实现3-深度ctr模型 FNN->PNN->DeepFM

    这一节我们总结FM三兄弟FNN/PNN/DeepFM,由远及近,从最初把FM得到的隐向量和权重作为神经网络输入的FNN,到把向量内/外积从预训练直接迁移到神经网络中的PNN,再到参考wide& ...

  2. CTR学习笔记&代码实现5-深度ctr模型 DeepCrossing -> DCN

    之前总结了PNN,NFM,AFM这类两两向量乘积的方式,这一节我们换新的思路来看特征交互.DeepCrossing是最早在CTR模型中使用ResNet的前辈,DCN在ResNet上进一步创新,为高阶特 ...

  3. CTR学习笔记&代码实现4-深度ctr模型 NFM/AFM

    这一节我们总结FM另外两个远亲NFM,AFM.NFM和AFM都是针对Wide&Deep 中Deep部分的改造.上一章PNN用到了向量内积外积来提取特征交互信息,总共向量乘积就这几种,这不NFM ...

  4. CTR学习笔记&代码实现6-深度ctr模型 后浪 xDeepFM/FiBiNET

    xDeepFM用改良的DCN替代了DeepFM的FM部分来学习组合特征信息,而FiBiNET则是应用SENET加入了特征权重比NFM,AFM更进了一步.在看两个model前建议对DeepFM, Dee ...

  5. CTR学习笔记&代码实现1-深度学习的前奏LR->FFM

    CTR学习笔记系列的第一篇,总结在深度模型称王之前经典LR,FM, FFM模型,这些经典模型后续也作为组件用于各个深度模型.模型分别用自定义Keras Layer和estimator来实现,哈哈一个是 ...

  6. GIS案例学习笔记-明暗等高线提取地理模型构建

    GIS案例学习笔记-明暗等高线提取地理模型构建 联系方式:谢老师,135-4855-4328,xiexiaokui#qq.com 目的:针对数字高程模型,通过地形分析,建立明暗等高线提取模型,生成具有 ...

  7. 【PyTorch深度学习】学习笔记之PyTorch与深度学习

    第1章 PyTorch与深度学习 深度学习的应用 接近人类水平的图像分类 接近人类水平的语音识别 机器翻译 自动驾驶汽车 Siri.Google语音和Alexa在最近几年更加准确 日本农民的黄瓜智能分 ...

  8. 深度学习笔记之关于总结、展望、参考文献和Deep Learning学习资源(五)

    不多说,直接上干货! 十.总结与展望 1)Deep learning总结 深度学习是关于自动学习要建模的数据的潜在(隐含)分布的多层(复杂)表达的算法.换句话来说,深度学习算法自动的提取分类需要的低层 ...

  9. [原创]java WEB学习笔记44:Filter 简介,模型,创建,工作原理,相关API,过滤器的部署及映射的方式,Demo

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

随机推荐

  1. moment太重? 那就试试miment--一个超轻量级的js时间库

    介绍 Miment 是一个轻量级的时间库(打包压缩后只有1K),没有太多的方法,Miment的设计理念就是让你以几乎为零的成本快速上手,无需一遍一遍的撸文档 由来 首先 致敬一下Moment,非常好用 ...

  2. Eureka在有虚拟网卡的情况下获取正确的IP

    发现问题 最近项目在Eureka注册时,发现一个问题:注册的IP地址不是 192.168.0.XXX 的网络IP,而是另外一个网段的地址,如图 通过 ipconfig 命令查看本机的IP地址发现,该I ...

  3. A. Reorder the Array

    You are given an array of integers. Vasya can permute (change order) its integers. He wants to do it ...

  4. echarts 图点击事件

    有三种方式,介绍一下,大家学习哈 1.利用tooltip记录信息,使用zr 监听事件,进行事件处理. 这种方法是利用showTip方法或者tooltip的formatter函数记录选中的数据信息,并在 ...

  5. UICollectionViewCell设置阴影

    //@mg:masksToBounds必须为NO否者阴影没有效果 // cell.layer.masksToBounds = NO; cell.layer.contentsScale = [UIScr ...

  6. jenkins操作

    jenkins忘记用户名以及登录密码的解决方法 1.jenkins 根目录下找到config.xml,修改配置  <useSecurity>true</useSecurity> ...

  7. Js数组代替写循环的几个方法

    简介 循环是个不可避免的结构,而且不好复用,同时循环还很难加入其他操作中.更麻烦的是,使用循环就意味着在每一个新的迭代中有更多变化需要响应. 上了循环的控制结构会使代码看起来变得复杂,故而这里提几个替 ...

  8. abp(net core)+easyui+efcore实现仓储管理系统——入库管理之四(四十)

    abp(net core)+easyui+efcore实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统——ABP总体介绍(一) abp(net core)+ ...

  9. vue-router需要注意的点

    1.在编程式导航中,如果提供了path,params会被忽略:需要提供name,或手写完整的带有参数的path;以下写法可取: const  userId = '123'; 1.this.$route ...

  10. 2020年IOS超级签最新实现原理详解

    相信2019年最火的应该就是这个东西了,我也是摸着石头过河,勉强混进了这个行业! 超级签这个东西吧,说白了就是用个人账号分发应用,大致分成以下几个步骤吧 一.使用配置文件获取UDID 苹果公司允许开发 ...