From 43e17c6744ff56d298ec349eedf968c04df431ce Mon Sep 17 00:00:00 2001 From: "weisu.yxd" Date: Fri, 20 Oct 2023 14:46:19 +0800 Subject: [PATCH] add custom op demo --- docs/source/component/custom_op.md | 37 +++++++++++++------------ docs/source/component/sequence.md | 1 + easy_rec/python/test/train_eval_test.py | 3 +- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/docs/source/component/custom_op.md b/docs/source/component/custom_op.md index c4f1d47fb..45b2d434d 100644 --- a/docs/source/component/custom_op.md +++ b/docs/source/component/custom_op.md @@ -3,22 +3,22 @@ 当内置的tf算子不能满足业务需求,或者通过组合现有算子实现需求的性能较差时,可以考虑自定义tf的OP。 1. 实现自定义算子,编译为动态库 - - 参考官方示例:[TensorFlow Custom Op](https://github.com/tensorflow/custom-op/) - - 注意:自定义Op的编译依赖tf版本需要与执行时的tf版本保持一致 - - 您可能需要为离线训练 与 在线推理服务 编译两个不同依赖环境的动态库 - - 在PAI平台上需要依赖 tf 1.12 版本编译 - - 在EAS的 [EasyRec Processor](https://help.aliyun.com/zh/pai/user-guide/easyrec) 中使用自定义Op需要依赖 tf 2.10.1 编译 -2. 在`EasyRec`中使用自定义Op的步骤 + - 参考官方示例:[TensorFlow Custom Op](https://github.com/tensorflow/custom-op/) + - 注意:自定义Op的编译依赖tf版本需要与执行时的tf版本保持一致 + - 您可能需要为离线训练 与 在线推理服务 编译两个不同依赖环境的动态库 + - 在PAI平台上需要依赖 tf 1.12 版本编译 + - 在EAS的 [EasyRec Processor](https://help.aliyun.com/zh/pai/user-guide/easyrec) 中使用自定义Op需要依赖 tf 2.10.1 编译 +1. 在`EasyRec`中使用自定义Op的步骤 1. 下载EasyRec的最新[源代码](https://github.com/alibaba/EasyRec) - 2. 把上一步编译好的动态库放到`easy_rec/python/ops/${tf_version}`目录,注意版本要子目录名一致 - 3. 开发一个使用自定义Op的组件 + 1. 把上一步编译好的动态库放到`easy_rec/python/ops/${tf_version}`目录,注意版本要子目录名一致 + 1. 开发一个使用自定义Op的组件 - 新组件的代码添加到 `easy_rec/python/layers/keras/custom_ops.py` - `custom_ops.py` 提供了一个自定义Op组件的示例 - 声明新组件,在`easy_rec/python/layers/keras/__init__.py`文件中添加导出语句 - 4. 编写模型配置文件,使用组件化的方式搭建模型,包含新定义的组件(参考下文) - 5. 运行`pai_jobs/deploy_ext.sh`脚本,打包EasyRec,并把打好的资源包(`easy_rec_ext_${version}_res.tar.gz`)上传到MaxCompute项目空间 - 6. (在DataWorks里 or 用odpscmd客户端工具) 训练 & 评估 & 导出 模型 - + 1. 编写模型配置文件,使用组件化的方式搭建模型,包含新定义的组件(参考下文) + 1. 运行`pai_jobs/deploy_ext.sh`脚本,打包EasyRec,并把打好的资源包(`easy_rec_ext_${version}_res.tar.gz`)上传到MaxCompute项目空间 + 1. (在DataWorks里 or 用odpscmd客户端工具) 训练 & 评估 & 导出 模型 + ## 导出自定义Op的动态库到 saved_model 的 assets 目录 ```bash @@ -36,11 +36,12 @@ pai -name easy_rec_ext ``` **注意**: + 1. 在 训练、评估、导出 命令中需要用`-Dres_project`指定上传easyrec资源包的MaxCompute项目空间名 -2. 在 训练、评估、导出 命令中需要用`-Dversion`指定资源包的版本 -3. asset_files参数指定的动态库会被线上推理服务加载,因此需要在与线上推理服务一致的tf版本上编译。(目前是EAS平台的EasyRec Processor依赖 tf 2.10.1版本)。 +1. 在 训练、评估、导出 命令中需要用`-Dversion`指定资源包的版本 +1. asset_files参数指定的动态库会被线上推理服务加载,因此需要在与线上推理服务一致的tf版本上编译。(目前是EAS平台的EasyRec Processor依赖 tf 2.10.1版本)。 - 如果 asset_files 参数还需要指定其他文件路径(比如 fg.json),多个路径之间用英文逗号隔开。 -4. 再次强调一遍,**导出的动态库依赖的tf版本需要与推理服务依赖的tf版本保持一致** +1. 再次强调一遍,**导出的动态库依赖的tf版本需要与推理服务依赖的tf版本保持一致** ## 自定义Op的示例 @@ -57,7 +58,7 @@ feature_config: { input_names: 'title' feature_type: PassThroughFeature } -} +} model_config: { model_class: 'RankModel' model_name: 'MLP' @@ -121,6 +122,6 @@ model_config: { 1. 如果自定义Op需要处理原始输入特征,则在定义特征时指定 `feature_type: PassThroughFeature` - 非 `PassThroughFeature` 类型的特征会在预处理阶段做一些变换,组件代码里拿不到原始值 -2. 自定义Op需要处理的原始输入特征按照顺序放置到同一个`feature group`内 -3. 配置一个类型为`raw_input`的输入组件,获取原始输入特征 +1. 自定义Op需要处理的原始输入特征按照顺序放置到同一个`feature group`内 +1. 配置一个类型为`raw_input`的输入组件,获取原始输入特征 - 这是目前EasyRec支持的读取原始输入特征的唯一方式 diff --git a/docs/source/component/sequence.md b/docs/source/component/sequence.md index de7026610..ddcbace7d 100644 --- a/docs/source/component/sequence.md +++ b/docs/source/component/sequence.md @@ -10,6 +10,7 @@ 所有 `SequenceFeature` 类型的子特征都被识别为`history behavior sequence`的一部分; 所有非`SequenceFeature` 类型的子特征都被识别为`target item`的一部分。 **两部分的子特征的顺序需要保持一致**。在下面的例子中, + - `concat([cate_id,brand], axis=-1)` 是`target item`最终的embedding(2D); - `concat([tag_category_list, tag_brand_list], axis=-1)` 是`history behavior sequence`最终的embedding(3D) diff --git a/easy_rec/python/test/train_eval_test.py b/easy_rec/python/test/train_eval_test.py index bd0f21f07..a13022fd8 100644 --- a/easy_rec/python/test/train_eval_test.py +++ b/easy_rec/python/test/train_eval_test.py @@ -407,7 +407,8 @@ def test_highway(self): 'EditDistanceOp only work before tf version == 2.0') def test_custom_op(self): self._success = test_utils.test_single_train_eval( - 'samples/model_config/mlp_on_movielens_with_custom_op.config', self._test_dir) + 'samples/model_config/mlp_on_movielens_with_custom_op.config', + self._test_dir) self.assertTrue(self._success) def test_cdn(self):