PyTorch常用代码段合集

作者丨Jack Stark@知乎

来源丨https://zhuanlan.zhihu.com/p/104019160

导读

 

本文是PyTorch常用代码段合集,涵盖基本配置、张量处理、模型定义与操作、数据处理、模型训练与测试等5个方面,还给出了多个值得注意的Tips,内容非常全面。

PyTorch最好的资料是官方文档。本文是PyTorch常用代码段,在参考资料[1](张皓:PyTorch Cookbook)的基础上做了一些修补,方便使用时查阅。

1. 基本配置

导入包和版本查询

45c7de6a23eba1a135d587cce5de76a3.png

可复现性

在硬件设备(CPU、GPU)不同时,完全的可复现性无法保证,即使随机种子相同。但是,在同一个设备上,应该保证可复现性。具体做法是,在程序开始的时候固定torch的随机种子,同时也把numpy的随机种子固定。

f0b1efab1951979152345caac6dedd0a.png

显卡设置

3774645da920fe8157ccc681a8e56664.png

2. 张量(Tensor)处理

张量的数据类型

PyTorch有9种CPU张量类型和9种GPU张量类型。

7f1bbe187df2f9e8a33f63661b0af2ae.png

张量基本信息

cd850c434d6409a8421a9c7eeaa5f141.png

命名张量

张量命名是一个非常有用的方法,这样可以方便地使用维度的名字来做索引或其他操作,大大提高了可读性、易用性,防止出错。

742694aa874a37be6639df3e308e7a3c.png

数据类型转换

ef8d24475b405456e7058b69984ce1a6.png

torch.Tensor与np.ndarray转换

除了CharTensor,其他所有CPU上的张量都支持转换为numpy格式然后再转换回来。

54eee052371caf76fe13db1017a4ce26.png

Torch.tensor与PIL.Image转换

7865476b365b639fb06863421e18c935.png

np.ndarray与PIL.Image的转换

f092c237f07dbaf65cf9c08e3c04a053.png

从只包含一个元素的张量中提取值

da7bd72fed05cc24dc3ab8e7492e06cd.png

张量形变

23279a0c8dfb6347f664e43ae287685e.png

打乱顺序

fe84131af6292dc1bbbc7845ec9c0e6b.png

水平翻转

385642e7116bc335b1e9328f90fa063c.png

复制张量

fb156eaf89a7dede07a06304d9a0a3a0.png

张量拼接

8f197effb172ef7236963d0e381fe903.png

将整数标签转为one-hot编码

15d098c95f802bcf49a23048c2eefbcc.png

得到非零元素

83130b4f7685dd044a0e2552c133c513.png

判断两个张量相等

e6b332a6ae5ae40765b28c9f8aea69f8.png

张量扩展

201db3b81583c9185cfeaaa4b4d4f311.png

矩阵乘法

1837a0daa44124594befe72ae2222c2e.png

计算两组数据之间的两两欧式距离

利用broadcast机制

6f4f6c8e496e83bc67325d72737a92d7.png

3. 模型定义和操作

一个简单两层卷积网络的示例

fe7e0fc79d60a412734d5f5be5e2326e.png

卷积层的计算和展示可以用这个网站辅助。

双线性汇合(bilinear pooling)

fbd37c3e595673d5ac167a15e3d6cf30.png

多卡同步 BN(Batch normalization)

当使用 torch.nn.DataParallel 将代码运行在多张 GPU 卡上时,PyTorch 的 BN 层默认操作是各卡上数据独立地计算均值和标准差,同步 BN 使用所有卡上的数据一起计算 BN 层的均值和标准差,缓解了当批量大小(batch size)比较小时对均值和标准差估计不准的情况,是在目标检测等任务中一个有效的提升性能的技巧。

e962e8e8942dce54ac2427c337c6a006.png

将已有网络的所有BN层改为同步BN层

76f3731dee795b861fd4b05872b0153e.png

类似 BN 滑动平均

如果要实现类似 BN 滑动平均的操作,在 forward 函数中要使用原地(inplace)操作给滑动平均赋值。

9095f038673649435ec1792d0775aa80.png

计算模型整体参数量

56b25d69c70b12dabce1434f91394901.png

查看网络中的参数

可以通过model.state_dict()或者model.named_parameters()函数查看现在的全部可训练参数(包括通过继承得到的父类中的参数)

f271f17f6942f2aa516d758efc41f24a.png

模型可视化(使用pytorchviz)

szagoruyko/pytorchvizgithub.com

类似 Keras 的 model.summary() 输出模型信息,使用pytorch-summary

sksq96/pytorch-summarygithub.com

模型权重初始化

注意 model.modules() 和 model.children() 的区别:model.modules() 会迭代地遍历模型的所有子层,而 model.children() 只会遍历模型下的一层。

6c8dac86cc132978cddeec292a42be4b.png

提取模型中的某一层

modules()会返回模型中所有模块的迭代器,它能够访问到最内层,比如self.layer1.conv1这个模块,还有一个与它们相对应的是name_children()属性以及named_modules(),这两个不仅会返回模块的迭代器,还会返回网络层的名字。

a85fd37a19e462d1e103048b70b22c29.png

部分层使用预训练模型

注意如果保存的模型是 torch.nn.DataParallel,则当前的模型也需要是

7af7768c8823ce62245b9d464fa490fc.png

将在 GPU 保存的模型加载到 CPU

2ff733bcf5e1cf23463c6f254129b739.png

导入另一个模型的相同部分到新的模型

模型导入参数时,如果两个模型结构不一致,则直接导入参数会报错。用下面方法可以把另一个模型的相同的部分导入到新的模型中。

2c3d9b6cadace2d25b4b67e1b7fbb973.png

4. 数据处理

计算数据集的均值和标准差

c5411f47d3d8dc95ab68dfa2eb5086bb.png

得到视频数据基本信息

9169410680bf081d07c70b7dcc0bb21b.png

TSN 每段(segment)采样一帧视频

45595b28847012f5207cb960d931613e.png

常用训练和验证数据预处理

其中 ToTensor 操作会将 PIL.Image 或形状为 H×W×D,数值范围为 [0, 255] 的 np.ndarray 转换为形状为 D×H×W,数值范围为 [0.0, 1.0] 的 torch.Tensor。

326b074a8390015a8c19549ea56d8f67.png

5. 模型训练和测试

分类模型训练代码

1c8f645d18feaf24cb61018a5fbedb7e.png

分类模型测试代码

cef22ec2a35b645d636e976d43b3e06e.png

自定义loss

继承torch.nn.Module类写自己的loss。

fd77d8dedcbaa9aacc6e2aca61c00dcc.png

标签平滑(label smoothing)

写一个label_smoothing.py的文件,然后在训练代码里引用,用LSR代替交叉熵损失即可。label_smoothing.py内容如下:

85ff762fd028ce94798d479d2545dca7.png

或者直接在训练文件里做label smoothing

7ce6847407db67bdfa8573054b3c6086.png

Mixup训练

a7f781b53096f8cad763eaf124eb4e2d.png

L1 正则化

7d22a7861b5afa175105ab2b29a75806.png

不对偏置项进行权重衰减(weight decay)

pytorch里的weight decay相当于l2正则

82ecae10da6c472450f7f6fd0e08cae8.png

梯度裁剪(gradient clipping)

252d17a93a4fbdf5c13d69114871cf29.png

得到当前学习率

fe26f2176f9d01c49162759c7c925439.png

另一种方法,在一个batch训练代码里,当前的lr是optimizer.param_groups[0]['lr']

学习率衰减

d35c8d619370cff023623cb418854c9c.png

优化器链式更新

从1.4版本开始,torch.optim.lr_scheduler 支持链式更新(chaining),即用户可以定义两个 schedulers,并交替在训练中使用。

b3cfc0678c7109573f82739f672fe4fb.png

模型训练可视化

PyTorch可以使用tensorboard来可视化训练过程。

安装和运行TensorBoard。

pip install tensorboard
tensorboard --logdir=runs

使用SummaryWriter类来收集和可视化相应的数据,放了方便查看,可以使用不同的文件夹,比如'Loss/train'和'Loss/test'。

76aecfebfecc0210db7b12499107e3b7.png

保存与加载断点

注意为了能够恢复训练,我们需要同时保存模型和优化器的状态,以及当前的训练轮数。

02b3253ed749b1582b6d26e70b899df5.png

提取 ImageNet 预训练模型某层的卷积特征

aa610ea321baed7e5e7ecd31d99cfbf3.png

提取 ImageNet 预训练模型多层的卷积特征

5b6b69a7580ef92230fd3c6d07896643.png

微调全连接层

82094691a9d10ee2b5ba91a549725997.png

以较大学习率微调全连接层,较小学习率微调卷积层

131dc552c7842b581319c5efa1132f83.png

6. 其他注意事项

不要使用太大的线性层。因为nn.Linear(m,n)使用的是的内存,线性层太大很容易超出现有显存。

不要在太长的序列上使用RNN。因为RNN反向传播使用的是BPTT算法,其需要的内存和输入序列的长度呈线性关系。

model(x) 前用 model.train() 和 model.eval() 切换网络状态。

不需要计算梯度的代码块用 with torch.no_grad() 包含起来。

model.eval() 和 torch.no_grad() 的区别在于,model.eval() 是将网络切换为测试状态,例如 BN 和dropout在训练和测试阶段使用不同的计算方法。torch.no_grad() 是关闭 PyTorch 张量的自动求导机制,以减少存储使用和加速计算,得到的结果无法进行 loss.backward()。

model.zero_grad()会把整个模型的参数的梯度都归零, 而optimizer.zero_grad()只会把传入其中的参数的梯度归零.

torch.nn.CrossEntropyLoss 的输入不需要经过 Softmax。torch.nn.CrossEntropyLoss 等价于 torch.nn.functional.log_softmax + torch.nn.NLLLoss。

loss.backward() 前用 optimizer.zero_grad() 清除累积梯度。

torch.utils.data.DataLoader 中尽量设置 pin_memory=True,对特别小的数据集如 MNIST 设置 pin_memory=False 反而更快一些。num_workers 的设置需要在实验中找到最快的取值。

用 del 及时删除不用的中间变量,节约 GPU 存储。

使用 inplace 操作可节约 GPU 存储,如

efbe130cedef84171089f4daec57bbd6.png

减少 CPU 和 GPU 之间的数据传输。例如如果你想知道一个 epoch 中每个 mini-batch 的 loss 和准确率,先将它们累积在 GPU 中等一个 epoch 结束之后一起传输回 CPU 会比每个 mini-batch 都进行一次 GPU 到 CPU 的传输更快。

使用半精度浮点数 half() 会有一定的速度提升,具体效率依赖于 GPU 型号。需要小心数值精度过低带来的稳定性问题。

时常使用 assert tensor.size() == (N, D, H, W) 作为调试手段,确保张量维度和你设想中一致。

除了标记 y 外,尽量少使用一维张量,使用 n*1 的二维张量代替,可以避免一些意想不到的一维张量计算结果。

统计代码各部分耗时

b9adc6e8327d0a41c74257f4d4b63435.png

使用TorchSnooper来调试PyTorch代码,程序在执行的时候,就会自动 print 出来每一行的执行结果的 tensor 的形状、数据类型、设备、是否需要梯度的信息。

ce11024805189ef898a65753f6649d35.png

https://github.com/zasdfgbnm/TorchSnoopergithub.com

模型可解释性,使用captum库:https://captum.ai/captum.ai

参考资料

  1. 张皓:PyTorch Cookbook(常用代码段整理合集),https://zhuanlan.zhihu.com/p/59205847?

  2. PyTorch官方文档和示例

  3. https://pytorch.org/docs/stable/notes/faq.html

  4. https://github.com/szagoruyko/pytorchviz

  5. https://github.com/sksq96/pytorch-summary

  6. 其他

觉得还不错就给我一个小小的鼓励吧!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值