diff --git a/docs/ThesisReproduction_CV.md b/docs/ThesisReproduction_CV.md index 259721c72324acd7c0aa63b275914fbdc24ee183..2875214fa21f142a1168a4796943ad861f946cf8 100644 --- a/docs/ThesisReproduction_CV.md +++ b/docs/ThesisReproduction_CV.md @@ -11,7 +11,7 @@ ### 1.2 前序工作 -基于本文规范复现论文过程中,建议开发者准备以下内容。 +基于本指南复现论文过程中,建议开发者准备以下内容。 * 了解该模型输入输出格式。以AlexNet图像分类任务为例,通过阅读论文与参考代码,了解到模型输入为`[batch_size, 3, 224, 244]`的tensor,类型为`float32`或者`float16`,label为`[batch, ]`的label,类型为`int64`。 * 准备好训练/验证数据集,用于模型训练与评估 @@ -27,21 +27,21 @@ ### 2.1 流程概览 -基于通用的计算机视觉任务,论文复现整体流程图如下所示。 +面对一篇计算机视觉论文,复现该论文的整体流程如下图所示。 ![图片](images/framework.png) +总共包含11个步骤。为了高效复现论文,设置了5个验收节点。如上图中黄色框所示。后续章节会详细介绍上述步骤和验收节点,具体内容安排如下: -总共包含11个步骤,为了高效复现论文,设置了5个验收节点。如上图中黄色框所示。对应地,第3章到第5章的内容安排如下: - -* 第3章:介绍11个复现步骤的理论知识以及操作方法 +* 第3章:介绍11个复现步骤的理论知识以及实战 * 第4章:介绍5个验收节点的自查与验收方法 -* 第5章:针对第3章在复现流程过程中可能出现的问题,在第5章会进行详细介绍。如果还是不能解决问题的话,可以进交流群讨论 +* 第5章:针对复现流程过程中每个步骤可能出现的问题,本章会进行详细介绍。如果还是不能解决问题,可以提ISSUE或进交流群讨论 -### 2.2 reprod_log whl包使用说明 +### 2.2 reprod_log whl包 -`reprod_log`是用于论文复现赛自动化测试和验收的工具,源代码地址在:[https://github.com/WenmuZhou/reprod_log](https://github.com/WenmuZhou/reprod_log)。主要功能包括: +#### 2.2.1 reprod_log工具简介 +`reprod_log`是用于论文复现赛中辅助自查和验收工具。该工具源代码地址在:[https://github.com/WenmuZhou/reprod_log](https://github.com/WenmuZhou/reprod_log)。主要功能如下: * 存取指定节点的输入输出tensor * 基于文件的tensor读写 @@ -96,9 +96,9 @@ * diff_threshold (float): 阈值,如果diff大于该阈值,则核验失败,默认为`1e-6` * path (str): 日志保存的路径,默认为`./diff.txt` -### 2.3 使用demo +#### 2.2.2 reprod_log使用demo -下面基于代码:[https://github.com/littletomatodonkey/AlexNet-Prod/tree/master/pipeline/reprod_log_demo](https://github.com/littletomatodonkey/AlexNet-Prod/tree/master/pipeline/reprod_log_demo),给出详细的工具包API使用功能。 +下面基于代码:[https://github.com/littletomatodonkey/AlexNet-Prod/tree/master/pipeline/reprod_log_demo](https://github.com/littletomatodonkey/AlexNet-Prod/tree/master/pipeline/reprod_log_demo),给出如何使用该工具。 文件夹中包含`write_log.py`和`check_log_diff.py`文件,其中`write_log.py`中给出了`ReprodLogger`类的使用方法,`check_log_diff.py`给出了`ReprodDiffHelper`类的使用方法,依次运行两个python文件,使用下面的方式运行代码。 @@ -123,9 +123,9 @@ python3.7 check_log_diff.py 可以看出:对于key为`demo_test_1`的矩阵,由于diff为0,小于设置的阈值`1e-6`,核验成功;对于key为`demo_test_2`的矩阵,由于diff为0.33,大于设置的阈值`1e-6`,核验失败。 -### 2.4 论文复现赛自动化测试 +#### 2.2.3 reprod_log在论文复现中应用 -假设基于上述工具的结果记录模块,产出下面若干文件 +在论文复现中,基于reprod_log的结果记录模块,产出下面若干文件 ``` log_reprod ├── forward_paddle.npy @@ -140,7 +140,7 @@ log_reprod ├── train_align_benchmark.npy # PaddlePaddle提供的参考评估指标 ``` -使用该工具中的`ReprodDiffHelper`模块,产出下面的日志文件。 +基于reprod_log的`ReprodDiffHelper`模块,产出下面5个日志文件。 ``` ├── forward_diff.log # forward_paddle.npy与forward_torch.npy生成的diff结果文件 @@ -150,79 +150,11 @@ log_reprod ├── train_align_diff.log # train_align_paddle.npy与train_align_benchmark.npy生成的diff结果文件 ``` -5个结果文件中,会显示基于`repod_log`的检查结果。 - -下面以后续的前向对齐为例,介绍下基于`repord_log`工具对齐的检查流程。其中与`reprod_log`工具有关的部分都是需要开发者需要去添加的部分。 - -具体代码地址为:[https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/pipeline/Step1/AlexNet_paddle/forward_alexnet.py](https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/pipeline/Step1/AlexNet_paddle/forward_alexnet.py)。 - -下载代码后,按照下面的步骤运行脚本。 - -```shell -# 进入文件夹 -cd pipeline/Step1/ -# 下载预训练模型 -wget -P ../weights https://paddle-model-ecology.bj.bcebos.com/model/alexnet_reprod/alexnet_paddle.pdparams -wget -P ../weights https://paddle-model-ecology.bj.bcebos.com/model/alexnet_reprod/alexnet-owt-7be5be79.pth - -# 生成paddle的前向数据 -cd AlexNet_paddle/ && python3.7 forward_alexnet.py -# 生成torch的前向数据 -cd ../AlexNet_torch && python3.7 forward_alexnet.py -# 对比生成log -cd .. -python3.7 check_step1.py -``` - -以PaddlePaddle为例,`forward_alexnet.py`的具体代码如下所示。 - -```python -import numpy as np -import paddle -# 导入模型 -from paddlevision.models.alexnet import alexnet -# 导入reprod_log中的ReprodLogger类 -from reprod_log import ReprodLogger - -reprod_logger = ReprodLogger() -# 组网并初始化 -model = alexnet(pretrained="../../weights/alexnet_paddle.pdparams" num_classes=1000) -model.eval() -# 读入fake data并转换为tensor,这里也可以固定seed在线生成fake data -fake_data = np.load("../../fake_data/fake_data.npy") -fake_data = paddle.to_tensor(fake_data) -# 模型前向 -out = model(fake_data) -# 保存前向结果,对于不同的任务,需要开发者添加。 -reprod_logger.add("logits", fake_data.cpu().detach().numpy()) -reprod_logger.save("forward_paddle.npy") -``` - -diff检查的代码可以参考:[check_step1.py](https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/pipeline/Step1/check_step1.py),具体代码如下所示。 - -```python -# https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/pipeline/Step1/check_step1.py -# 使用reprod_log排查diff -from reprod_log import ReprodDiffHelper -if __name__ == "__main__": - diff_helper = ReprodDiffHelper() - torch_info = diff_helper.load_info("AlexNet_torch/forward_torch.npy") - paddle_info = diff_helper.load_info("AlexNet_paddle/forward_paddle.npy") - diff_helper.compare_info(torch_info, paddle_info) - diff_helper.report(path="forward_diff.log") -``` - -产出日志如下。 - -``` -2021-09-27 10:35:46,172 - reprod_log.utils - INFO - logits: -2021-09-27 10:35:46,173 - reprod_log.utils - INFO - mean diff: check passed: True, value: 0.0 -2021-09-27 10:35:46,173 - reprod_log.utils - INFO - diff check passed -``` - -平均绝对误差为0,测试通过。 +上述文件的生成代码都需要开发者进行开发,验收时需要提供上面罗列的所有文件(不需要提供产生这些文件的可运行程序)以及完整的模型训练评估程序和日志。 +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文档提供了使用说明。 -## 3. 论文复现赛操作流程规范 +## 3. 论文复现理论知识以及实战 ### 3.1 模型结构对齐 @@ -230,23 +162,40 @@ if __name__ == "__main__": * 网络结构代码转换 * 权重转换 -* 给定完全相同输入,生成tensor,验证模型的正确性 +* 模型组网正确性验证 下面详细介绍这3个部分。 #### 3.1.1 网络结构代码转换 -由于PyTorch的API和PaddlePaddle的API非常相似,所以组网部分代码直接手动转换即可。如果是PaddlePaddle没有的API,可以尝试用多种API来组合,高优的API如果希望获得支持,也可以提给PaddlePaddle团队提[ISSUE](https://github.com/PaddlePaddle/Paddle/issues)。API对应的列表也可以参考:[PyTorch-PaddlePaddle API映射表](https://www.paddlepaddle.org.cn/documentation/docs/zh/guides/08_api_mapping/pytorch_api_mapping_cn.html)。 +**【基本流程】** + +由于PyTorch的API和PaddlePaddle的API非常相似,可以参考[PyTorch-PaddlePaddle API映射表](https://www.paddlepaddle.org.cn/documentation/docs/zh/guides/08_api_mapping/pytorch_api_mapping_cn.html) +,组网部分代码直接进行手动转换即可。 + +**【注意事项】** -对于AlexNet,PyTorch实现为: [alexnet-pytorch](https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/AlexNet-torch/torchvision/models/alexnet.py), 复现的PaddlePaddle实现为: [alexnet-paddle](https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/AlexNet-paddle/paddlevision/models/alexnet.py)。 +如果遇到PaddlePaddle没有的API,可以尝试用多种API来组合,也可以给PaddlePaddle团队提[ISSUE](https://github.com/PaddlePaddle/Paddle/issues),获得支持。 + +**【实战】** + +对于AlexNet网络结构的PyTorch实现 [alexnet-pytorch](https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/AlexNet-torch/torchvision/models/alexnet.py),[alexnet-paddle](https://github.com/littletomatodonkey/AlexNet-Prod/blob/master/AlexNet-paddle/paddlevision/models/alexnet.py) 提供了网络结构代码转换为PaddlePaddle的实现。 #### 3.1.2 权重转换 +**【基本流程】** + 组网代码转换完成之后,需要对模型权重进行转换,如果PyTorch repo中已经提供权重,那么可以直接下载并进行后续的转换;如果没有提供,则可以基于PyTorch代码,随机生成一个初始化权重(定义完model以后,使用`torch.save()` API保存模型权重),然后进行权重转换。 +**【注意事项】** + +在权重转换的时候,需要注意`paddle.nn.Linear`以及`paddle.nn.BatchNorm2D`等API的权重保存格式和名称等与PyTorch稍有diff,具体内容可以参考`5.1章节`。 + +**【实战】** + 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),核心函数如下所示。 -注:运行该代码需要首先下载PyTorch的AlexNet预训练模型到该目录下,下载地址为:[https://download.pytorch.org/models/alexnet-owt-7be5be79.pth](https://download.pytorch.org/models/alexnet-owt-7be5be79.pth) +注意:运行该代码需要首先下载PyTorch的AlexNet预训练模型到该目录下,下载地址为:[https://download.pytorch.org/models/alexnet-owt-7be5be79.pth](https://download.pytorch.org/models/alexnet-owt-7be5be79.pth) ```python # https://github.com/littletomatodonkey/AlexNet-Prod/blob/d7b1977c2043a346b3fee0039949d5334fb990a3/pipeline/weights/torch2paddle.py#L6 @@ -277,27 +226,32 @@ transfer() 运行完成之后,会在这里生成`alexnet_paddle.pdparams`文件,为PaddlePaddle的预训练模型。 -在权重转换的时候,需要注意`paddle.nn.Linear`以及`paddle.nn.BatchNorm2D`等API的权重保存格式和名称等与PyTorch稍有diff,具体内容可以参考`5.1章节`。 - #### 3.1.3 模型组网正确性验证 -* 操作流程 +**【基本流程】** + * 定义PyTorch模型,加载权重,固定seed,基于numpy生成随机数,转换为PyTorch可以处理的tensor,送入网络,获取输出,使用reprod_log保存结果。 * 定义PaddlePaddle模型,加载权重,固定seed,基于numpy生成随机数,转换为PaddlePaddle可以处理的tensor,送入网络,获取输出,使用reprod_log保存结果。 * 使用reprod_log排查diff,小于阈值,即可完成自测。 -* 注意事项 + +**【注意事项】** + * 模型在前向对齐验证时,需要调用`model.eval()`方法,保证组网中的随机量被关闭,比如BatchNorm、Dropout等。 - * 给定相同的输入数据,为保证可复现性,建议随机数生成时,固定seed进行生成。 - * 输出diff可以使用`np.mean(np.abs(o1 - o2))`进行计算,一般小于1e-6的话,可以认为前向没有问题。 - * 如果最终输出结果diff较大,可以使用二分的方法进行排查,比如说ResNet50,包含1个stem、4个res-stage、global avg-pooling以及最后的fc层,那么完成模型组网和权重转换之后,如果模型输出没有对齐,可以尝试输出中间某一个res-stage的tensor进行对比,如果相同,则向后进行排查;如果不同,则继续向前进行排查,以此类推,直到找到导致没有对齐的操作。 + * 给定相同的输入数据,为保证可复现性,如果有随机数生成,固定相关的随机种子。 + * 输出diff可以使用`np.mean(np.abs(o1 - o2))`进行计算,一般小于1e-6的话,可以认为前向没有问题。如果最终输出结果diff较大,可以使用二分的方法进行排查,比如说ResNet50,包含1个stem、4个res-stage、global avg-pooling以及最后的fc层,那么完成模型组网和权重转换之后,如果模型输出没有对齐,可以尝试输出中间某一个res-stage的tensor进行对比,如果相同,则向后进行排查;如果不同,则继续向前进行排查,以此类推,直到找到导致没有对齐的操作。 +**【实战】** -### 3.2 验证/测试集数据读取对齐 +AlexNet模型组网正确性验证可以参考如下示例代码: +[https://github.com/littletomatodonkey/AlexNet-Prod/tree/master/pipeline/Step1](https://github.com/littletomatodonkey/AlexNet-Prod/tree/master/pipeline/Step1) +### 3.2 验证/测试集数据读取对齐 #### 3.2.1 数据集类Dataset复现方法 +**【基本流程】** + 对于一个数据集,一般有以下一些信息需要重点关注 * 数据集名称、下载地址 @@ -305,9 +259,11 @@ transfer() * 数据集标注格式、标注信息 * 数据集通用的预处理方法 -PaddlePaddle中数据集类为`paddle.io.Dataset`,PyTorch中对应为`torch.utils.data.Dataset`,二者功能一致,在绝大多数情况下,可以使用该类构建数据集。它是描述Dataset方法和行为的抽象类,在具体实现的时候,需要继承这个基类,实现其中的`__getitem__`和`__len__`方法。更多使用细节可以参考论文中的说明。 +PaddlePaddle中数据集相关的API为`paddle.io.Dataset`,PyTorch中对应为`torch.utils.data.Dataset`,二者功能一致,在绝大多数情况下,可以使用该类构建数据集。它是描述Dataset方法和行为的抽象类,在具体实现的时候,需要继承这个基类,实现其中的`__getitem__`和`__len__`方法。除了参考代码中相关实现,也可以参考待复现论文中的说明。 -论文中一般会提供数据集的名称以及基本信息。复现过程中,我们在下载完数据之后,建议先检查下是否和论文中描述一致,否则可能存在的问题有: +**【注意事项】** + +此外,论文中一般会提供数据集的名称以及基本信息。复现过程中,我们在下载完数据之后,建议先检查下是否和论文中描述一致,否则可能存在的问题有: * 数据集年份不同,比如论文中使用了MS-COCO2014数据集,但是我们下载的是MS-COCO2017数据集,如果不对其进行检查,可能会导致我们最终训练的数据量等与论文中有diff * 数据集使用方式不同,有些论文中,可能只是抽取了该数据集的子集进行方法验证,此时需要注意抽取方法,需要保证抽取出的子集完全相同 @@ -318,6 +274,9 @@ PaddlePaddle中数据集类为`paddle.io.Dataset`,PyTorch中对应为`torch.ut * 有些自定义的数据处理方法,如果不涉及到深度学习框架的部分,可以直接复用。 * 对于特定任务中的数据预处理方法,比如说图像分类、检测、分割等,如果没有现成的API可以调用,可以参考官方模型套件中的一些实现方法,比如PaddleClas、PaddleDetection、PaddleSeg等。 +**【实战】** + + #### 3.2.2 数据加载器Dataloader复现方法 复现完Dataset之后,可以构建Dataloader,对数据进行组batch、批处理,送进网络进行计算。 @@ -392,9 +351,6 @@ INFO:reprod_log.utils: mean diff: check passed: True, value: 0.0 INFO:reprod_log.utils:diff check passed ``` - - - ### 3.3 评估指标对齐 #### 3.3.1 复现方法 @@ -751,7 +707,7 @@ python3.7 -m paddle.distributed.launch \ 注意:这里8卡训练时,虽然单卡的batch size没有变化(32),但是总卡的batch size相当于是单卡的8倍,因此学习率也设置为了单卡时的8倍。 -## 4. 验收点与验收方法 +## 4. 验收节点自查与验收方法 ### 4.1 模型结构对齐验收方法