如何修改Task内置方法?

了解如何修改Task内置方法,我们首先了解下Task中的事件。

Task定义了组网事件运行事件。其中运行事件的工作流程如下图。

Hook机制 - 图1

NOTE:

  • 图中提到的运行设置config参见RunConfig说明

  • “finetune_start_event”,”finetune_end_event”,”predict_start_event”,”predict_end_event”,”eval_start_event”,”eval_end_event”等事件是用于打印相应阶段的日志信息。”save_ckpt_interval_event”事件用于保存当前训练的模型参数。”log_interval_event”事件用于计算模型评价指标以及可视化这些指标。

如果您需要对图中提到的事件的具体实现进行修改,可以通过Task提供的事件回调hook机制进行改写。

如你想要改变任务评价指标,如下示例中将PaddleHub默认的accuracy评价指标改为F1评价指标。同时还想用自定义的可视化工具可视化模型训练过程,如下示例将可视化工具改写为tb-paddle。则你需要改写评估方法log_interval_event。这时候你可以用Hook实现。具体使用方法如下:

  1. import numpy as np
  2. def calculate_f1_np(preds, labels):
  3. # 计算F1分数
  4. # preds:预测label
  5. # labels: 真实labels
  6. # 返回F1分数
  7. preds = np.array(preds)
  8. labels = np.array(labels)
  9. tp = np.sum((labels == 1) & (preds == 1))
  10. tn = np.sum((labels == 0) & (preds == 0))
  11. fp = np.sum((labels == 0) & (preds == 1))
  12. fn = np.sum((labels == 1) & (preds == 0))
  13. p = tp / (tp + fp) if (tp + fp) else 0
  14. r = tp / (tp + fn) if (tp + fn) else 0
  15. f1 = (2 * p * r) / (p + r) if p + r else 0
  16. return f1
  17. # 自定义评估方法实现
  18. def calculate_metrics(self, run_states):
  19. # run_states: list类型,每个元素是一个RunState对象,指明了该step的运行状态
  20. # 返回评估得分,平均损失值和平局运行速度
  21. loss_sum = acc_sum = run_examples = 0
  22. run_step = run_time_used = 0
  23. all_labels = np.array([])
  24. all_infers = np.array([])
  25. for run_state in run_states:
  26. run_examples += run_state.run_examples
  27. run_step += run_state.run_step
  28. loss_sum += np.mean(
  29. run_state.run_results[-1]) * run_state.run_examples
  30. acc_sum += np.mean(
  31. run_state.run_results[2]) * run_state.run_examples
  32. np_labels = run_state.run_results[0]
  33. np_infers = run_state.run_results[1]
  34. all_labels = np.hstack((all_labels, np_labels.reshape([-1])))
  35. all_infers = np.hstack((all_infers, np_infers.reshape([-1])))
  36. run_time_used = time.time() - run_states[0].run_time_begin
  37. avg_loss = loss_sum / run_examples
  38. run_speed = run_step / run_time_used
  39. scores = OrderedDict()
  40. f1 = calculate_f1_np(all_infers, all_labels)
  41. scores["f1"] = f1
  42. return scores, avg_loss, run_speed
  43. # 利用自定义可视化工具tb-paddle记录训练过程中的损失值,评估指标等
  44. from tb_paddle import SummaryWriter
  45. tb_writer = SummaryWriter("PATH/TO/LOG")
  46. def record_value(evaluation_scores, loss, s)
  47. tb_writer.add_scalar(
  48. tag="Loss_{}".format(self.phase),
  49. scalar_value=loss,
  50. global_step=self._envs['train'].current_step)
  51. log_scores = ""
  52. for metric in evaluation_scores:
  53. self.tb_writer.add_scalar(
  54. tag="{}_{}".format(metric, self.phase),
  55. scalar_value=scores[metric],
  56. global_step=self._envs['train'].current_step)
  57. log_scores += "%s=%.5f " % (metric, scores[metric])
  58. print("step %d / %d: loss=%.5f %s[step/sec: %.2f]" %
  59. (self.current_step, self.max_train_steps, avg_loss,
  60. log_scores, run_speed))
  61. # 改写_log_interval_event实现
  62. def new_log_interval_event(self, run_states):
  63. # 改写的事件方法,参数列表务必与PaddleHub内置的相应方法保持一致
  64. print("This is the new log_interval_event!")
  65. scores, avg_loss, run_speed = calculate_metrics(run_states)
  66. record_value(scores, avg_loss, run_speed)
  67. # 利用Hook改写PaddleHub内置_log_interval_event实现,需要2步(假设task已经创建好)
  68. # 1.删除PaddleHub内置_log_interval_event实现
  69. # hook_type:你想要改写的事件hook类型
  70. # name:hook名字,“default”表示PaddleHub内置_log_interval_event实现
  71. task.delete_hook(hook_type="log_interval_event", name="default")
  72. # 2.增加自定义_log_interval_event实现(new_log_interval_event)
  73. # hook_type:你想要改写的事件hook类型
  74. # name: hook名字
  75. # func:自定义改写的方法
  76. task.add_hook(hook_type="log_interval_event", name="new_log_interval_event", func=new_log_interval_event)
  77. # 输出hook信息
  78. task.hook_info()

NOTE:

  • 关于上述提到的run_states参见RunEnv说明

  • tb-paddle详细信息参见官方文档

  • 改写的事件方法,参数列表务必与PaddleHub内置的相应方法保持一致。

  • 只支持改写/删除以下事件hook类型: “build_env_start_event”,”build_env_end_event”,”finetune_start_event”,”finetune_end_event”,”predict_start_event”,”predict_end_event”,”eval_start_event”,”eval_end_event”,”log_interval_event”,”save_ckpt_interval_event”,”eval_interval_event”,”run_step_event”。

  • 如果想要改写组网事件,Hook不支持。改写组网事件参见自定义Task

  • 如何创建Task,参见PaddleHub迁移学习示例