附录

训练功能特性流程

片上内存侧动态扩容模式

TensorFlow对Embedding的支持是通过变量实现的,用户需要预估每个表的大小,再通过create_table接口创建变量。Embedding表的大小在一开始就确认,后期无法扩大或者减小,这可能会导致显存的浪费或者空间不足。在推荐场景下,多个稀疏表的大小无法预估,为更好的适配用户场景及需求,增加片上内存稀疏表自动扩容功能,即显存随着模型训练增长。

片上内存侧动态扩容模式下,不支持特征淘汰。

训练流程介绍

本节介绍如何使用动态扩容模式进行训练,整体操作流程请参见图1

图 1 片上内存侧动态扩容模式训练流程图

训练流程分为以下部分,整体流程示例代码请参见示例代码

适配模型

关键步骤操作参考如下。

  1. 初始化框架。

    调用init接口,设置参数use_dynamic_expansion = True表示启用动态扩容功能,该参数默认为“False”。

  2. 稀疏优化器导入。

    调用mx_rec.optimizers包中对应优化器的create_hash_optimizer_by_address接口来创建稀疏表sparse_optimizer。具体可用优化器参考如下。

  3. 获取嵌入表示结果(emb)和映射地址(addr)。

    使用tf.get_collection("ASCEND_SPARSE_LOOKUP_LOCAL_EMB")接口获取训练用的嵌入表示结果,使用tf.get_collection("ASCEND_SPARSE_LOOKUP_ID_OFFSET")接口获取训练用的映射地址。

  4. 反向梯度计算。

    使用tf.gradients(loss, emb)接口对3获取的嵌入表示结果求导,得到梯度(grad)。

  5. 反向稀疏表更新。

    使用稀疏优化器导入创建的sparse_optimizer.apply_gradients([grad, addr])接口对映射地址对应位置的稀疏表进行更新。

启动训练

  1. 启动模型训练。
  2. 在模型训练完成后调用terminate_config_initializer释放资源。

示例代码

  1. 初始化框架。

    use_dynamic_expansion = bool(int(os.getenv("USE_DYNAMIC_EXPANSION", 0)))
    init(use_mpi, train_steps=args.train_steps, eval_steps=args.eval_steps, 
    use_dynamic_expansion=use_dynamic_expansion)
    
  2. 稀疏优化器导入。

    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
    
  3. 获取嵌入表示结果和映射地址。

    train_emb_list = tf.compat.v1.get_collection(ASCEND_SPARSE_LOOKUP_LOCAL_EMB)
    train_address_list = tf.compat.v1.get_collection(ASCEND_SPARSE_LOOKUP_ID_OFFSET)
    
  4. 反向梯度计算。

    local_grads = tf.gradients(loss, train_emb_list)  # local_embedding
    
  5. 反向稀疏表更新。

    grads_and_vars = [(grad, address) for grad, address in zip(local_grads, train_address_list)]
    train_ops.append(sparse_optimizer.apply_gradients(grads_and_vars))
    

    Note

    • 调用sparse_optimizer.apply_gradients(grads_and_vars)更新梯度时,若使用的vars(如address)是tensor而非variable,需要保证vars的维度和grads的第一个维度相等。
    • train_address_list地址列表需要是有效合法的,需通过3. 获取映射地址获取。若使用非法地址,运行时会抛出AICore Error等错误。

动态shape

Rec SDK TensorFlow训练框架支持动态shape,用户可参考使用流程启用动态shape功能。

启用动态shape功能前,需要安装ops算子包,具体操作请参见“《CANN 软件安装指南》的“安装CANN”章节的“安装ops”部分。

使用流程介绍

如需在Rec SDK TensorFlow训练框架使用动态shape功能,可在初始化框架时,配置init接口的“use_dynamic”参数为“True”。

示例代码

init(use_mpi, rank_id=rank_id, rank_size=rank_size, train_steps=train_steps, eval_steps=eval_steps, prefetch_batch_number=1, use_dynamic=True)

自动改图

使用流程介绍

本节介绍如何使用自动改图模式进行训练,整体操作流程请参见图1

图 1 自动改图使用流程

正常训练流程一般包含处理数据、创建稀疏表、查表、开始训练,使用自动改图模式和正常训练流程一致,仅需在查表接口设置“modify_graph”参数为“True”,并且在开始训练之前需要调用自动改图的接口。其中查表和调用自动改图接口操作为关键步骤。

关键步骤介绍

  1. 查询稀疏特征表。

    调用sparse_lookup接口,设置参数modify_graph=True表示在查表时采用自动改图模式,该参数默认为“False”。

  2. 调用自动改图接口。

    自动改图接口为modify_graph_and_start_emb_cache,但区分使用TF.Session训练使用NPUEstimator训练模式

    1. 使用TF.Session训练模式。

      在tf.Session训练模式下,需要显式调用modify_graph_and_start_emb_cache接口,同时sess.run(iterator.initializer)也需修改为自动改图的数据集初始化接口sess.run(get_initializer(True))或者sess.run(get_initializer(False)),前者用于训练(train)、后者用于评估(eval)。

    2. 使用NPUEstimator训练模式。

      在NPUEstimator模式下,需要在NPUEstimator的多个模式(train、predict、train_and_evaluate)中添加自动改图的GraphModifierHook,如当前为训练(train),则在训练的钩子(Hook)中添加GraphModifierHook,即可完成自动改图模式的训练。

示例代码

  1. 查询稀疏特征表。

    from mx_rec.core.embedding import sparse_lookup
    
    embedding = sparse_lookup(hash_table, feature, send_count, dim=None, is_train=is_train,
                              access_and_evict_config=access_and_evict_config,
                              name=hash_table.table_name + "_lookup", modify_graph=True, batch=batch)
    
  2. 调用改图接口。

    1. 使用tf.Session训练模式。

      from mx_rec.util.initialize import get_initializer
      from mx_rec.graph.modifier import modify_graph_and_start_emb_cache
      
      if MODIFY_GRAPH_FLAG:
          logging.info("start to modifying graph")
          modify_graph_and_start_emb_cache(dump_graph=True)
      else:
          start_asc_pipeline()
      
      # train
      with tf.compat.v1.Session(config=sess_config()) as sess:
          if MODIFY_GRAPH_FLAG:
              sess.run(get_initializer(True))
          else:
              sess.run(train_iterator.initializer)
      
      # eval
      def evaluate():
          if MODIFY_GRAPH_FLAG:
              sess.run(get_initializer(False))
          else:
              sess.run(eval_iterator.initializer)
      
    2. 使用NPUEstimator训练模式。

      from mx_rec.graph.modifier import GraphModifierHook
      
      est.train(input_fn=lambda: input_fn(), hooks=[GraphModifierHook()])   #est为创建的NPUEstimator对象
      

特征准入与淘汰

使用流程介绍

本节介绍如何使用特征准入与淘汰进行训练,涉及FeatureSpec模式与自动改图模式。

Note

开启淘汰功能后,不支持片上内存侧动态扩容。

图 1 特征准入与淘汰使用流程

关键步骤介绍

  • 在FeatureSpec模式下,请参考FeatureSpec进行配置。

  • 在自动改图模式下,请参考自动改图进行配置。

  • 环境变量USE_COMBINE_FAAE控制是否合表统计次数。

  • 提供一个CPU算子set_threshold支持在训练过程中更改准入阈值。

    Note

    如果set_threshold的第一个入参值为“0”,表示修改对应的emb表为特征不累加模式(准入阈值不变,但是特征计数不再累加,使用历史值)。

示例代码

  1. FeatureSpec模式。

    feature_spec_list = [FeatureSpec("user_ids", feat_count=cfg.user_feat_cnt, table_name="user_table",
                                     access_threshold=access_threshold,
                                     eviction_threshold=eviction_threshold,
                                     faae_coefficient=1),
                         FeatureSpec("item_ids", feat_count=cfg.item_feat_cnt, table_name="item_table",
                                     access_threshold=access_threshold,
                                     eviction_threshold=eviction_threshold,
                                     faae_coefficient=4),
                         FeatureSpec("timestamp", is_timestamp=True)]
    
    hook_evict = EvictHook(evict_enable=True, evict_time_interval=24*60*60, evict_step_interval=10000)
    
  2. 自动改图模式。

    config_for_user_table = dict(access_threshold=cfg.access_threshold, eviction_threshold=cfg.eviction_threshold,
                                faae_coefficient=1)
    
    embedding = sparse_lookup(hash_table, feature, send_count, dim=None, is_train=is_train,
                              access_and_evict_config=config_for_user_table ,
                              name=hash_table.table_name + "_lookup", modify_graph=modify_graph)
    hook_evict = EvictHook(evict_enable=True, evict_time_interval=24*60*60, evict_step_interval=10000)
    
  3. 更改准入阈值。

    from mx_rec.util.ops import import_host_pipeline_ops
    thres_tensor = tf.constant(60, dtype=tf.int32)
    set_threshold_op = import_host_pipeline_ops().set_threshold(thres_tensor,
                                            emb_name=self.table_list[0].table_name,
                                            ids_name=self.table_list[0].table_name + "_lookup")
    with tf.Session() as sess:
        sess.run(set_threshold_op)
    

Hot_Embedding

Hot_Embedding功能默认开启,无需配置。

示例代码

该功能自动开启,无需配置;为了确保使能成功,需要开启GatherV2算子的高性能模式,开启方法如下:

  1. 将op_impl_mode.ini配置项传入到Session。代码如下:

    import tensorflow as tf
    session_config = tf.compat.v1.ConfigProto(allow_soft_placement=False, log_device_placement=False)
    session_config.gpu_options.allow_growth = True
    custom_op = session_config.graph_options.rewrite_options.custom_optimizers.add()
    # 1. 将算子配置文件路径传入配置项
    custom_op.parameter_map["op_precision_mode"].s = tf.compat.as_bytes("op_impl_mode.ini")
    # 2. 建图
    # 3. 将config配置传入sess初始化中
    with tf.compat.v1.Session(config=sess_config) as sess:
    # 4. 训练
    
  2. 在模型的路径下创建op_impl_mode.ini文件,内容如下:

    GatherV2=high_performance
    

定制WarmStart

使用介绍

如需在Rec SDK TensorFlow训练框架使用定制WarmStart功能,需要在模型代码中创建NPUEstimator对象之前创建一个WarmStart的配置tf.estimator.WarmStartSettings,然后将这个配置传给NPUEstimator中warm_start_from参数即可。

Note

当前定制WarmStart仅支持TensorFlow 1.15.0版本下的HBM模式和DDR模式。

示例代码

定制WarmStart的使用示例如下:

示例1:模型从warm_start路径中加载稀疏表user_table。

import tensorflow as tf
from tf_adapter import NPUEstimator
 
warm_settings=tf.estimator.WarmStartSettings(ckpt_to_initialize_from="./warm_start",vars_to_warm_start ="user_table", var_name_to_vocab_info=None, var_name_to_prev_var_name=None)
est = NPUEstimator(
        model_fn=get_model_fn(create_fs_params, cfg, access_and_evict),
        params=params,
        model_dir=params.model_dir,
        config=run_config,
        warm_start_from=warm_settings 
)

表 1 tf.estimator.WarmStartSettings参数说明

参数 参数类型 说明
ckpt_to_initialize_from str(path) 指定从哪个检查点开始初始化。
vars_to_warm_start str/正则表达式/list[str]/list[variables] 指定从哪些变量开始初始化。dense层变量的指定方式保持与TF原生一致;Embedding参数支持:正则表达式、str(表名)和list(表名list)。
var_name_to_vocab_info dict 指定词汇表信息,用于恢复嵌入矩阵。
var_name_to_prev_var_name dict 用于存储变量名到WarmStart路径中变量名的映射关系。
说明
Embedding表名目前不支持名称映射。

示例2:模型从warm_start_1路径中加载所有参数,然后模型从warm_start_2路径中加载Embedding表user_table、item_table,替代已经加载的warm_start_1路径中的稀疏表结果。模型从warm_start_3路径中加载mlp_layer_w参数,替代warm_start_1的加载结果。

import tensorflow as tf
from tf_adapter import NPUEstimator
 
ckpt_to_initialize_from_list = ["./warm_start_1", "./warm_start_2", "./warm_start_3"]
vars_to_warm_start_list=[".*",  ["user_table", "item_table"], "mlp_layer_w" ]
var_name_to_prev_var_name_list = [{}, {}, {}]
warm_settings=tf.estimator.WarmStartSettings(
        ckpt_to_initialize_from=ckpt_to_initialize_from_list,
        vars_to_warm_start = vars_to_warm_start_list,
        var_name_to_vocab_info=None,
        var_name_to_prev_var_name=var_name_to_prev_var_name_list )
 
 est = NPUEstimator(
        model_fn=get_model_fn(create_fs_params, config, access_and_evict),
        params=params,
        model_dir=params.model_dir,
        config=run_config
        warm_start_from=warm_settings
    )

表 2 支持多路径WarmStart功能中tf.estimator.WarmStartSettings参数说明

参数 参数类型 说明
ckpt_to_initialize_from List(str(path)) 指定从哪个检查点开始初始化
vars_to_warm_start List(str/正则表达式/list[str]/list[variables]) 指定从哪些变量开始初始化。
dense层变量的指定方式保持与TF原生一致;Embedding参数支持:正则表达式、str(表名)和list(表名list)。
var_name_to_vocab_info List(dict) 指定词汇表信息,用于恢复嵌入矩阵。
var_name_to_prev_var_name List(dict) 用于存储变量名到WarmStart路径中变量名的映射关系。
Embedding表名目前不支持名称映射。

增量模型保存与加载

使用介绍

如需在Rec SDK TensorFlow训练框架使用增量模型保存与加载功能,可在初始化框架时,配置init接口的以下参数:

  • is_incremental_checkpoint=True:表示开启增量模型保存与加载功能。
  • save_checkpoint_due_time=xx:表示每隔xx秒保存一次全量模型。
  • save_delta_checkpoints_secs=xx:表示每隔xx秒保存一次增量模型。
  • restore_model_version=xx:表示指定加载step=xx的模型,如果不传这个参数则加载最新的模型;如果不需要加载模型可以不设置这个参数。

示例代码

使用示例如下:

from mx_rec.util.initialize import init
# set init
init(train_steps=args.train_steps,
     eval_steps=args.eval_steps,
      save_steps=args.save_checkpoints_steps,
      max_steps=args.max_steps,
      use_dynamic=use_dynamic,
      use_dynamic_expansion=use_dynamic_expansion,
      save_checkpoint_due_time=4,
      save_delta_checkpoints_secs=2,
      is_incremental_checkpoint=True,
      restore_model_version=3)

用户信息列表

请周期性地更新用户的密码,避免长期使用同一个密码带来的风险。

表 1 用户列表

用户名 描述 初始密码 密码修改方法
root 部署Rec SDK TensorFlow 用户自定义 使用passwd命令修改
HwHiAiUser 安装驱动,运行Demo依赖的用户 用户自定义 使用passwd修改

centos系统中Dockerfile示例的基础镜像用户

用户 初始密码 密码修改方法
root -
bin -
daemon -
adm -
lp -
sync -
shutdown -
halt -
mail -
operator -
games -
ftp -
nobody -
systemd-network -
dbus -

centos系统中RecSDK-TensorFlow组件容器内的用户

用户 描述 初始密码 密码修改方法
sshd - -