提交 04fbeb5e 编写于 作者: S Superjom

update markdown files

上级 4f6dd9d3
......@@ -2,48 +2,48 @@
<h2>Table of Contents</h2>
<div id="text-table-of-contents">
<ul>
<li><a href="#orgd3b5e47">1. 背景介绍</a>
<li><a href="#org50629cf">1. 背景介绍</a>
<ul>
<li><a href="#org281ac04">1.1. LR vs DNN</a></li>
<li><a href="#org82d29f2">1.1. LR vs DNN</a></li>
</ul>
</li>
<li><a href="#org7b0794d">2. 数据和任务抽象</a></li>
<li><a href="#orgb7d416a">3. Wide &amp; Deep Learning Model</a>
<li><a href="#org71b628e">2. 数据和任务抽象</a></li>
<li><a href="#orga33b812">3. Wide &amp; Deep Learning Model</a>
<ul>
<li><a href="#org34e65a5">3.1. 模型简介</a></li>
<li><a href="#org9aab6a2">3.2. 编写模型输入</a></li>
<li><a href="#org28eef19">3.3. 编写 Wide 部分</a></li>
<li><a href="#orga6a8e51">3.4. 编写 Deep 部分</a></li>
<li><a href="#org447552d">3.5. 两者融合</a></li>
<li><a href="#orgbf70727">3.6. 训练任务的定义</a></li>
<li><a href="#org83aff73">3.1. 模型简介</a></li>
<li><a href="#org5ea2bba">3.2. 编写模型输入</a></li>
<li><a href="#org17c16e7">3.3. 编写 Wide 部分</a></li>
<li><a href="#orged3e908">3.4. 编写 Deep 部分</a></li>
<li><a href="#org80056a6">3.5. 两者融合</a></li>
<li><a href="#org6afcbfa">3.6. 训练任务的定义</a></li>
</ul>
</li>
<li><a href="#orgefd4d16">4. 写在最后</a></li>
<li><a href="#orgbfe2993">4. 引用</a></li>
</ul>
</div>
</div>
<a id="orgd3b5e47"></a>
<a id="org50629cf"></a>
# 背景介绍
CTR(Click-through rate) 是用来表示用户点击一个特定链接的概率,
CTR(Click-through rate) 是用来表示用户点击一个特定链接的概率,
通常被用来衡量一个在线广告系统的有效性。
当有多个广告位时,CTR 预估一般会作为排序的基准。
比如在搜索引擎的广告系统里,当用户输入一个带商业价值的搜索词(query)时,系统大体上会执行下列步骤:
比如在搜索引擎的广告系统里,当用户输入一个带商业价值的搜索词(query)时,系统大体上会执行下列步骤来展示广告
1. 召回满足 query 的广告集合
2. 业务规则和相关性过滤
3. 根据拍卖机制和 CTR 排序
4. 展出
4. 展出广告
可以看到,CTR 在最终排序中起到了很重要的作用。
在业内,CTR 模型经历了如下的发展阶段:
- Logistic Regression(LR) + 特征工程
- Logistic Regression(LR) / GBDT + 特征工程
- LR + DNN 特征
- DNN + 特征工程
......@@ -51,52 +51,53 @@ CTR(Click-through rate) 是用来表示用户点击一个特定链接的概率
逐渐地接过 CTR 预估任务的大旗。
<a id="org281ac04"></a>
<a id="org82d29f2"></a>
## LR vs DNN
下图展示了 LR 和一个 \(3x2\) 的 NN 模型的结构:
![img](./img/lr-vs-dnn.jpg)
![img](./images/lr-vs-dnn.jpg)
LR 部分和蓝色箭头部分可以直接类比到 NN 中的结构,可以看到 LR 和 NN 有一些共通之处(比如权重累加),
但前者的模型复杂度在相同输入维度下比后者可能很多(从某方面讲,模型越复杂,越有潜力学习到更复杂的信息)。
但前者的模型复杂度在相同输入维度下比后者可能很多(从某方面讲,模型越复杂,越有潜力学习到更复杂的信息)。
如果 LR 要达到匹敌 NN 的学习能力,必须增加输入的维度,也就是增加特征的数量(作为输入)
如果 LR 要达到匹敌 NN 的学习能力,必须增加输入的维度,也就是增加特征的数量,
这也就是为何 LR 和大规模的特征工程必须绑定在一起的原因。
LR 对于 NN 模型的优势是对大规模稀疏特征的容纳能力,包括内存和计算量等方面,工业界都有非常成熟的优化方法。
而 NN 模型具有自己学习新特征的能力,一定程度上能够提升特征使用的效率,
这使得 NN 模型在同样规模特征的情况下,更有可能达到更好的学习效果。
LR 对于 NN 模型的优势是对大规模稀疏特征的容纳能力,包括内存和计算量等,工业界都有非常成熟的优化方法。
本文后面的章节会演示如何使用 PaddlePaddle 编写一个结合两者优点的模型。
<a id="org7b0794d"></a>
<a id="org71b628e"></a>
# 数据和任务抽象
我们可以将 \`click\` 作为学习目标,具体任务可以有以下几种方案:
我们可以将 `click` 作为学习目标,具体任务可以有以下几种方案:
1. 直接学习 click,0,1 作二元分类,或 pairwise rank(标签 1>0)
2. 统计每个广告的点击率,将同一个 query 下的广告两两组合,点击率高的>点击率低的
1. 直接学习 click,0,1 作二元分类
2. Learning to rank, 具体用 pairwise rank(标签 1>0)或者 list rank
3. 统计每个广告的点击率,将同一个 query 下的广告两两组合,点击率高的>点击率低的,做 rank 或者分类
这里,我们直接使用第一种方法做分类任务。
我们直接使用第一种方法做分类任务。
我们使用 Kaggle 上 \`Click-through rate prediction\` 任务的数据集[1] 来演示模型。
我们使用 Kaggle 上 `Click-through rate prediction` 任务的数据集[3] 来演示模型。
具体的特征处理方法参看 [data process](./dataset.md)
<a id="orgb7d416a"></a>
<a id="orga33b812"></a>
# Wide & Deep Learning Model
谷歌在 16 年提出了 Wide & Deep Learning 的模型框架,用于融合 适合学习抽象特征的 DNN 和 适用于大规模系数特征的 LR 两种模型的优点。
谷歌在 16 年提出了 Wide & Deep Learning 的模型框架,用于融合适合学习抽象特征的 DNN 和 适用于大规模稀疏特征的 LR 两种模型的优点。
<a id="org34e65a5"></a>
<a id="org83aff73"></a>
## 模型简介
......@@ -105,47 +106,54 @@ Wide & Deep Learning Model 可以作为一种相对成熟的模型框架使用
模型结构如下:
![img](./img/wide-deep.png)
![img](./images/wide-deep.png)
模型左边的 Wide 部分,可以容纳大规模系数特征,并且对一些特定的信息(比如 ID)有一定的记忆能力;
而模型右边的 Deep 部分,能够学习特征间的隐含关系,在相同数量的特征下有更好的学习和推导能力。
<a id="org9aab6a2"></a>
<a id="org5ea2bba"></a>
## 编写模型输入
模型只接受 3 个输入,分别是
- \`dnn<sub>input</sub>\` ,也就是 Deep 部分的输入
- \`lr<sub>input</sub>\` ,也就是 Wide 部分的输入
- \`click\` , 点击与否,作为二分类模型学习的标签
- `dnn_input` ,也就是 Deep 部分的输入
- `lr_input` ,也就是 Wide 部分的输入
- `click` , 点击与否,作为二分类模型学习的标签
```python
dnn_merged_input = layer.data(
name='dnn_input',
type=paddle.data_type.sparse_binary_vector(data_meta_info['dnn_input']))
lr_merged_input = layer.data(
name='lr_input',
type=paddle.data_type.sparse_binary_vector(data_meta_info['lr_input']))
click = paddle.layer.data(name='click', type=dtype.dense_vector(1))
<a id="org28eef19"></a>
<a id="org17c16e7"></a>
## 编写 Wide 部分
Wide 部分直接使用了 LR 模型但激活函数改成了 `RELU` 来加速
```python
def build_lr_submodel():
fc = layer.fc(
input=lr_merged_input, size=1, name='lr', act=paddle.activation.Relu())
return fc
<a id="orga6a8e51"></a>
<a id="orged3e908"></a>
## 编写 Deep 部分
Deep 部分使用了标准的多层前向传导的 NN 模型
```python
def build_dnn_submodel(dnn_layer_dims):
dnn_embedding = layer.fc(input=dnn_merged_input, size=dnn_layer_dims[0])
_input_layer = dnn_embedding
......@@ -159,10 +167,14 @@ Wide & Deep Learning Model 可以作为一种相对成熟的模型框架使用
return _input_layer
<a id="org447552d"></a>
<a id="org80056a6"></a>
## 两者融合
两个 submodel 的最上层输出加权求和得到整个模型的输出输出部分使用 `sigmoid` 作为激活函数得到区间\((0,1)\) 的预测值
来逼近训练数据中二元类别的分布最终作为 CTR 预估的值使用
```python
# conbine DNN and LR submodels
def combine_submodels(dnn, lr):
merge_layer = layer.concat(input=[dnn, lr])
......@@ -175,43 +187,44 @@ Wide & Deep Learning Model 可以作为一种相对成熟的模型框架使用
return fc
<a id="orgbf70727"></a>
<a id="org6afcbfa"></a>
## 训练任务的定义
```python
dnn = build_dnn_submodel(dnn_layer_dims)
lr = build_lr_submodel()
output = combine_submodels(dnn, lr)
# ==============================================================================
# cost and train period
# ==============================================================================
classification_cost = paddle.layer.multi_binary_label_cross_entropy_cost(
input=output, label=click)
params = paddle.parameters.create(classification_cost)
optimizer = paddle.optimizer.Momentum(momentum=0)
trainer = paddle.trainer.SGD(
cost=classification_cost, parameters=params, update_equation=optimizer)
dataset = AvazuDataset(train_data_path, n_records_as_test=test_set_size)
def event_handler(event):
if isinstance(event, paddle.event.EndIteration):
if event.batch_id % 100 == 0:
logging.warning("Pass %d, Samples %d, Cost %f" % (
event.pass_id, event.batch_id * batch_size, event.cost))
if event.batch_id % 1000 == 0:
result = trainer.test(
reader=paddle.batch(dataset.test, batch_size=1000),
feeding=field_index)
logging.warning("Test %d-%d, Cost %f" % (event.pass_id, event.batch_id,
result.cost))
trainer.train(
reader=paddle.batch(
paddle.reader.shuffle(dataset.train, buf_size=500),
......@@ -221,13 +234,12 @@ Wide & Deep Learning Model 可以作为一种相对成熟的模型框架使用
num_passes=100)
<a id="orgefd4d16"></a>
<a id="orgbfe2993"></a>
# 写在最后
# 引用
- [1] <https://en.wikipedia.org/wiki/Click-through_rate>
- [2] Strategies for Training Large Scale Neural Network Language Models
- <https://www.kaggle.com/c/avazu-ctr-prediction/data>
[1] <https://www.kaggle.com/c/avazu-ctr-prediction/data>
- [2] Mikolov, Tomáš, et al. "Strategies for training large scale neural network language models." Automatic Speech Recognition and Understanding (ASRU), 2011 IEEE Workshop on. IEEE, 2011.
- [3] <https://www.kaggle.com/c/avazu-ctr-prediction/data>
- [4] Cheng, Heng-Tze, et al. "Wide & deep learning for recommender systems." Proceedings of the 1st Workshop on Deep Learning for Recommender Systems. ACM, 2016.
......@@ -2,38 +2,38 @@
<h2>Table of Contents</h2>
<div id="text-table-of-contents">
<ul>
<li><a href="#orgb697e2a">1. 数据集介绍</a></li>
<li><a href="#org912d23e">2. 特征提取</a>
<li><a href="#orga96c5e8">1. 数据集介绍</a></li>
<li><a href="#orge73ddcc">2. 特征提取</a>
<ul>
<li><a href="#org59e1a78">2.1. 类别类特征</a></li>
<li><a href="#orgad86672">2.2. ID 类特征</a></li>
<li><a href="#orgeed4bfc">2.3. 数值型特征</a></li>
<li><a href="#orgbe379b1">2.1. 类别类特征</a></li>
<li><a href="#org811ca7c">2.2. ID 类特征</a></li>
<li><a href="#orgc1d7d23">2.3. 数值型特征</a></li>
</ul>
</li>
<li><a href="#orgbb21fbb">3. 特征处理</a>
<li><a href="#org609b660">3. 特征处理</a>
<ul>
<li><a href="#org9105d62">3.1. 类别型特征</a></li>
<li><a href="#org6131dd5">3.2. ID 类特征</a></li>
<li><a href="#org64a5228">3.3. 交叉类特征</a></li>
<li><a href="#orgdfa3224">3.4. 特征维度</a>
<li><a href="#org5fdd532">3.1. 类别型特征</a></li>
<li><a href="#orgad85d3e">3.2. ID 类特征</a></li>
<li><a href="#org0cbe90e">3.3. 交叉类特征</a></li>
<li><a href="#org4bdb372">3.4. 特征维度</a>
<ul>
<li><a href="#org4c15bfb">3.4.1. Deep submodel(DNN)特征</a></li>
<li><a href="#orga3f2dd5">3.4.2. Wide submodel(LR)特征</a></li>
<li><a href="#org0530a25">3.4.1. Deep submodel(DNN)特征</a></li>
<li><a href="#orged20ff2">3.4.2. Wide submodel(LR)特征</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#org55405cd">4. 输入到 PaddlePaddle 中</a></li>
<li><a href="#org70ad7d8">4. 输入到 PaddlePaddle 中</a></li>
</ul>
</div>
</div>
<a id="orgb697e2a"></a>
<a id="orga96c5e8"></a>
# 数据集介绍
数据集使用 \`csv\` 格式存储,其中各个字段内容如下:
数据集使用 `csv` 格式存储,其中各个字段内容如下:
- id: ad identifier
- click: 0/1 for non-click/click
......@@ -54,31 +54,34 @@
- C14-C21 &#x2013; anonymized categorical variables
<a id="org912d23e"></a>
<a id="orge73ddcc"></a>
# 特征提取
下面我们会简单演示几种特征的提取方式。
下面我们会简单演示几种特征的提取方式。
原始数据中的特征可以分为以下几类:
1. ID 类特征(稀疏,数量多)
```python
- id
- site<sub>id</sub>
- app<sub>id</sub>
- device<sub>id</sub>
2. 类别类特征稀疏但数量有限
```python
- C1
- site<sub>category</sub>
- device<sub>type</sub>
- C14-C21
3. 数值型特征转化为类别型特征
```python
- hour (可以转化成数值也可以按小时为单位转化为类别
<a id="org59e1a78"></a>
<a id="orgbe379b1"></a>
## 类别类特征
......@@ -88,7 +91,7 @@
2. 类似词向量用一个 Embedding Table 将每个类别映射到对应的向量
<a id="orgad86672"></a>
<a id="org811ca7c"></a>
## ID 类特征
......@@ -103,7 +106,7 @@ ID 类特征的特点是稀疏数据,但量比较大,直接使用 One-hot
上面的方法尽管存在一定的碰撞概率但能够处理任意数量的 ID 特征并保留一定的效果[2]
<a id="orgeed4bfc"></a>
<a id="orgc1d7d23"></a>
## 数值型特征
......@@ -113,12 +116,12 @@ ID 类特征的特点是稀疏数据,但量比较大,直接使用 One-hot
- 用区间分割处理成类别类特征稀疏化表示模糊细微上的差别
<a id="orgbb21fbb"></a>
<a id="org609b660"></a>
# 特征处理
<a id="org9105d62"></a>
<a id="org5fdd532"></a>
## 类别型特征
......@@ -126,18 +129,19 @@ ID 类特征的特点是稀疏数据,但量比较大,直接使用 One-hot
这种特征在输入到模型时一般使用 One-hot 表示相关处理方法如下
```python
class CategoryFeatureGenerator(object):
'''
Generator category features.
Register all records by calling `register` first, then call `gen` to generate
Register all records by calling ~register~ first, then call ~gen~ to generate
one-hot representation for a record.
'''
def __init__(self):
self.dic = {'unk': 0}
self.counter = 1
def register(self, key):
'''
Register record.
......@@ -145,10 +149,10 @@ ID 类特征的特点是稀疏数据,但量比较大,直接使用 One-hot
if key not in self.dic:
self.dic[key] = self.counter
self.counter += 1
def size(self):
return len(self.dic)
def gen(self, key):
'''
Generate one-hot representation for a record.
......@@ -158,20 +162,21 @@ ID 类特征的特点是稀疏数据,但量比较大,直接使用 One-hot
else:
res = self.dic[key]
return [res]
def __repr__(self):
return '<CategoryFeatureGenerator %d>' % len(self.dic)
本任务中,类别类特征会输入到 DNN 中使用。
<a id="org6131dd5"></a>
<a id="orgad85d3e"></a>
## ID 类特征
ID 类特征代稀疏值,且值的空间很大的情况,一般用模操作规约到一个有限空间,
之后可以当成类别类特征使用,这里我们会将 ID 类特征输入到 LR 模型中使用。
```python
class IDfeatureGenerator(object):
def __init__(self, max_dim):
'''
......@@ -179,40 +184,41 @@ ID 类特征代稀疏值,且值的空间很大的情况,一般用模操作
Size of the id elements' space
'''
self.max_dim = max_dim
def gen(self, key):
'''
Generate one-hot representation for records
'''
return [hash(key) % self.max_dim]
def size(self):
return self.max_dim
<a id="org64a5228"></a>
<a id="org0cbe90e"></a>
## 交叉类特征
LR 模型作为 Wide & Deep model 的 \`wide\` 部分,可以输入很 wide 的数据(特征空间的维度很大),
LR 模型作为 Wide & Deep model `wide` 部分可以输入很 wide 的数据特征空间的维度很大),
为了充分利用这个优势我们将演示交叉组合特征构建成更大维度特征的情况之后塞入到模型中训练
这里我们依旧使用模操作来约束最终组合出的特征空间的大小,具体实现是直接在 \`IDfeatureGenerator\` 中添加一个\`gen<sub>cross</sub><sub>feature</sub>\` 的方法:
这里我们依旧使用模操作来约束最终组合出的特征空间的大小具体实现是直接在 `IDfeatureGenerator` 中添加一个~gen<sub>cross</sub><sub>feature</sub>~ 的方法
```python
def gen_cross_fea(self, fea1, fea2):
key = str(fea1) + str(fea2)
return self.gen(key)
比如,我们觉得原始数据中,\`device<sub>id</sub>\`\`site<sub>id</sub>\` 有一些关联(比如某个 device 倾向于浏览特定 site),
比如,我们觉得原始数据中, `device_id``site_id` 有一些关联(比如某个 device 倾向于浏览特定 site),
我们通过组合出两者组合来捕捉这类信息。
<a id="orgdfa3224"></a>
<a id="org4bdb372"></a>
## 特征维度
<a id="org4c15bfb"></a>
<a id="org0530a25"></a>
### Deep submodel(DNN)特征
......@@ -271,7 +277,7 @@ LR 模型作为 Wide & Deep model 的 \`wide\` 部分,可以输入很 wide 的
</table>
<a id="orga3f2dd5"></a>
<a id="orged20ff2"></a>
### Wide submodel(LR)特征
......@@ -330,23 +336,24 @@ LR 模型作为 Wide & Deep model 的 \`wide\` 部分,可以输入很 wide 的
</table>
<a id="org55405cd"></a>
<a id="org70ad7d8"></a>
# 输入到 PaddlePaddle 中
Deep 和 Wide 两部分均以 \`sparse<sub>binary</sub><sub>vector</sub>\` 的格式[1]输入,输入前需要将相关特征拼合,模型最终只接受 3 个 input,
Deep 和 Wide 两部分均以 `sparse_binary_vector` 的格式[1]输入,输入前需要将相关特征拼合,模型最终只接受 3 个 input,
分别是
1. \`dnn input\`,DNN 的输入
2. \`lr input\`, LR 的输入
3. \`click\`, 标签
1. ~dnn input~,DNN 的输入
2. `lr input`, LR 的输入
3. ~click~, 标签
拼合特征的方法:
```python
def concat_sparse_vectors(inputs, dims):
'''
concaterate sparse vectors into one
@inputs: list
list of sparse vector
@dims: list of int
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册