# Embedding Lookup异步化 ## 背景 在分布式训练的场景下,随着稀疏模型越来越复杂,模型的输入特征也越来越多。这导致每步训练时worker节点需要在ps节点进行大量的Embedding lookup操作,该操作的在整个端到端的耗时也不断增长,成为模型训练速度的瓶颈,导致不能高效地利用计算资源。 DeepRec提供了Embedding lookup异步化的功能,该功能能够自动地将Embedding lookup部分子图划分出来,并实现与计算主图部分的异步执行,从而实现通信过程与计算过程的重叠,消除模型通信瓶颈对训练的影响,提高计算资源利用率。优化整张图的执行效率,提升训练性能。 由于Embedding lookup操作异步化后,worker端梯度更新部分与Embedding lookup部分位于两张图内,将导致worker端无法获得PS端最新的Embedding lookup结果,有可能影响训练收敛速度和模型效果。 ## 功能说明 在用户的原图有io stage阶段的前提下,通过开启async embedding功能,实现Embedding子图的自动切分,并实现embedding lookup的异步化,从而提高训练性能。 **注意:** 1. 该功能开启的前提条件是用户的原图中存在一个io stage阶段,该阶段应当在读取样本之后,embedding lookup之前。相关内容请参见[流水线-Stage](./Stage.md)一节。 2. 该功能与[自动流水线-SmartStage](./Smart-Stage.md)冲突,开启async embedding功能后将自动关闭SmartStage功能。 ## 用户接口 目前,该功能实现了DeepRec中以下Embedding lookup函数接口的支持。 ```python tf.contrib.feature_column.sequence_input_layer() tf.contrib.layers.safe_embedding_lookup_sparse() tf.contirb.layers.input_from_feature_columns() tf.contirb.layers.sequence_input_from_feature_columns() tf.feature_column.input_layer() tf.nn.embedding_lookup() tf.nn.embedding_lookup_sparse() tf.nn.safe_embedding_lookup_sparse() tf.nn.fused_embedding_lookup_sparse() tf.python.ops.embedding_ops.fused_safe_embedding_lookup_sparse() ``` 该功能在ConfigProto中定义了如下配置选项 ```python sess_config = tf.ConfigProto() sess_config.graph_options.optimizer_options.do_async_embedding = True sess_config.graph_options.optimizer_options.async_embedding_options.threads_num = 4 sess_config.graph_options.optimizer_options.async_embedding_options.capacity = 4 sess_config.graph_options.optimizer_options.async_embedding_options.use_stage_subgraph_thread_pool = False # 可选 sess_config.graph_options.optimizer_options.async_embedding_options.stage_subgraph_thread_pool_id = 0 # 可选 ``` 其中: | 配置选项 | 含义 | 默认值 | | ------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------- | ----------------------------- | | do_async_embedding | Async Embedding开关 | False(关闭) | | async_embedding_options.threads_num | 异步化执行embedding lookup子图线程数 | 0 (需手动指定) | | async_embedding_options.capacity | 缓存异步化执行embedding lookup子图结果的最大个数 | 0 (需手动指定) | | async_embedding_options.use_stage_subgraph_thread_pool | 是否使用独立线程池运行embedding lookup子图,需要先创建独立线程池。 | False(可选,若为True则必须先创建独立线程池) | | async_embedding_options.stage_subgraph_thread_pool_id | 如果启用独立线程池运行embedding lookup子图,该选项用于指定独立线程池索引,需要先创建独立线程池,并打开async_embedding_options.use_stage_subgraph_thread_pool选项。 | 0,(可选,索引范围为[0, 创建的独立线程池数量-1]) | **注意事项** 1. `async_embedding_threads_num` 并不是越大越好,只需要可以让计算主图部分不必等待embedding lookup子图的结果即可,数量更大会抢占模型训练的计算资源,同时也会占用更多的通信带宽。建议按下述公式设置,可以从1开始向上调整。 ![](./Async-Embedding-Stage/1.png) 2. `async_embedding_capacity` 更大会消耗更多的内存或缓存。同时也会造成缓存的embedding lookup子图结果与从PS端获取的最新结果有较大差异,造成训练收敛慢。建议设置为`async_embedding_threads_num` 的大小,可以从1开始向上调整。 3. 独立线程池功能可以使不同的Stage子图运行在不同的线程池中,避免与计算主图和其他子图竞争默认线程池。关于如何创建独立线程池,可以参见[流水线Stage](./Stage.md) 一节。 ## CPU集群性能对比 机型为Aliyun ECS实例 ecs.hfc7.24xlarge,10台组成训练集群。 集群配置如下表所示。 | 项目 | 说明 | | ---- | -------------------------------------------------- | | CPU | Intel Xeon Platinum (Cooper Lake) 8369 96核心 | | MEM | 192 GiB | | 网络带宽 | 32 Gbps | 训练配置 | 项目 | 说明 | | ---------- | --- | | PS 数量 | 8 | | worker数量 | 30 | | PS 核心数 | 15 | | worker 核心数 | 10 | 模型性能 | 模型 | baseline性能(global steps/sec) | async embedding功能性能(global steps/sec) | 加速比 | | ---- | ---------------------------- | ------------------------------------- | ------ | | DLRM | 1008.6968 | 1197.932 | 1.1876 |