AI调参经验
训练AI的调参经验总结
环境配置
2023/10/09更新
conda安装
用miniconda,没必要用anaconda。
1 |
|
重装miniconda的时候,提前备份安装目录下的envs文件夹以保留环境。
CUDA安装
下载CUDA11.7。
双击exe安装即可,安装选项选择自定义,如果已有nvidia驱动(使用nvidia-smi
命令判断)可以只勾选CUDA,否则全部勾选。一直下一步。
安装完成后使用nvcc -V
确定自己的CUDA版本。
输出如下:
1 |
|
cuDNN安装
下载cuDNN,选择Download cuDNN v8.5.0 (August 8th, 2022), for CUDA 11.x。
解压压缩包,将里面的 bin / include / lib
三个文件夹直接复制到CUDA安装目录下(如果安装CUDA时默认安装路径,应该是C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.7
),即合并到同名文件夹下。
在include文件夹下的cudnn.h中可以看到cudnn版本。
备注
CUDA有driver api和runtime api。nvidia-smi
命令显示的 CUDA
Version是driver api版本,nvcc -V
显示是runtime
api版本。runtime api的版本要低于或者等于driver api。
driver api是显卡驱动自带的,安装CUDA一般指安装CUDA Toolkit以支持runtime api。
如果安装有pytorch,可以使用pytorch查看 ptorch、CUDA 、 cuDNN 版本。
1 |
|
本地开发pytorch程序并不是必须在电脑上安装CUDA和cuDNN。可以在conda环境下安装pytorch时顺便安装pytorch-cuda,这样就自带了。
1 |
|
pytorch
训练
训练时使用model.train()
,测试时使用model.eval()
。BatchNormalization在测试时参数固定,Dropout在测试时不再生效。
测试时使用model.eval()
虽然梯度不再传播,但仍然计算。with torch.no_grad():
,防止计算梯度,节省资源。
学习率大时收敛快,但收敛到一定程度后不再收敛,需要降低学习率。使用torch.optim.lr_scheduler.ExponentialLR()
之类的API。
标准训练流程为(代码选自《pytorch深度学习实战》笔记 - Homeworld):
1 |
|
optimizer.zero_grad()
也可以放在训练之前,只要不出现在loss.backward()
和optimizer.step()
之间即可。参考Where
should I place .zero_grad()? - PyTorch Forums。
模型存取
保存整个模型
1
2
3
4
5
6# 保存
model = Model()
torch.save(model, 'model_name.pth')
# 读取
model = torch.load('model_name.pth')保存模型参数
1
2
3
4
5
6
7
8
9# 保存
model = Model()
# 可以保存字典,用于同时保存多个模型等情况
torch.save({'model': model.state_dict()}, 'model_name.pth')、
# 读取
model = Model() # 先定义
state_dict = torch.load('model_name.pth')
model.load_state_dict(state_dict['model'])第一种方法可以直接保存模型,加载模型的时候直接把读取的模型给一个参数就行。它包含四个键,分别是model,optimizer,scheduler,iteration。
第二种方法在读取模型参数前要先定义一个模型(模型必须与原模型相同的构造),然后对这个模型导入参数。
权重初始化
使用方法:
1 |
|
不同的初始化API:torch.nn.init — PyTorch 1.12 documentation
Pytorch线性层采取的默认初始化方式是kaiming_uniform_初始化。
BN
1 |
|
Paper \[ y=\frac {x-E[x]} {\sqrt{Var[x]+\epsilon} } *\gamma+\beta \] 在最小批的每个维度上计算均值和标准差,\(\gamma\) 和\(\beta\)则是可学习参数向量,大小为输入的特征数或通道数。\(\gamma\) 默认为1,\(\beta\)默认为0。
为了将输入调整到激活函数的敏感区,BatchNorm层要加在激活函数前面。
Dropout
1 |
|
在训练过程中,按伯努利分布采样概率p随机将输入张量的元素置零。在每次调用中每个通道将被独立地置零。这已经被证明是正则化的有效手段。
注意,训练时输出会乘以\(\frac{1}{1-p}\)。测试时模块简单计算一个恒等函数。
BN层的加入可以起到抑制过拟合的作用,在训练过程对每个单个样本的forward均引入多个样本(Batch个)的统计信息,相当于自带一定噪音,起到正则效果,无需添加Dropout。BN和Dropout同时使用会使精度下降,参考论文:
Li X, Chen S, Hu X, et al. Understanding the disharmony between dropout and batch normalization by variance shift[C]//Proceedings of the IEEE/CVF conference on computer vision and pattern recognition. 2019: 2682-2690.
Dropout层一般放在激活函数层之后。
tensor操作
可以认为,对于tensor a:
1 |
|
tensor与numpy之间的转换:
1 |
|
并行化
训练AI模型有两类并行化,数据并行化和模型并行化。数据并行化指一张GPU处理一个数据切片(如一个batch的一部分),模型并行化指一张GPU处理一个模型切片(如模型的一层)。
对于数据并行化,pytorch有两种接口,torch.nn.DataParallel
和torch.nn.parallel.DistributedDataParallel
,前者为单机多线程,后者为单机/多机多进程且和模型并行化兼容。
对于模型并行化,有Pipleline并行化、Tensor并行化、Sequential并行化等方法,没有直接的接口。Pipleline并行化对模型按层划分到不同GPU上加速执行(类似CPU Pipeline),实现可以参考Single-Machine Model Parallel Best Practices — PyTorch Tutorials 2.1.0+cu121 documentation。
loss nan
出现loss nan可能有以下原因
训练数据中含有nan
计算过程中溢出
- 上溢出,进行譬如\(exp(x)\)之类的运算。
- 下溢出,进行譬如\(\log(0)\)之类的运算。
梯度爆炸
- 每个batch前梯度没有零,
optimizer.zero_grad()
(pytorch) - 学习率过大
- batchsize过大
- 可以用
torch.nn.utils.clip_grad_norm_
(pytorch)避免
- 每个batch前梯度没有零,
参数配置
常用的参数配置库有argparse和configparse。
argparse从命令行读取参数。
1 |
|
如果希望将argparse读取的参数写入文件,直接从文件读取,可以这样做:
1 |
|
configparse从文件读取参数。