快速入门
使用前说明
本章节指导用户基于Rec SDK TensorFlow为用户提供的little-demo样例,理解使用一个tf.Session进行模型训练需要准备的相关文件和关键接口适配。little-demo仅是一个代码示例,并介绍了调用相关接口的逻辑,不包含具体的模型,没有实现具体的功能。
little-demo仅作参考学习,不支持在little-demo上适配用户自己的模型。little-demo存放路径为:链接。
Note
在train_and_evaluate场景下不支持多轮eval。
表 1 little-demo文件说明
| 文件名 | 说明 |
|---|---|
| config.py | 模型相关配置。 |
| dataset.py | 数据集预处理。 |
| deterministic_loss | 确定性计算loss样例。 |
| main.py | 模型训练入口。 |
| model.py | 模型搭建。 |
| op_impl_mode.ini | 算子配置文件。 |
| optimizer.py | 优化器。 |
| random_data_generator.py | 数据集随机生成。 |
| README.md | demo模型运行说明。 |
| run_deterministic.sh | 运行确定性计算的脚本。 |
| run_model.py | 训练、推理流程封装。 |
| run.sh | 模型训练启动脚本。 |
| utils.py | 精度检测工具。 |
接口调用介绍

-
初始化框架。在main.py中调用init接口,传入初始化框架需要的相关参数。相关参数请参见init。
# nbatch function needs to be used together with the prefetch and host_vocabulary_size != 0 init(max_steps=max_steps, train_steps=TRAIN_steps, eval_steps=EVAL_STEPS, save_steps=SAVE_STEPS, use_dynamic=use_dynamic, use_dynamic_expansion=use_dynamic_expansion) -
定义数据集。在main.py中调用get_asc_insert_func接口,创建数据集并对数据集进行预处理。相关参数请参见参数说明。
if not MODIFY_GRAPH_FLAG: insert_fn = get_asc_insert_func(tgt_key_specs=feature_spec_list, is_training=is_training, dump_graph=dump_graph) dataset = dataset.map(insert_fn) dataset = dataset.prefetch(100) iterator = dataset.make_initializable_iterator() batch = iterator.get_next() return batch, iterator -
定义优化器。在optimizer.py中定义优化器,支持的优化器类型和相关参数请参见优化器。
# coding: UTF-8 import logging import tensorflow as tf from mx_rec.optimizers.lazy_adam import create_hash_optimizer from mx_rec.optimizers.lazy_adam_by_addr import create_hash_optimizer_by_address from mx_rec.util.initialize import get_use_dynamic_expansion def get_dense_and_sparse_optimizer(cfg): dense_optimizer = tf.compat.v1.train.AdamOptimizer(learning_rate=cfg.learning_rate) use_dynamic_expansion = get_use_dynamic_expansion() if use_dynamic_expansion: sparse_optimizer = create_hash_optimizer_by_address(learning_rate=cfg.learning_rate) logging.info("optimizer lazy_adam_by_addr") else: sparse_optimizer = create_hash_optimizer(learning_rate=cfg.learning_rate) logging.info("optimizer lazy_adam") return dense_optimizer, sparse_optimizer -
建立稀疏表。在main.py中调用create_table接口,建立稀疏表,创建稀疏网络层。相关参数请参见参数说明。
user_hashtable = create_table(key_dtype=tf.int64, dim=tf.Tensorshape([cfg.user_hashtable_dim]), name='user_table', emb_initializer=tf.compat.v1.truncated_normal_initializer(), device_vocabulary_size=cfg.user_vocab_size * 10, host_vocabulary_size=0) # cfg.user_vocab_size * 100, # for h2d test item_hashtable = create_table(key_dtype=tf.int64, dim=tf.Tensorshape([cfg.item_hashtable_dim]), name='item_table', emb_initializer=tf.compat.v1.truncated_normal_initializer(), device_vocabulary_size=cfg.item_vocab_size * 10, host_vocabulary_size=0) # cfg.user_vocab_size * 100, # for h2d test -
建立计算图。传入稀疏网络层和特征列表,创建模型计算图,在计算图中调用sparse_lookup进行特征查询和误差计算。相关参数请参见参数说明。
def model_forward(input_list, batch, is_train, modify_graph, config_dict=None): embedding_list = [] feature_list, hash_table_list, send_count_list = input_list for feature, hash_table, send_count in zip(feature_list, hash_table_list, send_count_list): access_and_evict_config = None if isinstance(config_dict, dict): access_and_evict_config = config_dict.get(hash_table.table_name) embedding = sparse_lookup(hash_table, feature, send_count, is_train=is_train, access_and_evict_config=access_and_evict_config, name=hash_table.table_name + "_lookup", modify_graph=modify_graph, batch=batch) reduced_embedding = tf.reduce_sum(embedding, axis=1, keepdims=False) embedding_list.append(reduced_embedding) my_model = MyModel() my_model(embedding_list, batch["label_0"], batch["label_1"]) return my_model -
定义梯度计算和优化过程。在main.py中调用get_dense_and_sparse_variable接口,得到密集网络层和稀疏网络层的参数,通过优化器计算梯度并执行优化。接口说明请参见get_dense_and_sparse_variable。
train_iterator, train_model = build_graph([user_hashtable, item_hashtable], is_train=True, feature_spec_list=train_feature_spec_list, config_dict=ACCESS_AND_EVICT, batch_number=cfg.batch_number) eval_iterator, eval_model = build_graph([user_hashtable, item_hashtable], is_train=False, feature_spec_list=eval_feature_spec_list, config_dict=ACCESS_AND_EVICT, batch_number=cfg.batch_number) dense_variables, sparse_variables = get_dense_and_sparse_variable() -
启动数据加载和预处理。在main.py中调用modify_graph_and_start_emb_cache(改图模式)/start_asc_pipeline(非改图模式)接口,启动数据流水线(示例代码中使用if判断配置文件中的MODIFY_GRAPH_FLAG来控制是否使用改图模式)。接口说明请参见modify_graph_and_start_emb_cache。
saver = tf.compat.v1.train.Saver() if MODIFY_GRAPH_FLAG: logging.info("start to modifying graph") modify_graph_and_start_emb_cache(dump_graph=True) else: start_asc_pipeline() with tf.compat.v1.Session(config=sess_config(dump_data=False)) as sess: if MODIFY_GRAPH_FLAG: sess.run(get_initializer(True)) else: sess.run(train_iterator.initializer) sess.run(tf.compat.v1.global_variables_initializer()) EPOCH = 0 if os.path.exists(f"./saved-model/sparse-model-{rank_id}-%d" % 0): saver.restore(sess, f"./saved-model/model-{rank_id}-%d" % 0) else: saver.save(sess, f"./saved-model/model-{rank_id}", global_step=0) for i in range(1, 201): logging.info(f"################ training at step {i} ################") try: sess.run([train_ops, train_model.loss_list]) except tf.errors.OutOfRangeError: logging.info(f"Encounter the end of Sequence for training.") break else: if i % TRAIN_INTERVAL == 0: EPOCH += 1 evaluate() if i % SAVING_INTERVAL == 0: saver.save(sess, f"./saved-model/model-{rank_id}", global_step=i) saver.save(sess, f"./saved-model/model-{rank_id}", global_step=i) -
启动Session计算并在训练过程中保存模型。在main.py中调用saver接口,启动Session计算并在训练过程中保存模型。
saver = tf.compat.v1.train.Saver() if MODIFY_GRAPH_FLAG: logging.info("start to modifying graph") modify_graph_and_start_emb_cache(dump_graph=True) else: start_asc_pipeline() with tf.compat.v1.Session(config=sess_config(dump_data=False)) as sess: if MODIFY_GRAPH_FLAG: sess.run(get_initializer(True)) else: sess.run(train_iterator.initializer) sess.run(tf.compat.v1.global_variables_initializer()) EPOCH = 0 if os.path.exists(f"./saved-model/sparse-model-{rank_id}-%d" % 0): saver.restore(sess, f"./saved-model/model-{rank_id}-%d" % 0) else: saver.save(sess, f"./saved-model/model-{rank_id}", global_step=0) for i in range(1, 201): logging.info(f"################ training at step {i} ################") try: sess.run([train_ops, train_model.loss_list]) except tf.errors.OutOfRangeError: logging.info(f"Encounter the end of Sequence for training.") break else: if i % TRAIN_INTERVAL == 0: EPOCH += 1 evaluate() if i % SAVING_INTERVAL == 0: saver.save(sess, f"./saved-model/model-{rank_id}", global_step=i) saver.save(sess, f"./saved-model/model-{rank_id}", global_step=i) -
关闭数据流释放资源。在main.py中调用terminate_config_initializer,关闭数据流释放资源。接口说明请参见terminate_config_initializer。
terminate_config_initializer() logging.info("Demo done!")
启动模型训练
单机单卡和单机多卡训练
本章节介绍通过环境变量设置资源信息,启动训练任务,包含单机单卡和单机多卡场景。
使用该方案启动训练任务,需要设置如下环境变量。详细的配置环境变量的方法可参考little-demo的配置文件;关于环境变量的说明可参见配置环境变量。
CM_CHIEF_IP={host_ip}
CM_CHIEF_PORT=60000
CM_CHIEF_DEVICE=0
CM_WORKER_IP={host_ip}
CM_WORKER_SIZE=8
-
如果需要自定义卡的数量,需要修改local_rank_size=自定义卡的数量,CM_WORKER_SIZE=local_rank_size * 训练节点数。
Note
- 自定义卡的数量≤容器(或进程)中可见的卡的数量。
- 若是以特权模式启动的容器,容器中可见卡的数量=环境中卡的总数;若是以非特权模式启动的容器,容器中可见卡的数量 = 启动容器时实际挂卡的数量。
- 若是要进一步控制训练进程中可见卡的数量,可通过环境变量ASCEND_RT_VISIBLE_DEVICES来指定当前容器中可见的卡哪些对当前进程可见。该环境变量通常可指定参与训练的Device。
- 若是当前进程可见卡的数量为8,支持的自定义卡数量包括1、2、4、8。
下面的示例以环境中可见8卡为例,卡逻辑ID列表为[0,1,2,3,4,5,6,7]
-
local_rank_size = 1,则export CM_CHIEF_DEVICE可选[0,1,2,3,4,5,6,7]的任一卡号。
-
local_rank_size = 2,取值说明如下:
-
local_rank_size = 4,取值说明如下:
- export CM_CHIEF_DEVICE=0(表示0、1、2、3卡参与训练)
- export CM_CHIEF_DEVICE=4(表示4、5、6、7卡参与训练)
-
local_rank_size = 8,取值说明如下:
export CM_CHIEF_DEVICE=0(表示0、1、2、3、4、5、6、7卡参与训练)
Note
Rec SDK TensorFlow默认使用8卡训练,16卡使能需要执行以下命令。
for pdev in `lspci -vvv|grep -E "^[a-f]|^[0-9]|ACSCtl"|grep ACSCtl -B1|grep -E "^[a-f]|^[0-9]"|awk '{print $1}'` do setpci -s $pdev ECAP_ACS+06.w=0000 done -
直接在启动命令后传入配置Master节点的Host侦听IP,命令格式如下。
bash run.sh main.py {host_ip}Note
正常开始执行,打印信息参考如下。
ip: {host_ip} available. The ranktable solution is removed. CM_CHIEF_IP={host_ip} CM_CHIEF_PORT=60000 CM_CHIEF_DEVICE=0 CM_WORKER_IP={host_ip} CM_WORKER_SIZE=8 ASCEND_VISIBLE_DEVICES=0-8 py is main.py use horovod to start tasks ...执行完成,日志信息显示参考如下。
ASC manager has been destroyed. MPI has been destroyed. Demo done!
多机多卡训练
本章节以双机(单节点8卡)为示例,介绍通过环境变量设置资源信息,在多机多卡场景下启动训练任务。
-
设置如下环境变量。详细的配置环境变量的方法可参考little-demo的配置文件;关于环境变量的说明可参见配置环境变量。
CM_CHIEF_IP={host_ip} CM_CHIEF_PORT=60000 CM_CHIEF_DEVICE=0 CM_WORKER_IP={host_ip} CM_WORKER_SIZE=8 -
双机节点little_demo模型代码路径和配置IP的网卡名称需要保持一致。
-
已完成集群内的组网配置。详细方法可参见《Ascend Training Solution 组网指南》的“组网介绍”章节。
-
已经根据制作Rec SDK TensorFlow训练镜像,制作Rec SDK TensorFlow的训练镜像。
-
已完成基础集群环境的网络配置检查,例如确认多机节点的NPU device IP能互相ping通,多机节点的NPU device的TLS配置相同等。如果集群通信失败,可参考多机训练HCCL集群通信失败解决。
多机训练的配置的主要步骤为:下载Rec SDK TensorFlow镜像并创建容器后,修改SSH配置并启动服务,然后配置物理机节点之间的免密登录,最后配置little_demo模型,进而拉起训练进程,实现多机训练。双机时可任选一节点为主节点。

-
双机节点创建并配置容器。
i. 确定节点需要使用的端口号。所有节点都需要用同一未被占用的端口号。可在物理机上执行以下命令,查询端口是否使用。以端口12345为例。```bash ss -tuln | grep 12345 ``` >[!NOTE] >若ss指令不存在需安装iproute软件包。 - 结果为空,表示端口未使用 =\> 继续执行[1.b](#li9821162384914) - 结果不为空,表示端口已使用 =\> 重复查询其他端口号```bash vi /etc/ssh/sshd_config ``` 1. 取消“\#Port 22”所在行的注释,并将端口号修改为未使用的端口号(如“12345”),便于mpi通过指定端口进入其他节点容器。同时,Host侧防火墙策略中需允许访问该端口。 2. 取消“\#ListenAddress 0.0.0.0”的注释,并将“0.0.0.0”修改为当前节点IP。如果采用导出最新容器镜像并复制到其他环境的方式部署集群环境,在其他节点启动并进入容器后,需手动修改容器内SSH服务侦听IP为对应节点IP。 >[!NOTE] >如果不执行该步骤,不会影响集群训练,但是会侦听宿主机全零IP的对应端口。出于安全考虑,建议进行修改。iii. 在容器内执行以下命令重启SSH服务。
```bash systemctl restart sshd ``` 重启后,执行**systemctl status sshd**命令查看SSH服务的状态。 可执行**ss -tuln | grep** _12345_查看侦听端口是否为配置的端口。 如需停止容器内SSH服务,可在容器内执行: ```bash kill -9 `ps -ef | grep sshd | grep -v grep | awk '{print $2}'` > /dev/null 2>&1 ```iv. 设置容器内环境变量。
将启动训练前需要配置的环境变量设置到容器内的\~/.bashrc文件,便于主节点免密登录到其他节点容器内时能直接使用,无需配置环境变量。 示例如下,按需配置: 1. 打开“\~/.bashrc”文件。 ```bash vi ~/.bashrc ``` 2. 在文件末尾添加以下内容。 ```bash source /etc/profile source /usr/local/Ascend/cann/set_env.sh source /usr/local/Ascend/driver/bin/setenv.bash export PATH=/usr/local/openmpi/bin:$PATH export PATH=/usr/local/python3.7.5/bin:$PATH export PATH=/usr/local/gcc7.3.0/bin:$PATH export LD_LIBRARY_PATH=/usr/local/python3.7.5/lib:$LD_LIBRARY_PATH export LD_LIBRARY_PATH=/usr/local/gcc7.3.0/lib64:$LD_LIBRARY_PATH export LD_LIBRARY_PATH=/usr/local/openmpi/lib:$LD_LIBRARY_PATH ``` 3. 按“Esc”键,输入<b>:wq!</b>,按“Enter”保存并退出编辑。 4. 执行**source \~/.bashrc**使环境变量配置生效。 -
配置little_demo模型。
i. 使用以下命令查看8卡芯片的device IP,命令参考如下。```bash for i in {0..7}; do hccn_tool -i $i -ip -g ; done ```ii. 配置资源信息。 - ranktable方式启动时,所有节点中均需要“hccl_json_16p_2_host.json”配置文件,且文件内容一样。“hccl_json_16p_2_host.json”文件配置样例参考如下。
示例为双机节点“hccl\_json\_16p\_2\_host.json”配置,主节点的device信息需配置在第一个device中。\{device\_ip\}和\{host\_ip\}需要根据真实环境配置进行替换,rank\_id需要保持升序。 ```bash { "server_count":"2", "server_list":[ { "device":[ { "device_id":"0", "device_ip":"{device_0_ip}", "rank_id":"0" }, { "device_id":"1", "device_ip":"{device_1_ip}", "rank_id":"1" }, { "device_id":"2", "device_ip":"{device_2_ip}", "rank_id":"2" }, { "device_id":"3", "device_ip":"{device_3_ip}", "rank_id":"3" }, { "device_id":"4", "device_ip":"{device_4_ip}", "rank_id":"4" }, { "device_id":"5", "device_ip":"{device_5_ip}", "rank_id":"5" }, { "device_id":"6", "device_ip":"{device_6_ip}", "rank_id":"6" }, { "device_id":"7", "device_ip":"{device_7_ip}", "rank_id":"7" } ], "server_id":"{host_1_ip}" }, { "device":[ { "device_id":"0", "device_ip":"{device_8_ip}", "rank_id":"8" }, { "device_id":"1", "device_ip":"{device_9_ip}", "rank_id":"9" }, { "device_id":"2", "device_ip":"{device_10_ip}", "rank_id":"10" }, { "device_id":"3", "device_ip":"{device_11_ip}", "rank_id":"11" }, { "device_id":"4", "device_ip":"{device_12_ip}", "rank_id":"12" }, { "device_id":"5", "device_ip":"{device_13_ip}", "rank_id":"13" }, { "device_id":"6", "device_ip":"{device_14_ip}", "rank_id":"14" }, { "device_id":"7", "device_ip":"{device_15_ip}", "rank_id":"15" } ], "server_id":"{host_2_ip}" } ], "status":"completed", "version":"1.0" } ``` - no ranktable启动时,不需要配置hccl json文件,但需要在所有备节点little\_demo模型代码的main.py中手动设置环境变量,修改如下: 在main.py顶部import os的下一行添加如下代码: ```bash # no ranktable时设置CM_WORKER_IP环境变量为当前节点ip,{host_ip}为当前节点ip。 if not os.getenv("RANK_TABLE_FILE", ""): os.environ['CM_WORKER_IP'] = "{host_ip}" ```iii. 修改run.sh脚本(仅需修改主节点)。
1. num\_server修改为实际节点数(比如2)。 2. 删除mpi\_args变量值中的“-mca btl\_tcp\_if\_exclude docker0”字符串。 3. 将“interface”的值修改为配置当前host ip的网卡名。可通过**ip addr**进行查询。 4. 使用ranktable启动方案时,还需修改export RANK\_TABLE\_FILE变量值中的json文件名称,使其与[•ranktable方式启动时,所有节点中均需要...](#li488122614226)中配置的双机的hccl json文件名一致,例如: 将 ```bash export RANK_TABLE_FILE="${cur_path}/hccl_json_${local_rank_size}p.json" ``` 修改为: ```bash export RANK_TABLE_FILE="${cur_path}/hccl_json_16p_2_host.json" ``` 5. 通过horovodrun启动指令指定端口号并修改host参数,修改如下内容: 在run.sh脚本末尾,将 ```bash xxx --mpi-args "${mpi_args}" --mpi -H localhost:${local_rank_size} ``` 修改为: ```bash xxx --mpi-args "${mpi_args}" -p 12345 --mpi -H {host_1_ip}:8,{host_2_ip}:8 ``` >[!NOTE] >- -p 12345:容器内ssh server侦听端口号。 >- 8:单节点参与训练的device数。 -
在每个节点上互相设置免密登录。
i. 在每个节点的容器内执行以下命令,设置免密登录。其中{target_host_user}为对端节点的用户名,{target_host_ip}为对端节点的IP。```bash ssh-copy-id -i ~/.ssh/id_rsa.pub {target_host_user}@{target_host_ip} ``` >[!NOTE] >该命令默认将公钥追加到对端节点宿主机的\~/.ssh/authorized\_keys文件中,需要用户将宿主机上的authorized\_keys文件拷贝到容器内的\~/.ssh目录下。 若提示没有id\_rsa.pub,可以使用如下命令在容器内生成。为了安全起见,在执行命令前需将当前umask值改为0077,执行完后再恢复为原值;并建议在提示“Enter passphrase”时输入符合复杂度要求的密钥密码。 ```bash ssh-keygen -t rsa -b 3072 -f ~/.ssh/id_rsa ``` >[!NOTE] >以上为示例,请注意SSH密钥和密钥密码在使用和保管过程中的风险,特别是密钥未加密时的风险,用户应按照所在组织的安全策略进行相关配置,如口令复杂度要求、安全配置(协议、加密套件、密钥长度、是否允许使用ssh-keygen等)。ii. 设置SSH代理管理SSH密钥。
设置SSH代理命令如下: a. 开启ssh-agent的bash进程。 ```bash ssh-agent bash ``` >[!NOTE] >执行此命令时容器内的环境变量会被重置。建议将必要的环境变量保存到容器内的\~/.bashrc文件中,并在执行完该命令后使用**source \~/.bashrc**命令重新配置。 b. 向ssh-agent添加私钥。 ```bash ssh-add ~/.ssh/id_rsa ``` 执行如上命令会提示“Enter passphrase for /root/.ssh/id\_rsa:”,此时需要输入生成id\_rsa私钥时设置的密码。 c. 验证私钥是否添加成功。 ```bash ssh-add -l ```iii. 检查免密登录是否设置成功。
```bash ssh-keygen -R {target_host_ip} # 删除当前节点中目标ip的host key缓存 ssh-keygen -R "[{target_host_ip}]:12345" # 删除当前host上保存的目标ip对应端口的host key缓存 ssh {target_host_user}@{target_host_ip} # 验证免密登录目标ip ssh {target_host_user}@{target_host_ip} -p 12345 # 验证免密登录目标ip指定端口 ``` -
在主节点执行以下命令,拉起模型。只需要在主节点拉起即可,备节点不需要手动拉起训练任务,mpi会自动跳转过去拉起训练任务。
-
rank table模式:
bash run.sh main.py -
去rank table模式,其中{host_1_ip}为主节点IP。
bash run.sh main.py {host_1_ip}Note
执行完拉起训练任务后,请使用exit命令退出ssh-agent的bash进程,避免安全风险。
-
Rec SDK TensorFlow执行样例
RecSDK TensorFlow目前已适配以下模型,各模型的具体运行步骤请参考对应文档:
| 模型 | 说明 | 文档链接 |
|---|---|---|
| little_demo | 基础示例(sess 模式) | 查看文档 |
| little_demo_estimator | 基础示例(Estimator 模式) | 查看文档 |
| DCNv2 | 深度交叉网络 v2 | 查看文档 |
| DLRM | 深度学习推荐模型 | 查看文档 |
| MMOE | 多任务混合专家模型 | 查看文档 |
| WideDeep | 宽深学习模型 | 查看文档 |