混合精度训练
功能介绍
通过工具迁移完成后,默认精度模式为allow_fp32_to_fp16(优先保持原图精度,当算子不支持float32数据类型时,直接降低精度到float16),如果需要修改精度模式,需要参考本节内容。当前系统支持的精度模式包括:
- allow_fp32_to_fp16:优先保持原图精度,当算子不支持float32数据类型时,直接降低精度到float16。当前不支持float32类型的算子都是卷积类和矩阵类算子,例如Conv2D、DepthwiseConv2D等。当前版本,对于Matmul/BatchMatmul类算子系统会直接采用float16方式处理,可能引起精度降低,用户可以通过customize_dtypes自定义算子计算精度。
- force_fp16:当算子既支持float16又支持float32数据类型时,强制选择float16。
- force_fp32:算子既支持float16又支持float32数据类型时,强制选择float32。
- must_keep_origin_dtype:保持原图精度。此种方式下,如果整网中有Conv2D算子,由于该算子仅支持float16类型,在原图输入是float32类型的情况下,训练会报错中止。
- allow_mix_precision:自动混合精度。可以针对全网中float32数据类型的算子,按照内置的优化策略,自动将部分float32的算子降低精度到float16,从而在精度损失很小的情况下提升系统性能并减少内存使用。但需要注意的是:当前昇腾AI处理器仅支持float32到float16的精度调整。如果用户原始脚本中已经实现了手动混合精度功能,比如显式调用cast算子转换计算精度,则无需开启昇腾AI处理器的自动混合精度功能。
在昇腾AI处理器进行混合精度训练时,推荐使能Loss Scale,从而补偿降低精度带来的精度损失。
Estimator模式修改
- 检查迁移后的脚本是否存在“init_resource”。
- 如果存在,则需要参考下面示例进行修改;修改完后,执行下一步。
- 如果不存在,则直接执行下一步。
if __name__ == '__main__': session_config = tf.ConfigProto() custom_op = session_config.graph_options.rewrite_options.custom_optimizers.add() custom_op.name = "NpuOptimizer" custom_op.parameter_map["precision_mode"].s = tf.compat.as_bytes("allow_mix_precision") (npu_sess, npu_shutdown) = init_resource(config=session_config) tf.app.run() shutdown_resource(npu_sess, npu_shutdown) close_session(npu_sess)
- 在迁移后的脚本中找到“npu_run_config_init”:
session_config = tf.ConfigProto(allow_soft_placement=True) run_config = tf.estimator.RunConfig( train_distribute=distribution_strategy, session_config=session_config, save_checkpoints_secs=60*60*24) classifier = tf.estimator.Estimator( model_fn=model_function, model_dir=flags_obj.model_dir, config=npu_run_config_init(run_config=run_config))
- 配置“precision_mode”:
session_config = tf.ConfigProto(allow_soft_placement=True) custom_op = session_config.graph_options.rewrite_options.custom_optimizers.add() custom_op.name = 'NpuOptimizer' custom_op.parameter_map["precision_mode"].s = tf.compat.as_bytes("allow_mix_precision") run_config = tf.estimator.RunConfig( train_distribute=distribution_strategy, session_config=session_config, save_checkpoints_secs=60*60*24) classifier = tf.estimator.Estimator( model_fn=model_function, model_dir=flags_obj.model_dir, config=npu_run_config_init(run_config=run_config))
- 如果脚本中的运行配置函数,例如RunConfig中没有传入session_config参数,需要自行传入session_config:
session_config = tf.ConfigProto() custom_op = session_config.graph_options.rewrite_options.custom_optimizers.add() custom_op.name = 'NpuOptimizer' custom_op.parameter_map["precision_mode"].s = tf.compat.as_bytes("allow_mix_precision") run_config = tf.estimator.RunConfig( train_distribute=distribution_strategy, session_config=session_config, save_checkpoints_secs=60*60*24) classifier = tf.estimator.Estimator( model_fn=model_function, model_dir=flags_obj.model_dir, config=npu_run_config_init(run_config=run_config))
sess.run模式修改
- 检查迁移后的脚本是否存在“init_resource”。
- 如果存在,则需要参考下面示例进行修改;修改完后,执行下一步。
- 如果不存在,则直接执行下一步。
if __name__ == '__main__': session_config = tf.ConfigProto() custom_op = session_config.graph_options.rewrite_options.custom_optimizers.add() custom_op.name = "NpuOptimizer" custom_op.parameter_map["precision_mode"].s = tf.compat.as_bytes("allow_mix_precision") (npu_sess, npu_shutdown) = init_resource(config=session_config) tf.app.run() shutdown_resource(npu_sess, npu_shutdown) close_session(npu_sess)
- 在脚本中找到“npu_config_proto”:
with tf.Session(config=npu_config_proto()) as sess: sess.run(tf.global_variables_initializer()) interaction_table.init.run()
- 配置“precision_mode”:
config_proto = tf.ConfigProto() custom_op = config_proto.graph_options.rewrite_options.custom_optimizers.add() custom_op.name = 'NpuOptimizer' custom_op.parameter_map["precision_mode"].s = tf.compat.as_bytes("allow_mix_precision") config = npu_config_proto(config_proto=config_proto) with tf.Session(config=config) as sess: sess.run(tf.global_variables_initializer()) interaction_table.init.run()
tf.keras模式修改
- 检查迁移后的脚本是否存在“init_resource”。
- 如果存在,则需要参考下面示例进行修改;修改完后,执行下一步。
- 如果不存在,则直接执行下一步。
if __name__ == '__main__': session_config = tf.ConfigProto() custom_op = session_config.graph_options.rewrite_options.custom_optimizers.add() custom_op.name = "NpuOptimizer" custom_op.parameter_map["precision_mode"].s = tf.compat.as_bytes("allow_mix_precision") (npu_sess, npu_shutdown) = init_resource(config=session_config) tf.app.run() shutdown_resource(npu_sess, npu_shutdown) close_session(npu_sess)
- 在脚本中找到“set_keras_session_npu_config”:
import tensorflow as tf import tensorflow.python.keras as keras from tensorflow.python.keras import backend as K from npu_bridge.npu_init import * npu_keras_sess = set_keras_session_npu_config() #数据预处理... #模型搭建... #模型编译... #模型训练...
- 配置“precision_mode”:
import tensorflow as tf import tensorflow.python.keras as keras from tensorflow.python.keras import backend as K from npu_bridge.npu_init import * config_proto = tf.ConfigProto() custom_op = config_proto.graph_options.rewrite_options.custom_optimizers.add() custom_op.name = 'NpuOptimizer' custom_op.parameter_map["precision_mode"].s = tf.compat.as_bytes("allow_mix_precision") npu_keras_sess = set_keras_session_npu_config(config=config_proto) #数据预处理... #模型搭建... #模型编译... #模型训练...
修改混合精度黑白灰名单
allow_mix_precision混合精度模式下,针对全网中float32数据类型的算子,按照内置的优化策略,自动将部分float32的算子降低精度到float16,从而在精度损失很小的情况下提升系统性能并减少内存使用。
内置优化策略在“OPP安装目录/opp/built-in/op_impl/ai_core/tbe/config/ascend910/aic-ascend910-ops-info.json”,例如:
"Conv2D":{ "precision_reduce":{ "flag":"true" },
- true:(白名单)允许将当前float32类型的算子,降低精度到float16。
- false:(黑名单)不允许将当前float32类型的算子,降低精度到float16。
- 不配置:(灰名单)当前算子的混合精度处理机制和前一个算子保持一致,即如果前一个算子支持降精度处理,当前算子也支持降精度;如果前一个算子不允许降精度,当前算子也不支持降精度。
用户可以在内置优化策略基础上进行调整,自行指定哪些算子允许降精度,哪些算子不允许降精度。下面介绍两种方法:
- (推荐)方法一,通过modify_mixlist指定需要修改的混合精度黑白灰算子名单。
custom_op.parameter_map["modify_mixlist"].s = tf.compat.as_bytes("/home/test/ops_info.json")
ops_info.json中可以指定算子类型,多个算子使用英文逗号分隔,样例如下:
{ "black-list": { // 黑名单 "to-remove": [ // 黑名单算子转换为灰名单算子 "Xlog1py" ], "to-add": [ // 白名单或灰名单算子转换为黑名单算子 "Matmul", "Cast" ] }, "white-list": { // 白名单 "to-remove": [ // 白名单算子转换为灰名单算子 "Conv2D" ], "to-add": [ // 黑名单或灰名单算子转换为白名单算子 "Bias" ] } }
假设算子A默认在白名单中,如果您希望将该算子配置为黑名单算子,当前支持的配置方法和系统处理逻辑为:
- (正确示例)用户将该算子添加到黑名单中:
{ "black-list": { "to-add": ["A"] } }
则系统会将该算子从白名单中删除,并添加到黑名单中,最终该算子在黑名单中。
- (正确示例)用户将该算子从白名单中删除,同时添加到黑名单中:
{ "black-list": { "to-add": ["A"] }, "white-list": { "to-remove": ["A"] } }
则系统会将该该算子从白名单中删除,并添加到黑名单中,最终该算子在黑名单中。
- (错误示例)用户将该算子从白名单中删除,此时算子最终是在灰名单中,而不是黑名单。
{ "white-list": { "to-remove": ["A"] } }
此时,系统会将该算子从白名单中删除,然后添加到灰名单中,最终该算子在灰名单中。
对于只从黑/白名单中删除,而不添加到白/黑名单的情况,系统会将该算子添加到灰名单中。
- (正确示例)用户将该算子添加到黑名单中:
- 方法二,直接修改算子信息库。
对内置算子信息库进行修改,可能会对其他网络造成影响,请谨慎修改。
- 切换到“OPP安装目录/opp/built-in/op_impl/ai_core/tbe/config/ascend910”目录下。
- 对aic-ascend910-ops-info.json文件增加写权限。
chmod u+w aic-ascend910-ops-info.json
当前目录下的所有json文件都会被加载到算子信息库中,如果您需要备份原来的json文件,建议备份到其他目录下。
- 修改或增加算子信息库aic-ascend910-ops-info.json文件中对应算子的precision_reduce字段。