ArticleReproduction_CV.md 55.6 KB
Newer Older
littletomatodonkey's avatar
littletomatodonkey 已提交
1
# 论文复现赛指南
littletomatodonkey's avatar
littletomatodonkey 已提交
2

3 4 5 6 7 8
> 本文为针对 `CV` 方向的复现赛指南;
>
> 如果希望查阅 `NLP` 方向的复现赛指南,可以参考:[./ArticleReproduction_NLP.md](./ArticleReproduction_NLP.md);
> 
> 如果希望查阅 `推荐` 方向的复现赛指南,可以参考:[./ArticleReproduction_REC.md](./ArticleReproduction_REC.md)。

littletomatodonkey's avatar
littletomatodonkey 已提交
9 10 11 12 13 14 15 16
## 目录

- [1. 总览](#1)
    - [1.1 背景](#1.1)
    - [1.2 前序工作](#1.2)
- [2. 整体框图](#2)
    - [2.1 流程概览](#2.1)
    - [2.2 reprod_log whl包](#2.2)
littletomatodonkey's avatar
littletomatodonkey 已提交
17

littletomatodonkey's avatar
littletomatodonkey 已提交
18 19 20 21 22 23 24 25 26 27 28 29
- [3. 论文复现理论知识及实战](#3)
    - [3.1 模型结构对齐](#3.1)
    - [3.2 验证/测试集数据读取对齐](#3.2)
    - [3.3 评估指标对齐](#3.3)
    - [3.4 损失函数对齐](#3.4)
    - [3.5 优化器对齐](#3.5)
    - [3.6 学习率对齐](#3.6)
    - [3.7 正则化策略对齐](#3.7)
    - [3.8 反向对齐](#3.8)
    - [3.9 训练集数据读取对齐](#3.9)
    - [3.10 网络初始化对齐](#3.10)
    - [3.11 模型训练对齐](#3.11)
D
dyning 已提交
30
    - [3.12 单机多卡训练](#3.12)
littletomatodonkey's avatar
littletomatodonkey 已提交
31
    - [3.13 TIPC基础链条测试接入](#3.13)
littletomatodonkey's avatar
littletomatodonkey 已提交
32
- [4. 论文复现注意事项与FAQ](#4)
33 34 35 36 37 38
    - [4.1 通用注意事项](#4.0)
    - [4.2 模型结构对齐](#4.1)
    - [4.3 验证/测试集数据读取对齐](#4.2)
    - [4.4 评估指标对齐](#4.3)
    - [4.5 损失函数对齐](#4.4)
    - [4.6 优化器对齐](#4.5)
littletomatodonkey's avatar
littletomatodonkey 已提交
39
    - [4.6 学习率对齐](#4.6)
40 41 42 43 44
    - [4.8 正则化策略对齐](#4.7)
    - [4.9 反向对齐](#4.8)
    - [4.10 训练集数据读取对齐](#4.9)
    - [4.11 网络初始化对齐](#4.10)
    - [4.12 模型训练对齐](#4.11)
littletomatodonkey's avatar
littletomatodonkey 已提交
45
    - [4.13 TIPC基础链条测试接入](#4.13)
littletomatodonkey's avatar
littletomatodonkey 已提交
46 47

<a name="1"></a>
littletomatodonkey's avatar
littletomatodonkey 已提交
48 49
## 1. 总览

littletomatodonkey's avatar
littletomatodonkey 已提交
50
<a name="1.1"></a>
littletomatodonkey's avatar
littletomatodonkey 已提交
51 52
### 1.1 背景

D
dyning 已提交
53 54 55 56
* 以深度学习为核心的人工智能技术仍在高速发展,通过论文复现,开发者可以获得
    * 学习成长:自我能力提升
    * 技术积累:对科研或工作有所帮助和启发
    * 社区荣誉:成果被开发者广泛使用
littletomatodonkey's avatar
littletomatodonkey 已提交
57

littletomatodonkey's avatar
littletomatodonkey 已提交
58
<a name="1.2"></a>
littletomatodonkey's avatar
littletomatodonkey 已提交
59 60
### 1.2 前序工作

D
dyning 已提交
61
基于本指南复现论文过程中,建议开发者准备以下内容。
littletomatodonkey's avatar
littletomatodonkey 已提交
62 63 64 65 66 67 68 69 70

* 了解该模型输入输出格式。以AlexNet图像分类任务为例,通过阅读论文与参考代码,了解到模型输入为`[batch_size, 3, 224, 244]`的tensor,类型为`float32`或者`float16`,label为`[batch, ]`的label,类型为`int64`
* 准备好训练/验证数据集,用于模型训练与评估
* 准备好fake input data以及label,与模型输入shape、type等保持一致,用于后续模型前向对齐。
    * 在对齐模型前向过程中,我们不需要考虑数据集模块等其他模块,此时使用fake data是将模型结构和数据部分解耦非常合适的一种方式。
    * 将fake data以文件的形式存储下来,也可以保证PaddlePaddle与参考代码的模型结构输入是完全一致的,更便于排查问题。
    * 在该步骤中,以AlexNet为例,生成fake data的脚本可以参考:[gen_fake_data.py](https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/pipeline/fake_data/gen_fake_data.py)
* 在特定设备(CPU/GPU)上,跑通参考代码的预测过程(前向)以及至少2轮(iteration)迭代过程,保证后续基于PaddlePaddle复现论文过程中可对比。
* 本文档基于 `AlexNet-Prod` 代码以及`reprod_log` whl包进行说明与测试。如果希望体验,建议参考[AlexNet-Reprod文档](https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/README.md)进行安装与测试。
littletomatodonkey's avatar
littletomatodonkey 已提交
71 72 73
* 在复现的过程中,只需要将PaddlePaddle的复现代码以及打卡日志上传至github,不能在其中添加`参考代码的实现`,在验收通过之后,需要删除打卡日志。建议在初期复现的时候,就将**复现代码与参考代码分成2个文件夹进行管理**
* 飞桨训推一体认证 (Training and Inference Pipeline Certification, TIPC) 是一个针对飞桨模型的测试工具,方便用户查阅每种模型的训练推理部署打通情况,并可以进行一键测试。论文训练对齐之后,需要为代码接入TIPC基础链条测试文档与代码,关于TIPC基础链条测试接入规范的文档可以参考:[链接](https://github.com/PaddlePaddle/models/blob/tipc/docs/tipc_test/development_specification_docs/train_infer_python.md)。更多内容在`3.13`章节部分也会详细说明。

littletomatodonkey's avatar
littletomatodonkey 已提交
74

littletomatodonkey's avatar
littletomatodonkey 已提交
75
<a name="2"></a>
littletomatodonkey's avatar
littletomatodonkey 已提交
76 77
## 2. 整体框图

littletomatodonkey's avatar
littletomatodonkey 已提交
78
<a name="2.1"></a>
littletomatodonkey's avatar
littletomatodonkey 已提交
79 80
### 2.1 流程概览

D
dyning 已提交
81
面对一篇计算机视觉论文,复现该论文的整体流程如下图所示。
littletomatodonkey's avatar
littletomatodonkey 已提交
82

littletomatodonkey's avatar
littletomatodonkey 已提交
83
![图片](images/framework_reprodcv.png)
littletomatodonkey's avatar
littletomatodonkey 已提交
84

85
总共包含12个步骤。为了高效复现论文,设置了6个验收节点。如上图中黄色框所示。后续章节会详细介绍上述步骤和验收节点,具体内容安排如下:
littletomatodonkey's avatar
littletomatodonkey 已提交
86

87
* 第3章:介绍12个复现步骤的理论知识、实战以及验收流程。
littletomatodonkey's avatar
littletomatodonkey 已提交
88
* 第4章:针对复现流程过程中每个步骤可能出现的问题,本章会进行详细介绍。如果还是不能解决问题,可以提ISSUE进行讨论,提ISSUE地址:[https://github.com/PaddlePaddle/Paddle/issues/new/choose](https://github.com/PaddlePaddle/Paddle/issues/new/choose)
littletomatodonkey's avatar
littletomatodonkey 已提交
89

littletomatodonkey's avatar
littletomatodonkey 已提交
90
<a name="2.2"></a>
D
dyning 已提交
91
### 2.2 reprod_log whl包
littletomatodonkey's avatar
littletomatodonkey 已提交
92

D
dyning 已提交
93 94
#### 2.2.1 reprod_log工具简介
`reprod_log`是用于论文复现赛中辅助自查和验收工具。该工具源代码地址在:[https://github.com/WenmuZhou/reprod_log](https://github.com/WenmuZhou/reprod_log)。主要功能如下:
littletomatodonkey's avatar
littletomatodonkey 已提交
95 96 97 98 99 100

* 存取指定节点的输入输出tensor
* 基于文件的tensor读写
* 2个字典的对比验证
* 对比结果的输出与记录

littletomatodonkey's avatar
littletomatodonkey 已提交
101
更多API与使用方法可以参考:[reprod_log API使用说明](https://github.com/WenmuZhou/reprod_log/blob/master/README.md)
littletomatodonkey's avatar
littletomatodonkey 已提交
102

D
dyning 已提交
103
#### 2.2.2 reprod_log使用demo
littletomatodonkey's avatar
littletomatodonkey 已提交
104

D
dyning 已提交
105
下面基于代码:[https://github.com/littletomatodonkey/AlexNet-Prod/tree/master/pipeline/reprod_log_demo](https://github.com/littletomatodonkey/AlexNet-Prod/tree/master/pipeline/reprod_log_demo),给出如何使用该工具。
littletomatodonkey's avatar
littletomatodonkey 已提交
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129

文件夹中包含`write_log.py``check_log_diff.py`文件,其中`write_log.py`中给出了`ReprodLogger`类的使用方法,`check_log_diff.py`给出了`ReprodDiffHelper`类的使用方法,依次运行两个python文件,使用下面的方式运行代码。

```shell
# 进入文件夹
cd pipeline/reprod_log_demo
# 随机生成矩阵,写入文件中
python3.7 write_log.py
# 进行文件对比,输出日志
python3.7 check_log_diff.py
```

最终会输出以下内容

```
2021-09-28 01:07:44,832 - reprod_log.utils - INFO - demo_test_1:
2021-09-28 01:07:44,832 - reprod_log.utils - INFO -     mean diff: check passed: True, value: 0.0
2021-09-28 01:07:44,832 - reprod_log.utils - INFO - demo_test_2:
2021-09-28 01:07:44,832 - reprod_log.utils - INFO -     mean diff: check passed: False, value: 0.3336232304573059
2021-09-28 01:07:44,832 - reprod_log.utils - INFO - diff check failed
```

可以看出:对于key为`demo_test_1`的矩阵,由于diff为0,小于设置的阈值`1e-6`,核验成功;对于key为`demo_test_2`的矩阵,由于diff为0.33,大于设置的阈值`1e-6`,核验失败。

D
dyning 已提交
130
#### 2.2.3 reprod_log在论文复现中应用
littletomatodonkey's avatar
littletomatodonkey 已提交
131

D
dyning 已提交
132
在论文复现中,基于reprod_log的结果记录模块,产出下面若干文件
littletomatodonkey's avatar
littletomatodonkey 已提交
133 134 135 136 137 138 139 140 141 142 143 144 145 146
```
log_reprod
├── forward_paddle.npy
├── forward_torch.npy    # 与forward_paddle.npy作为一并核查的文件对
├── metric_paddle.npy
├── metric_torch.npy     # 与metric_paddle.npy作为一并核查的文件对
├── loss_paddle.npy
├── loss_torch.npy       # 与loss_paddle.npy作为一并核查的文件对
├── bp_align_paddle.npy
├── bp_align_torch.npy   # 与bp_align_paddle.npy作为一并核查的文件对
├── train_align_paddle.npy
├── train_align_benchmark.npy # PaddlePaddle提供的参考评估指标
```

D
dyning 已提交
147
基于reprod_log的`ReprodDiffHelper`模块,产出下面5个日志文件。
littletomatodonkey's avatar
littletomatodonkey 已提交
148 149 150 151 152 153 154 155 156

```
├── forward_diff.log     # forward_paddle.npy与forward_torch.npy生成的diff结果文件
├── metric_diff.log      # metric_paddle.npy与metric_torch.npy生成的diff结果文件
├── loss_diff.log          # loss_paddle.npy与loss_torch.npy生成的diff结果文件
├── bp_align_diff.log    # bp_align_paddle.npy与bp_align_torch.npy生成的diff结果文件
├── train_align_diff.log # train_align_paddle.npy与train_align_benchmark.npy生成的diff结果文件
```

D
dyning 已提交
157
上述文件的生成代码都需要开发者进行开发,验收时需要提供上面罗列的所有文件(不需要提供产生这些文件的可运行程序)以及完整的模型训练评估程序和日志。
littletomatodonkey's avatar
littletomatodonkey 已提交
158 159 160 161 162 163

AlexNet-Prod项目提供了基于reprod_log的前5个验收点对齐验收示例,参考代码地址为:[https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/pipeline/](https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/pipeline/),每个文件夹中的README.md文档提供了使用说明。

InsightFace项目中提供了`TIPC基础链条验收点`的验收示例,参考代码地址为:[https://github.com/deepinsight/insightface/blob/master/recognition/arcface_paddle/test_tipc/readme.md](https://github.com/deepinsight/insightface/blob/master/recognition/arcface_paddle/test_tipc/readme.md),更多关于TIPC基础链条测试接入规范的代码可以参考:[https://github.com/PaddlePaddle/models/blob/tipc/docs/tipc_test/development_specification_docs/train_infer_python.md](https://github.com/PaddlePaddle/models/blob/tipc/docs/tipc_test/development_specification_docs/train_infer_python.md)


littletomatodonkey's avatar
littletomatodonkey 已提交
164

littletomatodonkey's avatar
littletomatodonkey 已提交
165 166
<a name="3"></a>
## 3. 论文复现理论知识及实战
littletomatodonkey's avatar
littletomatodonkey 已提交
167

littletomatodonkey's avatar
littletomatodonkey 已提交
168
<a name="3.1"></a>
littletomatodonkey's avatar
littletomatodonkey 已提交
169 170 171 172 173 174
### 3.1 模型结构对齐

对齐模型结构时,一般有3个主要步骤:

* 网络结构代码转换
* 权重转换
D
dyning 已提交
175
* 模型组网正确性验证
littletomatodonkey's avatar
littletomatodonkey 已提交
176 177 178 179 180

下面详细介绍这3个部分。

#### 3.1.1 网络结构代码转换

D
dyning 已提交
181 182 183 184 185 186
**【基本流程】**

由于PyTorch的API和PaddlePaddle的API非常相似,可以参考[PyTorch-PaddlePaddle API映射表](https://www.paddlepaddle.org.cn/documentation/docs/zh/guides/08_api_mapping/pytorch_api_mapping_cn.html)
,组网部分代码直接进行手动转换即可。

**【注意事项】**
littletomatodonkey's avatar
littletomatodonkey 已提交
187

D
dyning 已提交
188 189 190 191
如果遇到PaddlePaddle没有的API,可以尝试用多种API来组合,也可以给PaddlePaddle团队提[ISSUE](https://github.com/PaddlePaddle/Paddle/issues),获得支持。

**【实战】**

littletomatodonkey's avatar
littletomatodonkey 已提交
192 193 194 195
AlexNet网络结构的PyTorch实现: [alexnet-pytorch](https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/pipeline/Step1/AlexNet_torch/torchvision/models/alexnet.py)

对应转换后的PaddlePaddle实现: [alexnet-paddle](https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/pipeline/Step1/AlexNet_paddle/paddlevision/models/alexnet.py)

littletomatodonkey's avatar
littletomatodonkey 已提交
196 197 198

#### 3.1.2 权重转换

D
dyning 已提交
199 200
**【基本流程】**

littletomatodonkey's avatar
littletomatodonkey 已提交
201 202
组网代码转换完成之后,需要对模型权重进行转换,如果PyTorch repo中已经提供权重,那么可以直接下载并进行后续的转换;如果没有提供,则可以基于PyTorch代码,随机生成一个初始化权重(定义完model以后,使用`torch.save()` API保存模型权重),然后进行权重转换。

D
dyning 已提交
203 204
**【注意事项】**

littletomatodonkey's avatar
littletomatodonkey 已提交
205
在权重转换的时候,需要注意`paddle.nn.Linear`以及`paddle.nn.BatchNorm2D`等API的权重保存格式和名称等与PyTorch稍有diff,具体内容可以参考`4.1章节`
D
dyning 已提交
206 207 208

**【实战】**

littletomatodonkey's avatar
littletomatodonkey 已提交
209
AlexNet的代码转换脚本可以在这里查看:[https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/pipeline/weights/torch2paddle.py](https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/pipeline/weights/torch2paddle.py)
littletomatodonkey's avatar
littletomatodonkey 已提交
210

D
dyning 已提交
211
注意:运行该代码需要首先下载PyTorch的AlexNet预训练模型到该目录下,下载地址为:[https://download.pytorch.org/models/alexnet-owt-7be5be79.pth](https://download.pytorch.org/models/alexnet-owt-7be5be79.pth)
littletomatodonkey's avatar
littletomatodonkey 已提交
212 213

```python
littletomatodonkey's avatar
littletomatodonkey 已提交
214
# https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/pipeline/weights/torch2paddle.py
littletomatodonkey's avatar
littletomatodonkey 已提交
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239

import numpy as np
import torch
import paddle

def transfer():
    input_fp = "alexnet-owt-7be5be79.pth"
    output_fp = "alexnet_paddle.pdparams"
    torch_dict = torch.load(input_fp)
    paddle_dict = {}
    fc_names = [
        "classifier.1.weight", "classifier.4.weight", "classifier.6.weight"
    ]
    for key in torch_dict:
        weight = torch_dict[key].cpu().detach().numpy()
        flag = [i in key for i in fc_names]
        if any(flag):
            print("weight {} need to be trans".format(key))
            weight = weight.transpose()
        paddle_dict[key] = weight
    paddle.save(paddle_dict, output_fp)

transfer()
```

littletomatodonkey's avatar
littletomatodonkey 已提交
240
运行完成之后,会在当前目录生成`alexnet_paddle.pdparams`文件,即为转换后的PaddlePaddle预训练模型。
littletomatodonkey's avatar
littletomatodonkey 已提交
241 242 243 244


#### 3.1.3 模型组网正确性验证

D
dyning 已提交
245 246
**【基本流程】**

littletomatodonkey's avatar
littletomatodonkey 已提交
247 248 249 250
1. 定义PyTorch模型,加载权重,固定seed,基于numpy生成随机数,转换为PyTorch可以处理的tensor,送入网络,获取输出,使用reprod_log保存结果。
2. 定义PaddlePaddle模型,加载权重,固定seed,基于numpy生成随机数,转换为PaddlePaddle可以处理的tensor,送入网络,获取输出,使用reprod_log保存结果。
3.  使用reprod_log排查diff,小于阈值,即可完成自测。

D
dyning 已提交
251 252
**【注意事项】**

littletomatodonkey's avatar
littletomatodonkey 已提交
253 254 255
* 模型在前向对齐验证时,需要调用`model.eval()`方法,保证组网中的随机量被关闭,比如BatchNorm、Dropout等。
* 给定相同的输入数据,为保证可复现性,如果有随机数生成,固定相关的随机种子。
* 输出diff可以使用`np.mean(np.abs(o1 - o2))`进行计算,一般小于1e-6的话,可以认为前向没有问题。如果最终输出结果diff较大,可以使用二分的方法进行排查,比如说ResNet50,包含1个stem、4个res-stage、global avg-pooling以及最后的fc层,那么完成模型组网和权重转换之后,如果模型输出没有对齐,可以尝试输出中间某一个res-stage的tensor进行对比,如果相同,则向后进行排查;如果不同,则继续向前进行排查,以此类推,直到找到导致没有对齐的操作。
littletomatodonkey's avatar
littletomatodonkey 已提交
256

D
dyning 已提交
257
**【实战】**
littletomatodonkey's avatar
littletomatodonkey 已提交
258

D
dyning 已提交
259 260
AlexNet模型组网正确性验证可以参考如下示例代码:
[https://github.com/littletomatodonkey/AlexNet-Prod/tree/master/pipeline/Step1](https://github.com/littletomatodonkey/AlexNet-Prod/tree/master/pipeline/Step1)
littletomatodonkey's avatar
littletomatodonkey 已提交
261 262


littletomatodonkey's avatar
littletomatodonkey 已提交
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
**【验收】**

对于待复现的项目,前向对齐验收流程如下。

1. 准备输入:fake data
    * 使用参考代码的dataloader,生成一个batch的数据,保存下来,在前向对齐时,直接从文件中读入。
    * 固定随机数种子,生成numpy随机矩阵,转化tensor
2. 保存输出:
    * PaddlePaddle/PyTorch:dict,key为tensor的name(自定义),value为tensor的值。最后将dict保存到文件中。建议命名为`forward_paddle.npy``forward_pytorch.npy`
3. 自测:使用reprod_log加载2个文件,使用report功能,记录结果到日志文件中,建议命名为`forward_diff_log.txt`,观察diff,二者diff小于特定的阈值即可。
4. 提交内容:新建文件夹,将`forward_paddle.npy``forward_pytorch.npy``forward_diff_log.txt`文件放在文件夹中,后续的输出结果和自查日志也放在该文件夹中,一并打包上传即可。
5. 注意:
    * PaddlePaddle与PyTorch保存的dict的key需要保持相同,否则report过程可能会提示key无法对应,从而导致report失败,之后的`【验收】`环节也是如此。
    * 如果是固定随机数种子,建议将fake data保存到dict中,方便check参考代码和PaddlePaddle的输入是否一致。

<a name="3.2"></a>
### 3.2 验证/测试集数据读取对齐
littletomatodonkey's avatar
littletomatodonkey 已提交
280

D
dyning 已提交
281 282
**【基本流程】**

littletomatodonkey's avatar
littletomatodonkey 已提交
283 284 285 286 287 288 289
对于一个数据集,一般有以下一些信息需要重点关注

* 数据集名称、下载地址
* 训练集/验证集/测试集图像数量、类别数量、分辨率等
* 数据集标注格式、标注信息
* 数据集通用的预处理方法

D
dyning 已提交
290
PaddlePaddle中数据集相关的API为`paddle.io.Dataset`,PyTorch中对应为`torch.utils.data.Dataset`,二者功能一致,在绝大多数情况下,可以使用该类构建数据集。它是描述Dataset方法和行为的抽象类,在具体实现的时候,需要继承这个基类,实现其中的`__getitem__``__len__`方法。除了参考代码中相关实现,也可以参考待复现论文中的说明。
littletomatodonkey's avatar
littletomatodonkey 已提交
291

littletomatodonkey's avatar
littletomatodonkey 已提交
292 293 294 295
复现完Dataset之后,可以构建Dataloader,对数据进行组batch、批处理,送进网络进行计算。

`paddle.io.DataLoader`可以进行数据加载,将数据分成批数据,并提供加载过程中的采样。PyTorch对应的实现为`torch.utils.data.DataLoader`,二者在功能上一致,只是在参数方面稍有diff:(1)PaddlePaddle缺少对`pin_memory`等参数的支持;(2)PaddlePaddle增加了`use_shared_memory`参数来选择是否使用共享内存加速数据加载过程。

D
dyning 已提交
296 297
**【注意事项】**

littletomatodonkey's avatar
littletomatodonkey 已提交
298
论文中一般会提供数据集的名称以及基本信息。复现过程中,我们在下载完数据之后,建议先检查下是否和论文中描述一致,否则可能存在的问题有:
littletomatodonkey's avatar
littletomatodonkey 已提交
299 300

* 数据集年份不同,比如论文中使用了MS-COCO2014数据集,但是我们下载的是MS-COCO2017数据集,如果不对其进行检查,可能会导致我们最终训练的数据量等与论文中有diff
littletomatodonkey's avatar
littletomatodonkey 已提交
301 302
* 数据集使用方式不同,有些论文中,可能只是抽取了该数据集的子集进行方法验证,此时需要注意抽取方法,需要保证抽取出的子集完全相同。
* 在评估指标对齐时,我们可以固定batch size,关闭Dataloader的shuffle操作。
littletomatodonkey's avatar
littletomatodonkey 已提交
303 304 305

构建数据集时,也会涉及到一些预处理方法,以CV领域为例,PaddlePaddle提供了一些现成的视觉类操作api,具体可以参考:[paddle.vision类API](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/vision/Overview_cn.html)。对应地,PyTorch中的数据处理api可以参考:[torchvision.transforms类API](https://pytorch.org/vision/stable/transforms.html)。对于其中之一,可以找到另一个平台的实现。

littletomatodonkey's avatar
littletomatodonkey 已提交
306
此外,
littletomatodonkey's avatar
littletomatodonkey 已提交
307 308 309
* 有些自定义的数据处理方法,如果不涉及到深度学习框架的部分,可以直接复用。
* 对于特定任务中的数据预处理方法,比如说图像分类、检测、分割等,如果没有现成的API可以调用,可以参考官方模型套件中的一些实现方法,比如PaddleClas、PaddleDetection、PaddleSeg等。

D
dyning 已提交
310 311
**【实战】**

littletomatodonkey's avatar
littletomatodonkey 已提交
312 313
AlexNet模型复现过程中,数据预处理和Dataset、Dataloader的检查可以参考该文件:
[https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/pipeline/Step2/test_data.py](https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/pipeline/Step2/test_data.py)
D
dyning 已提交
314

littletomatodonkey's avatar
littletomatodonkey 已提交
315

littletomatodonkey's avatar
littletomatodonkey 已提交
316
使用方法可以参考[数据检查文档](https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/pipeline/Step2/README.md)
littletomatodonkey's avatar
littletomatodonkey 已提交
317

littletomatodonkey's avatar
littletomatodonkey 已提交
318
<a name="3.3"></a>
littletomatodonkey's avatar
littletomatodonkey 已提交
319 320
### 3.3 评估指标对齐

littletomatodonkey's avatar
littletomatodonkey 已提交
321
**【基本流程】**
littletomatodonkey's avatar
littletomatodonkey 已提交
322

littletomatodonkey's avatar
littletomatodonkey 已提交
323
PaddlePaddle提供了一系列Metric计算类,比如说`Accuracy`, `Auc`, `Precision`, `Recall`等,而PyTorch中,目前可以通过组合的方式实现metric计算,或者调用[torchmetrics](https://torchmetrics.readthedocs.io/en/latest/),在论文复现的过程中,需要注意保证对于该模块,给定相同的输入,二者输出完全一致。具体流程如下。
littletomatodonkey's avatar
littletomatodonkey 已提交
324

littletomatodonkey's avatar
littletomatodonkey 已提交
325 326 327
1. 定义PyTorch模型,加载训练好的权重(需要是官网repo提供好的),获取评估结果,使用reprod_log保存结果。
2. 定义PaddlePaddle模型,加载训练好的权重(需要是从PyTorch转换得到),获取评估结果,使用reprod_log保存结果。
3. 使用reprod_log排查diff,小于阈值,即可完成自测。
littletomatodonkey's avatar
littletomatodonkey 已提交
328

littletomatodonkey's avatar
littletomatodonkey 已提交
329
**【注意事项】**
littletomatodonkey's avatar
littletomatodonkey 已提交
330

littletomatodonkey's avatar
littletomatodonkey 已提交
331
在评估指标对齐之前,需要注意保证对于该模块,给定相同的输入,二者输出完全一致。
littletomatodonkey's avatar
littletomatodonkey 已提交
332 333


littletomatodonkey's avatar
littletomatodonkey 已提交
334
**【实战】**
littletomatodonkey's avatar
littletomatodonkey 已提交
335

littletomatodonkey's avatar
littletomatodonkey 已提交
336
评估指标对齐检查方法可以参考文档:[评估指标对齐检查方法文档](https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/pipeline/Step2/README.md#%E6%93%8D%E4%BD%9C%E6%AD%A5%E9%AA%A4)
littletomatodonkey's avatar
littletomatodonkey 已提交
337 338


littletomatodonkey's avatar
littletomatodonkey 已提交
339
**【验收】**
littletomatodonkey's avatar
littletomatodonkey 已提交
340

littletomatodonkey's avatar
littletomatodonkey 已提交
341
对于待复现的项目,评估指标对齐验收流程如下。
littletomatodonkey's avatar
littletomatodonkey 已提交
342

littletomatodonkey's avatar
littletomatodonkey 已提交
343 344 345 346 347 348 349 350
1. 输入:dataloader, model
2. 输出:
    * PaddlePaddle/PyTorch:dict,key为tensor的name(自定义),value为具体评估指标的值。最后将dict使用reprod_log保存到各自的文件中,建议命名为`metric_paddle.npy``metric_pytorch.npy`
    * 自测:使用reprod_log加载2个文件,使用report功能,记录结果到日志文件中,建议命名为`metric_diff_log.txt`,观察diff,二者diff小于特定的阈值即可。
3. 提交内容:将`metric_paddle.npy``metric_pytorch.npy``metric_diff_log.txt`文件备份到`3.1节验收环节`新建的文件夹中,后续的输出结果和自查日志也放在该文件夹中,一并打包上传即可。
4. 注意:
    * 数据需要是真实数据
    * 需要检查论文是否只是抽取了验证集/测试集中的部分文件,如果是的话,则需要保证PaddlePaddle和参考代码中dataset使用的数据集一致。
littletomatodonkey's avatar
littletomatodonkey 已提交
351 352


littletomatodonkey's avatar
littletomatodonkey 已提交
353 354
<a name="3.4"></a>
### 3.4 损失函数对齐
littletomatodonkey's avatar
littletomatodonkey 已提交
355

littletomatodonkey's avatar
littletomatodonkey 已提交
356
**【基本流程】**
littletomatodonkey's avatar
littletomatodonkey 已提交
357

littletomatodonkey's avatar
littletomatodonkey 已提交
358 359
PaddlePaddle与PyTorch均提供了很多loss function,用于模型训练,具体的API映射表可以参考:[Loss类API映射列表](https://www.paddlepaddle.org.cn/documentation/docs/zh/guides/08_api_mapping/pytorch_api_mapping_cn.html#lossapi)。以CrossEntropyLoss为例,主要区别为:
* PaddlePaddle提供了对软标签、指定softmax计算纬度的支持。
littletomatodonkey's avatar
littletomatodonkey 已提交
360

littletomatodonkey's avatar
littletomatodonkey 已提交
361
如果论文中使用的loss function没有指定的API,则可以尝试通过组合API的方式,实现自定义的loss function。
littletomatodonkey's avatar
littletomatodonkey 已提交
362

littletomatodonkey's avatar
littletomatodonkey 已提交
363
具体流程如下。
littletomatodonkey's avatar
littletomatodonkey 已提交
364

littletomatodonkey's avatar
littletomatodonkey 已提交
365 366 367
1. 定义PyTorch模型,加载权重,加载fake data 和 fake label(或者固定seed,基于numpy生成随机数),转换为PyTorch可以处理的tensor,送入网络,获取loss结果,使用reprod_log保存结果。
2. 定义PaddlePaddle模型,加载fake data 和 fake label(或者固定seed,基于numpy生成随机数),转换为PaddlePaddle可以处理的tensor,送入网络,获取loss结果,使用reprod_log保存结果。
3. 使用reprod_log排查diff,小于阈值,即可完成自测。
littletomatodonkey's avatar
littletomatodonkey 已提交
368

littletomatodonkey's avatar
littletomatodonkey 已提交
369
**【注意事项】**
littletomatodonkey's avatar
littletomatodonkey 已提交
370

littletomatodonkey's avatar
littletomatodonkey 已提交
371
* 计算loss的时候,建议设置`model.eval()`,避免模型中随机量的问题。
littletomatodonkey's avatar
littletomatodonkey 已提交
372

littletomatodonkey's avatar
littletomatodonkey 已提交
373
**【实战】**
littletomatodonkey's avatar
littletomatodonkey 已提交
374

littletomatodonkey's avatar
littletomatodonkey 已提交
375
本部分可以参考文档:[https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/pipeline/Step3/README.md](https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/pipeline/Step3/README.md)
littletomatodonkey's avatar
littletomatodonkey 已提交
376

littletomatodonkey's avatar
littletomatodonkey 已提交
377
**【验收】**
littletomatodonkey's avatar
littletomatodonkey 已提交
378

littletomatodonkey's avatar
littletomatodonkey 已提交
379
对于待复现的项目,损失函数对齐验收流程如下。
littletomatodonkey's avatar
littletomatodonkey 已提交
380

littletomatodonkey's avatar
littletomatodonkey 已提交
381 382 383 384 385
1. 输入:fake data & label
2. 输出:
    * PaddlePaddle/PyTorch:dict,key为tensor的name(自定义),value为具体评估指标的值。最后将dict使用reprod_log保存到各自的文件中,建议命名为`loss_paddle.npy``loss_pytorch.npy`
3. 自测:使用reprod_log加载2个文件,使用report功能,记录结果到日志文件中,建议命名为`loss_diff_log.txt`,观察diff,二者diff小于特定的阈值即可。
4. 提交内容:将`loss_paddle.npy``loss_pytorch.npy``loss_diff_log.txt`文件备份到`3.1节验收环节`新建的文件夹中,后续的输出结果和自查日志也放在该文件夹中,一并打包上传即可。
littletomatodonkey's avatar
littletomatodonkey 已提交
386

littletomatodonkey's avatar
littletomatodonkey 已提交
387 388
<a name="3.5"></a>
### 3.5 优化器对齐
littletomatodonkey's avatar
littletomatodonkey 已提交
389

littletomatodonkey's avatar
littletomatodonkey 已提交
390
**【基本流程】**
littletomatodonkey's avatar
littletomatodonkey 已提交
391

littletomatodonkey's avatar
littletomatodonkey 已提交
392
PaddlePaddle中的optimizer有`paddle.optimizer`等一系列实现,PyTorch中则有`torch.Optim`等一系列实现。
littletomatodonkey's avatar
littletomatodonkey 已提交
393

littletomatodonkey's avatar
littletomatodonkey 已提交
394
**【注意事项】**
littletomatodonkey's avatar
littletomatodonkey 已提交
395

littletomatodonkey's avatar
littletomatodonkey 已提交
396
以SGD等优化器为例,PaddlePaddle与Pytorch的优化器区别主要如下。
littletomatodonkey's avatar
littletomatodonkey 已提交
397 398 399 400

* PaddlePaddle在优化器中增加了对梯度裁剪的支持,在训练GAN或者一些NLP、多模态任务中,这个用到的比较多。
* PaddlePaddle的SGD不支持动量更新、动量衰减和Nesterov动量,这里需要使用`paddle.optimizer.Momentum` API实现这些功能。

littletomatodonkey's avatar
littletomatodonkey 已提交
401 402 403 404
**【实战】**

本部分对齐建议对照[PaddlePaddle优化器API文档](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/optimizer/Overview_cn.html)与参考代码的优化器实现进行对齐,用之后的反向对齐统一验证该模块的正确性。

littletomatodonkey's avatar
littletomatodonkey 已提交
405

littletomatodonkey's avatar
littletomatodonkey 已提交
406
<a name="3.6"></a>
littletomatodonkey's avatar
littletomatodonkey 已提交
407 408
### 3.6 学习率对齐

littletomatodonkey's avatar
littletomatodonkey 已提交
409
**【基本流程】**
littletomatodonkey's avatar
littletomatodonkey 已提交
410

littletomatodonkey's avatar
littletomatodonkey 已提交
411
* 学习率策略主要用于指定训练过程中的学习率变化曲线,这里可以将定义好的学习率策略,不断step,即可得到对应的学习率值,可以将学习率值保存在列表或者矩阵中,使用`reprod_log`工具判断二者是否对齐。
littletomatodonkey's avatar
littletomatodonkey 已提交
412

littletomatodonkey's avatar
littletomatodonkey 已提交
413 414 415 416 417
**【注意事项】**

PaddlePaddle中,需要首先构建学习率策略,再传入优化器对象中;对于PyTorch,如果希望使用更丰富的学习率策略,需要先构建优化器,再传入学习率策略类API。

**【实战】**
littletomatodonkey's avatar
littletomatodonkey 已提交
418

littletomatodonkey's avatar
littletomatodonkey 已提交
419
学习率复现对齐,可以参考代码:[学习率对齐验证文档](https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/pipeline/Step4/README.md#%E5%AD%A6%E4%B9%A0%E7%8E%87%E5%AF%B9%E9%BD%90%E9%AA%8C%E8%AF%81)
littletomatodonkey's avatar
littletomatodonkey 已提交
420

littletomatodonkey's avatar
littletomatodonkey 已提交
421
<a name="3.7"></a>
littletomatodonkey's avatar
littletomatodonkey 已提交
422 423
### 3.7 正则化策略对齐

littletomatodonkey's avatar
littletomatodonkey 已提交
424 425
**【基本流程】**

littletomatodonkey's avatar
littletomatodonkey 已提交
426 427
L2正则化策略用于模型训练,可以防止模型对训练数据过拟合,L1正则化可以用于得到稀疏化的权重矩阵,PaddlePaddle中有`paddle.regularizer.L1Decay``paddle.regularizer.L2Decay` API。PyTorch中,torch.optim集成的优化器只有L2正则化方法,直接在构建optimizer的时候,传入`weight_decay`参数即可。

littletomatodonkey's avatar
littletomatodonkey 已提交
428
**【注意事项】**
littletomatodonkey's avatar
littletomatodonkey 已提交
429

littletomatodonkey's avatar
littletomatodonkey 已提交
430
* PaddlePaddle的optimizer中支持L1Decat/L2Decay。
littletomatodonkey's avatar
littletomatodonkey 已提交
431 432
* PyTorch的optimizer支持不同参数列表的学习率分别设置,params传入字典即可,而PaddlePaddle目前尚未支持这种行为,可以通过设置`ParamAttr``learning_rate`参数,来确定相对学习率倍数,使用链接可以参考:[PaddleClas-ResNet model](https://github.com/PaddlePaddle/PaddleClas/blob/d67a352fcacc49ae6bbc7d1c7158e2c65f8e06d9/ppcls/arch/backbone/legendary_models/resnet.py#L121)

littletomatodonkey's avatar
littletomatodonkey 已提交
433 434 435 436 437
**【实战】**

本部分对齐建议对照[PaddlePaddle正则化API文档](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/regularizer/L2Decay_cn.html)与参考代码的优化器实现进行对齐,用之后的反向对齐统一验证该模块的正确性。

<a name="3.8"></a>
littletomatodonkey's avatar
littletomatodonkey 已提交
438 439
### 3.8 反向对齐

littletomatodonkey's avatar
littletomatodonkey 已提交
440
**【基本流程】**
littletomatodonkey's avatar
littletomatodonkey 已提交
441

littletomatodonkey's avatar
littletomatodonkey 已提交
442
此处可以通过numpy生成假的数据和label(推荐),也可以准备固定的真实数据。具体流程如下。
littletomatodonkey's avatar
littletomatodonkey 已提交
443

littletomatodonkey's avatar
littletomatodonkey 已提交
444 445 446 447
1. 检查两个代码的训练超参数全部一致,如优化器及其超参数、学习率、BatchNorm/LayerNorm中的eps等。
2. 将PaddlePaddle与PyTorch网络中涉及的所有随机操作全部关闭,如dropout、drop_path等,推荐将模型设置为eval模式(`model.eval()`
3. 加载相同的weight dict(可以通过PyTorch来存储随机的权重),将准备好的数据分别传入网络并迭代,观察二者loss是否一致(此处batch-size要一致,如果使用多个真实数据,要保证传入网络的顺序一致)
4. 如果经过2轮以上,loss均可以对齐,则基本可以认为反向对齐。
littletomatodonkey's avatar
littletomatodonkey 已提交
448 449


littletomatodonkey's avatar
littletomatodonkey 已提交
450
**【注意事项】**
littletomatodonkey's avatar
littletomatodonkey 已提交
451

littletomatodonkey's avatar
littletomatodonkey 已提交
452 453
* 如果第一轮loss就没有对齐,则需要仔细排查一下模型前向部分。
* 如果第二轮开始,loss开始无法对齐,则首先需要排查下超参数的差异,没问题的话,在`loss.backward()`方法之后,使用`tensor.grad`获取梯度值,二分的方法查找diff,定位出PaddlePaddle与PyTorch梯度无法对齐的API或者操作,然后进一步验证并反馈。
littletomatodonkey's avatar
littletomatodonkey 已提交
454

littletomatodonkey's avatar
littletomatodonkey 已提交
455
梯度的打印方法示例代码如下所示,注释掉的内容即为打印网络中所有参数的梯度shape。
littletomatodonkey's avatar
littletomatodonkey 已提交
456

littletomatodonkey's avatar
littletomatodonkey 已提交
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
```python
    # 代码地址:https://github.com/littletomatodonkey/AlexNet-Prod/blob/63184b258eda650e7a8b7f2610b55f4337246630/pipeline/Step4/AlexNet_paddle/train.py#L93
    loss_list = []
    for idx in range(max_iter):
        image = paddle.to_tensor(fake_data)
        target = paddle.to_tensor(fake_label)

        output = model(image)
        loss = criterion(output, target)
        loss.backward()
        # for name, tensor in model.named_parameters():
        #     grad = tensor.grad
        #     print(name, tensor.grad.shape)
        #     break
        optimizer.step()
        optimizer.clear_grad()
        loss_list.append(loss)
littletomatodonkey's avatar
littletomatodonkey 已提交
474 475 476
```


littletomatodonkey's avatar
littletomatodonkey 已提交
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497


**【实战】**

本部分可以参考文档:[反向对齐操作文档](https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/pipeline/Step4/README.md#%E5%8F%8D%E5%90%91%E5%AF%B9%E9%BD%90%E6%93%8D%E4%BD%9C%E6%96%B9%E6%B3%95)

**【验收】**

对于待复现的项目,反向对齐验收流程如下。

1. 输入:fake data & label
2. 输出:
    * PaddlePaddle/PyTorch:dict,key为tensor的name(自定义),value为具体loss的值。最后将dict使用reprod_log保存到各自的文件中,建议命名为`bp_align_paddle.npy``bp_align_pytorch.npy`
3. 自测:使用reprod_log加载2个文件,使用report功能,记录结果到日志文件中,建议命名为`bp_align_diff_log.txt`,观察diff,二者diff小于特定的阈值即可。
4. 提交内容:将`bp_align_paddle.npy``bp_align_pytorch.npy``bp_align_diff_log.txt`文件备份到`3.1节验收环节`新建的文件夹中,后续的输出结果和自查日志也放在该文件夹中,一并打包上传即可。
5. 注意:
    * loss需要保存至少2轮以上。
    * 在迭代的过程中,需要保证模型的batch size等超参数完全相同
    * 在迭代的过程中,需要设置`model.eval()`,使用固定的假数据,同时加载相同权重的预训练模型。

<a name="3.9"></a>
littletomatodonkey's avatar
littletomatodonkey 已提交
498 499
### 3.9 训练集数据读取对齐

littletomatodonkey's avatar
littletomatodonkey 已提交
500 501
**【基本流程】**

littletomatodonkey's avatar
littletomatodonkey 已提交
502 503
该部分内容与3.2节内容基本一致,参考PyTorch的代码,实现训练集数据读取与预处理模块即可。

littletomatodonkey's avatar
littletomatodonkey 已提交
504 505
**【注意事项】**

littletomatodonkey's avatar
littletomatodonkey 已提交
506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
该部分内容,可以参考3.8节的自测方法,将输入的`fake data & label`替换为训练的dataloader,但是需要注意的是:
* 在使用train dataloader的时候,建议设置random seed,对于PyTorch来说

```python
#initialize random seed
torch.manual_seed(config.SEED)
torch.cuda.manual_seed_all(config.SEED)
np.random.seed(config.SEED)
random.seed(config.SEED)
```

对于PaddlePaddle来说

```python
paddle.seed(config.SEED)
np.random.seed(config.SEED)
random.seed(config.SEED)
```

littletomatodonkey's avatar
littletomatodonkey 已提交
525 526 527 528 529
**【实战】**

本部分对齐建议对照[PaddlePaddle vision高层API文档](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/vision/Overview_cn.html)与参考代码的数据预处理实现进行对齐,用之后的训练对齐统一验证该模块的正确性。

<a name="3.10"></a>
littletomatodonkey's avatar
littletomatodonkey 已提交
530 531
### 3.10 网络初始化对齐

littletomatodonkey's avatar
littletomatodonkey 已提交
532 533
**【基本流程】**

littletomatodonkey's avatar
littletomatodonkey 已提交
534 535 536 537 538 539 540 541 542
* 下面给出了部分初始化API的映射表。

|PaddlePaddle API | PyTorch API |
|---|---|
| paddle.nn.initializer.KaimingNormal | torch.nn.init.kaiming_normal_ |
| paddle.nn.initializer.KaimingUniform | torch.nn.init.kaiming_uniform_ |
| paddle.nn.initializer.XavierNormal | torch.nn.init.xavier_normal_ |
| paddle.nn.initializer.XavierUniform | torch.nn.init.xavier_uniform_ |

littletomatodonkey's avatar
littletomatodonkey 已提交
543 544 545
**【注意事项】**

* 更多初始化API可以参考[PyTorch初始化API文档](https://pytorch.org/docs/stable/nn.init.html)以及[PaddlePaddle初始化API文档](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/Overview_cn.html#chushihuaxiangguan)
littletomatodonkey's avatar
littletomatodonkey 已提交
546

littletomatodonkey's avatar
littletomatodonkey 已提交
547
**【实战】**
littletomatodonkey's avatar
littletomatodonkey 已提交
548

littletomatodonkey's avatar
littletomatodonkey 已提交
549
本部分对齐建议对照[PaddlePaddle 初始化API文档](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/Overview_cn.html#chushihuaxiangguan)与参考代码的初始化实现对齐。
littletomatodonkey's avatar
littletomatodonkey 已提交
550

littletomatodonkey's avatar
littletomatodonkey 已提交
551
<a name="3.11"></a>
littletomatodonkey's avatar
littletomatodonkey 已提交
552 553
### 3.11 模型训练对齐

littletomatodonkey's avatar
littletomatodonkey 已提交
554 555 556
**【基本流程】**

完成前面的步骤之后,就可以开始全量数据的训练对齐任务了。按照下面的步骤进行训练对齐。
littletomatodonkey's avatar
littletomatodonkey 已提交
557

littletomatodonkey's avatar
littletomatodonkey 已提交
558 559 560 561 562
1. 准备train/eval data, loader, model
2. 对model按照论文所述进行初始化(如果论文中提到加载pretrain,则按需加载pretrained model)
3. 加载配置,开始训练,迭代得到最终模型与评估指标,将评估指标使用reprod_log保存到文件中。
4. 将PaddlePaddle提供的参考指标使用reprod_log提交到另一个文件中。
5. 使用reprod_log排查diff,小于阈值,即可完成自测。
littletomatodonkey's avatar
littletomatodonkey 已提交
563

littletomatodonkey's avatar
littletomatodonkey 已提交
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
**【注意事项】**

* 【强烈】建议先做完反向对齐之后再进行模型训练对齐,二者之间的不确定量包括:数据集、PaddlePaddle与参考代码在模型training mode下的区别,初始化参数。
* 在训练对齐过程中,受到较多随机量的影响,精度有少量diff是正常的,以ImageNet1k数据集的分类为例,diff在0.15%以内可以认为是正常的,这里可以根据不同的任务,适当调整对齐检查的阈值(`ReprodDiffHelper.report`函数中的`diff_threshold`参数)。
* 训练过程中的波动是正常的,如果最终收敛结果不一致,可以
    * 仔细排查Dropout、BatchNorm以及其他组网模块及超参是否无误。
    * 基于参考代码随机生成一份预训练模型,转化为PaddlePaddle的模型,并使用PaddlePaddle加载训练,对比二者的收敛曲线与最终结果,排查初始化影响。
    * 使用参考代码的Dataloader生成的数据,进行模型训练,排查train dataloader的影响。

**【实战】**

本部分可以参考文档:[训练对齐操作文档](https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/pipeline/Step5/README.md)

**【验收】**

对于待复现的项目,训练对齐验收流程如下。

1. 输入:train/eval dataloader, model
2. 输出:
    * PaddlePaddle:dict,key为保存值的name(自定义),value为具体评估指标的值。最后将dict使用reprod_log保存到文件中,建议命名为`train_align_paddle.npy`
    * benchmark:dict,key为保存值的name(自定义),value为论文复现赛的评估指标要求的值。最后将dict使用reprod_log保存到文件中,建议命名为`train_align_benchmark.npy`
3. 自测:使用reprod_log加载2个文件,使用report功能,记录结果到日志文件中,建议命名为`train_align_diff_log.txt`,观察diff,二者diff小于特定的阈值即可。
4. 提交内容:将`train_align_paddle.npy``train_align_benchmark.npy``train_align_diff_log.txt`文件备份到`3.1节验收环节`新建的文件夹中,最终一并打包上传即可。

<a name="3.12"></a>
littletomatodonkey's avatar
littletomatodonkey 已提交
589

littletomatodonkey's avatar
littletomatodonkey 已提交
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672
### 3.12 单机多卡训练

如果希望使用单机多卡提升训练效率,可以从以下几个过程对代码进行修改。

#### 3.12.1 数据读取

对于PaddlePaddle来说,多卡数据读取这块主要的变化在sampler

对于单机单卡,sampler实现方式如下所示。

```python
train_sampler = paddle.io.RandomSampler(dataset)
train_batch_sampler = paddle.io.BatchSampler(
    sampler=train_sampler, batch_size=args.batch_size)
```

对于单机多卡任务,sampler实现方式如下所示。

```python
train_batch_sampler = paddle.io.DistributedBatchSampler(
        dataset=dataset,
        batch_size=args.batch_size,
        shuffle=True,
        drop_last=False
    )
```

注意:在这种情况下,单机多卡的代码仍然能够以单机单卡的方式运行,因此建议以这种sampler方式进行论文复现。


#### 3.12.2 多卡模型初始化

如果以多卡的方式运行,需要初始化并行训练环境,代码如下所示。

```python
if paddle.distributed.get_world_size() > 1:
        paddle.distributed.init_parallel_env()
```

在模型组网并初始化参数之后,需要使用`paddle.DataParallel()`对模型进行封装,使得模型可以通过数据并行的模式被执行。代码如下所示。

```python
if paddle.distributed.get_world_size() > 1:
    model = paddle.DataParallel(model)
```


#### 3.12.3 模型保存、日志保存等其他模块

以模型保存为例,我们只需要在0号卡上保存即可,否则多个trainer同时保存的话,可能会造成写冲突,导致最终保存的模型不可用。


#### 3.12.4 程序启动方式

对于单机单卡,启动脚本如下所示。

```shell
export CUDA_VISIBLE_DEVICES=0
python3.7 train.py \
    --data-path /paddle/data/ILSVRC2012_torch \
    --lr 0.00125 \
    --batch-size 32 \
    --output-dir "./output/"
```


对于单机多卡(示例中为8卡训练),启动脚本如下所示。

```shell
export CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7

python3.7 -m paddle.distributed.launch \
    --gpus="0,1,2,3,4,5,6,7" \
    train.py \
    --data-path /paddle/data/ILSVRC2012_torch \
    --lr 0.01 \
    --batch-size 32 \
    --output-dir "./output/"
```

注意:这里8卡训练时,虽然单卡的batch size没有变化(32),但是总卡的batch size相当于是单卡的8倍,因此学习率也设置为了单卡时的8倍。


673 674 675 676
**【实战】**

本部分可以参考文档:[单机多卡训练脚本](https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/pipeline/Step5/AlexNet_paddle/train_dist.sh)

littletomatodonkey's avatar
littletomatodonkey 已提交
677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704

<a name="3.13"></a>

### 3.13 TIPC基础链条测试接入

**【基本流程】**

* 完成模型的训练、导出inference、基于PaddleInference的推理过程的文档与代码。参考链接:
    * [insightface训练预测使用文档](https://github.com/deepinsight/insightface/blob/master/recognition/arcface_paddle/README_cn.md)
    * [PaddleInference使用文档](https://www.paddlepaddle.org.cn/documentation/docs/zh/guides/05_inference_deployment/inference/inference_cn.html)
* 基于[TIPC基础链条测试接入规范](https://github.com/PaddlePaddle/models/blob/tipc/docs/tipc_test/development_specification_docs/train_infer_python.md),完成该模型的TIPC基础链条开发以及测试文档/脚本,目录为`test_tipc`,测试脚本名称为`test_train_inference_python.sh`,该任务中只需要完成`少量数据训练模型,少量数据预测`的模式即可,用于测试TIPC流程的模型和少量数据需要放在当前repo中。



**【注意事项】**

* 基础链条测试接入时,只需要验证`少量数据训练模型,少量数据预测`的模式,只需要在Linux下验证通过即可。
* 在文档中需要给出一键测试的脚本与使用说明。

**【实战】**

TIPC基础链条测试接入用例可以参考:[InsightFace-paddle TIPC基础链条测试开发文档](https://github.com/deepinsight/insightface/blob/master/recognition/arcface_paddle/test_tipc/readme.md)


**【验收】**

* TIPC基础链条测试文档清晰,`test_train_inference_python.sh`脚本可以成功执行并返回正确结果。

littletomatodonkey's avatar
littletomatodonkey 已提交
705
<a name="4"></a>
littletomatodonkey's avatar
littletomatodonkey 已提交
706

littletomatodonkey's avatar
littletomatodonkey 已提交
707
## 4. 论文复现注意事项与FAQ
littletomatodonkey's avatar
littletomatodonkey 已提交
708

709 710 711
本部分主要总结大家在论文复现赛过程中遇到的问题,如果本章内容没有能够解决你的问题,欢迎给该文档提出优化建议或者给Paddle提[ISSUE](https://github.com/PaddlePaddle/Paddle/issues/new/choose)

<a name="4.0"></a>
littletomatodonkey's avatar
littletomatodonkey 已提交
712

713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728
### 4.1 通用注意事项

* 需要仔细对照PaddlePaddle与参考代码的优化器参数实现,确保优化器参数严格对齐。
* 如果遇到一些Paddle不支持的API操作,可以尝试使用替代实现进行复现。如下面的PyTorch代码,PaddlePaddle中可以通过slice + concat API的组合形式进行功能实现。同时,对于这个问题,建议优先给Paddle提[ISSUE](https://github.com/PaddlePaddle/Paddle/issues/new/choose),列出Paddle不支持的实现,开发人员会根据优先级进行开发。

```python
torch.stack([
    per_locations[:, 0] - per_box_regression[:, 0],
    per_locations[:, 1] - per_box_regression[:, 1],
    per_locations[:, 0] + per_box_regression[:, 2],
    per_locations[:, 1] + per_box_regression[:, 3],
], dim=1)
```
* 如果遇到Paddle不包含的OP或者API,比如(1) 如果是某些算法实现存在调用了外部OP,而且Paddle也不包含该OP实现;(2) 其他框架存在的API或者OP,但是Paddle中没有这些OP。此时:
    * 对于Paddle资深用户来说,可以尝试使用Paddle的自定义算子功能,存在一定的代码开发量。
    * 对于初学者来说,可以给Paddle提[ISSUE](https://github.com/PaddlePaddle/Paddle/issues/new/choose),列出Paddle不支持的实现,Paddle开发人员会根据优先级进行实现。
littletomatodonkey's avatar
littletomatodonkey 已提交
729
* PaddlePaddle与PyTorch对于不同名称的API,实现的功能可能是相同的,复现的时候注意,比如[paddle.optimizer.lr.StepDecay](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/optimizer/lr/StepDecay_cn.html#stepdecay)[torch.optim.lr_scheduler.StepLR](https://pytorch.org/docs/stable/generated/torch.optim.lr_scheduler.StepLR.html#torch.optim.lr_scheduler.StepLR) ,关于PaddlePaddle与PyTorch更多API的映射关系可以参考:[API映射表](https://www.paddlepaddle.org.cn/documentation/docs/zh/guides/08_api_mapping/pytorch_api_mapping_cn.html)
730
* 对于PaddlePaddle来说,通过`paddle.set_device`函数(全局)来确定模型结构是运行在什么设备上,对于torch来说,是通过`model.to("device")` (局部)来确定模型结构的运行设备,这块在复现的时候需要注意。
731

littletomatodonkey's avatar
littletomatodonkey 已提交
732

littletomatodonkey's avatar
littletomatodonkey 已提交
733
<a name="4.1"></a>
734
### 4.2 模型结构对齐
littletomatodonkey's avatar
littletomatodonkey 已提交
735

736 737
#### 4.2.1 API
* 对于 `paddle.nn.Linear` 层的weight参数,PaddlePaddle与PyTorch的保存方式不同,在转换时需要进行转置,示例代码可以参考[AlexNet权重转换脚本](https://github.com/littletomatodonkey/AlexNet-Prod/blob/e3855e0b1992332c2765ccf627d0c5f5f68232fe/pipeline/weights/torch2paddle.py#L19)
littletomatodonkey's avatar
littletomatodonkey 已提交
738
* `paddle.nn.BatchNorm2D` 包含4个参数`weight`, `bias`, `_mean`, `_variance`,torch.nn.BatchNorm2d包含4个参数`weight`,  `bias`, `running_mean`, `running_var`, `num_batches_tracked`。 其中,`num_batches_tracked`在PaddlePaddle中没有用到,剩下4个的对应关系为
littletomatodonkey's avatar
littletomatodonkey 已提交
739
    * `weight` -> `weight`
littletomatodonkey's avatar
littletomatodonkey 已提交
740
    * `bias` -> `bias`
littletomatodonkey's avatar
littletomatodonkey 已提交
741 742
    * `_variance` -> `running_var`
    * `_mean` -> `running_mean`
743
* [`paddle.nn.AvgPool2D`](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/nn/AvgPool2D_cn.html#avgpool2d)需要将 `exclusive` 参数设为 `False` ,结果才能 PyTorch 的默认行为一致。
744 745 746
* `torch.masked_fill`函数的功能目前可以使用`paddle.where`进行实现,可以参考:[链接](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/faq/train_cn.html#paddletorch-masked-fillapi)
* `pack_padded_sequence``pad_packed_sequence`这两个API目前PaddlePaddle中没有实现,可以直接在RNN或者LSTM的输入中传入`sequence_length`来实现等价的功能。

747 748 749 750 751 752 753 754 755 756 757

#### 4.2.2 权重转换

* 在权重转换的时候,不能只关注参数的名称,比如说有些`paddle.nn.Linear`层,但是定义的变量名称为`conv`,这种也是需要进行权重转置的。
* 权重转换时,建议同时打印 Paddle 和 PyTorch 对应权重的shape,以防止名称相似但是shape不同的参数权重转换报错。

#### 4.2.3 模型组网正确性验证

* 在论文复现的过程中,可能会遇到一些经典的模型结构,比如ResNet等,Paddle官方也提供了ResNet的实现,但是这里建议自己根据PyTorch代码重新实现一遍,一方面是对整体的模型结构更加熟悉,另一方面也保证模型结构和权重完全对齐。
* 在复杂的网络结构中,如果前向结果对不齐,可以按照模块排查问题,比如依次获取backbone、neck、head输出等,看下问题具体出现在哪个子模块,再进到子模块详细排查。
* 网络结构对齐后,尽量使用训练好的预训练模型和真实的图片进行前向diff计算,这样更准确。
littletomatodonkey's avatar
littletomatodonkey 已提交
758

littletomatodonkey's avatar
littletomatodonkey 已提交
759
<a name="4.2"></a>
760
### 4.3 验证/测试集数据读取对齐
littletomatodonkey's avatar
littletomatodonkey 已提交
761

762 763
* 如果使用 PaddlePaddle 提供的数据集API,比如 `paddle.vision.datasets.Cifar10`等,可能无法完全与参考代码在数据顺序上保持一致,但是这些数据集的实现都是经过广泛验证的,可以使用。此时对数据预处理和后处理进行排查就好。`数据集+数据处理`的部分可以通过评估指标对齐完成自查。
* 需要仔细排查数据预处理,不仅包含的预处理方法相同,也需要保证预处理的流程相同,比如先padding再做归一化与先做归一化再padding,得到的结果是不同的。
littletomatodonkey's avatar
littletomatodonkey 已提交
764

littletomatodonkey's avatar
littletomatodonkey 已提交
765
<a name="4.3"></a>
766 767 768 769 770 771 772
### 4.4 评估指标对齐

* 真实数据评估时,需要注意评估时 `paddle.io.DataLoader```drop_last`` 参数是否打开(文档[链接](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/io/DataLoader_cn.html#dataloader)),复现代码需要与参考代码保持一致,否则最后不够batch-size的数据的评估会有diff。
* 在识别或者检索过程中,为了加速评估过程,往往会将评估函数由CPU实现改为GPU实现,由此会带来评估函数输出的不一致。这是由于sort函数对于相同值的排序结果不同带来的。在复现的过程中,如果可以接受轻微的指标不稳定,可以使用PaddlePaddle的sort函数,如果对于指标非常敏感,同时对速度性能要求很高,可以给PaddlePaddle提[ISSUE](https://github.com/PaddlePaddle/Paddle/issues/new/choose),由研发人员高优开发。
* 在检测任务中,评估流程往往和训练流程有一定差异,例如RPN阶段NMS的参数等,这里需要仔细检查评估时的超参数,不要将训练超参和评估超参弄混淆。
* 在OCR等任务中,需要注意评估过程也会对gt信息进行修正,比如大小写等,也会过滤掉一些样本,这里需要注意过滤规则,确保有效评估数据集一致。

littletomatodonkey's avatar
littletomatodonkey 已提交
773

littletomatodonkey's avatar
littletomatodonkey 已提交
774
<a name="4.4"></a>
775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793
### 4.5 损失函数对齐

* 部分算法的损失函数中会用到 bool 索引,这时候可以使用[paddle.where](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/where_cn.html#where) 代替。
* `paddle.nn.CrossEntropyLoss` 默认是在最后一维(axis=-1)计算损失函数,而 `torch.nn.CrossEntropyLoss` 是在axis=1的地方计算损失函数,因此如果输入的维度大于2,这里需要保证计算的维(axis)相同,否则可能会出错。
* 在生成模型中会遇到梯度损失,需要对模型中的算子求二次梯度,目前`MaxPooling`暂时不支持二次梯度,如果复现的过程中遇到了需要对`MaxPooling`求二次梯度的情况,可以和Paddle官方开发同学反馈,进一步确认解决方案。
* 在保存损失函数值的时候,注意要使用`paddle.no_grad`,或者仅仅保存转换成 numpy 的数组,避免损失没有析构导致内存泄漏问题。

```python
# 错误示范
loss = celoss(pred, label)
avg_loss += loss
# 正确示范1
loss = celoss(pred, label)
avg_loss += loss.numpy()
# 正确示范2
loss = celoss(pred, label)
with paddle.no_grad()
    avg_loss += loss
```
littletomatodonkey's avatar
littletomatodonkey 已提交
794

795 796
* 目前PaddlePaddle中没有HingeEmbeddingLoss API,可以使用组合的方式进行实现,参考实现:[链接](https://github.com/ImportPaddle/DiscoGAN-Paddle/blob/main/discogan/loss_fn.py)

littletomatodonkey's avatar
littletomatodonkey 已提交
797
<a name="4.5"></a>
798
### 4.6 优化器对齐
littletomatodonkey's avatar
littletomatodonkey 已提交
799

800 801
* Paddle目前支持在 ``optimizer`` 中通过设置 ``params_groups`` 的方式设置不同参数的更新方式,可以参考[代码示例](https://github.com/PaddlePaddle/Paddle/blob/develop/python/paddle/optimizer/optimizer.py#L107)
* 有些模型训练时,会使用梯度累加策略,即累加到一定step数量之后才进行参数更新,这时在实现上需要注意对齐。
littletomatodonkey's avatar
littletomatodonkey 已提交
802
* 在某些任务中,比如说深度学习可视化、可解释性等任务中,一般只要求模型前向过程,不需要训练,此时优化器、学习率等用于模型训练的模块对于该类论文复现是不需要的。
803
* 在图像分类领域,大多数Vision Transformer模型都采用了AdamW优化器,并且会设置weigh decay,同时部分参数设置为no weight decay,例如位置编码的参数通常设置为no weight decay,no weight decay参数设置不正确,最终会有明显的精度损失,需要特别注意。一般可以通过分析模型权重来发现该问题,分别计算官方模型和复现模型每层参数权重的平均值、方差,对每一层依次对比,有显著差异的层可能存在问题,因为在weight decay的作用下,参数权重数值会相对较小,而未正确设置no weight decay,则会造成该层参数权重数值异常偏小。
804 805
* 在OCR识别等任务中,`Adadelta`优化器常常被使用,该优化器与PyTorch实现目前稍有不同,但是不影响模型训练精度对齐,在做前反向对齐时,需要注意可以将该优化器替换为Adam等优化器(PaddlePaddle与参考代码均需要替换);对齐完成之后,再使用`Adadelta`优化器进行训练对齐。

littletomatodonkey's avatar
littletomatodonkey 已提交
806

littletomatodonkey's avatar
littletomatodonkey 已提交
807
<a name="4.6"></a>
808 809 810 811 812
### 4.7 学习率对齐

* PaddlePaddle 中参数的学习率受到优化器学习率和`ParamAttr`中设置的学习率影响,因此跟踪学习率需要将二者结合进行跟踪。
* 对于复现代码和参考代码,学习率在整个训练过程中在相同的轮数相同的iter下应该保持一致,可以通过`reprod_log`工具、打印学习率值或者可视化二者学习率的log来查看diff。
* 有些网络的学习率策略比较细致,比如带warmup的学习率策略,这里需要保证起始学习率等参数都完全一致。
813
* `torch.optim.lr_scheduler.MultiplicativeLR` API目前PaddlePaddle中没有实现,可以使用`paddle.optimizer.lr.LambdaDecay`替换实现,参考代码:[链接](https://github.com/Paddle-Team-7/PixelCNN-Paddle/blob/607ef1d1ca6a489cecdcd2182d3acc5b2df7c779/src/pixel_cnn.py#L161)
814

littletomatodonkey's avatar
littletomatodonkey 已提交
815

littletomatodonkey's avatar
littletomatodonkey 已提交
816
<a name="4.7"></a>
817 818 819
### 4.8 正则化策略对齐

* 在如Transformer或者少部分CNN模型中,存在一些参数不做正则化(正则化系数为0)的情况。这里需要找到这些参数并对齐取消实施正则化策略,可以参考[这里](https://github.com/PaddlePaddle/PaddleClas/blob/release%2F2.3/ppcls/arch/backbone/model_zoo/resnest.py#L72),对特定参数进行修改。
littletomatodonkey's avatar
littletomatodonkey 已提交
820

littletomatodonkey's avatar
littletomatodonkey 已提交
821
<a name="4.8"></a>
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842
### 4.9 反向对齐

* Paddle打印反向和参数更新,可以参考[代码实例](https://github.com/jerrywgz/PaddleDetection/blob/debug_gfl/ppdet/modeling/backbones/resnet.py#L581);PyTorch打印反向和参数更新,可以参考[代码实例](https://github.com/jerrywgz/mmdetection/blob/debug_gfl/mmdet/models/backbones/resnet.py#L630)
* 反向对齐时,如果第二轮开始,loss开始无法对齐,则首先需要排查下超参数的差异,没问题的话,在`loss.backward()`方法之后,使用`tensor.grad`获取梯度值,二分的方法查找diff,定位出PaddlePaddle与PyTorch梯度无法对齐的API或者操作,然后进一步验证。第3章中给出了获取所有参数的梯度方法,如果只希望打印特定参数的梯度,可以用下面的方式。


```python
import paddle

def print_hook_fn(grad):
    print(grad)

x = paddle.to_tensor([0., 1., 2., 3.], stop_gradient=False)
h = x.register_hook(print_hook_fn)
w = x * 4
w.backward()
# backward之后会输出下面的内容
#     Tensor(shape=[4], dtype=float32, place=CPUPlace, stop_gradient=False,
#            [4., 4., 4., 4.])
```

littletomatodonkey's avatar
littletomatodonkey 已提交
843

littletomatodonkey's avatar
littletomatodonkey 已提交
844
<a name="4.9"></a>
845 846 847 848 849 850 851 852 853 854 855 856 857
### 4.10 训练集数据读取对齐

#### 4.10.1 API

* 在前向过程中,如果数据预处理过程运行出错,请先将 ``paddle.io.DataLoader````num_workers`` 参数设为0,然后根据单个进程下的报错日志定位出具体的bug。
* 如果使用PaddlePaddle提供的数据集API,比如`paddle.vision.datasets.Cifar10`等,可能无法完全与参考代码在数据顺序上保持一致,如果是全量数据使用,对结果不会有影响,如果是按照比例选取子集进行训练,则建议重新根据参考代码实现数据读取部分,保证子集完全一致。

#### 4.10.2 数据预处理

* 数据读取需要注意图片读取方式是opencv还是PIL.Image,图片格式是RGB还是BGR,复现时,需要保证复现代码和参考代码完全一致。
* 如果数据处理过程中涉及到随机数生成,建议固定seed (`np.random.seed(0)`, `random.seed(0)`),查看复现代码和参考代码处理后的数据是否有diff。
* 不同的图像预处理库,使用相同的插值方式可能会有diff,建议使用相同的库对图像进行resize。
* 视频解码时,不同库解码出来的图像数据会有diff,注意区分解码库是opencv、decord还是pyAV,需要保证复现代码和参考代码完全一致。
littletomatodonkey's avatar
littletomatodonkey 已提交
858

littletomatodonkey's avatar
littletomatodonkey 已提交
859
<a name="4.10"></a>
860
### 4.11 网络初始化对齐
littletomatodonkey's avatar
littletomatodonkey 已提交
861

862
* 对于不同的深度学习框架,网络初始化在大多情况下,即使值的分布完全一致,也无法保证值完全一致,这里也是论文复现中不确定性比较大的地方。如果十分怀疑初始化导致的问题,建议将参考的初始化权重转成paddle模型,加载该初始化模型训练,看下收敛精度。
littletomatodonkey's avatar
littletomatodonkey 已提交
863
* CNN对于模型初始化相对来说没有那么敏感,在迭代轮数与数据集足够的情况下,最终精度指标基本接近;而transformer系列模型对于初始化比较敏感,在transformer系列模型训练对齐过程中,建议对这一块进行重点检查。
864 865 866
* 生成模型尤其是超分模型,对初始化比较敏感,建议对初始化重点检查。
* 领域自适应算法由于需要基于初始模型生成伪标签,因此对初始网络敏感,建议加载预训练的模型进行训练。

littletomatodonkey's avatar
littletomatodonkey 已提交
867

littletomatodonkey's avatar
littletomatodonkey 已提交
868
<a name="4.11"></a>
869 870 871 872 873 874 875 876 877 878 879
### 4.12 模型训练对齐

#### 4.12.1 训练对齐通用问题

* 有条件的话,复现工作之前最好先基于官方代码完成训练,保证与官方指标能够对齐,并且将训练策略和训练过程中的关键指标记录保存下来,比如每个epoch的学习率、Train Loss、Eval Loss、Eval Acc等,在复现网络的训练过程中,将关键指标保存下来,这样可以将两次训练中关键指标的变化曲线绘制出来,能够很方便的进行对比。
* 训练过程中可以对loss或者acc进行可视化,和竞品loss或者acc进行直观的对比;如果训练较大的数据集,1次完整训练的成本比较高,此时可以隔一段时间查看一下,如果精度差异比较大,建议先停掉实验,排查原因。
* 如果训练的过程中出nan,一般是因为除0或者log0的情况, 可以着重看下几个部分:
    * 如果有预训练模型的话,可以确认下是否加载正确
    * 确认下reader的预处理中是否会出现box(或mask)为空的情况
    * 模型结构中计算loss的部分是否有考虑到正样本为0的情况
    * 也可能是某个API的数值越界导致的,可以测试较小的输入是否还会出现nan。
littletomatodonkey's avatar
littletomatodonkey 已提交
880
* 如果训练过程中出现不收敛的情况,可以
881 882 883 884 885
    * 简化网络和数据,实验是否收敛;
    * 如果是基于原有实现进行改动,可以尝试控制变量法,每次做一个改动,逐个排查;
    * 检查学习率是否过大、优化器设置是否合理,排查下weight decay是否设置正确;
    * 保存不同step之间的模型参数,观察模型参数是否更新。

886

887 888
#### 4.12.2 细分场景特定问题

littletomatodonkey's avatar
littletomatodonkey 已提交
889
* 小数据上指标波动可能比较大,时间允许的话,可以跑多次实验,取平均值。
890 891 892 893
* transformer 系列模型对于数据增广与模型初始化非常敏感,因此在保证前反向对齐后,如果训练仍无法对齐,可以考虑使用官方的PyTorch模型训练代码,结合复现的Paddle组网代码进行训练,这样可以验证是否是数据预处理/数据增强策略存在问题。
* 检测、分割等任务中,训练通常需要加载backbone的权重作为预训练模型,注意在完成模型对齐后,将转换的权重修改为backbone权重。
* 生成任务中,训练时经常需要固定一部分网络参数。对于一个参数`param`,可以通过`param.trainable = False`来固定。
* 在训练GAN时,通常通过GAN的loss较难判断出训练是否收敛,建议每训练几次迭代保存一下训练生成的图像,通过可视化判断训练是否收敛。
894
* 在训练GAN时,如果PaddlePaddle实现的代码已经可以与参考代码完全一致,参考代码和PaddlePaddle代码均难以收敛,则可以在训练的时候,可以判断一下loss,如果loss大于一个阈值或者直接为NAN,说明训崩了,就终止训练,使用最新存的参数重新继续训练。可以参考该链接的实现:[链接](https://github.com/JennyVanessa/Paddle-GI)
littletomatodonkey's avatar
littletomatodonkey 已提交
895 896 897 898 899 900 901 902


<a name="4.13"></a>

### 4.13 TIPC基础链条测试接入

* 在接入时,建议将少量用于测试的数据打包(`tar -zcf lite_data.tar data/`),放在data目录下,后续在进行环境准备的时候,直接解压该压缩包即可。
* 接入过程中,需要依赖于inference模型,因此建议首先提供模型导出和基于inference模型的预测脚本,之后再接入TIPC测试代码与文档。