diff --git a/ctr/README.md b/ctr/README.md
index 50eadab4fe7e10eff3f0abe825526f5cb6ac591d..653e599382676284b07277caa0bb1390979b592b 100644
--- a/ctr/README.md
+++ b/ctr/README.md
@@ -1,32 +1,6 @@
-
-
-
-
-
-# 背景介绍
+# CTR预估
+
+## 背景介绍
CTR(Click-through rate) 是用来表示用户点击一个特定链接的概率,
通常被用来衡量一个在线广告系统的有效性。
@@ -40,7 +14,7 @@ CTR(Click-through rate) 是用来表示用户点击一个特定链接的概率
4. 展出广告
可以看到,CTR 在最终排序中起到了很重要的作用。
-
+### 发展阶段
在业内,CTR 模型经历了如下的发展阶段:
- Logistic Regression(LR) / GBDT + 特征工程
@@ -51,9 +25,7 @@ CTR(Click-through rate) 是用来表示用户点击一个特定链接的概率
逐渐地接过 CTR 预估任务的大旗。
-
-
-## LR vs DNN
+### LR vs DNN
下图展示了 LR 和一个 \(3x2\) 的 NN 模型的结构:
@@ -73,9 +45,7 @@ LR 对于 NN 模型的优势是对大规模稀疏特征的容纳能力,包括
本文后面的章节会演示如何使用 PaddlePaddle 编写一个结合两者优点的模型。
-
-
-# 数据和任务抽象
+## 数据和任务抽象
我们可以将 `click` 作为学习目标,具体任务可以有以下几种方案:
@@ -90,16 +60,12 @@ LR 对于 NN 模型的优势是对大规模稀疏特征的容纳能力,包括
具体的特征处理方法参看 [data process](./dataset.md)
-
-
-# Wide & Deep Learning Model
+## Wide & Deep Learning Model
谷歌在 16 年提出了 Wide & Deep Learning 的模型框架,用于融合适合学习抽象特征的 DNN 和 适用于大规模稀疏特征的 LR 两种模型的优点。
-
-
-## 模型简介
+### 模型简介
Wide & Deep Learning Model 可以作为一种相对成熟的模型框架使用,
在 CTR 预估的任务中工业界也有一定的应用,因此本文将演示使用此模型来完成 CTR 预估的任务。
@@ -112,9 +78,7 @@ Wide & Deep Learning Model 可以作为一种相对成熟的模型框架使用
而模型右边的 Deep 部分,能够学习特征间的隐含关系,在相同数量的特征下有更好的学习和推导能力。
-
-
-## 编写模型输入
+### 编写模型输入
模型只接受 3 个输入,分别是
@@ -132,13 +96,9 @@ lr_merged_input = layer.data(
type=paddle.data_type.sparse_binary_vector(data_meta_info['lr_input']))
click = paddle.layer.data(name='click', type=dtype.dense_vector(1))
-
-
```
-
-
-## 编写 Wide 部分
+### 编写 Wide 部分
Wide 部分直接使用了 LR 模型,但激活函数改成了 `RELU` 来加速
@@ -147,13 +107,9 @@ def build_lr_submodel():
fc = layer.fc(
input=lr_merged_input, size=1, name='lr', act=paddle.activation.Relu())
return fc
-
-
```
-
-
-## 编写 Deep 部分
+### 编写 Deep 部分
Deep 部分使用了标准的多层前向传导的 NN 模型
@@ -169,13 +125,9 @@ def build_dnn_submodel(dnn_layer_dims):
name='dnn-fc-%d' % no)
_input_layer = fc
return _input_layer
-
-
```
-
-
-## 两者融合
+### 两者融合
两个 submodel 的最上层输出加权求和得到整个模型的输出,输出部分使用 `sigmoid` 作为激活函数,得到区间\((0,1)\) 的预测值,
来逼近训练数据中二元类别的分布,最终作为 CTR 预估的值使用。
@@ -191,13 +143,9 @@ def combine_submodels(dnn, lr):
# use sigmoid function to approximate ctr rate, a float value between 0 and 1.
act=paddle.activation.Sigmoid())
return fc
-
-
```
-
-
-## 训练任务的定义
+### 训练任务的定义
```python
dnn = build_dnn_submodel(dnn_layer_dims)
@@ -240,16 +188,10 @@ trainer.train(
feeding=field_index,
event_handler=event_handler,
num_passes=100)
-
-
```
-
-
-# 引用
-
-- [1]
-- [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]
-- [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.
-
+## 引用
+1.
+2. Mikolov T, Deoras A, Povey D, et al. Strategies for training large scale neural network language models[C]//Automatic Speech Recognition and Understanding (ASRU), 2011 IEEE Workshop on. IEEE, 2011: 196-201.
+3.
+4. 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.
diff --git a/ctr/data_provider.py b/ctr/data_provider.py
index a004a3e547a5d6d933167956c72dddfca7606f79..f02d3d33e75163cf772921ef54729a3fc8da022b 100644
--- a/ctr/data_provider.py
+++ b/ctr/data_provider.py
@@ -150,8 +150,8 @@ for key in id_features:
fields[key] = IDfeatureGenerator(10000)
# used as feed_dict in PaddlePaddle
-field_index = dict(
- (key, id) for id, key in enumerate(['dnn_input', 'lr_input', 'click']))
+field_index = dict((key, id)
+ for id, key in enumerate(['dnn_input', 'lr_input', 'click']))
def detect_dataset(path, topn, id_fea_space=10000):
@@ -175,7 +175,7 @@ def detect_dataset(path, topn, id_fea_space=10000):
feature_dims[key] = item.size()
#for key in id_features:
- #feature_dims[key] = id_fea_space
+ #feature_dims[key] = id_fea_space
feature_dims['hour'] = 24
feature_dims['click'] = 1
@@ -222,8 +222,7 @@ class AvazuDataset(object):
def train(self):
self.mode = self.TRAIN_MODE
- return self._parse(
- self.train_path, skip_n_lines=self.n_records_as_test)
+ return self._parse(self.train_path, skip_n_lines=self.n_records_as_test)
def test(self):
self.mode = self.TEST_MODE
@@ -257,7 +256,8 @@ class AvazuDataset(object):
else:
fea0 = fields[key].cross_fea0
fea1 = fields[key].cross_fea1
- record.append(fields[key].gen_cross_fea(row[fea0], row[fea1]))
+ record.append(
+ fields[key].gen_cross_fea(row[fea0], row[fea1]))
sparse_input = concat_sparse_vectors(record, id_dims)
diff --git a/ctr/dataset.md b/ctr/dataset.md
index 7ea9b59f7cdba6803b16634986924c6c990b7727..62511be2e99de38a3f6bcdc4d1b204d2e098aba5 100644
--- a/ctr/dataset.md
+++ b/ctr/dataset.md
@@ -1,44 +1,12 @@
-
-
-
-
-
-# 数据集介绍
+# 数据及处理
+## 数据集介绍
数据集使用 `csv` 格式存储,其中各个字段内容如下:
- `id` : ad identifier
- `click` : 0/1 for non-click/click
- `hour` : format is YYMMDDHH, so 14091123 means 23:00 on Sept. 11, 2014 UTC.
-- `C1` – anonymized categorical variable
+- `C1` : anonymized categorical variable
- `banner_pos`
- `site_id`
- `site_domain`
@@ -51,45 +19,33 @@
- `device_model`
- `device_type`
- `device_conn_type`
-- `C14-C21` – anonymized categorical variables
+- `C14-C21` : anonymized categorical variables
-
-
-# 特征提取
+## 特征提取
下面我们会简单演示几种特征的提取方式。
原始数据中的特征可以分为以下几类:
1. ID 类特征(稀疏,数量多)
-```python
- `id`
- `site_id`
- `app_id`
- `device_id`
-```
-
2. 类别类特征(稀疏,但数量有限)
-```python
+
- `C1`
- `site_category`
- `device_type`
- `C14-C21`
-```
-
3. 数值型特征转化为类别型特征
-```python
-- hour (可以转化成数值,也可以按小时为单位转化为类别)
-
-
-```
-
+- hour (可以转化成数值,也可以按小时为单位转化为类别)
-## 类别类特征
+### 类别类特征
类别类特征的提取方法有以下两种:
@@ -97,9 +53,7 @@
2. 类似词向量,用一个 Embedding Table 将每个类别映射到对应的向量
-
-
-## ID 类特征
+### ID 类特征
ID 类特征的特点是稀疏数据,但量比较大,直接使用 One-hot 表示时维度过大。
@@ -111,25 +65,17 @@ ID 类特征的特点是稀疏数据,但量比较大,直接使用 One-hot
上面的方法尽管存在一定的碰撞概率,但能够处理任意数量的 ID 特征,并保留一定的效果[2]。
-
-
-
-## 数值型特征
+### 数值型特征
一般会做如下处理:
- 归一化,直接作为特征输入模型
- 用区间分割处理成类别类特征,稀疏化表示,模糊细微上的差别
+## 特征处理
-
-# 特征处理
-
-
-
-
-## 类别型特征
+### 类别型特征
类别型特征有有限多种值,在模型中,我们一般使用 embedding table 将每种值映射为连续值的向量。
@@ -171,15 +117,11 @@ class CategoryFeatureGenerator(object):
def __repr__(self):
return '' % len(self.dic)
-
```
本任务中,类别类特征会输入到 DNN 中使用。
-
-
-
-## ID 类特征
+### ID 类特征
ID 类特征代稀疏值,且值的空间很大的情况,一般用模操作规约到一个有限空间,
之后可以当成类别类特征使用,这里我们会将 ID 类特征输入到 LR 模型中使用。
@@ -201,13 +143,9 @@ class IDfeatureGenerator(object):
def size(self):
return self.max_dim
-
-
```
-
-
-## 交叉类特征
+### 交叉类特征
LR 模型作为 Wide & Deep model 的 `wide` 部分,可以输入很 wide 的数据(特征空间的维度很大),
为了充分利用这个优势,我们将演示交叉组合特征构建成更大维度特征的情况,之后塞入到模型中训练。
@@ -218,139 +156,33 @@ LR 模型作为 Wide & Deep model 的 `wide` 部分,可以输入很 wide 的
def gen_cross_fea(self, fea1, fea2):
key = str(fea1) + str(fea2)
return self.gen(key)
-
```
比如,我们觉得原始数据中, `device_id` 和 `site_id` 有一些关联(比如某个 device 倾向于浏览特定 site),
我们通过组合出两者组合来捕捉这类信息。
-
-
-
-## 特征维度
-
-
-
-
-### Deep submodel(DNN)特征
-
-
-
-
-
-
-
-
-
-
-
-feature |
-dimention |
-
-
-
-
-
-`app_category` |
-21 |
-
-
-
-
-`site_category` |
-22 |
-
-
-
-
-`device_conn_type` |
-5 |
-
-
-
-
-`hour` |
-24 |
-
-
-
-
-`banner_pos` |
-7 |
-
-
-
-
-
-Total |
-79 |
-
-
-
-
-
-
-
-### Wide submodel(LR)特征
-
-
-
-
-
-
-
-
-
-
-
-Feature |
-Dimention |
-
-
-
-
-
-`id` |
-100000 |
-
-
-
-
-`site_id` |
-100000 |
-
-
-
-
-`app_id` |
-100000 |
-
-
-
-
-`device_id` |
-100000 |
-
-
-
-
-`device_id` X `site_id` |
-10000000 |
-
-
-
-
-
-Total |
-10,400,000 |
-
-
-
-
-
-
-
-# 输入到 PaddlePaddle 中
+### 特征维度
+#### Deep submodel(DNN)特征
+| feature | dimention |
+|------------------+-----------|
+| app_category | 21 |
+| site_category | 22 |
+| device_conn_type | 5 |
+| hour | 24 |
+| banner_pos | 7 |
+| **Total** | 79 |
+
+#### Wide submodel(LR)特征
+| Feature | Dimention |
+|---------------------+-----------|
+| id | 10000 |
+| site_id | 10000 |
+| app_id | 10000 |
+| device_id | 10000 |
+| device_id X site_id | 1000000 |
+| **Total** | 1,040,000 |
+
+## 输入到 PaddlePaddle 中
Deep 和 Wide 两部分均以 `sparse_binary_vector` 的格式[1]输入,输入前需要将相关特征拼合,模型最终只接受 3 个 input,
分别是
@@ -379,8 +211,6 @@ def concat_sparse_vectors(inputs, dims):
res.append(v + start)
start += dims[no]
return res
-
```
-[1]
-
+1.