pytorch问题大全
本文目录
实验室定期的学习交流会,整理一份我自己主讲的pytorch框架的笔记,主要针对看论文学习过程中遇到的一些问题,因为之前是学的tensorflow
一、pytorch的简单说明
1️⃣PyTorch 的设计遵循tensor
→variable(autograd)
→nn.Module
2️⃣三个由低到高的抽象层次,分别代表高维数组(张量)
、自动求导(变量)
和神经网络(层/模块)
,而且这三个抽象之间联系紧密,可以同时进行修改和操作
3️⃣PyTorch的源码只有TensorFlow的十分之一左右,更少的抽象、更直观的设计使得PyTorch的源码更易于阅读
🍦特点
- PyTorch 提供了运行在
GPU/CPU
之上、基础的张量操作库; - 可以内置的神经网络库;
- 提供模型训练功能;
- 支持共享内存的多进程并发(multiprocessing )库等;
- 处于机器学习第一大语言 Python 的生态圈之中,使得开发者能使用广大的 Python 库和软件;如 NumPy、SciPy 和 Cython(为了速度把 Python 编译成 C 语言);
- (最大优势)改进现有的神经网络,提供了更快速的方法——不需要从头重新构建整个网络,这是由于 PyTorch 采用了动态计算图(dynamic computational graph)结构,而不是大多数开源框架(TensorFlow、Caffe、CNTK、Theano 等)采用的静态计算图;
- 提供工具包,如
torch
、torch.nn
、torch.optim
等;
📂Pytorch常用工具包
torch
:类似 NumPy 的张量库,强 GPU 支持 ;torch.autograd
:基于 tape 的自动区别库,支持 torch 之中的所有可区分张量运行;torch.nn
:为最大化灵活性未涉及、与 autograd 深度整合的神经网络库;torch.optim
:与 torch.nn 一起使用的优化包,包含 SGD、RMSProp、LBFGS、Adam 等标准优化方式;torch.multiprocessing
: python 多进程并发,进程之间 torch Tensors 的内存共享;torch.utils
:数据载入器。具有训练器和其他便利功能;torch.legacy(.nn/.optim)
:处于向后兼容性考虑,从 Torch 移植来的 legacy 代码;
二、pytorch resnet专题📌
resnet18
数字代表的是网络的深度,这里的18指定的是带有权重的18层,包括卷积层和全连接层,不包括池化层和BN层
从Resnet论文中的这张图可以看出,Resnet18由17个卷积层+1个全连接层组成
无论哪一种resnet,除了公共部分(conv1)
外,都是由4大块组成,con2x
, con3x
, con4x
, con5x
我笔记里面提到的动态区就是这4大块,静态区就是conv1
了
BasicBlock和Bottleneck的区别
1️⃣ BasicBlock 两层的残差块 resnet18/34
class BasicBlock(nn.Module):
"""
"""
def __init__(self, inplanes, planes, stride=1):
super(BasicBlock, self).__init__()
self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
self.bn1 = nn.BatchNorm2d(planes)
self.relu = nn.ReLU(inplace=True)
self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, padding=1, bias=False)
self.bn2 = nn.BatchNorm2d(planes)
# 重要的forward函数
def forward(self, x):
residual = x
out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out)
out = self.conv2(out)
out = self.bn2(out)
out += residual
out = self.relu(out)
return out
2️⃣ Bottleneck 三层的残差块 resnet50/101/152
class Bottleneck(nn.Module):
def __init__(self, inplanes, planes, stride=1, downsample=None):
super(Bottleneck, self).__init__()
self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, stride=stride, bias=False)
self.bn1 = nn.BatchNorm2d(planes)
self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False)
self.bn2 = nn.BatchNorm2d(planes)
self.conv3 = nn.Conv2d(planes, planes*4, kernel_size=1, bias=False)
self.bn3 = nn.BatchNorm2d(planes*4)
self.relu = nn.ReLU(inplace=True)
def forward(self, x):
residual = x
out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out)
out = self.conv2(out)
out = self.bn2(out)
out = self.relu(out)
out = self.conv3(out)
out = self.bn3(out)
out += residual
out = self.relu(out)
return out
三、add_module()
📕为什么要用add_module()函数
- 某些pytorch项目,需要动态调整结构。比如简单的三层全连接 l 1 , l 2 , l 3 l1, l2, l3 l1,l2,l3,在训练几个epoch后根据loss选择将全连接 l 2 l2 l2 替换为其它结构 l 2 ′ l2′ l2′
- 使用了别人编写的pytorch代码,希望快速地将模型中的特定结构替换掉而不改动别人的源码。
📗什么是add_module()函数
可以看到,是Module类的成员函数,输入参数为
Module.add_module(name: str, module: Module)
功能为,为Module添加一个子module,对应名字为name。
📘怎么用add_module()函数
现在回忆一下,一般定义模型时,Module A的子module都是在A.init(self)
中定义的,比如A中一个卷积子模块self.conv1 = torch.nn.Conv2d(…)
。此时,这个卷积模块在A的名字其实是’conv1’。
对比之下,add_module()函数就可以在A.init(self
以外定义A的子模块。如定义同样的卷积子模块,可以通过A.add_module(‘conv1’, torch.nn.Conv2d(…))
。
以上是给A添加一个子模块。那么删除就是del A.conv1
。而替换同样采用add_module()函数,只要name与被替换模块相同即可完成替换。如之前已经定义了A.conv1,但此时希望将其替换为新的自定义模块NewOne(torch.nn.Module),只需要A.add_module(‘conv1’, NewOne())
即可。
🔔注意事项<