偶然的看到了这个活动 刚好又看见模型列表有个迁移起来挺简单的模型就参加了!修改的代码不多迁移起来也很简单
领域 | 模型名称 | 论文 | 参考数据集 |
Question Answering | BERT | BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding | SQuAD2.0 |
代码的迁移
首先先从Google Research下载用TF实现的源码(url)
根据模型列表给出的SQuAD2.0数据集 今天就来修改run_squad.py相关的文件
文件头部加入NPU模块
from npu_bridge.estimator.npu.npu_config import NPURunConfig from npu_bridge.estimator import npu_ops from npu_bridge.estimator.npu.npu_estimator import NPUEstimator,NPUEstimatorSpec
初始化TF的GPU调用
gpu_thread_count = 2 os.environ['TF_GPU_THREAD_MODE'] = 'gpu_private' os.environ['TF_GPU_THREAD_COUNT'] = str(gpu_thread_count) os.environ['TF_USE_CUDNN_BATCHNORM_SPATIAL_PERSISTENT'] = '1' os.environ['TF_ENABLE_WINOGRAD_NONFUSED'] = '1'
mian的修改:
因为原版的是兼容TPU训练所以基本上看见TPU的函数全都要改掉或删掉
我就直接删掉了
if FLAGS.use_tpu and FLAGS.tpu_name: tpu_cluster_resolver = tf.contrib.cluster_resolver.TPUClusterResolver( FLAGS.tpu_name, zone=FLAGS.tpu_zone, project=FLAGS.gcp_project)
然后就是estimator的运行配置修改
run_config = tf.contrib.tpu.RunConfig( cluster=tpu_cluster_resolver, master=FLAGS.master, model_dir=FLAGS.output_dir, save_checkpoints_steps=FLAGS.save_checkpoints_steps, tpu_config=tf.contrib.tpu.TPUConfig( iterations_per_loop=FLAGS.iterations_per_loop, num_shards=FLAGS.num_tpu_cores, per_host_input_for_training=is_per_host)) #改为 config = tf.ConfigProto( inter_op_parallelism_threads=0, intra_op_parallelism_threads=0, allow_soft_placement=True) config.gpu_options.allow_growth = True run_config = NPURunConfig( model_dir=FLAGS.output_dir, save_checkpoints_steps=FLAGS.save_checkpoints_steps, iterations_per_loop=FLAGS.iterations_per_loop, session_config=config, precision_mode="allow_mix_precision",#开启混合精度训练 keep_checkpoint_max=15)
estimator = tf.contrib.tpu.TPUEstimator( use_tpu=FLAGS.use_tpu, model_fn=model_fn, config=run_config, train_batch_size=FLAGS.train_batch_size, predict_batch_size=FLAGS.predict_batch_size) #改为 estimator = NPUEstimator( model_fn=model_fn, config=run_config, model_dir=FLAGS.output_dir, params={"batch_size":FLAGS.train_batch_size,"predict_batch_size":FLAGS.predict_batch_size})
然后修改model_fn_builder模型初始化函数
还是一样为了省事 TPU的删掉
if use_tpu: def tpu_scaffold(): tf.train.init_from_checkpoint(init_checkpoint, assignment_map) return tf.train.Scaffold()
然后TPUEstimatorSpec迁移
output_spec = tf.contrib.tpu.TPUEstimatorSpec( mode=mode, loss=total_loss, train_op=train_op, scaffold_fn=scaffold_fn) #改为 这里加了个loss打印 不影响训练无所谓加不加 logging_hook = tf.train.LoggingTensorHook({"loss": total_loss}, every_n_iter=FLAGS.iterations_per_loop) output_spec = NPUEstimatorSpec( mode=mode, loss=total_loss, training_hooks=[logging_hook], train_op=train_op, scaffold=scaffold_fn) #预测: output_spec = tf.contrib.tpu.TPUEstimatorSpec( mode=mode, predictions=predictions, scaffold_fn=scaffold_fn) #改为 output_spec = NPUEstimatorSpec( mode=mode, predictions=predictions, scaffold=scaffold_fn)
然后是input_fn_builder 数据输入函数的修改
数据输入大小必须要和batch_size大小一致
"一般情况下,直接迁移,无需改造。但如下情况需要进行适配修改: 如下情况需要进行适配修改: 由于当前仅支持固定shape下的训练, 也就是在进行图编译时shape的值必须是已知 的。当原始网络脚本中使用dataset.batch(batch_size)返回动态形状时, 由于数据流中 剩余的样本数可能小于batch大小,因此,在昇腾AI处理器上进行训练时, 请将 drop_remainder设置为True: dataset = dataset.batch(batch_size, drop_remainder=True) 这可能会丢弃文件中的后几个样本,以确保每个批量都具有静态形状 (batch_size)。但需要注意的是:推理时,当后一次迭代的推理数据量小于batch size时,需要补齐空白数据到batch size,因为有些脚本后会加个断言,预测结果的 数量要和预测数据的数量一致,此种情况会导致训练失败。"
d = d.apply( tf.contrib.data.map_and_batch( lambda record: _decode_record(record, name_to_features), batch_size=batch_size, drop_remainder=drop_remainder)) #改为 d = d.apply( tf.contrib.data.map_and_batch( lambda record: _decode_record(record, name_to_features), batch_size=batch_size, drop_remainder=True))#不一致直接丢掉
至此训练文件就修改完成了!
然后是模型定义文件modeling.py
头部引入NPU模块
from npu_bridge.estimator import npu_ops from npu_bridge.estimator.npu_unary_ops import npu_unary_ops
修改dropout函数:
output = tf.nn.dropout(input_tensor, 1.0 - dropout_prob) #改为 output = npu_ops.dropout(input_tensor, 1.0 - dropout_prob)
修改gelu激活函数:
def gelu(x): """Gaussian Error Linear Unit. This is a smoother version of the RELU. Original paper: https://arxiv.org/abs/1606.08415 Args: x: float Tensor to perform activation. Returns: `x` with the GELU activation applied. """ cdf = 0.5 * (1.0 + tf.tanh( (np.sqrt(2 / np.pi) * (x + 0.044715 * tf.pow(x, 3))))) return x * cdf #改为 def gelu(x): return npu_unary_ops.gelu(x)
模型文件也改完了!
然后改优化器文件optimization.py 其实直接用原版也是可以的 但可能是混合精度训练的问题会导致最后的精度很大概率会在65-71之间徘徊达不到官方的76(但我最好的训练结果是在原版文件下训练的)!这里也可以使用NVIDIA的文件修改为NPU的(url)
有很多启动参数可以直接删掉这里就不写出来了,重要的是LossScale的修改
头部引入NPU模块
from npu_bridge.estimator.npu.npu_optimizer import NPUDistributedOptimizer from npu_bridge.estimator.npu import npu_loss_scale_optimizer as lso from npu_bridge.estimator.npu import npu_loss_scale_manager as lsm_lib
LossScale:
if use_fp16: loss_scaler = tf.train.experimental.DynamicLossScale(initial_loss_scale=init_loss_scale, increment_period=1000, multiplier=2.0) optimizer = tf.train.experimental.enable_mixed_precision_graph_rewrite(optimizer, loss_scaler) loss_scale_value = tf.identity(loss_scaler(), name="loss_scale") if manual_fp16: loss_scale_manager = tf.contrib.mixed_precision.ExponentialUpdateLossScaleManager(init_loss_scale=init_loss_scale, incr_every_n_steps=1000, decr_every_n_nan_or_inf=2, decr_ratio=0.5) optimizer = tf.contrib.mixed_precision.LossScaleOptimizer(optimizer, loss_scale_manager) #这里偷懒直接就改成固定了 optimizer = NPUDistributedOptimizer(optimizer) opt_tmp = optimizer loss_scale_manager = lsm_lib.ExponentialUpdateLossScaleManager(init_loss_scale=2**32, incr_every_n_steps=1000, decr_every_n_nan_or_inf=2, decr_ratio=0.5) optimizer = lso.NPULossScaleOptimizer(opt_tmp, loss_scale_manager) #你也可以根据网络模型移植训练指南.pdf 来改成自定义参数 if FLAGS.use_fp16 and (FLAGS.npu_bert_loss_scale not in [None, -1]): opt_tmp = opt if FLAGS.npu_bert_loss_scale == 0: loss_scale_manager = ExponentialUpdateLossScaleManager(init_loss_scale=2**32, incr_every_n_steps=1000, decr_every_n_nan_or_inf=2, decr_ratio=0.5) elif FLAGS.npu_bert_loss_scale >= 1: loss_scale_manager = FixedLossScaleManager(loss_scale=FLAGS.npu_bert_loss_scale) else: raise ValueError("Invalid loss scale: %d" % FLAGS.npu_bert_loss_scale) if ops_adapter.size() > 1: opt = NPULossScaleOptimizer(opt_tmp, loss_scale_manager, is_distributed=True) else: opt = NPULossScaleOptimizer(opt_tmp, loss_scale_manager)
到这里全部代码就已经迁移完成了!可以看到迁移起来非常简单一共就没几行需要修改的
这里为了方便ModelArts的训练修改了启动参数可以直接参考我修改好的源码
优秀。先不回帖打扰。。。
... 查看全部