1 知识储备

实现aft-full/simple/conv,用它们替换代码中的tokenmixer部分,并做cifar100训练。

如果要替换代码中的token_mixer部分,需要首先实现aft-full/simple/conv

1.1 cifar100

CIFAR100数据集有100个类。每个类有600张大小为32 × 32的彩色图像,其中500张作为训练集,100张作为测试集。对于每一张图像,它有fine_labels和coarse_labels两个标签,分别代表图像的细粒度和粗粒度标签,对应下图中的classessuperclass。也就是说,CIFAR100数据集是层次的。

1.1.1 Top-1和Top-5

我们在训练完某个分类网络后,假设我们需要分类的数量为50类,我们需要评估它的分类性能。输入测试集的每张图片,会得到它的50个类别的的概率。

Top-5准确率:在这张测试的图片50的类别中,取出概率最大的前五个类别,如果真实类别在这五个类别中,则预测正确,否则预测错误。

$$
top5_{Accuracy}=\frac{真实类别在预测的5个类别中的数量}{所有测试集的数量}
$$

Top-1准确率:平常我们评估预测的准确性指标

$$
top1_{Accuracy}=\frac{预测正确的数量}{所有测试集的数量}
$$

而Top-5错误率与Top-1错误率恰好与top-5准确率和top-1准确率相反,他们的和为1。

1.2 metaformer

Transformer在计算机视觉任务中显示出了巨大的潜力。一个普遍的观念就是,基于注意力的token mixer module对Transformer的贡献最大。然而,最近的研究表明,Transformer中基于注意力的模块可以被spatial MLPs所取代,并且所得到的模型仍然表现得很好。

基于这一结果,作者假设,Transformer的一般架构对模型来说更为重要,而不是特定的token mixer module。为了验证这一假设,作者故意将Transformer中的注意力模块替换为简单空间池化操作,以便只进行最基本的token mixer。令人惊讶的是**PoolFormer**在多个计算机视觉任务上都取得了具有竞争力的性能。

例如,在ImageNet-1K上,PoolFormer达到了82.1%的Top-1精度,超过了DeiTB/MLP-B240.3%/1.1%,参数减少了35%/52%,mac减少了48%/60%。PoolFormer的有效性验证了作者的假设,并敦促启动MetaFormer的概念,这是一种从Transformer中抽象出来的一般架构,没有指定的token mixer

基于大量的实验,作者认为MetaFormer是为最近的Transformer和类似MLP的视觉任务模型获得优越结果的关键。这项工作需要更多的未来研究,致力于改进MetaFormer,而不是专注于token mixer module。此外,作者提出的**PoolFormer**可以作为未来MetaFormer设计的Baseline。


2 实现过程

需要找一下怎么跑这个模型?metaformer的模型使用代码在哪个地方?

2.1 遇到的问题

2.1.1 git bash不能切换环境

首先我尝试在git中修改使用的conda环境,输入命令后报错如下:

可能由于环境变量出现问题,参考网上一个帖子的做法,首先进入..\Anaconda\etc\profile.d目录下,在此打开git bash,然后输入以下命令:

1
echo ". '${PWD}'/conda.sh" >> ~/.bashrc

之后再次切换环境,如下图所示,切换成功。

2.1.2 bash运行使用的python程序不对

运行实验的代码需要运行.sh脚本,然后使用bash命令,这个bash命令默认是git中的,而且执行时显示的路径为:F:\env\gcc\msys64\mingw64\bin\python3.exe

发现问题了,原因在于在sh脚本中使用的python是默认的,如下:

1
2
3
4
5
#!/bin/bash
NUM_PROC=$1
shift
python3 -m torch.distributed.launch --nproc_per_node=$NUM_PROC train.py "$@"

将其中的python3修改为指定的python环境即可,修改后运行结果如下:

虽然还是报错,但是起码能跑起来了。

2.1.3 local_rank参数报错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 train.py: error: unrecognized arguments: --local-rank=0 
E0710 10:43:26.383000 21308 torch\distributed\elastic\multiprocessing\api.py:826] failed (exitcode: 2) local_rank: 0 (pid: 16056) of binary: F:\anaconda\anaconda3\envs\DeltaZero\python.exe
Traceback (most recent call last):
File "F:\anaconda\anaconda3\envs\DeltaZero\lib\runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "F:\anaconda\anaconda3\envs\DeltaZero\lib\runpy.py", line 86, in _run_code
exec(code, run_globals)
File "F:\anaconda\anaconda3\envs\DeltaZero\lib\site-packages\torch\distributed\launch.py", line 198, in <module>
main()
File "F:\anaconda\anaconda3\envs\DeltaZero\lib\site-packages\torch\distributed\launch.py", line 194, in main
launch(args)
File "F:\anaconda\anaconda3\envs\DeltaZero\lib\site-packages\torch\distributed\launch.py", line 179, in launch
run(args)
File "F:\anaconda\anaconda3\envs\DeltaZero\lib\site-packages\torch\distributed\launcher\api.py", line 132, in __call__
return launch_agent(self._config, self._entrypoint, list(args))
File "F:\anaconda\anaconda3\envs\DeltaZero\lib\site-packages\torch\distributed\launcher\api.py", line 263, in launch_agent
raise ChildFailedError(
torch.distributed.elastic.multiprocessing.errors.ChildFailedError:
============================================================
train.py FAILED
------------------------------------------------------------
Failures:
<NO_OTHER_FAILURES>
------------------------------------------------------------
Root Cause (first observed failure):
[0]:
time : 2024-07-10_10:43:26
host : DESKTOP-PIQBNCN
rank : 0 (local_rank: 0)
exitcode : 2 (pid: 16056)
error_file: <N/A>
traceback : To enable traceback see: https://pytorch.org/docs/stable/elastic/errors.html
============================================================

报错的地方用红字体标出,可以看到由于一个未知的参数--local-rank=0,接下来找一下这个参数在哪传入的。

这个参数不能是用户自己设置的,应该是pytorch自动帮你填写。

在运行文件之前加入参数--use_env得以解决,如下:

1
2
3
NUM_PROC=1
shift
F:/anaconda/anaconda3/envs/DeltaZero/python -m torch.distributed.launch --nproc_per_node=$NUM_PROC --use_env train.py "$@"

2.1.4 AssertionError: Torch not compiled with CUDA enabled

使用如下命令查看有否有可用的cuda,发现返回False。

1
2
import torch
print(torch.cuda.is_available())

然后查看conda环境中的pytorch是CPU版本还是GPU版本,突然发现找不到pytorch包,但是我记得之前下过,有点尴尬。

所以需要下载pytorch包。

安装完成之后,运行程序,上述报错解决。

2.1.5 RuntimeError: Found 0 images in subfolders

在创建数据集的时候出现了错误,完整报错如下:

1
2
3
4
5
6
7
8
9
10
11
File "D:\Code\Paper-code\metaformer\train.py", line 572, in main
dataset_train = create_dataset(
File "F:\anaconda\anaconda3\envs\DeltaZero\lib\site-packages\timm\data\dataset_factory.py", line 142, in create_dataset
ds = ImageDataset(root, parser=name, class_map=class_map, load_bytes=load_bytes, **kwargs)
File "F:\anaconda\anaconda3\envs\DeltaZero\lib\site-packages\timm\data\dataset.py", line 32, in __init__
parser = create_parser(parser or '', root=root, class_map=class_map)
File "F:\anaconda\anaconda3\envs\DeltaZero\lib\site-packages\timm\data\parsers\parser_factory.py", line 27, in create_parser
parser = ParserImageFolder(root, **kwargs)
File "F:\anaconda\anaconda3\envs\DeltaZero\lib\site-packages\timm\data\parsers\parser_image_folder.py", line 73, in __init__
raise RuntimeError(
RuntimeError: Found 0 images in subfolders of D:\Code\Paper-code\metaformer\cifar-100\train. Supported image extensions are .png, .jpg, .jpeg

感觉这个应该是原来是使用imagenet进行训练,但是我换成了cifar100的原因。

手动将数据集换成了cifar100,使用timm库中的create_dataset可以自动进行下载,设置代码如下:

1
2
args.dataset = "torch/CIFAR100"
args.dataset_download = True

运行结果如下,解决了上述报错问题。

2.1.6 ValueError: too many values to unpack (expected 3)

数据集更换为cifar100后,运行程序,完整报错如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  File "D:\Code\Paper-code\metaformer\train.py", line 792, in train_one_epoch
output = model(input)
File "F:\anaconda\anaconda3\envs\DeltaZero\lib\site-packages\torch\nn\modules\module.py", line 1501, in _call_impl
return forward_call(*args, **kwargs)
File "D:\Code\Paper-code\metaformer\metaformer_baselines.py", line 666, in forward
x = self.forward_features(x)
File "D:\Code\Paper-code\metaformer\metaformer_baselines.py", line 662, in forward_features
x = self.stages[i](x)
File "F:\anaconda\anaconda3\envs\DeltaZero\lib\site-packages\torch\nn\modules\module.py", line 1501, in _call_impl
return forward_call(*args, **kwargs)
File "F:\anaconda\anaconda3\envs\DeltaZero\lib\site-packages\torch\nn\modules\container.py", line 217, in forward
input = module(input)
File "F:\anaconda\anaconda3\envs\DeltaZero\lib\site-packages\torch\nn\modules\module.py", line 1501, in _call_impl
return forward_call(*args, **kwargs)
File "D:\Code\Paper-code\metaformer\metaformer_baselines.py", line 522, in forward
self.token_mixer(self.norm1(x))
File "F:\anaconda\anaconda3\envs\DeltaZero\lib\site-packages\torch\nn\modules\module.py", line 1501, in _call_impl
return forward_call(*args, **kwargs)
File "D:\Code\Paper-code\metaformer\aft\aft_full.py", line 17, in forward
batch_size, seq_len, _ = x.shape
ValueError: too many values to unpack (expected 3)

从报错信息可以看出,应该是替换的aft_full模块的输入和真实数据的输入有偏差。

跑程序的时候显存都快占满了,希望电脑别崩。

可以将aft_full模块的输入打印出来看一下:

x.shape: torch.Size([256, 56, 56, 64])

现在需要弄明白这4个维度分别代表什么意思,应该从上一个模块的输出开始分析。

同时发现模型的初始输入的形状与上面相同,所以应该分析data_loader数据的形状。从其中取出的input的形状为[256, 3, 224, 224],其中的224是什么来的?

  • 256:batch_size
  • 56:数据增强之后的高
  • 56:数据增强之后的宽
  • 64:通道数

2.1.7 RuntimeError: FIND was unable to find an engine to execute this computation

上面问题解决后,又出现了下面这个报错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Traceback (most recent call last):
File "D:\Code\Paper-code\metaformer\train.py", line 935, in <module>
main()
File "D:\Code\Paper-code\metaformer\train.py", line 709, in main
train_metrics = train_one_epoch(
File "D:\Code\Paper-code\metaformer\train.py", line 790, in train_one_epoch
output = model(input)
File "F:\anaconda\anaconda3\envs\DeltaZero\lib\site-packages\torch\nn\modules\module.py", line 1501, in _call_impl
return forward_call(*args, **kwargs)
File "D:\Code\Paper-code\metaformer\metaformer_baselines.py", line 666, in forward
x = self.forward_features(x)
File "D:\Code\Paper-code\metaformer\metaformer_baselines.py", line 661, in forward_features
x = self.downsample_layers[i](x)
File "F:\anaconda\anaconda3\envs\DeltaZero\lib\site-packages\torch\nn\modules\module.py", line 1501, in _call_impl
return forward_call(*args, **kwargs)
File "D:\Code\Paper-code\metaformer\metaformer_baselines.py", line 210, in forward
x = self.conv(x)
File "F:\anaconda\anaconda3\envs\DeltaZero\lib\site-packages\torch\nn\modules\module.py", line 1501, in _call_impl
return forward_call(*args, **kwargs)
File "F:\anaconda\anaconda3\envs\DeltaZero\lib\site-packages\torch\nn\modules\conv.py", line 463, in forward
return self._conv_forward(input, self.weight, self.bias)
File "F:\anaconda\anaconda3\envs\DeltaZero\lib\site-packages\torch\nn\modules\conv.py", line 459, in _conv_forward
return F.conv2d(input, weight, bias, self.stride,
RuntimeError: FIND was unable to find an engine to execute this computation

nvidia-smi 中的CUDA 版本与 nvcc不一致,nvidia-smi的结果显示CUDA版本是12.3,而从nvcc-V命令来看,却是CUDA 11.8。

其实是因为CUDA 有两种API,分别是运行时 API 和 驱动API,即所谓的 Runtime API 与 Driver API。

  • nvidia-smi 的结果除了有 GPU 驱动版本型号,还有 CUDA Driver API的型号,这里是 12.3
  • nvcc的结果是对应 CUDA Runtime API
命令 CUDA API类型 显示 CUDA版本号例子 说明
nvidia-smi Driver API GPU 驱动版本号;CUDA Driver API号 11.0
nvcc -V Runtime API CUDA Runtime API 10.0 安装python包(例如torch)需要匹配runtime cuda版本

从网上查了相关资料,有的说可能由于pytorch版本过高,我的版本是2.0.1。将pytorch 2.0.0更改为torch1.13.1+cu117后解决。

1
pip install torch==1.13.1+cu117 torchvision==0.14.1+cu117 --extra-index-url https://download.pytorch.org/whl/cu117

2.1.8 RuntimeError: cuDNN error: CUDNN_STATUS_INTERNAL_ERROR

上面那个错误解决之后,又报了下面这个错误,麻了😂:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
RuntimeError: cuDNN error: CUDNN_STATUS_INTERNAL_ERROR
You can try to repro this exception using the following code snippet. If that doesn't trigger the error, please include your original repro script when reporting this issue.

import torch
torch.backends.cuda.matmul.allow_tf32 = False
torch.backends.cudnn.benchmark = True
torch.backends.cudnn.deterministic = False
torch.backends.cudnn.allow_tf32 = True
data = torch.randn([256, 64, 56, 56], dtype=torch.float, device='cuda', requires_grad=True)
net = torch.nn.Conv2d(64, 128, kernel_size=[3, 3], padding=[1, 1], stride=[2, 2], dilation=[1, 1], groups=1)
net = net.cuda().float()
out = net(data)
out.backward(torch.randn_like(out))
torch.cuda.synchronize()

使用下述命令解决:

1
2
torch.backends.cudnn.enabled = False

2.1.9 RuntimeError: CUDA error: out of memory

上面那个错误解决之后,又报了下面这个错误,麻了😂:

1
2
3
4
5
File "D:\Code\Paper-code\metaformer\aft\aft_full.py", line 25, in forward
num = torch.exp(w_bias) @ (torch.exp(k) * v)
RuntimeError: CUDA error: out of memory
CUDA kernel errors might be asynchronously reported at some other API call,so the stacktrace below might be incorrect.
For debugging consider passing CUDA_LAUNCH_BLOCKING=1.

这个错误 RuntimeError: CUDA error: out of memory 表明 GPU 内存不足以执行当前的运算。这通常发生在处理大型数据集或复杂模型时,特别是当所有输入、模型参数和中间结果都存储在 GPU 上时。

把batch_size从1024调至128,可以成功运行。


3 训练

3.1 模型太大

训练的时候感觉速度很慢,听学长的看了一下模型大小,发现14G,改小一点吧。

现在回头看,原来这是个大坑,改小也没让你改那么小啊🤪