|
| 1 | +# ElasticDL: 结构化数据的分布式深度学习建模 |
| 2 | + |
| 3 | +## 背景 |
| 4 | + |
| 5 | +有很多场景都是使用结构化数据,例如搜索、推荐和广告的场景,已经大量实践证明 |
| 6 | +深度学习模型在这些场景中取得了很好的效果。在结构化数据场景中,使用深度学习 |
| 7 | +建模流程主要包括两阶段:数据预处理和模型训练。 |
| 8 | + |
| 9 | +- 在数据预处理阶段,常常不同的业务场景的数据特征不同,需要定义不同的特征预 |
| 10 | +处理逻辑,而且特征预处理过程还需要尽量减少特征的信息损失。 |
| 11 | +- 在模型训练阶段,搜索、推荐和广告等场景的数据量往往很大,需要进行分布式训练。 |
| 12 | +在共用一个分布式集群时,申请资源的等待时间会成为影响模型训练和迭代效率的关键 |
| 13 | +因素。 |
| 14 | + |
| 15 | +为了提高这两阶段的开发效率,ElasticDL 针对这个难点提供了对应的解决方案: |
| 16 | + |
| 17 | +- 开发了结构化数据特征预处理库,能对数据集进行统计分析和特征变换,方便用户 |
| 18 | +实现特征预处理,本文介绍结构化数据特征预处理方案。 |
| 19 | +- 开发了 Parameter Server 的分布式训练框架,支持在 Kubernetes 上对 worker |
| 20 | +进行弹性调度。在资源不足的情况下,能快速开始训练任务,缩短模型迭代等待时间。 |
| 21 | +详细见 [ElasticDL:同时提升研发效率和机群利用率](./elasticdl-antfin-introduction.md) |
| 22 | + |
| 23 | +## 深度学习中结构化数据的特征预处理 |
| 24 | + |
| 25 | +在对结构化数据进行深度学习建模时,常需要将数据转换成更适合深度学习算法训练的格 |
| 26 | +式,常见的特征变换方式有: |
| 27 | + |
| 28 | +- 对数值型特征进行[标准化](https://en.wikipedia.org/wiki/Feature_scaling#Standardization_(Z-score_Normalization)) |
| 29 | +变换。 |
| 30 | +- 对数值型特征进行[分桶](https://en.wikipedia.org/wiki/Data_binning)变换, |
| 31 | +输出特征值所在分桶的整数序号。 |
| 32 | +- 对字符型特征进行[哈希](https://en.wikipedia.org/wiki/Hash_function) |
| 33 | +分桶变换,即对字符串进行哈希后对桶数取模,映射成整数输出。 |
| 34 | +- 对字符型特征进行查词表变换,输出词在词表中的整数序号。 |
| 35 | + |
| 36 | +然而在特征变换之前,需要对数据集进行统计分析,得到特征的全局统计量。利用全 |
| 37 | +局统计量做特征变换,可以降低变换时的特征信息损失。不同特征变换所需要的特征 |
| 38 | +统计量: |
| 39 | + |
| 40 | +| 特征变换 | 特征统计量 | |
| 41 | +|--------| --------- | |
| 42 | +| 标准化变换 | 均值,方差| |
| 43 | +| 分箱 | 等频统计边界 | |
| 44 | +| 哈希分桶 | 特征值集合的大小 | |
| 45 | +| 查词表 | 特征值的集合 | |
| 46 | + |
| 47 | +## ElasticDL 特征预处理与模型定义 |
| 48 | + |
| 49 | +在阿里云上,结构化数据主要以 MaxCompute 表的形式存储,为此 ElasticDL 针对 |
| 50 | +MaxCompute 表提供了特征统计和变换的特征预处理方案。 |
| 51 | + |
| 52 | +### MaxCompute 表的特征统计 |
| 53 | + |
| 54 | +针对常用的特征变换所需要的统计量,ElasticDL 利用 MaxCompute SQL 开发了特征统计 |
| 55 | +工具,并在 [PAI](https://pai.alipay.com) 上开发了 "ElasticDL 特征统计" 组件。 |
| 56 | + |
| 57 | + |
| 58 | + |
| 59 | +组件所执行的统计功能如下: |
| 60 | + |
| 61 | +| 特征列统计配置 | 统计量 | MaxCompute SQL 算子 | |
| 62 | +| ---------- | ------ | ----- | |
| 63 | +| 数值特征列 | 统计所选特征列的最大值、最小值、均值方差和等频分10个箱的边界 | MAX, MIN, STDDEV, AVG| |
| 64 | +| 数量统计特征列 | 统计所选特征列的特征值集合的大小 | COUNT(DISTINCT) | |
| 65 | +| 词表统计 | 统计所选特征列的特征值结合,如果配置了词表频次过滤阈值,会过滤掉低频的特征值 | DISTINCT | |
| 66 | + |
| 67 | +组件统计的结果会存入 MaxCompute 表中,分别存储特征统计量和特征词表。 |
| 68 | + |
| 69 | +### 特征变换 Keras layer |
| 70 | + |
| 71 | +ElasticDL 支持分布式训练 Keras 模型,为了方便用户将特征预处理与 Keras 模型定义 |
| 72 | +相结合,ElasticDL 利用 TensorFlow op 开发了特征变换的 Keras layer 库 |
| 73 | +`elasticdl_preprocessing`。在训练时,TensorFlow 会将特征变换和模型定义组成 |
| 74 | +一张完整的计算图,在训练结束后,保存模型时会将完整的计算图以 SavedModel 格式 |
| 75 | +导出,保证了训练和预测的特征变换一致性。 |
| 76 | + |
| 77 | +`elasticdl_preprocessing` 的特征变换 layer 介绍: |
| 78 | + |
| 79 | +| 特征变换 layer | 功能 | 所需的统计量 | |
| 80 | +| --- | --- | --- | |
| 81 | +| Normalizer | 对数值进行归一化或者标准化操作 | 均值、方差| |
| 82 | +| Discretization | 将数值进行分箱,输出特征值所在的箱子的整数 id | 分享边界| |
| 83 | +| LogRound | 将数值进行对数运算后取整 | 最大值 | |
| 84 | +| RoundIdentity | 将数值进行取整操作 | 最大值 | |
| 85 | +| Hashing | 将字符串进行 hashing 后对 bins 数量求余运算 | 特征值集合的大小| |
| 86 | +| IndexLookup | 将字符串通过查词表转成整数,输出词所在词表的索引 | 特征值集合(词表) | |
| 87 | + |
| 88 | +特征变换 layer 的使用教程请查看 |
| 89 | +[Preprocess Inputs using ElasticDL Preprocessing Layers](https://github.com/sql-machine-learning/elasticdl/blob/develop/docs/tutorials/preprocessing_tutorial.md) |
| 90 | + |
| 91 | +### Keras 模型训练定义 |
| 92 | + |
| 93 | +ElasticDL 支持直接训练原生的 Keras 模型,用户只需使用 Keras API 来定义模型 |
| 94 | +即可。但是一个完整的深度学习训练定义,除了模型以外还需要定义 loss,optimizer |
| 95 | +和 dataset,在 ElasticDL 中的定义方式如下: |
| 96 | + |
| 97 | +```python |
| 98 | +from elasticdl_preprocessing.layers import Normalizer |
| 99 | + |
| 100 | +def custom_model(): |
| 101 | + inputs = tf.keras.layers.Input(shape=(4, ), name="input") # 定义输入 |
| 102 | + standardization = Normalizer(0.0, 1.0)(inputs) # 特征预处理 |
| 103 | + x = tf.keras.layers.Flatten()(standardization) |
| 104 | + outputs = tf.keras.layers.Dense(3, name="output")(x) |
| 105 | + return tf.keras.Model(inputs=inputs, outputs=outputs, name="simple-model") |
| 106 | + |
| 107 | + |
| 108 | +def loss(labels, predictions): |
| 109 | + return tf.reduce_mean( |
| 110 | + tf.nn.sparse_softmax_cross_entropy_with_logits( |
| 111 | + tf.cast(tf.reshape(labels, [-1]), tf.int32), predictions |
| 112 | + ) |
| 113 | + ) |
| 114 | + |
| 115 | + |
| 116 | +def optimizer(lr=0.1): |
| 117 | + return tf.optimizers.SGD(lr) |
| 118 | + |
| 119 | + |
| 120 | +def eval_metrics_fn(): |
| 121 | + return { |
| 122 | + "accuracy": lambda labels, predictions: tf.equal( |
| 123 | + tf.argmax(predictions, 1, output_type=tf.int32), |
| 124 | + tf.cast(tf.reshape(labels, [-1]), tf.int32), |
| 125 | + ) |
| 126 | + } |
| 127 | + |
| 128 | + |
| 129 | +def dataset_fn(dataset, mode, metadata): |
| 130 | + def _parse_data(record): |
| 131 | + features = tf.strings.to_number(record[0:-1], tf.float32) |
| 132 | + label = tf.strings.to_number(record[-1], tf.float32) |
| 133 | + return features, label |
| 134 | + |
| 135 | + dataset = dataset.map(_parse_data) |
| 136 | + return dataset |
| 137 | +``` |
| 138 | + |
| 139 | +模型定义完成后,在ElasticDL提供的基础镜像中,放入模型文件生成新的镜像,即可在 PAI 平台上提交分布式训练。 |
| 140 | + |
| 141 | +## PAI 平台上集成特征预处理的 DeepCTR 算法 |
| 142 | + |
| 143 | +为了让用户能快速将 ElasticDL 应用到真实业务场景,ElasticDL 在 [PAI](https://pai.alipay.com) |
| 144 | +平台上提供了 ElasticDL-DeepCTR 组件,如下图所示: |
| 145 | + |
| 146 | + |
| 147 | + |
| 148 | +该算法组件有如下特点: |
| 149 | + |
| 150 | +- 根据用户配置的特征来自动生成特征预处理逻辑,并与深度学习 CTR 算法相结合,组成完整的模型。 |
| 151 | +- 提供了常用的 CTR 预估算法,包括 Wide & Deep, DeepFM, Deep Cross Network 和 xDeepFM。 |
| 152 | +- 分布式策略采用 ParameterServer,可以根据数据量来配置 worker 的数量来加速模型训练。 |
| 153 | + |
| 154 | +为了验证模型性能,我们选用了 [Kaggle Display Advertising Challenge](https://www.kaggle.com/c/criteo-display-ad-challenge) |
| 155 | +的数据集,来测试模型性能。将组件的标准化特征列和分箱特征列都配置成 I0-I13, |
| 156 | +哈希特征列配置成 C0-C13,最终使用 xDeepFM 模型的 logloss 为 |
| 157 | +0.45634 (Kaggle best logloss: 0.44463)。通过很简单的配置, |
| 158 | +就可以训练处一个性能比较好的模型,适合新场景数据集来快速实现 baseline。 |
| 159 | + |
| 160 | +ElasticDL DeepCTR 算法的实现原理如下图: |
| 161 | + |
| 162 | + |
0 commit comments