Migration and Training
Training Scenarios
Introduction to Training Scenarios
Rec SDK TensorFlow provides two training scenarios: tf.Session and NPUEstimator.
tf.Sessiontraining scenario: Start model running by creating a newSessioninstance, which returns tensor examples for customized model training.- NPUEstimator training scenario: Based on the encapsulation of control over different stages of machine learning, you do not need to repeatedly write training, evaluation, and prediction code for new machine learning tasks. You can focus on the control of the network structure.
Note
- Rec SDK TensorFlow does not support Keras currently.
- Rec SDK TensorFlow currently supports only the migration of model training scripts using TensorFlow native APIs. It does not support third-party frameworks (such as tf_adapter, HugeCTR, and DeepRec).
- Rec SDK TensorFlow currently supports only the tf.data.Dataset format for model input data.
- When large and small loops are enabled, the total number of training iterations must be an integer multiple of the small loop (that is,
iterations_per_loop).
Mapping Between TensorFlow and Rec SDK TensorFlow APIs
During model migration, determine whether the sparse table APIs are used based on the actual model code and context. If a TensorFlow API is related to sparse tables, change it to the corresponding Rec SDK TensorFlow API as shown in Table 1.
| TensorFlow API | Rec SDK TensorFlow API | Description |
|---|---|---|
| create_table | Creates a sparse table. | |
| sparse_lookup | Queries a sparse table. |
API examples:
-
TensorFlow example
import tensorflow as tf from tensorflow.contrib.lookup import MutableHashTable # ....... user_id = features["user_ids"] user_emb_table = MutableHashTable(key_dtype=tf.int64, value_dtype=tf.float32, default_value=0.0) user_emb = user_emb_table.lookup(user_id) -
Rec SDK TensorFlow example
import tensorflow as tf from mx_rec.core.embedding import create_table, sparse_lookup # ....... user_emb_table = create_table(key_dtype=tf.int64, value_dtype=tf.float32, name="user_table", dim=tf.Tensorshape([1]), emb_initializer=tf.compat.v1.truncated_normal_initializer(mean=10), device_vocabulary_size= 800000, host_vocabulary_size=0) user_emb = sparse_lookup(user_emb_table, feature_spec_list, batch_size*16, is_train=True, name=user_emb_table.table_name + "_lookup", modify_graph=False)
Estimator Migration and Training
Estimator Migration
If the original TensorFlow network is constructed based on the Estimator API, refer to this section for the manual migration process.
You are advised to use the model training samples provided by Rec SDK TensorFlow for adaptation. If you use open-source recommendation projects, direct API migration may cause compatibility issues.
Estimator Overview
As a high-level API of TensorFlow 1.10 released in 2018, Estimator greatly streamlines the programming process of machine learning. Estimator has many advantages, for example, good support for distribution, simplified model creation, and code sharing between model developers.
The process of developing a training script using Estimator is as follows:
- Perform data preprocessing and create the input function
input_fn. - Build the model and construct the model function
model_fn. - Configure running, instantiate the Estimator, and pass a
RunConfigobject as a running parameter. - Perform training by calling the training method
Estimator.train()on Estimator to train the model with specified inputs for a fixed number of steps.
The following describes how to migrate an Estimator training script for training on Ascend AI Processors.
Adding Header Files
For Python files modified in the following steps, add the following header file references to import NPU-related libraries.
from npu_bridge.npu_init import *
Note
After you import the preceding header file, the training script runs on the Ascend AI Processor by default.
Data Preprocessing
Generally, this part of code does not need to be modified. Adapt the code in the following scenario:
If the original network script uses dataset.batch(batch_size) to return a dynamic shape, the number of remaining samples in the data stream may be smaller than the batch size. This makes the shape of the last step inconsistent with preceding shapes, triggering the dynamic shape compilation process. To improve compilation performance, set drop_remainder to True to discard the last few samples in the file and ensure consistent shapes for every step in the network.
dataset = dataset.batch(batch_size, drop_remainder=True)
Note: During inference, if the amount of inference data in the last iteration is smaller than the batch size, you must pad the data to the batch size. This is because some scripts include an assertion at the end to verify that the number of results matches the number of validation data.
assert num_written_lines == num_actual_predict_examples
Model Construction
Generally, this part of code does not need to be modified. Adapt the code in the following scenario:
-
For
dropoutin the original network, you are advised to replace it with the corresponding CANN API implementation for better performance, while paying attention to the impact on network accuracy.-
If
tf.nn.dropoutexists, you are advised to change it to:layers = npu_ops.dropout() -
If
tf.layers.dropout,tf.layers.Dropout,tf.keras.layers.Dropout,tf.keras.layers.SpatialDropout1D,tf.keras.layers.SpatialDropout2D, ortf.keras.layers.SpatialDropout3Dexists, add the following header file reference:from npu_bridge.estimator.npu import npu_convert_dropout
-
-
For
geluin the original network, you are advised to replace it with the corresponding CANN API implementation for better performance.Original TensorFlow code:
def gelu(x): cdf = 0.5 * (1.0 + tf.tanh( (np.sqrt(2 / np.pi) * (x + 0.044715 * tf.pow(x, 3))))) return x*cdf layers = gelu()Migrated code:
layers = npu_unary_ops.gelu(x)
Running Configuration
TensorFlow configures running parameters through RunConfig. You need to migrate RunConfig to NPURunConfig. Since the NPURunConfig class inherits from the RunConfig class, you can modify the script as follows. Most parameters can remain unchanged.
Original TensorFlow code:
config=tf.estimator.RunConfig(
model_dir=FLAGS.model_dir,
save_checkpoints_steps=FLAGS.save_checkpoints_steps,
session_config=tf.ConfigProto(allow_soft_placement=True, log_device_placement=False))
Migrated code:
npu_config=NPURunConfig(
model_dir=FLAGS.model_dir,
save_checkpoints_steps=FLAGS.save_checkpoints_steps,
# If code related to tf.device is used in the original network, add the session configuration "allow_soft_placement=True" to allow TensorFlow to automatically allocate devices.
session_config=tf.ConfigProto(allow_soft_placement=True, log_device_placement=False)
)
However, some parameters (including train_distribute, device_fn, protocol, eval_distribute, and experimental_distribute) are not supported in NPURunConfig. If they are used in the original script, delete them.
If code related to tf.device is used in the original network, add the session configuration allow_soft_placement=True to allow TensorFlow to automatically allocate devices.
Additionally, some parameters are added to NPURunConfig to improve training performance and accuracy, such as iterations_per_loop and precision_mode. For detailed parameter information, see "NPURunConfig Constructor" in TensorFlow Adapter API (1.x).
Creating an Estimator Object
You need to migrate the TensorFlow Estimator object to NPUEstimator. Since the NPUEstimator class inherits from the Estimator class, you can directory change the API as follows during migration, and the parameters can remain unchanged.
Original TensorFlow code:
mnist_classifier=tf.estimator.Estimator(
model_fn=cnn_model_fn,
config=config,
model_dir="/tmp/mnist_convnet_model")
Migrated code:
mnist_classifier=NPUEstimator(
model_fn=cnn_model_fn,
config=npu_config,
model_dir="/tmp/mnist_convnet_model"
)
Performing Training
Train the model with specified inputs. This part of code does not need to be modified.
mnist_classifier.train(
input_fn=train_input_fn,
steps=20000,
hooks=[logging_hook])
Note
If an error occurs during migration and training, see the FAQ or contact technical support.
Training with Estimator
Estimator Scenario Description
Estimator encapsulates control over different stages of machine learning, so you do not need to repeatedly write training, evaluation, and prediction code for new machine learning tasks. You can focus on the control of the network structure. NPUEstimator is an encapsulation based on Estimator and supports model training on Ascend devices.
Training Process Introduction
This section describes how to use NPUEstimator for model training. For the overall operation process, see Figure 1.
Figure 1 NPUEstimator training process

Adapting the Model
You need to adapt the model to be used and can add functional features provided by Rec SDK TensorFlow during the adaptation process. This section introduces key steps in model adaptation and how to add desired functional features.
Note
Functional features can be used in combination. You need to modify and adapt them in the corresponding key steps. To view the calling process of a single functional feature, see Training Feature Process. Feature eviction and the on-chip memory dynamic expansion mode cannot be enabled at the same time.
The key steps are as follows:
-
Initialize the framework.
Call the init API to initialize the Rec SDK TensorFlow model training framework.
To add functional features, select the desired features in this step and make corresponding modifications.
Table 1 Functional features
Feature Operation Dynamic expansion Set use_dynamic_expansion = Trueto enable the on-chip memory dynamic expansion function. The value isFalseby default. The DDR and SSD modes support only dynamic expansion on the memory/drive side.Dynamic shape Set use_dynamic = Truefor the init API. Before enabling the dynamic shape function, install the ops operator package. For details, see "Installing ops" in "Installing CANN" of the CANN Software Installation Guide.Automatic graph modification - Feature admission and eviction - -
Choose to define features or automatically modify the graph.
- Define the feature list and model.
Use
FeatureSpecto define the feature list and configure the corresponding model.To add functional features, select the desired features in this step and make corresponding modifications.
Table 2 Functional features
Feature Operation Dynamic expansion - Dynamic shape - Feature admission and eviction - To enable the admission function, set the admission threshold
access_thresholdto a value greater than or equal to 0 (unit: times). A parameter error will be reported if the threshold is less than -1. - To enable the eviction function, perform the following steps:
- Set the eviction threshold
eviction_thresholdto a value greater than or equal to 0 (unit: seconds). A parameter error will be reported if the threshold is less than -1. - Set
FeatureSpecwithindex_keyastimestampand the parameteris_timestamp=True, indicating that the dataset contains timestamps. - Use the
EvictHookAPI to set a hook for the eviction trigger. This API has three parameters:evict_enable=True,evict_time_interval=24 * 60 * 60, andevict_step_interval=10000, representing the eviction function switch, eviction trigger time interval (unit: seconds), and global step interval, respectively. You can choose eitherevict_time_intervalorevict_step_interval.
- Set the eviction threshold
- The feature eviction hook is used only in training mode.
- To enable the admission function, set the admission threshold
- Automatic graph modification
In the NPUEstimator mode, add
GraphModifierHookfor automatic graph modification to multiple modes (train,predict, andtrain_and_evaluate) of NPUEstimator. For example, if the current mode istrain, addGraphModifierHookto the training hook to complete training in automatic graph modification mode.To add functional features, select the desired features and make corresponding modifications.
Table 3 Functional features
Feature Operation Dynamic expansion - Dynamic shape - Feature admission and eviction When using the sparse_lookupAPI, set theaccess_and_evict_configparameter, which is of the dictionary type. The dictionary consists of two key-value pairs. The keys areaccess_thresholdandeviction_threshold, and the values are the corresponding thresholds.
- Define the feature list and model.
-
Define the dataset. Skip this step if you choose the automatic graph modification mode.
When using
FeatureSpecto define the feature list, create a dataset based on the feature list and perform preprocessing. Call theget_asc_insert_funcAPI to obtain the Rec SDK TensorFlow data preprocessing interface and apply it to the dataset. -
Define the optimizer.
Select an optimizer under
mx_rec.optimizersand call the corresponding API to obtain the optimizer object for the sparse network layer. For currently available optimizers, see Optimizers. For the optimization interface of the dense network layer, use the TensorFlow built-in optimizer.To add functional features, select the desired features in this step and make corresponding modifications.
Table 4 Functional features
Feature Operation Dynamic expansion For dynamic expansion on the on-chip memory side, call the create_hash_optimizer_by_addressAPI of the corresponding optimizer in themx_rec.optimizerspackage to createsparse_optimizerfor sparse tables. Available optimizers are:Dynamic shape - Automatic graph modification - Feature admission and eviction - -
Create a sparse table.
Call the
create_tableAPI to create a sparse network layer. You can create a sparse network layer for each sparse feature.Note
In the Estimator mode, the
create_tableAPI must be called inside themodel_fnpassed to the Estimator. The Estimator source code creates a new graph instance when callingmodel_fn, which is different from the default graph where the entry function main is located. -
Pass the sparse network layer and feature list to create the model computational graph. Call
sparse_lookupin the computational graph for feature lookup and error calculation.Table 5 Functional features
Feature Operation Dynamic expansion - Dynamic shape - Automatic graph modification Query the sparse feature table. Call the sparse_lookupAPI and setmodify_graph=Trueto use the automatic graph modification mode during table lookup. The default value of this parameter isFalse.Feature admission and eviction - -
Define gradient calculation and the optimization process.
Call the
get_dense_and_sparse_variableinterface to obtain parameters for the dense and sparse network layers. Calculate gradients and perform optimization through the optimizer.To add functional features, select the desired features in this step and make corresponding modifications.
Table 6 Functional features
Feature Operation Dynamic expansion Dynamic expansion on the on-chip memory side: - Obtain the embedding result (
emb) and mapping address (addr).- Use the
tf.get_collection("ASCEND_SPARSE_LOOKUP_LOCAL_EMB")API to obtain the embedding result for training. - Use the
tf.get_collection("ASCEND_SPARSE_LOOKUP_ID_OFFSET")API to obtain the mapping address for training.
- Use the
- Perform backward gradient calculation. Use the
tf.gradients(loss, emb)API to calculate the derivative of the embedding result obtained in the preceding step to get the gradient (grad). - Update the backward sparse table. Use the sparse optimizer and import the created
sparse_optimizer.apply_gradients([grad, addr])API to update the sparse table at the location corresponding to the mapping address.
Dynamic shape - Automatic graph modification - Feature admission and eviction - - Obtain the embedding result (
-
Start data loading and preprocessing. Skip this step if you choose the automatic graph modification mode.
When using
FeatureSpecto define the feature list, callstart_asc_pipelineto start the data pipeline.
Starting Training
Call tf.estimator.train_and_evaluate to start model training.
See Performing Training in the Estimator Migration section.
Note
When performing train_and_evaluate in the Estimator scenario, if dynamic expansion on the on-chip memory side is not enabled, tables will be created twice. If a table is very large, accelerator memory may be insufficient. In this case, use the on-chip memory dynamic expansion mode, as the expansion mode creates the table only once.
Completing Training and Viewing Results
The key steps are as follows:
-
View the training results.
-
To export sparse table data in .npy format, call the
exportAPI. -
To export a .pb model file, call the
export_saved_modelAPI of the Estimator. The example is as follows:import os import tensorflow as tf if tf.__version__.startswith("1"): from npu_bridge.npu_init import NPURunConfig, NPUEstimator else: from npu_device.compat.v1.npu_init import NPURunConfig, NPUEstimator # See "Running Configuration" and "Creating an Estimator Object" in the Estimator Migration section. run_config = NPURunConfig(...) est = NPUEstimator(...) # Generally, the export_saved_model API is called after train or train_and_evaluate. def _serving_input_fn(): # Adjust the configuration based on the specific service model. The following uses the input of the little demo estimator model as an example. inputs = { "user_ids": tf.compat.v1.placeholder(shape=(None, 32), dtype=tf.int64, name="user_ids"), "item_ids": tf.compat.v1.placeholder(shape=(None, 8), dtype=tf.int64, name="item_ids"), "label_0": tf.compat.v1.placeholder(shape=(None,), dtype=tf.float32, name="label_0"), "label_1": tf.compat.v1.placeholder(shape=(None,), dtype=tf.float32, name="label_1"), } return tf.estimator.export.ServingInputReceiver(features=inputs, receiver_tensors=inputs) target_pb_path = os.path.abspath("pb_model_path") # Call the export_saved_model API of the estimator to save the .pb file. export_path = est.export_saved_model(target_pb_path, _serving_input_fn).decode("utf-8") print(f"The export saved model path is {export_path}.")
-
-
Call the
terminate_config_initializerAPI to close the data stream and release resources.
sess.run Migration and Training
sess.run Migration
If the original TensorFlow network is constructed based on the sess.run API, refer to this section for the manual migration process.
You are advised to use the model training samples provided by Rec SDK TensorFlow for adaptation. If you use open-source recommendation projects, direct API migration may cause compatibility issues.
sess.run Overview
As a low-level API of TensorFlow, sess.run appears more flexible than Estimator. On the flip side, using it for model implementation could be complex.
The process of developing a training script using sess.run is as follows:
- Data preprocessing
- Model construction, loss calculation, and gradient update
- Creating a session and initializing resources
- Performing training
The following describes how to migrate a sess.run training script for training on Ascend AI Processors.
Adding Header Files
For Python files modified in the following steps, add the following header file references to import NPU-related libraries.
from npu_bridge.npu_init import *
Note
After you import the preceding header file, the training script runs on the Ascend AI Processor by default.
Generally, this part of code does not need to be modified. Adapt the code in the following scenario:
If the original network script uses dataset.batch(batch_size) to return a dynamic shape, the number of remaining samples in the data stream may be smaller than the batch size. This makes the shape of the last step inconsistent with preceding shapes, triggering the dynamic shape compilation process. To improve compilation performance, set drop_remainder to True to discard the last few samples in the file and ensure consistent shapes for every step in the network.
dataset = dataset.batch(batch_size, drop_remainder=True)
Note: During inference, if the amount of inference data in the last iteration is smaller than the batch size, you must pad the data to the batch size. This is because some scripts include an assertion at the end to verify that the number of results matches the number of validation data.
assert num_written_lines == num_actual_predict_examples
Model Construction, Loss Calculation, and Gradient Update
Generally, this part of code does not need to be modified. Adapt the code in the following scenario:
-
For
dropoutin the original network, replace it with the corresponding CANN API implementation for better performance, while paying attention to the impact on network accuracy.-
If
tf.nn.dropoutexists, change it to:layers = npu_ops.dropout() -
If
tf.layers.dropout,tf.layers.Dropout,tf.keras.layers.Dropout,tf.keras.layers.SpatialDropout1D,tf.keras.layers.SpatialDropout2D, ortf.keras.layers.SpatialDropout3Dexists, add the following header file reference:from npu_bridge.estimator.npu import npu_convert_dropout
-
-
For
geluin the original network, replace it with the corresponding CANN API implementation for better performance.Original TensorFlow code:
def gelu(x): cdf = 0.5 * (1.0 + tf.tanh( (np.sqrt(2 / np.pi) * (x + 0.044715 * tf.pow(x, 3))))) return x*cdf layers = gelu()Migrated code:
layers = npu_unary_ops.gelu(x)
Creating a Session and Initializing Resources
When you run a training script on the Ascend AI Processor in sess.run mode, note the following configurations:
-
The following configuration is disabled by default and should remain disabled:
rewrite_options.disable_model_pruning -
The following configurations are enabled by default and should remain enabled:
rewrite_options.function_optimizationrewrite_options.constant_foldingrewrite_options.shape_optimizationrewrite_options.arithmetic_optimizationrewrite_options.loop_optimizationrewrite_options.dependency_optimizationrewrite_options.layout_optimizer
-
The following configuration is enabled by default and should be disabled explicitly:
rewrite_options.remappingrewrite_options.memory_optimization
-
If code related to
tf.deviceis used in the original network, add the session configurationallow_soft_placement=Trueto allow TensorFlow to automatically allocate devices.
Original TensorFlow code:
#Construct an iterator.
iterator=Iterator.from_structure(train_dataset.output_types, train_dataset.output_shapes)
#Obtain the batch data.
next_batch=iterator.get_next()
#Initialize the iterator.
training_init_op=iterator.make_initializer(train_dataset)
#Initialize the variables.
init=tf.global_variables_initializer()
sess=tf.Session()
sess.run(init)
#Get the number of training/validation steps per epoch
train_batches_per_epoch=int(np.floor(train_size/batch_size))
Migrated code:
#Construct an iterator.
iterator=Iterator.from_structure(train_dataset.output_types, train_dataset.output_shapes)
#Obtain the batch data.
next_batch=iterator.get_next()
#Initialize the iterator.
training_init_op=iterator.make_initializer(train_dataset)
#Initialize the variables.
init=tf.global_variables_initializer()
#Create a session. If code related to tf.device is used in the original network, add the session configuration "allow_soft_placement=True" to allow TensorFlow to automatically allocate devices.
config = tf.ConfigProto(allow_soft_placement=True)
custom_op = config.graph_options.rewrite_options.custom_optimizers.add()
custom_op.name = "NpuOptimizer"
# You must explicitly disable the remapping and memory_optimization functions of TensorFlow to avoid conflicts with functions in the NPU.
config.graph_options.rewrite_options.remapping = RewriterConfig.OFF # Explicitly disable.
config.graph_options.rewrite_options.memory_optimization = RewriterConfig.OFF # Explicitly disable.
sess = tf.Session(config=config)
sess.run(init)
#Get the number of training/validation steps per epoch
train_batches_per_epoch=int(np.floor(train_size/batch_size))
All native tf.Session functions are supported on the Ascend platform.
Additionally, the Ascend platform supports functions such as automatic mixed precision. To enable these functions, see "Session Configuration" in the TF Adapter API (1.x).
This part of the code does not need modification. For example:
#Start loop iterations.
for epoch in range(num_epochs):
##Initialize the iterator with the training dataset.
sess.run(training_init_op)
for step in range(train_batches_per_epoch):
#Get the next batch of data.
img_batch,label_batch=sess.run(next_batch)
#Run the training operation.
_,train_loss = sess.run([train_op, loss],feed_dict={x:img_batch, y_:label_batch, is_training:True})
After the session object created by tf.Session is used, you must explicitly call session.close() or use the with statement to create the session (which calls close() automatically through the context). See the following examples:
Example 1: Explicitly call sess.close().
sess = tf.Session(config=config)
sess.run(...)
sess.close()
Example 2: Use with to create a session.
with tf.Session(config=config) as sess:
sess.run(...)
Note
If an error occurs during migration and training, see the FAQ or contact technical support.
Training with tf.Session
sess.run Scenario Description
You need to define placeholders, variables, and operators to form a complete computational graph. Start the model running with a new Session instance. The Session instance will execute the graph in a distributed manner, input data, update variables based on the optimization algorithm, and return execution results, that is, tensor instances. Model training with tf.Session is more customizable, and you can adapt and modify it based on the training method used by the model.
Training Process Introduction
Figure 1 tf.Session training process

Adapting the Model
You need to adapt the model to be used and can add functional features provided by Rec SDK TensorFlow during the adaptation process. This section introduces key steps in model adaptation and how to add desired functional features.
Note
Functional features can be used in combination. You need to modify and adapt them in the corresponding key steps. To view the calling process of a single functional feature, see Training Feature Process. Feature eviction and the on-chip memory dynamic expansion mode cannot be enabled at the same time.
The key steps are as follows:
-
Initialize the framework.
Call the init API to initialize the Rec SDK TensorFlow model training framework.
To add functional features, select the desired features in this step and make corresponding modifications.
Table 1 Functional features
Feature Operation Dynamic expansion Set use_dynamic_expansion = Trueto enable the on-chip memory dynamic expansion function. The value isFalseby default. The DDR and SSD modes support only dynamic expansion on the memory/drive side.Dynamic shape Set use_dynamic = Truefor the init API. Before enabling the dynamic shape function, install the ops operator package. For details, see "Installing ops" in "Installing CANN" of the CANN Software Installation Guide.Automatic graph modification - Feature admission and eviction - -
Define the optimizer.
Select an optimizer under
mx_rec.optimizersand call the corresponding API to obtain the optimizer object for the sparse network layer. For currently available optimizers, see Optimizers. For the optimization interface of the dense network layer, use the TensorFlow built-in optimizer.To add functional features, select the desired features in this step and make corresponding modifications.
Table 2 Functional features
Feature Operation Dynamic expansion For dynamic expansion on the on-chip memory side, call the create_hash_optimizer_by_addressAPI of the corresponding optimizer in themx_rec.optimizerspackage to createsparse_optimizerfor sparse tables. Available optimizers are:Dynamic shape - Automatic graph modification - Feature admission and eviction - -
Choose to define features or automatically modify the graph.
-
Define a feature list and model.
Use
FeatureSpecto define the feature list and configure the corresponding model.To add functional features, select the desired features in this step and make corresponding modifications.
Table 3 Functional features
Feature Operation Dynamic expansion - Dynamic shape - Feature admission and eviction In FeatureSpec mode, see FeatureSpec for configuration. - To enable the admission function, set the admission threshold
access_thresholdto a value greater than or equal to 0 (unit: times). A parameter error will be reported if the threshold is less than -1. - To enable the eviction function, perform the following steps:
- Set the eviction threshold
eviction_thresholdto a value greater than or equal to 0 (unit: seconds). A parameter error will be reported if the threshold is less than -1. - Set
FeatureSpecwithindex_keyastimestampand the parameteris_timestamp=True, indicating that the dataset contains timestamps. - Use the
EvictHookAPI to set a hook for the eviction trigger. This API has three parameters:evict_enable=True,evict_time_interval=24 * 60 * 60, andevict_step_interval=10000, representing the eviction function switch, eviction trigger time interval (unit: seconds), and global step interval, respectively. You can choose eitherevict_time_intervalorevict_step_interval.
- Set the eviction threshold
- The feature eviction hook is used only in training mode.
- To enable the admission function, set the admission threshold
-
Automatic graph modification
Skip this step if you choose the automatic graph modification mode.
-
-
Define the dataset. Skip this step if you choose the automatic graph modification mode.
When using
FeatureSpecto define the feature list, create a dataset based on the feature list and perform preprocessing. Call theget_asc_insert_funcAPI to obtain the Rec SDK TensorFlow data preprocessing interface and apply it to the dataset. -
Create a sparse table.
Call the
create_tableAPI to create a sparse network layer. You can create a sparse network layer for each sparse feature. -
Create a model computational graph.
Pass the sparse network layer and feature list to create the model computational graph. Call
sparse_lookupin the computational graph for feature lookup and error calculation.To add functional features, select the desired features in this step and make corresponding modifications.
Table 4 Functional features
Feature Operation Dynamic expansion - Dynamic shape - Automatic graph modification When querying a sparse feature table, call the sparse_lookupAPI and setmodify_graph=Trueto use the automatic graph modification mode during table lookup. The default value of this parameter isFalse.Feature admission and eviction In automatic graph modification mode, when using the sparse_lookupAPI, set theaccess_and_evict_configparameter, which is of the dictionary type. The dictionary consists of two key-value pairs. The keys areaccess_thresholdandeviction_threshold, and the values are the corresponding thresholds. -
Define gradient calculation and the optimization process.
Call the
get_dense_and_sparse_variableinterface to obtain parameters for the dense and sparse network layers. Calculate gradients and perform optimization through the optimizer.To add functional features, select the desired features in this step and make corresponding modifications.
Table 5 Functional features
Feature Operation Dynamic expansion Dynamic expansion on the on-chip memory side: - Obtain the embedding result (
emb) and mapping address (addr).- Use the
tf.get_collection("ASCEND_SPARSE_LOOKUP_LOCAL_EMB")API to obtain the embedding result for training. - Use the
tf.get_collection("ASCEND_SPARSE_LOOKUP_ID_OFFSET")API to obtain the mapping address for training.
- Use the
- Perform backward gradient calculation. Use the
tf.gradients(loss, emb)API to calculate the derivative of the embedding result obtained in 1 to get the gradient (grad). - Update the backward sparse table. Use the sparse optimizer and import the created
sparse_optimizer.apply_gradients([grad, addr])API to update the sparse table at the location corresponding to the mapping address.
Dynamic shape - Automatic graph modification - Feature admission and eviction - - Obtain the embedding result (
-
Start data loading and preprocessing.
-
FeatureSpec mode
Call
start_asc_pipelineto start the data pipeline. -
Automatic graph modification mode
Call modify_graph_and_start_emb_cache. Additionally,
sess.run(iterator.initializer)must be changed to the dataset initialization API for automatic graph modification, that is,sess.run([get_initializer](./api/automatic_graph_modification.md#get_initializer)(True))orsess.run(get_initializer(False)). The former is used for training and the latter for evaluation.
-
Starting Training
The key steps are as follows:
- Define
Saverfor saving and loading models during training. StartSessioncalculation and save (tf.compat.v1.train.Saver.save) or load (tf.compat.v1.train.Saver.restore) models during training. - Start the training task. Start the training task. See Single-Node Single-Card and Single-Node Multi-Card Training.
Completing Training and Viewing Results
The key steps are as follows:
- View the training results.
- Call the
terminate_config_initializerAPI to close the data stream and release resources.
Note
To convert an NPU format model saved based on Rec SDK TensorFlow into a model that can be loaded and used by the GPU and CPU, see the model conversion tool instructions.
Distributed Training Script Migration
Data Parallelism Support (AllReduce)
AllReduce is a mainstream data parallelism architecture where each node works collaboratively based on algorithms. It is suitable for scenarios with high training power requirements and large scale of devices. This section describes how to perform distributed training of a TensorFlow training script on the Ascend AI Processor using the AllReduce architecture.
Implementation Principle of AllReduce
In large-scale AI training clusters, data parallelism is usually used for training. In data parallelism, each device uses the same model but different training samples. Gradient data calculated by each device must be aggregated before parameter updates.
Figure 1 Data parallelism training

Mainstream implementations of data parallelism include the parameter server-worker (PS-worker) architecture and the AllReduce architecture based on gradient aggregation methods. In the AllReduce architecture, each device participating in training forms a ring, and there is no central node to aggregate all calculated gradients. The AllReduce algorithm places participating devices in a logical ring. Each device receives data from the upstream device and sends data to the downstream device, fully utilizing the upstream and downstream bandwidth of each device.
The AllReduce architecture is an improved architecture proposed to solve the linear scaling issue of the PS-worker architecture. Each node works collaboratively according to an algorithm designed to reduce the volume of transmitted data and make full use of hardware communication bandwidth. It is generally suitable for scenarios with high training power requirements and large scale of devices. The following figure shows the implementation of the AllReduce architecture.
The Ring algorithm (called Ring-AllReduce) is used to introduce the Allreduce mode. As shown in Figure 2, in the Ring-AllReduce architecture, each device is a worker and forms a ring without a central node to aggregate gradients calculated by all workers. During an iteration, each worker completes the forward calculation and backward calculation of a mini-batch sample data to obtain gradient data, and then uses the Ring-AllReduce algorithm to synchronize gradient data. The Ring-AllReduce algorithm includes Scatter-Reduce and AllGather. Gradient data is passed to the next worker in the ring in multiple steps, while the worker also receives gradient data from the preceding worker multiple times. For a ring containing N workers, each worker needs to receive gradient data 2 × (N - 1) times from other workers (1/N of the data each time) and send gradient data 2 × (N - 1) times to other nodes (1/N of the data each time).
APIs Used
In TensorFlow, tf.distribute.Strategy is generally used for distributed training. For details, see this link. However, Ascend AI Processors do not support the aforementioned distributed strategy. TF Adapter provides the distributed API npu_distributed_optimizer_wrapper to add the AllReduce operation of the NPU to the passed optimizer gradient function, and finally returns the input optimizer. This supports gradient aggregation between devices in networking modes such as single-node multi-card and multi-node multi-card. After you call this function, AllReduce operator nodes are inserted between gradient calculation and update operators in the generated training graph.
Figure 3 APIs used

Therefore, the original TensorFlow training script must be modified to support distributed training on the Ascend AI Processor.
Dataset Sharding
During distributed training, you can use the TensorFlow API for dataset sharding. If processor resource information is required for dataset sharding, obtain the number of Ascend AI Processors through the collective communication API get_rank_size and obtain the processor ID through get_rank_id. For example:
dataset = dataset.shard(get_rank_size(),get_rank_id())
Script Migration in Estimator Mode
-
TensorFlow passes strategy objects to
Runconfigof Estimator, but TF Adapter does not support this mode. You need to delete relevant code. For example:Before migration:
mirrored_strategy = tf.distribute.MirroredStrategy() config = tf.estimator.RunConfig( train_distribute=mirrored_strategy, eval_distribute=mirrored_strategy, session_config=session_config, save_checkpoints_secs=60*60*24)After migration:
config = tf.estimator.NPURunConfig( session_config=session_config, save_checkpoints_secs=60*60*24) -
Then call
npu_distributed_optimizer_wrapper(seenpu_distributed_optimizer_wrapperin TF Adapter API (1.x)) to add the AllReduce operation of the NPU to the passed optimizer gradient function and return the input optimizer, implementing distributed calculation on the Ascend AI Processor. The method is as follows:def cnn_model_fn(features,labels,mode): #Build the network. xxx #Calculate loss. xxx #Configure the TrainingOp(for TRAIN mode) if mode == tf.estimator.ModeKeys.TRAIN: optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001) # Use the SGD optimizer. optimizer = npu_distributed_optimizer_wrapper(optimizer) # Use NPU distributed computing to update gradients. train_op=optimizer.minimize(loss=loss,global_step=tf.train.get_global_step()) # Minimize loss. return tf.estimator.EstimatorSpec(mode=mode,loss=loss,train_op=train_op)Note
- The NPUDistributedOptimizer distributed optimizer is compatible in the current version.
- In Estimator mode, when
npu_distributed_optimizer_wrapperis used to implement the AllReduce function,NPUBroadcastGlobalVariablesHookis automatically added inNPUEstimator. You do not need to manually implement the broadcast function.
If the original script uses the TensorFlow API to calculate gradients, such as
grads = tf.gradients(loss, tvars), you need to call thenpu_AllReduceAPI to perform AllReduce on the gradients after calculation.Before migration:
grads = tf.gradients(a + b, [a, b], stop_gradients=[a, b])After migration:
grads = npu_allreduce(tf.gradients(a + b, [a, b], stop_gradients=[a, b]))
Script Migration in sess.run Mode
In Estimator mode, when npu_distributed_optimizer_wrapper is used to implement the AllReduce function, NPUBroadcastGlobalVariablesHook is automatically added in NPUEstimator. You do not need to manually implement the broadcast function. However, you must manually implement the broadcast function in the sess.run training script. The method is as follows:
-
After variable initialization and before training, broadcast variables through the collective communication API broadcast. For details about the broadcast API, see the HCCL APIs.
from npu_bridge.npu_init import * def broadcast_global_variables(root_rank, index): """Broadcasts all global variables from root rank to all other processes. Arguments: root_rank: rank of the process from which global variables will be broadcasted to all other processes. index: rank_id """ op_list = [] for var in tf.trainable_variables(): # the input and out tensor of HCOMBroadcast interface are list if "float" in var.dtype.name: inputs = [var] outputs=hccl_ops.broadcast(tensor=inputs,root_rank=root_rank) if outputs is not None: op_list.append(outputs[0].op) op_list.append(tf.assign(var, outputs[0])) return tf.group(op_list) ... bcast_op = broadcast_global_variables(root_rank, index) sess = tf.Session() ... sess.run(bcast_op)In addition, the broadcast API includes a graph modification operation. If the graph cannot be modified (for example, the graph is finalized or a session is created using
tf.train.Supervisor), you need to unfreeze the graph first:with sv.managed_session() as sess: sess.graph._unsafe_unfinalize() # Unfreeze the graph. sess.run(bcast_op) -
During training, call
npu_distributed_optimizer_wrapperto aggregate gradient data after calculating the data for each device using the gradient optimizer:from npu_bridge.npu_init import * optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001) # Use the SGD optimizer. distributedOptimizer=npu_distributed_optimizer_wrapper(optimizer) # Use NPU distributed computing to update gradients.Note
The NPUDistributedOptimizer distributed optimizer is compatible in the current version.
If the original script uses the TensorFlow API to calculate gradients, such as
grads = tf.gradients(loss, tvars), you need to call thenpu_AllReduceAPI to perform AllReduce on the gradients after calculation.grads = npu_allreduce(tf.gradients(a + b, [a, b], stop_gradients=[a, b]))
Data Parallelism Support (PS-Worker)
In recommendation networks, feature data is saved in an embedding table. The data volume can reach the terabyte TB level and cannot be saved on the device side. Therefore, data must be saved in the host memory through the PS-worker mode. This section describes how to perform distributed training of a TensorFlow training script on the Ascend AI Processor using the PS-worker architecture.
Implementation Principle of PS-Worker
Figure 1 PS-worker mode

In the PS-worker architecture, nodes in a cluster are divided into two types: parameter servers and workers. Parameter servers store model parameters, and workers are responsible for calculating parameter gradients. In each iteration, workers obtain parameters from the parameter servers and return calculated gradients to the parameter servers. The parameter servers aggregate the gradients returned from the workers, update the parameters, and broadcast the new parameters to the workers.
The following describes how to perform distributed training on the Ascend AI Processor through the PS-worker architecture using a training script developed based on the TensorFlow Python API.
Configuring Cluster Information
[!NOTICE]
- Distributed training through the PS-worker architecture on the Ascend AI Processor currently supports only the NPUEstimator mode.
- Currently, only one worker process is supported on one device.
- In the PS-worker cluster scenario, you are advised to use high-speed NICs.
In the PS-worker architecture, cluster information is configured through the environment variable TF_CONFIG. TF_CONFIG consists of two parts: cluster and task. cluster provides information about the entire cluster, that is, workers and parameter servers in the cluster. task provides information about the current task. For details, see the TensorFlow official website.
The following uses two servers, each with one parameter server and eight workers, as an example.
-
Set
TF_CONFIGinformation.os.environ['TF_CONFIG'] = json.dumps({ 'cluster': { ##'chief':chief_hosts, # This parameter is optional. 'worker': worker_hosts, 'ps': ps_hosts, 'evaluator': evaluator_hosts, # This parameter is optional if evaluation is not performed. }, 'task': {'type': job_name, 'index': task_index} }) -
ps_hostsandworker_hostsinformation can be configured usingFLAGSas follows:ps_hosts = FLAGS.ps_hosts.split(',') worker_hosts = FLAGS.worker_hosts.split(',') evaluator_hosts = FLAGS.evaluator_hosts.split(',') task_index = FLAGS.task_index job_name = FLAGS.job_name flags.DEFINE_string("ps_hosts", '192.168.1.100:2222,192.168.1.200:2222',) flags.DEFINE_string("worker_hosts", '192.168.1.100:2223,192.168.1.100:2224,192.168.1.100:2225,192.168.1.100:2226,' '192.168.1.100:2227,192.168.1.100:2228,192.168.1.100:2229,192.168.1.100:2230,' '192.168.1.200:2223,192.168.1.200:2224,192.168.1.200:2225,192.168.1.200:2226,' '192.168.1.200:2227,192.168.1.200:2228,192.168.1.200:2229,192.168.1.200:2230',) flags.DEFINE_string("evaluator_hosts", '192.168.1.100:2231',) flags.DEFINE_string("job_name", '', "One of 'ps', 'worker', 'evaluator', chief") flags.DEFINE_integer("task_index", 0, "Index of task within the job")Configuration description:
-
worker_hosts/ps_hosts: Separate entries with commas (,). Do not add a space after the comma. -
chief_hosts: There can be only one chief host. It can also be omitted as in this example. Ifchiefis not set, the first worker is the chief by default. Like other workers, the chief performs model training. In addition to model training, the chief worker manages other workers (such as saving and restoring checkpoints and writing summary information). -
evaluator_hosts: There can be only one evaluator host. Omit it if evaluation is not performed.Next, correctly set the environment variable
TF_CONFIGfor all workers.
-
Defining a ParameterServerStrategy Instance
To support distributed training under the PS-worker architecture, you need to define a tf.distribute.experimental.ParameterServerStrategy instance first. For more details about this strategy, see this link.
strategy = tf.distribute.experimental.ParameterServerStrategy()
Training and Evaluating the Model
You need to specify the distributed strategy for NPUEstimator through the distribute parameter in NPURunConfig, and then call tf.estimator.train_and_evaluate to train and evaluate the model.
In addition, ensure that the NPURunConfig.model_dir of all workers is set to the same directory, such as a shared file system accessible to all workers. That is, if worker1 sets a directory, worker2 must mount this shared directory, and their NPURunConfig.model_dir values must be consistent.
from npu_bridge.npu_init import *
run_config = NPURunConfig(
model_dir=flags_obj.model_dir,
session_config=session_config,
keep_checkpoint_max=5,
save_summary_steps=1,
log_step_count_steps=1,
save_checkpoints_steps=100,
enable_data_pre_proc=True,
mix_compile_mode=True, # In PS mode, only mixed calculation mode is supported.
iterations_per_loop=1, # In mixed calculation mode, this must be 1.
precision_mode='allow_mix_precision',
distribute=strategy)
classifier = tf.estimator.NPUEstimator(
model_fn=model_fn,
model_dir='/tmp/multiworker',
config=run_config)
tf.estimator.train_and_evaluate(
classifier,
train_spec=tf.estimator.TrainSpec(input_fn=input_fn),
eval_spec=tf.estimator.EvalSpec(input_fn=input_fn))
[!NOTICE] Evaluation processes can run on the device or on the host CPU, each with its own pros and cons. You can choose either of them as required. For example, in the scenario where one server is equipped with eight cards, one parameter server process and eight worker processes are required, and the eight worker processes run on the device side.
- If you evaluate while training, the total number of evaluator and worker processes that start cannot exceed the maximum number of devices on the current server, which is currently eight. Because the worker processes already occupy the devices, evaluation needs to be performed on the host CPU. This approach lets evaluation run during training, but it cannot use the performance advantages of the Ascend AI Processor during evaluation. However, it can run in parallel with training. When you use this approach, you are advised to set the checkpoint save interval to a value longer than the evaluation execution time.
To implement host-side evaluation, you must call the native TensorFlow Estimator directly for evaluation. You cannot convert it to NPUEstimator. Otherwise, evaluation requires device resources and fails because training already occupies the devices.- If you evaluate after training finishes, you only need to make sure the evaluator starts after worker training ends. In this case, both training and evaluation can run on the device side for better performance.
Running the Script
If you run the script according to ps_hosts, worker_hosts, and other information defined in the Python script itself, with no chief defined in the Python script:
python resnet50_ps_strategy.py --job_name=ps --task_index=0
python resnet50_ps_strategy.py --job_name=ps --task_index=1
python resnet50_ps_strategy.py --job_name=worker --task_index=0
python resnet50_ps_strategy.py --job_name=worker --task_index=1
python resnet50_ps_strategy.py --job_name=worker --task_index=2
python resnet50_ps_strategy.py --job_name=worker --task_index=3
python resnet50_ps_strategy.py --job_name=worker --task_index=4
python resnet50_ps_strategy.py --job_name=worker --task_index=5
python resnet50_ps_strategy.py --job_name=worker --task_index=6
python resnet50_ps_strategy.py --job_name=worker --task_index=7
If you need to redefine information such as ps_hosts and worker_hosts, with no chief defined in the Python script:
python resnet50_ps_strategy.py \
--ps_hosts=192.168.1.79:2222,192.168.1.80:2222 \
--worker_hosts=192.168.1.79:2223,192.168.1.79:2224,192.168.1.79:2225,192.168.1.79:2226,192.168.1.79:2227,192.168.1.79:2228,192.168.1.79:2229,192.168.1.79:2230,192.168.1.80:2223,192.168.1.80:2224,192.168.1.80:2225,192.168.1.80:2226,192.168.1.80:2227,192.168.1.80:2228,192.168.1.80:2229,192.168.1.80:2230 \
--job_name=ps \
--task_index=0
If you need to run chief and evaluator, change job_name to the corresponding defined value:
python resnet50_ps_strategy.py --job_name=chief --task_index=0
python resnet50_ps_strategy.py --job_name=evaluator --task_index=0
Note
For the environment variables required to run the script, see "Single-Device Training Execution" in the TensorFlow 1.15 Model Porting Guide.
Horovod Script Migration
Horovod is a distributed training framework built on TensorFlow, Keras, PyTorch, and MXNet. It aims to improve distributed training performance. Unlike the traditional PS-worker distributed training architecture in TensorFlow, Horovod uses AllReduce to aggregate gradients, which better utilizes bandwidth and helps remove the PS-worker bottleneck. This section describes how to migrate a distributed training script developed with Horovod so it can run distributed training on the Ascend AI Processor.
For more information about Horovod, see the official Horovod website.
Original Horovod code:
import tensorflow as tf
import horovod.tensorflow as hvd
# Initialize Horovod
hvd.init()
# Pin GPU to be used to process local rank (one GPU per process)
config = tf.ConfigProto()
config.gpu_options.visible_device_list = str(hvd.local_rank())
# Build model...
loss = ...
opt = tf.train.AdagradOptimizer(0.01 * hvd.size())
# Add Horovod Distributed Optimizer
opt = hvd.DistributedOptimizer(opt)
# Add hook to broadcast variables from rank 0 to all other processes during
# initialization.
hooks = [hvd.BroadcastGlobalVariablesHook(0)]
# Make training operation
train_op = opt.minimize(loss)
# Save checkpoints only on worker 0 to prevent other workers from corrupting them.
checkpoint_dir = '/tmp/train_logs' if hvd.rank() == 0 else None
# The MonitoredTrainingSession takes care of session initialization,
# restoring from a checkpoint, saving to a checkpoint, and closing when done
# or an error occurs.
with tf.train.MonitoredTrainingSession(checkpoint_dir=checkpoint_dir,
config=config,
hooks=hooks) as mon_sess:
while not mon_sess.should_stop():
# Perform synchronous training.
mon_sess.run(train_op)
Migrated code:
# Import the NPU library.
import tensorflow as tf
from npu_bridge.npu_init import *
# This example uses the HCCL group management API, so you need to start a separate session to initialize HCCL. For more information, see the "Collective Communication Initialization" section of the TensorFlow 1.15 Model Portal Guide.
npu_int = npu_ops.initialize_system()
npu_shutdown = npu_ops.shutdown_system()
config = tf.ConfigProto()
custom_op = config.graph_options.rewrite_options.custom_optimizers.add()
custom_op.name = "NpuOptimizer"
config.graph_options.rewrite_options.remapping = RewriterConfig.OFF
config.graph_options.rewrite_options.memory_optimization = RewriterConfig.OFF
init_sess = tf.Session(config=config)
init_sess.run(npu_int)
# Pin GPU to be used to process local rank (one GPU per process)
config.gpu_options.visible_device_list = str(get_local_rank_id()) # Replace hvd.local_rank with get_local_rank_id.
# Build model...
loss = ...
opt = tf.train.AdagradOptimizer(0.01 * get_rank_size()) # Replace hvd.size with get_rank_size.
# NPU Allreduce
# Replace hvd.DistributedOptimizer with npu_distributed_optimizer_wrapper.
opt = npu_distributed_optimizer_wrapper(opt)
# Add hook to broadcast variables from rank 0 to all other processes during initialization.
hooks = [NPUBroadcastGlobalVariablesHook(0)]
# Use the broadcast interface of collective communication in session.run mode to broadcast variables.
input = tf.trainable_variables()
bcast_global_variables_op = hccl_ops.broadcast(input, 0)
# Make training operation
train_op = opt.minimize(loss)
# Save checkpoints only on worker 0 to prevent other workers from corrupting them.
checkpoint_dir = '/tmp/train_logs' if get_rank_id() == 0 else None # Replace hvd.rank with get_rank_id.
# The MonitoredTrainingSession takes care of session initialization,
# restoring from a checkpoint, saving to a checkpoint, and closing when done
# or an error occurs.
with tf.train.MonitoredTrainingSession(checkpoint_dir=checkpoint_dir,
config=config,
hooks=hooks) as mon_sess:
# Broadcast variables.
mon_sess.run(bcast_global_variables_op)
while not mon_sess.should_stop():
# Perform synchronous training.
mon_sess.run(train_op)
# Run shutdown_system after training finishes, then close the session.
init_sess.run(npu_shutdown)
init_sess.close()
Note
The NPUDistributedOptimizer distributed optimizer is compatible in the current version.
Precision Monitoring
Introduction to Precision Monitoring
The precision of recommendation models is critical. However, the area under the curve (AUC) metric of specific open-source models cannot fully reflect latent functional issues. A lower AUC definitely indicates a problem, but meeting the AUC target does not mean that the implementation is fully correct. At the same time, because AUC is an end-to-end metric, it cannot pinpoint the exact stage where a problem occurs. This makes precision issues hard to locate and obscures the boundary of responsibility.
By instrumenting each stage of the existing little_demo model and providing tools for automated monitoring, you can significantly improve precision monitoring, identify the exact stage where a problem is introduced, and speed up precision issue localization.
Tool Access
Model: link
Tool: link
Run little_demo Precision Monitoring Mode
In the little_demo training script, such as run.sh, set the PRECISION_CHECK environment variable. 0 disables precision monitoring and 1 enables precision monitoring. The default value is 0.
export PRECISION_CHECK=0
or
export PRECISION_CHECK=1
After precision alignment is enabled, a precision_check data file will be generated in the same directory as the run.sh script for later comparison.
For details about the generated files, see the "Enable Precision Alignment Mode" section in the code repository.
Use the precrec-python Tool for Parsing and Comparison
After you run two tasks in little_demo precision alignment mode and generate the corresponding trace files, use precision_check.py to compare the paths.
Example:
/home/little_demo/precision_check/20240807_091347
/home/little_demo/precision_check/20240807_101855 // Run the task twice to generate the corresponding trace files.
python precision_check.py /home/little_demo/precision_check/20240807_091347 /home/little_demo/precision_check/20240807_101855 // Use precision_check.py to compare the paths.
For detailed usage of the precrec-python precision comparison tool, see this link.
Precision Tuning
Precision Tuning Scenarios
If a model is migrated from GPU/CPU training to NPU training, or if precision does not meet expectations during version iterations on NPU training, for example when the loss curve does not match expectations or the validation accuracy does not match expectations, refer to this section to tune precision and identify the problematic operator or component.
The scenarios where precision does not meet expectations are mainly divided into four categories:
- If a model is migrated from GPU/CPU training to NPU training and precision does not meet expectations, refer to End-to-End Network Comparison between GPU/CPU and NPU for precision tuning.
- If a model is continuously trained on NPU and precision does not meet expectations after the software version or configuration changes, refer to End-to-End Network Comparison between NPUs for precision tuning.
- If a model trained on NPU produces
NaNoutput values, refer to NaN Overflow Localization for precision tuning. - If a model trained on NPU shows random precision errors, that is, precision may occasionally fail to meet expectations after multiple training runs, refer to Random Error Localization for precision tuning.
If you find any issues during tuning or encounter difficulties while operating, you are advised to visit the GitCode community and submit feedback or ask for help.
Preparations Before Tuning
Migration Check
For scenarios where a model is migrated from GPU/CPU training to NPU training, perform the following checks to rule out possible issues introduced during migration.
-
Check the consistency of precision across multiple training runs.
Train the model multiple times on the GPU/CPU and multiple times on the NPU. If the results of the multiple runs fluctuate within the same range for both the GPU/CPU and the NPU, you cannot conclude that NPU training has a precision issue. If the average precision of multiple GPU/CPU runs is significantly higher than the average precision of multiple NPU runs and exceeds the normal fluctuation range, you can conclude that NPU training has a precision issue.
-
Check the migrated model configuration.
- Make sure the mixed precision mode on the NPU matches that on the GPU. Use the
precision_mode_v2option with the valueorigin. For details, see the "Session Configuration Parameter Description" section in TF Adapter API (1.x). - Make sure the loss scaling function is enabled correctly on the NPU. If the GPU/CPU version uses
LossScaleManagerfor dynamic LossScale calculation, you need to migrate it toNPULossScaleOptimizeron the NPU. For details, see the "Loss Scale" section in the TensorFlow 1.15 Model Porting Guide. - Make sure the GPU/CPU training and NPU training use the same dataset, data preprocessing method, and model hyperparameters, except for the interface changes involved in migration.
- Make sure the mixed precision mode on the NPU matches that on the GPU. Use the
-
Use the high-precision mode.
If precision issues still exist after the preceding checks, you can enable the high-precision mode for NPU training and train again to check whether the issue was introduced by the operator precision mode.
Example configuration for
session.runmode training:custom_op.parameter_map["op_select_implmode"].s = tf.compat.as_bytes("high_precision")For details, see the "Session Configuration Parameter Description" section in TF Adapter API (1.x).
Example configuration for Estimator mode training:
config = NPURunConfig(op_select_implmode="high_precision")For details, see the "NPURunConfig Configuration Parameter Description" section in TF Adapter API (1.x).
Fixed Randomness Removal
Removing Data Randomness
If you first use interfaces like os.listdir to get a file list when reading data, call sort on the file list to ensure the same file order is obtained across different devices or repeated runs.
If dataset.shuffle is used in the dataset to randomly shuffle the data, comment out that line of code.
Remove or deterministically modify other kinds of random data processing as well.
Removing Initialization Randomness
- If the code uses the
randommodule for random initialization, callrandom.seedbefore the random initialization to set a fixed seed. You are advised to change the initialization directly to a fixed value. - If the code uses NumPy for random initialization, for example
randominitialization, callnumpy.random.seedbefore the initialization to set a fixed seed. You are advised to change the random initialization directly to a fixed value, for example by usingnumpy.fullto fill a fixed value. - If the code uses TensorFlow random initialization, for example
tf.truncated_normal_initializer, calltf.set_random_seedin TensorFlow 1 ortf.random.set_seedin TensorFlow 2 before the initialization to set a fixed seed. You are advised to change the random initialization directly to a fixed value, for example by usingtf.constant_initializerto fill a fixed value. - If the code loads a pre-trained model for initialization, make sure the same pre-trained model is loaded across different devices or repeated runs.
- Remove or deterministically modify other kinds of random initialization as well.
Removing Randomness in the Network Structure
If the network uses dropout, such as tf.nn.dropout, change the rate input parameter to 0. If it uses slim.dropout, change the keep_prob input parameter to 1.
If the network calls TensorFlow random modules, such as tf.random_uniform, you are advised to replace the random value directly with a constant such as tf.constant.
Remove or deterministically modify other kinds of random network structures as well.
Enabling Deterministic Computing
When you train on the GPU or NPU, repeated runs may produce different results. This difference usually comes from asynchronous multithreaded execution in operator implementations, which changes the order of floating-point accumulation. On the NPU, you can enable deterministic computation to make repeated results the same and improve the accuracy of precision comparison. However, operator execution becomes slower and performance drops, so you can choose whether to enable it as required.
-
Example configuration for
session.runmode training:custom_op.parameter_map["deterministic"].i = 1For details, see the "Session Configuration Parameter Description" section in TF Adapter API (1.x).
-
Example configuration for Estimator mode training:
config = NPURunConfig(deterministic=1)For details, see the "NPURunConfig Configuration Parameter Description" section in TF Adapter API (1.x).
Validating Fixed Randomness
To determine whether randomness has been removed, perform the following checks:
- After training the same model multiple times, compare the loss values of a run against itself. If the first-step loss is exactly the same and later loss values differ only slightly, but the difference is much smaller than when randomness is not removed, for example if the loss difference is less than 0.001, you can conclude that randomness has been removed.
- If you train on the CPU, or if you enable deterministic computation on the NPU, the multi-step loss values across repeated runs must be exactly the same. If the loss difference is large, the network may still contain randomness, and you need to keep checking whether all randomness has been fixed.
Tool Deployment
For scenarios that require full-network comparison, deploy the precision analysis tool. Upload the precision_tool folder from the Ascend tools project to any directory in the training working directory. You need this tool both for collecting training precision data and for performing precision comparison analysis after training.
End-to-End Network Comparison between GPU/CPU and NPU
GPU/CPU Data Dump
-
Install the dump tool dependencies.
pip3 install gnureadline pexpect -
Modify the training script and insert the dump configuration.
-
Example configuration for
session.runmode training:import precision_tool.tf_config as npu_tf_config sess = npu_tf_config.sess_dump(sess=sess) -
Example configuration for Estimator mode training:
import precision_tool.tf_config as npu_tf_config estim_specs = tf.estimator.EstimatorSpec(training_hooks=[npu_tf_config.estimator_dump()])
Note
- In
session.runmode, you cannot use dump configuration and Rec SDK TensorFlow model saving at the same time. - During multi-card training, you only need to add dump configuration to the training of one card. Otherwise, saving data from multiple cards at the same time will cause data conflicts.
-
-
Perform training.
Change the maximum number of training steps to 1 and run training. Dump data will be generated in the
precision_data/tf/tf_debug/directory. -
Parse the dump data.
After you run
python3 precision_tool/cli.py tf_dump, parsed dump data will be generated in theprecision_data/tf/dump/directory. If you need to regenerate dump data, delete the generated data and run training and parsing again.
NPU Data Dump
-
Modify the training script and insert the dump configuration.
-
Example configuration for
session.runmode training:import precision_tool.tf_config as npu_tf_config config = npu_tf_config.session_dump_config(config, action='dump') sess = tf.Session(config) -
Example configuration for Estimator mode training:
import precision_tool.tf_config as npu_tf_config dump_config=npu_tf_config.estimator_dump_config(action='dump') npu_config = NPURunConfig(dump_config=dump_config)
Note
- In
session.runmode, you cannot use dump configuration and Rec SDK TensorFlow model saving at the same time. - During multi-card training, you only need to add dump configuration to the training of one card. Otherwise, saving data from multiple cards at the same time will cause data conflicts.
-
-
Perform training.
Change the maximum number of training steps to 1 and run training. The dump data files will be generated in the directory specified by
precision_data/npu/debug_0/, that is, inprecision_data/npu/debug_0/dump/{time}/{deviceid}/{model_name}/{model_id}/{data_index}. Example directory structure:precision_data/npu/debug_0/dump/20240125153144/0/ge_default_20240125153322_41/6/0/Table 1 Dump data file path format
Path Key Description Remarks dump_path Path for storing dump data. If a relative path is set, the full path after concatenation is used. - time Time when the dump data files are written to the drive. The format is YYYYMMDDHHMMSS. deviceid Device ID. - model_name Subgraph name. There may be multiple folders at the model_namelevel. Use the data under the directory that corresponds to the computational graph name.
Ifmodel_namecontains dots (.), slashes (/), backslashes (), or spaces, they are converted into underscores (_).model_id Subgraph ID. - data_index Iteration number used to save the dump data for the corresponding iteration. If dump_stepis specified,data_indexis the same asdump_step. Ifdump_stepis not specified,data_indexstarts at0and increments by 1 for each dumped iteration.
Dump Data Comparison
Preparing Data
Upload the precision_tool and precision_data folders, including the GPU/CPU benchmark data and the NPU precision data, to any directory in the Toolkit installation environment. Example directory structure:
├── precision_tool
│ ├── cli.py
│ ├── ...
├── precision_data
│ ├── npu
│ │ ├── debug_0 // Stores NPU dump data.
│ ├── tf
│ │ ├── dump // Stores GPU/CPU dump data.
│ ├── ...
Installing Dependencies
# Graphviz is an optional dependency. Install it only when you need to draw operator subgraphs.
pip3 install rich graphviz
# ubuntu/Debian
sudo apt-get install graphviz
# fedora/CentOS
sudo yum install graphviz
Modify config.py in the precision_tool/lib/config directory.
# This tool depends on the atc and msaccucmp.py tools in the Toolkit package, so configure the Toolkit installation directory.
# By default, the Toolkit package is installed in /usr/local/Ascend, so you do not need to modify it unless you installed it in a different directory.
CMD_ROOT_PATH = '/usr/local/Ascend'
Comparing Data
-
Start the PrecisionTool interactive CLI:
python3 ./precision\_tool/cli.py -
Enter the interactive CLI. To exit, press
Ctrl + C.PrecisionTool \> -
Run the
ac -l [limit_num] (-c)command to perform full-network precision comparison. For details, see the "precision_tool Command Reference" section of the TensorFlow 1.15 Model Migration Guide.PrecisionTool > ac -cThe comparison takes different amounts of time depending on the data volume.
The comparison results are stored in CSV format in the
precision_data/temp/vector_comparedirectory.
Analyzing Precision
Open the CSV file in the precision_data/temp/vector_compare directory and search from top to bottom for the first operator whose output cosine similarity is less than 0.98. For details, see the "Full-Network Precision Comparison Result File Description" section of the TensorFlow 1.15 Model Porting Guide. You can also use the vcs -f [file_name] -c [cos_sim_threshold] -l [limit] command to filter comparison results. See the "precision_tool Command Reference" section of the TensorFlow 1.15 Model Porting Guide. If the 0.98 threshold does not filter any results, you can increase the threshold and keep filtering.
The following figure shows an example vcs command result.

- Left indicates the name of the operator that generated dump data based on NPU execution.
- Right indicates the name of the operator that generated npy or dump data based on GPU/CPU execution.
- Input and Output indicate the cosine similarity comparison result for each input and output of the operator. The range is [-1, 1]. The closer the result is to 1, the more similar the two values are. The closer it is to -1, the more opposite the two values are.
From the comparison result in the preceding figure, you can see that the operator inputs are basically the same, but the first output differs significantly from the benchmark, with a cosine similarity of 0.806927, which is less than 0.98. This indicates that the operator may have a precision issue. If the operator inputs already differ significantly, you need to continue checking the comparison result of the input node.
Note
Run the ni (-n) [op_name] -g [graph] -a [attr] -s [save sub graph depth] command to query the input and output node information of the operator. For details, see the "precision_tool Command Reference" section of the TensorFlow 1.15 Model Porting Guide.
The ni command can obtain the following key information based on the operator name you pass in.
The text inside [] is the operator type. In the preceding figure, the operator type is Add. If PassName is included, the operator is a fusion operator, and the corresponding value is the name of the fusion rule. OriginOp indicates the operator before fusion.
Problem Source Isolation
-
After you use the preceding commands to find the first operator whose input is similar but whose output differs, you can determine that the issue lies in that operator. The following is an example.
Figure 1 Unique operator output differs in the vcs command output

-
If the operator is a fusion operator, the precision issue is caused by operator fusion. You can disable the fusion and perform precision comparison again to determine whether other issues still exist. The following is an example.
Figure 2 AutomaticBufferFusionOp output differs in the vcs command output

-
If the input or output of the operator contains an embedding variable and the embedding variable differs, the issue is a precision issue in Rec SDK TensorFlow table lookup. The following is an example.
Figure 3 Output differs for a Rec SDK TensorFlow table lookup operator in the CSV file generated by the vcs command

End-to-End Network Comparison between NPUs
NPU Data Dump
Follow the instructions in NPU Data Dump. The data is saved by default in the precision_data/npu/debug_0 directory. Copy the data to the precision_data/npu/debug_1 directory with the copy command mv precision_data/npu/debug_0/ precision_data/npu/debug_1, then run training again in the NPU environment and collect dump data. The new data is saved by default in the precision_data/npu/debug_0 directory.
Comparing Dump Data
-
Start the PrecisionTool interactive CLI:
python3 ./precision_tool/cli.py -
Enter the interactive CLI. To exit, press
Ctrl + C.PrecisionTool > -
Run the
vc -lt [left_path] -rt [right_path] -g [graph]command to perform full-network data comparison:vc -lt precision_data/npu/debug_1/dump/20211016164504/1/ge_default_20211016164504_1/1/0 -rt precision_data/npu/debug_0/dump/20211016180613/1/ge_default_20211016180613_1/1/0Precision comparison results are generated in the
out_dirdirectory. For data analysis, see the "Full-Network Precision Comparison Result File Description" section of the TensorFlow 1.15 Model Porting Guide. Open the CSV file in the directory and search from top to bottom for the first operator whose output cosine similarity is less than 0.98. -
For the preceding results, you can also use the
precision_toolcommandni (-n) [op_name] -g [graph] -a [attr] -s [save sub graph deep]for single-layer data comparison analysis. For details, see the "precision_tool Command Reference" section of the TensorFlow 1.15 Model Porting Guide. -
When both
debug_0anddebug_1exist in theprecision_data/npu/directory, thenicommand parses the dump files with the same operator name in both folders at the same time. From the parsing result, you can clearly see the data differences.
Opis the operator type. In the preceding figure, the operator name istrans_Cast_4940.
Problem Source Isolation
- After you find the first operator whose input is similar but whose output differs, you can determine that the issue lies in that operator.
- If the operator is a fusion operator, the precision issue is caused by operator fusion. You can disable the fusion and perform precision comparison again to determine whether other issues still exist.
- If the input or output of the operator contains an embedding variable and the embedding variable differs, the issue is a precision issue in Rec SDK TensorFlow table lookup.
NaN Overflow Localization
Determine the Overflow Step
Overflow localization depends on precision data dumps. If you can reliably reproduce the model output NaN issue at a certain training iteration after fixed randomness is removed, you can specify the dump step for training:
-
Modify
config.pyin theprecision_tool/lib/configdirectory and specify the step for which you want to dump data.# Dump data for a specific step. In general, you only need to compare the first dumped layer, that is, keep the default value. If you need to specify a particular step, you can change it, for example to '0|5|10'. TF_DUMP_STEP = '0' -
Change
TF_DUMP_STEPto the step whereNaNappears. Note thatTF_DUMP_STEP=0corresponds to the first training step of the dumped model.If the loss
NaNissue cannot be stably reproduced at a certain training iteration, you can modifyTF_DUMP_STEPto a range or run multiple times as needed so that the precision data for the corresponding step is dumped before you proceed to the next analysis step. Because dump data uses a large amount of memory, make sure you do not dump too much data and delete useless dump data in time.
NPU Data Dump
Follow the instructions in NPU Data Dump. The data is saved by default in the precision_data/npu/debug_0 directory.
Parsing Dump Data
-
Run the command to parse the original dump binary data files into
npyfiles that NumPy can read.find precision_data/npu/debug_0 -type f -name "*" | xargs -i python3 /usr/local/Ascend/ascend-toolkit/latest/tools/operator_cmp/compare/msaccucmp.py convert -d {} -out dump_data_npy/ -v 2This command converts the files in the
precision_data/npu/debug_0directory by using themsaccucmp.pyscript and saves them to thedump_data_npydirectory. The/usr/local/Ascend/ascend-toolkit/directory is the CANN installation directory. You can change it as needed. For details about themsaccucmp.pycommand, see the "Dump Data File Format Conversion" section in the CANN Model Accuracy Analyzer User Guide. -
Find the source of
NaNin thenpyfiles.The converted
npydata is stored in thedump_data_npydirectory and contains input and output data for all operators in the network. The five positions after the file name is split by periods (.) are the timestamp. Sort all files by timestamp in ascending order and determine whetherNaNexists in the files one by one. Find the first data file that containsNaN. If one exists, print the file name and stop the loop. If nothing is printed, the file does not containNaN, and you need to check whether the dump step ran correctly. For details about the file naming format, see the "Data Format Requirements" section in the CANN Model Accuracy Analyzer User Guide.Run the
python3 find_nan.pycommand. Thefind_nan.pyfile is as follows:import glob import numpy as np files = glob.glob("dump_data_npy/*") files.sort(key = lambda x : int(x.split(".")[4])) for i in files: f = np.load(i) if np.isnan(f).any(): print(i) break
Problem Source Isolation
After you find the dump data file for the first operator that contains NaN, determine the root cause as follows:
- If
NaNappears in the output data of an operator, take the input data of that operator and run the same operator logic on the CPU to obtain the CPU operator output. If the CPU operator output does not match the NPU operator output, theNaNwas caused by incorrect operator execution, and you can isolate the issue to that operator. If the CPU operator output matches the NPU operator output, theNaNwas caused by normal operator execution, and you need to keep tracing upstream to determine whether an upstream operator has an execution issue or other issues. - If
NaNappears in the input data of an operator, continue tracing upstream to find the source ofNaN. If the upstream operator output is normal but the current operator input is abnormal, you can isolate the issue to memory corruption that occurred in the interval between the upstream operator execution and the current operator. Otherwise, keep checking whether the upstream operator has other issues. - If
NaNappears in an embedding variable, the issue is in Rec SDK TensorFlow table lookup.
Random Error Localization
Localization Approach
In scenarios where occasional errors during NPU training cause precision to fall below expectations, for example when the loss suddenly changes in a certain iteration of one training run, the issue may not be reproducible in a stable way. Because dump data takes time to collect and consumes a lot of memory, it is difficult to use a dump-based comparison solution. In this case, you can use model file comparison to investigate the issue. Compare all variables in the model file from the abnormal run and the model file from a normal run. Find the variable with the lowest cosine similarity. If its cosine similarity is below a certain value, for example 0.98, you can conclude that the issue was introduced by the operator that outputs that variable.
Model Training and Saving
After you follow Fixed Randomness Removal without necessarily enabling deterministic computation, reduce the model save interval as much as possible, for example save every five steps, so that you can reproduce the precision anomaly within a reasonable amount of time. Then take the model file from the step immediately after the loss anomaly occurs and compare it with the model file from the same step in a normal training run.
Model Comparison
Change checkpoint_path1 in ckpt_compare.py to the path of the abnormal model file and checkpoint_path2 to the path of the normal model file. Then run the following python ckpt_compare.py script in the TensorFlow 1.15 environment. The script outputs variable names and cosine similarities from low to high.
from tensorflow.python import pywrap_tensorflow
import numpy as np
checkpoint_path1 = "path1/model-200"
checkpoint_path2 = "path2/model-200"
reader1 = pywrap_tensorflow.NewCheckpointReader(checkpoint_path1)
reader2 = pywrap_tensorflow.NewCheckpointReader(checkpoint_path2)
var_to_shape_map = reader1.get_variable_to_shape_map()
key_cos = {}
for key in var_to_shape_map:
tensor1 = reader1.get_tensor(key).reshape(-1)
tensor2 = reader2.get_tensor(key).reshape(-1)
key_cos[key] = np.dot(tensor1,tensor2)/(np.linalg.norm(tensor1)*np.linalg.norm(tensor2))
key_cos = list(key_cos.items())
key_cos.sort(key = lambda x : x[1])
for key, cos in key_cos:
print(key, cos)

Problem Source Isolation
- Find the first variable name. If the cosine similarity of that variable is low, you can conclude that the precision issue was introduced by the operator that outputs that variable.
- If the operator is a fusion operator, the precision issue is caused by operator fusion. You can disable the fusion and perform precision comparison again to determine whether other issues still exist.
- If the operator related to that variable is associated with the Rec SDK TensorFlow table lookup component, the issue is a precision issue in Rec SDK TensorFlow table lookup.
References
precision_tool Command Reference
Full-Network Precision Comparison Result File Description
Performance Optimization
Host Operators
Overview
In inference workloads for recommendation models, some operators, such as where, have poor affinity on the NPU and may be split to the CPU for execution. Therefore, TensorFlow CPU operators are optimized with the SVE instruction set. For more information about SVE, see Introduction to SVE and Arm C Language Extensions for SVE.
This section uses the SVE instruction set to optimize four TensorFlow CPU operators: less, greater, floormod, and where.
You can obtain the component source code from the Rec SDK TensorFlow source repository. For implementation, see the cust_op/tf_cpu_op/README.md file in the source code.
less
Function |
Returns the element-wise truth value of |
|---|---|
Function Prototype |
less(
x, y, name=None
)
|
Usage |
The usage is the same as the native TensorFlow For installation instructions, see the Rec SDK TensorFlow source tree file |
Constraints |
|
greater
Function |
Returns the element-wise truth value of |
|---|---|
Function Prototype |
greater(
x, y, name=None
)
|
Usage |
The usage is the same as the native TensorFlow For installation instructions, see the Rec SDK TensorFlow source tree file |
Constraints |
|
floormod
Function |
Returns the element-wise remainder after division. |
|---|---|
Function Prototype |
floormod(
x, y, name=None
)
|
Usage |
The usage is the same as the native TensorFlow For installation instructions, see the Rec SDK TensorFlow source tree file |
Constraints |
|
where
Function |
Returns elements from |
|---|---|
Function Prototype |
where(
condition, x, y, name=None
)
|
Usage |
The usage is the same as the native TensorFlow For installation instructions, see the Rec SDK TensorFlow source tree file |
Constraints |
|
Rec SDK TensorFlow Migration Examples
Rec SDK TensorFlow supports migration and adaptation of open-source TensorFlow recommendation models. You can refer to the following migration examples:
DCNv2 Model Development Guide
This section provides guidance on migrating the DCNv2 recommendation model based on TensorFlow 1.15.0 from a GPU environment to the Huawei Ascend NPU environment, using the automatic graph modification mode of the tf_rec_v1 component. For the adapted model code, see DCNv2 Model.
Prerequisites
Refer to the Ascend Community sess.run Migration Guide to complete the model migration from GPUs to NPUs.
Step 1: Replacing Sparse Feature Lookup APIs
-
Distinguish sparse features from dense features.
Using the Criteo dataset as an example:
- 26 sparse features: categorical features, require embedding
- 13 dense features: numerical features, input directly
features = { # Extract features using the keys set during creation 'label': tf.compat.v1.FixedLenFeature(shape=(config.line_per_sample,), dtype=tf.int64), 'sparse_feature': tf.compat.v1.FixedLenFeature(shape=(26 * config.line_per_sample,), dtype=tf.int64), 'dense_feature': tf.compat.v1.FixedLenFeature(shape=(13 * config.line_per_sample,), dtype=tf.float32), } -
Replace the embedding lookup API.
from mx_rec.core.embedding import create_table, sparse_lookup # 1. Create a sparse table (replacing tf.get_variable). sparse_hashtable = create_table( key_dtype=cfg.key_type, dim=tf.TensorShape([cfg.emb_dim]), name="sparse_embeddings", emb_initializer=emb_initializer, **cfg.get_emb_table_cfg() ) # 2. Sparse feature lookup (replacing tf.nn.embedding_lookup). feature = batch["sparse_feature"] embedding = sparse_lookup(sparse_hashtable, feature, cfg.send_count, dim=None, is_train=is_train, name="user_embedding_lookup", modify_graph=True, batch=batch, access_and_evict_config=None)Note: The 26 sparse features in the Criteo dataset are already offset and merged into
sparse_featureduring preprocessing, so only onecreate_tablecall is needed. If the features are not merged, a separate table must be created for each field.
Step 2: Replacing the Sparse Feature Optimizer
Sparse feature parameters are stored in a custom hash table and must be updated using the custom create_hash_optimizer.
import tensorflow as tf
from mx_rec.optimizers.lazy_adam import create_hash_optimizer
from delay_loss_scale import DenseLossScaleOptimizer, SparseLossScaleOptimizer
def get_dense_and_sparse_optimizer(cfg):
"""
Create optimizers for dense and sparse layers respectively.
"""
# Dense layer optimizer: TensorFlow native Adam
dense_optimizer = tf.compat.v1.train.AdamOptimizer(learning_rate=cfg.learning_rate[0])
# Sparse layer optimizer: Lazy Adam provided by Rec SDK
sparse_optimizer = create_hash_optimizer(learning_rate=cfg.learning_rate[1])
# Add loss scaling.
sparse_optimizer = SparseLossScaleOptimizer(sparse_optimizer, 65536)
dense_optimizer = DenseLossScaleOptimizer(dense_optimizer, 65536)
return dense_optimizer, sparse_optimizer
Step 3: Modifying Gradient Calculation Code
from mx_rec.util.variable import get_dense_and_sparse_variable
# Get the parameter variables for dense layers and sparse layers in the model.
dense_variables, sparse_variables = get_dense_and_sparse_variable()
rank_size = rec_sdk_common.communication.hccl.hccl_info.get_rank_size() # Get the number of distributed training devices.
train_ops = []
for loss, (dense_optimizer, sparse_optimizer) in zip([train_model.get("loss")], optimizer_list):
# ========== Dense layer gradient calculation ==========
grads = dense_optimizer.compute_gradients(loss, var_list=dense_variables)
avg_grads = []
for grad, var in grads:
if rank_size > 1:
grad = hccl_ops.allreduce(grad, "sum") if grad is not None else None
if grad is not None:
avg_grads.append((grad / 8.0, var))
# Apply gradient updates.
train_ops.append(dense_optimizer.apply_gradients(avg_grads))
# ========== Sparse layer gradient calculation ==========
sparse_grads = sparse_optimizer.compute_gradients(loss, sparse_variables)
logger.info(f"sparse_grads_tensor: {sparse_grads}")
grads_and_vars = [(grad, variable) for grad, variable in zip(sparse_grads, sparse_variables)]
train_ops.append(sparse_optimizer.apply_gradients(grads_and_vars))
Step 4: Adapting the Model Training Workflow
-
Initialize the Rec SDK framework.
Call the
initAPI before model training starts and before data loading:from mx_rec.util.initialize import ConfigInitializer, init, terminate_config_initializer init(train_steps=cm.train_steps, eval_steps=cm.eval_steps, use_dynamic=use_dynamic, use_dynamic_expansion=False) -
Enable the automatic graph modification mode.
Call the
modify_graph_and_start_emb_cacheAPI after gradient calculation and before initializing all global variables:from mx_rec.graph.modifier import modify_graph_and_start_emb_cache from mx_rec.util.initialize import ConfigInitializer, init, terminate_config_initializer # Enable automatic graph modification, data loading, and data preprocessing. modify_graph_and_start_emb_cache(dump_graph=True) # Create a Session. sess = tf.compat.v1.Session(config=sess_config(dump_data=False)) # Initialize all global variables. sess.run(ConfigInitializer.get_instance().train_params_config.get_initializer(True))Note: In the automatic graph modification mode, use
ConfigInitializer.get_instance().train_params_config.get_initializer(True)instead oftf.compat.v1.global_variables_initializer()to initialize all global variables. -
Deinitialize the framework.
Call the
terminate_config_initializerAPI after model training ends andsess.close():from mx_rec.util.initialize import ConfigInitializer, init, terminate_config_initializer # Close the Session. sess.close() # Deinitialize and release resources. terminate_config_initializer()
