记录&总结一下自己写model时需要用到的函数。官方文档
pytorch-lightning
torchvision
torch.nn.Conv1d(in_channels, #int 输入信号的通道
out_channels, # int 卷积产生的通道
kernel_size, # int/tuple 卷积核的尺寸
stride=1, #int/tuple, opt卷积步长
padding=0, #int/tuple, opt 输入的每一条边补充0的层数
dilation=1, #int/tuple, opt 卷积核元素之间的间距
groups=1, #int, opt 从输入通道到输出通道的阻塞连接数
bias=True # bool, opt 如果bias=True,添加偏置)
shape
输入: ( N , C i n , L i n ) (N,C_{in},L_{in}) (N,Cin,Lin)
weight: ( C o u t , C i n , k _ s ) (C_{out}, C_{in}, k\_s) (Cout,Cin,k_s) Cout个卷积核并行运算
输出: ( N , C o u t , L o u t ) (N,C_{out},L_{out}) (N,Cout,Lout)
L o u t = [ L i n + 2 p − d ( k _ s − 1 ) − 1 ] / s + 1 L_{out}=[L_{in}+2p-d(k\_s-1)-1]/s+1 Lout=[Lin+2p−d(k_s−1)−1]/s+1
con1d的输入输出的计算方式
Example
# [1,5,7] 卷积核[2,5,3] = [1, 3, 6]
a = torch.ones(1,5,7)
b = nn.Conv1d(in_channels=5, out_channels=3, kernel_size=2)(a)
print(b.size()) #torch.Size([1, 3, 6])
torch.nn.Conv2d(in_channels,
out_channels,
kernel_size,
stride=1,
padding=0,
dilation=1,
groups=1,
bias=True)
参数kernel_size
,stride,padding
,dilation
shape
输入: ( N , C i n , H i n , W i n ) (N, C_{in}, H_{in}, W_{in}) (N,Cin,Hin,Win)
weight: ( C o u t , C i n , k _ s ) (C_{out}, C_{in}, k\_s) (Cout,Cin,k_s)
输出: ( N , C o u t , H o u t , W o u t ) (N, C_{out}, H_{out}, W_{out}) (N,Cout,Hout,Wout)
H o u t = [ H i n + 2 p [ 0 ] − d [ 0 ] ( k _ s [ 0 ] − 1 ) − 1 ] / s [ 0 ] + 1 W o u t = [ W i n + 2 p [ 1 ] − d [ 1 ] ( k _ s [ 1 ] − 1 ) − 1 ] / s [ 1 ] + 1 H_{out}=[H_{in}+2p[0]-d[0](k\_s[0]-1)-1]/s[0]+1 \\ W_{out}=[W_{in}+2p[1]-d[1](k\_s[1]-1)-1]/s[1]+1 Hout=[Hin+2p[0]−d[0](k_s[0]−1)−1]/s[0]+1Wout=[Win+2p[1]−d[1](k_s[1]−1)−1]/s[1]+1
1维的解卷积操作(transposed convolution operator,注意改视作操作可视作解卷积操作,但并不是真正的解卷积操作)
注意
由于内核的大小,输入的最后的一些列的数据可能会丢失。因为输入和输出是不是完全的互相关。因此,用户可以进行适当的填充(padding操作)。
torch.nn.ConvTranspose1d(in_channels,
out_channels,
kernel_size,
stride=1,
padding=0, #输入的每一条边补充0的层数
output_padding=0, #输出的每一条边补充0的层数
groups=1,
bias=True)
shape
输入: ( N , C i n , L i n ) (N,C_{in},L_{in}) (N,Cin,Lin)
输出: ( N , C o u t , L o u t ) (N,C_{out},L_{out}) (N,Cout,Lout)
L o u t = ( L i n − 1 ) s − 2 p + k _ s + o _ p L_{out}=(L_{in}-1)s-2p+k\_s+o\_p Lout=(Lin−1)s−2p+k_s+o_p
变量
self.rnn = nn.LSTM(self.ninput, self.nhidden,
self.nlayers, batch_first=True,
dropout=self.drop_prob, bidirectional=self.bidirectional)
回顾模型保存:torch.save(model.state_dict())
,model.state_dict()
是一个字典,里边存着我们模型各个部分的参数。
在model中,我们需要更新其中的参数,训练结束将参数保存下来。但在某些时候,我们可能希望模型中的某些参数参数不更新(从开始到结束均保持不变),但又希望参数保存下来(model.state_dict()
),这是我们就会用到 register_buffer()
参考网址
torch.nn.BCELoss(weight=None, size_average=True)
计算了输出与target之间的二进制交叉熵
l o s s ( o , t ) = − 1 n ∑ i [ t [ i ] l o g ( o [ i ] ) + ( 1 − t [ i ] ) l o g ( 1 − o [ i ] ) ] loss(o,t)=-\frac{1}{n}\sum_i[t[i] log(o[i])+(1-t[i]) log(1-o[i])] loss(o,t)=−n1i∑[t[i]log(o[i])+(1−t[i])log(1−o[i])] 如果weight被指定 : l o s s ( o , t ) = − 1 n ∑ i w e i g h t s [ i ] ( t [ i ] l o g ( o [ i ] ) + ( 1 − t [ i ] ) ∗ l o g ( 1 − o [ i ] ) ) loss(o,t)=-\frac{1}{n}\sum_iweights[i] (t[i] log(o[i])+(1-t[i])* log(1-o[i])) loss(o,t)=−n1i∑weights[i](t[i]log(o[i])+(1−t[i])∗log(1−o[i]))
这个用于计算 auto-encoder 的 reconstruction error。注意 0<=target[i]<=1。
默认情况下,loss会基于element平均,如果size_average=False的话,loss会被累加。
.cuda()
cuda放到了gpu上,CPU和GPU的tensor不能直接想加,会报错
设置gpu
#第一种写法(更推荐)
import os
os.environ[“CUDA_VISIBLE_DEVICES”] = “2”
#第二种写法pytorch
import torch
torch.cuda.set_device(id)
打印当前gpu
numpy->torch
>>> a=np.ones(5)
>>> b=torch.from_numpy(a)
torch->numpy
>>> a = torch.ones(5)
>>> b=a.numpy()
参考:
https://zhuanlan.zhihu.com/p/55419865
开始改模型代码的时候发现模型里的torch有很多维度变换,不熟悉这些函数或者不认真看的话就数据维度就会乱七八糟,自己改的模型很容易跑不起来(在这里反省一下我本科居然读的还是软件工程,真的好不专业TAT)
参数的个数,不能少于被操作的张量的维度的个数
>>> a = torch.randn(33, 55)
>>> a.size()
torch.Size([33, 55])
>>> a.repeat(1,2).size() # 原始值:torch.Size([33, 55])
torch.Size([33, 110])
>>> a.repeat(1,1,2).size() # 原始值:torch.Size([33, 55])
torch.Size([1, 33, 110])
>>> a.repeat(1,1,1,1).size() # 原始值:torch.Size([33, 55])
torch.Size([1, 1, 33, 55])
transpose()
交换指定的两个维度的内容
>>>a = torch.tensor([[[1, 2, 3, 4], [4, 5, 6, 7]], [[7, 8, 9, 10], [10, 11, 12, 13]], [[13, 14, 15, 16], [17, 18, 19, 20]]])
>>>print(a, a.shape)
tensor([[[ 1, 2, 3, 4],[ 4, 5, 6, 7]],
[[ 7, 8, 9, 10],[10, 11, 12, 13]],
[[13, 14, 15, 16],[17, 18, 19, 20]]])
torch.Size([3, 2, 4])
>>>b = a.transpose(1,2)
>>>print(b, b.shape)
tensor([[[ 1, 4],
[ 2, 5],
[ 3, 6],
[ 4, 7]],
[[ 7, 10],
[ 8, 11],
[ 9, 12],
[10, 13]],
[[13, 17],
[14, 18],
[15, 19],
[16, 20]]])
torch.Size([3, 4, 2])
permute()
可以一次性交换多个维度
>>>c = a.permute(2, 1, 0)
>>>print(c, c.shape)
tensor([[[ 1, 7, 13],
[ 4, 10, 17]],
[[ 2, 8, 14],
[ 5, 11, 18]],
[[ 3, 9, 15],
[ 6, 12, 19]],
[[ 4, 10, 16],
[ 7, 13, 20]]]) torch.Size([4, 2, 3])
把原先tensor中的数据按照行优先的顺序排成一个一维的数据(地址是连续存储的),然后按照参数组合成其他形状的tensor。(相当于tensorflow里边的reshape)
参数不可为空,参数中的-1就代表这个位置由其他位置的数字来推断,不允许同时有两个-1。
view()不影响传入的tensor
>>> a=torch.Tensor([[[1,2,3],[4,5,6]]])
>>> print(a.view(3,2))
tensor([[1., 2.],
[3., 4.],
[5., 6.]])
torch.squeeze()
用于对数据的维度进行压缩,去掉维数为1的的维度。squeeze(a)就是将a中所有为1的维度删掉,不为1的维度没有影响。a.squeeze(N) 和 b=torch.squeeze(a,N) 就是去掉a中指定的维数为一的维度。
torch.unsqueeze()
用于对数据维度进行扩充,给指定位置加上维数为一的维度。a.squeeze(N) 和 b=torch.squeeze(a,N) 就是在a中指定位置N加上一个维数为1的维度。
torch.rand(*sizes, out=None)
→ Tensor用来计算两个tensor之间乘积(两个tensor必须都是三维的)
维度有限制,要求啊a,b两个tensor有如下格式:
a: ( z , x , y ) (z,x,y) (z,x,y)
b: ( z , y , c ) (z,y,c) (z,y,c)
则result = torch.bmm(a,b),维度为: ( z , x , c ) (z,x,c) (z,x,c)
Pytorch计算机视觉工具包,包含三大模块
torchvision.transforms
: 常用的图像预处理方法
• 数据中心化\quad• 数据标准\quad• 缩放 \quad• 裁剪
• 旋转\quad• 翻转\quad• 填充 \quad• 噪声添加
• 灰度变换\quad• 线性变换\quad• 仿射变换\quad• 亮度、饱和度及对比度变换
torchvision.datasets
: 常用数据集的dataset实现,MNIST,CIFAR-10,ImageNet等
torchvision.models
: 常用的模型预训练,AlexNet,VGG, ResNet,GoogLeNet等
参考:torchvision / torchvision官方文档
self.norm = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
image_transform = transforms.Compose([
transforms.Scale(int(imsize * 76 / 64)),
transforms.RandomCrop(imsize),
transforms.RandomHorizontalFlip()])
transforms.Normalize(mean,std,inplace=False)
功能:逐channel的对图像进行标准化
o u t p u t = i n p u t − m e a n s t d output =\frac{input-mean}{std} output=stdinput−mean
• mean:各通道的均值
• std:各通道的标准差
• inplace:是否原地操作
transforms.ToTensor()
将shape为(H, W, C)的nump.ndarray
或img
转为shape为(C, H, W)的tensor
,其将每一个数值归一化到[0,1],其归一化方法比较简单,直接除以255即可。
transforms.Resize(size[, interpolation, max_size, …])
用于对载入的图片数据按需求的大小进行缩放。
size可以是一个整形数据,也可以是一个类似于(h,w)的序列,其中,h代表高度,w代表宽度,但是如果使用的是一个整形数据,那么代表缩放的宽度和高度都是这个整形数据的值。
transforms.Scale()
用于对载入的图片数据按需求进行缩放,和torchvision.transforms.Resize()用法类似。
transforms.RandomCrop(size, padding=None, pad_if_needed=False, fill=0, padding_mode='constant')
Crop the given image at a random location.
transforms.RandomHorizontalFlip(p=0.5)
Horizontally flip the given image randomly with a given probability.
models
model = models.inception_v3()
url = 'https://download.pytorch.org/models/inception_v3_google-1a9a5a14.pth'
model.load_state_dict(model_zoo.load_url(url))
for param in model.parameters():
param.requires_grad = False
ViT_H_14_Weights.IMAGENET1K_SWAG_E2E_V1
Acc@1 88.552
Acc@5 98.694
633.5M
可以理解为keras之于tensorflow
为了让用户能够脱离PyTorch一些繁琐的细节,专注于核心代码的构建,提供了许多实用工具,可以让实验更加高效
PyTorch Lightning 官方文档
参考教程
Lightning将大部分AI相关代码分为三个部分:
研究代码,主要是模型的结构、训练等部分。被抽象为LightningModule类
。
研究代码可划分为以下几个组件:
工程代码,这部分代码重复性强,比如16位精度,分布式训练。被抽象为Trainer类
。
非必要代码,这部分代码和实验没有直接关系,不加也可以,加上可以辅助,比如梯度检查,log输出等。被抽象为Callbacks类
。
import pytorch_lightning as pl
pl.seed_everything(1234) # 这个是用于固定seed用
# args
parser = ArgumentParser()
parser = pl.Trainer.add_argparse_args(parser)
parser = LitClassifier.add_model_specific_args(parser)
parser = MNISTDataModule.add_argparse_args(parser)
args = parser.parse_args()
# data
dm = MNISTDataModule.from_argparse_args(args)
# model
model = LitClassifier(args.hidden_dim, args.learning_rate)
# training
trainer = pl.Trainer.from_argparse_args(args)
trainer.fit(model, datamodule=dm)
result = trainer.test(model, datamodule=dm)
pprint(result)
GPU 相关的 flag:在一般场景下,只要简单地在 PyTorch 程序开头将其值设置为 True,就可以大大提升卷积神经网络的运行速度。