本文分享自華為雲社群《TensorFlow模型訓練常見案例》,作者: 昇騰CANN。
基於TensorFlow的Python API開發的訓練指令碼預設執行在CPU/GPU/TPU上,為了使這些指令碼能夠利用昇騰AI處理器的強大算力,需要將其遷移到昇騰平臺。
本期分享幾個TensorFlow網路遷移到昇騰平臺後執行失敗或者執行效能差的典型案例,並給出原因分析及解決方法。
01 資料預處理中存在資源類運算元,導致訓練異常
問題現象
TensorFlow網路執行時,報如下錯誤:
[2021-03-19 13:50:24.895266: W tensorflow/core/framework/op_kernel.cc:1651] OP_REQUIRES failed at lookup_table_op.cc:809 : Failed precondition: Table not initialized. [2021-03-19 13:50:24.895283: W tensorflow/core/framework/op_kernel.cc:1651] OP_REQUIRES failed at lookup_table_op.cc:809 : Failed precondition: Table not initialized.
原因分析
初始化圖中存在資源類運算元HaskTableV2 ,資料預處理中存在資源類運算元LookupTableFindV2,兩個運算元需要配對使用。
昇騰AI處理器預設採用計算全下沉模式,即所有的計算類運算元(包括初始化圖中的資源類運算元)全部在Device側執行,資料預處理仍在Host執行。這樣資料預處理中的LookupTableFindV2運算元與初始化圖中的HaskTableV2運算元未在同一裝置執行,導致網路執行出錯。
解決方案
需要修改訓練指令碼,使能混合計算能力,將資源類運算元的初始化圖也留在Host側執行,訓練指令碼修改方法如下:
from npu_bridge.npu_init import * config = tf.ConfigProto() custom_op = config.graph_options.rewrite_options.custom_optimizers.add() custom_op.name = "NpuOptimizer" custom_op.parameter_map["mix_compile_mode"].b = True config.graph_options.rewrite_options.remapping = RewriterConfig.OFF config.graph_options.rewrite_options.memory_optimization = RewriterConfig.OFF with tf.Session(config=config) as sess: sess.run(...)
其中配置引數“mix_compile_mode”是混合計算開啟開關,當此開關配置為“True”後,會將需要成對使用的資源類運算元留在前端框架線上執行。
補充說明:當使用者的預處理指令碼中存在需要成對使用的tf.contrib.lookup下Table類的API時,需要參考此方法使能混合計算功能,將初始化圖中的對應運算元留在Host側執行。
02 資料預處理中存在tf.Variable,導致訓練異常
問題現象
TensorFlow網路執行時,報如下錯誤:
tensorflow.python.framework.errors_impl.FailedPreconditionError: Error while reading resource variable inference/embed_continuous from Container: localhost. This could mean that the variable was uninitialized. Not found: Resource localhost/inference/embed_continuous/N10tensorflow3VarE does not exist.
原因分析
此問題是由於資料預處理指令碼中存在tf.Variable變數。訓練指令碼在昇騰平臺執行時,tf.Variable變數在Host側執行,而tf.Variable變數的初始化在Device側執行,變數執行和變數初始化不在同一裝置執行,導致訓練異常。
使用了tf.Variable的訓練指令碼程式碼示例如下:
batch_size = tf.Variable( tf.placeholder(tf.int64, [], 'batch_size'), trainable= False, collections=[] ) train_dataset = train_dataset.batch(batch_size, drop_remainder=True)
解決方案
需要修改訓練指令碼,將tf.Variable修改成常量,修改示例如下:
batch_size = 64 train_dataset = train_dataset.batch(batch_size, drop_remainder=True) batch_size = 64 train_dataset = train_dataset.batch(batch_size, drop_remainder=True)
03 動態shape網路執行時報v1控制流運算元不支援的錯誤
問題現象
TensorFlow 1.15版本的動態shape網路執行時,報如下錯誤:
node node_name(node_type) is v1 control operator, which is not supported, please convert to v2 control operator
原因分析
由於當前TensorFlow網路為動態shape網路,且存在V1版本的控制流運算元。在昇騰AI處理器執行TensorFlow動態shape網路當前不支援V1版本的控制流運算元,所以會造成網路執行失敗。
解決方案
將網路中的TensorFlow V1版本的控制流運算元轉換為V2版本,即可解決此問題。
方法一:透過設定如下環境變數將TensorFlow V1版本的控制流運算元轉換為V2版本。
export ENABLE_FORCE_V2_CONTROL=1
方法二:修改網路指令碼,在import tensorflow as tf後增加如下兩條指令,將TensorFlow V1版本的控制流運算元轉換為V2版本。
tf.enable_control_flow_v2()
tf.enable_resource_variables()
04 網路調測時ReduceSum運算元執行效能差
問題現象
網路調測時,網路整體效能較慢。透過Profiling工具獲取網路的Profiling資料,並進行運算元的效能資料分析,發現ReduceSum運算元的效能很差。
檢視Profiling效能資料中ReduceSum運算元的詳細資訊,關鍵欄位如下表藍色字型所示:
op_type |
block_dim |
input_shape |
input_data_type |
input_formats |
ReduceSum |
1 |
1,256,256,3 |
DT_FLOAT16 |
NHWC |
ReduceSum運算元的輸入資料型別(input_data_type)為“DT_FLOAT16”,block_dim欄位的值為“1”,說明該運算元未開啟多核平行計算。
原因分析
針對昇騰AI處理器的ReduceSum運算元,若輸入資料型別為float16,由於硬體限制,某些場景下會無法開啟多核計算。
解決方案
ReduceSum運算元輸入資料是float16的情況可能有如下兩種場景:
場景一:
網路調測時未開啟混合精度,ReduceSum運算元的輸入資料本身就是float16型別,此種情況下,若ReduceSum運算元的效能較差,可嘗試在ReduceSum運算元前插入一個Cast運算元,將運算元的輸入資料型別從float16轉換為float32。
ReduceSum運算元在輸入型別為float32的場景下,會使能多核併發計算,從而達到提升該運算元效能的效果。
場景二:
網路調測時開啟了混合精度,將ReduceSum運算元的輸入資料型別從float32轉換成了float16,此種情況下,可將ReduceSum運算元加入混合精度黑名單,這樣網路調測時ReduceSum運算元就不會被轉換成float16型別,從而避免該運算元效能的劣化。
將ReduceSum運算元加入混合精度黑名單的方法如下:
1) 修改網路指令碼,透過modify_mixlist引數指定需要修改的混合精度運算元黑名單,修改示例如下:
# Estimator模式修改方法 npu_config=NPURunConfig( ... precision_mode="allow_mix_precision", modify_mixlist="/home/test/ops_info.json" ) # sess.run模式修改方法 config = tf.ConfigProto() custom_op = config.graph_options.rewrite_options.custom_optimizers.add() custom_op.name = "NpuOptimizer" custom_op.parameter_map["use_off_line"].b = True custom_op.parameter_map["precision_mode"].s = tf.compat.as_bytes("allow_mix_precision") custom_op.parameter_map["modify_mixlist"].s = tf.compat.as_bytes("/home/test/ops_info.json")
2) 在ops_info.json檔案中進行運算元黑名單的配置,配置示例如下:
{ "black-list": { "to-add": ["ReduceSumD"] } }
補充說明:僅在ReduceSum運算元效能較差時,且符合本案例中的問題現象時,可嘗試使用此方法進行效能提升。
05 更多介紹
[1]昇騰檔案中心:https://www.hiascend.com/zh/document
[2]昇騰社群線上課程:https://www.hiascend.com/zh/edu/courses
[3]昇騰論壇:https://www.hiascend.com/forum