第一章 What is pytorch?
初始化
torch.empty(3,4)
生成未初始化的tensor
torch.rand(5,3)
随机初始化
torch.zeros(3,4)
用0初始化
torch.tensor([3,4,5])
从list初始化
torch.from_numpy(arr)
从numpy初始化
x.new_ones(5, 3, dtype=torch.double)
从已有的tensor全一初始化,继承x的所有属性,包括device,dtype等
x = torch.randn_like(x, dtype=torch.float)
从已有的tensor随机初始化,shape同x
tensor基本操作
x.size()
查看shape
torch.add(x, y)
加法
torch.add(x, y, out=result)
把结果保存到result,result可能需要提前用empty或其他方式声明
y.add_(x)
加法,注意,所有 a.操作() 的方法都有一个_后缀
x.view(-1, 8)
pytorch中的resize
x.item()
查看x的具体数值
a.numpy()
把tensor转换成numpy.array
注意! 无论是numpy转tensor还是tensor转Numpy,他们都共享地址,变更一个的值另外一个也会跟着变!
第二章 AUTOGRAD: AUTOMATIC DIFFERENTIATION
tensor的一些属性
requires_grad=True
设置tensor是否自动求导,为true的话会自动搜集求导需要的信息
如果全都不需要反向传播(比如测试的时候),可以用with torch.no_grad():关闭所有的
也可以通过**a.requires_grad_(True)**来改变一个tensor的属性(默认是False)
grad_fn
只要tensor是由一个操作比如加减法得到的,就有grad_fn属性,指明了得到tensor的方法,比如grad_fn=<AddBackward0>
out.backward()
对out进行后向传播,同时out所涉及到的tensor的梯度会被记录在其grad属性中,如x.grad
backward的参数问题参考https://www.cnblogs.com/JeasonIsCoding/p/10164948.html
结论是参数维度应该与out维度相同,同时把参数看做一个行向量arg,最终其他tensor的雅克比矩阵就为( arg * Jacobi )T
第三章 NEURAL NETWORKS
Define the network
CLASS torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode=‘zeros’)
nn.Conv2d()定义一个卷积层,eg.self.conv2 = nn.Conv2d(6, 16, 3)
Conv2d()是二维卷积,就是对图像的卷积,而Conv1d是一维卷积,是对文本数据的卷积。
CLASS torch.nn.Linear(in_features, out_features, bias=True)
nn.Linear()定义一个线性层,eg.self.fc1 = nn.Linear(16 * 6 * 6, 120)
torch.nn与torch.nn.functional之间的区别和联系
参考https://blog.csdn.net/GZHermit/article/details/78730856
与https://blog.csdn.net/xiaohuihui1994/article/details/89207534
结论是nn.Conv2d是建立一个类,建立时weight,bias等变量(Variable)已经定义好了,不用再手动去定义,同时由于是class,需要先在init中实例化,才能在forward中使用,于是如果层内有Variable(如全链接层,卷积层),那么用nn定义,反之(如pooling,relu),则用nn.functional定义,同时nn定义的层都是写在init里的
看下面代码中的中文注释
import torch
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
# 1 input image channel, 6 output channels, 3x3 square convolution
# kernel
self.conv1 = nn.Conv2d(1, 6, 3)#先实例化一个Conv2d类
self.conv2 = nn.Conv2d(6, 16, 3)#再实例化一个Conv2d类
# an affine operation: y = Wx + b
self.fc1 = nn.Linear(16 * 6 * 6, 120) # 6*6 from image dimensio
#卷积输出大小=[(输入大小-卷积核(过滤器)大小+2*P)/步长]+1
#池化输出大小=[(输入大小-卷积核(过滤器)大小)/步长]+1
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
# Max pooling over a (2, 2) window
x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))#conv1->relu->maxpool这行语句定义了三层网络
# If the size is a square you can only specify a single number
x = F.max_pool2d(F.relu(self.conv2(x)), 2)#再经过一个conv->relu->maxpool层
x = x.view(-1, self.num_flat_features(x))#改变上层输出的shape,保留第一个维度的值,把x变为2维的,因为全连接层必须要2维的输入?
x = F.relu(self.fc1(x))#经过一个全链接层
x = F.relu(self.fc2(x))#又一个全链接层
x = self.fc3(x)#最后一个全连接层,输出
return x
def num_flat_features(self, x):
size = x.size()[1:] # all dimensions except the batch dimension x.size()得到的是一个list,x的shape,[1:]即将list切片,不要第一个数
num_features = 1
for s in size:#遍历list
num_features *= s
return num_features
net = Net()
print(net)
Note: 为什么Conv2d是一个类,但是却可以当做函数使用呢?:self.conv1(x)
答:Conv2d的顶级父类定义了__call__()函数,这样就可以把类当函数使用了
net.parameters()返回网络的所有参数,包括每层的weight,bias等
另外注意,net(input),input默认是4维的,也就是个数*channels*w*h,如果你只有一个样本,那么就要用input.unsqueeze(0)
去增加一个维度
Loss Function
criterion = nn.MSELoss()#先实例化均方误差类
loss = criterion(output, target)#得到Loss
Backprop
在后向传播之前,要先清除掉之前的梯度值
net.zero_grad()
然后直接loss.backward()就好(把各个参数求导后的梯度值赋给他们的grad)
Update the weights
方法一:直接遍历所有的参数,用它自己减去学习率*梯度值
for f in net.parameters():
f.data.sub_(f.grad.data * learning_rate)
方法二:用torch.optim建立优化器来优化
CLASS torch.optim.SGD(params, lr=, momentum=0, dampening=0, weight_decay=0, nesterov=False)
eg.
import torch.optim as optim
# create your optimizer
optimizer = optim.SGD(net.parameters(), lr=0.01)#优化器包含所有参数,设置学习率
optimizer.zero_grad() # zero the gradient buffers同样要把梯度置0
output = net(input)
loss = criterion(output, target)
loss.backward()
optimizer.step() # Does the update 更新优化所有参数
第四章 TRAINING A CLASSIFIER
前言
对于cv,pytorch有专门的包torchvision可以处理常见的数据集,如Imagenet, CIFAR10, MNIST, etc,比如torchvision.datasets 和 torch.utils.data.DataLoader
除此之外,也可以用其他的python包来处理,
对于image,可以用Pillow,OpenCV; 音频audio可以用scipy and librosa; 文本用其他的……
Loading and normalizing CIFAR10
首先设置好要进行的处理
用torch.transforms
transform = transforms.Compose(
[transforms.ToTensor(),#ToTensor是把PIL image或者numpy array转换成tensor
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])#torchvision.transforms.Normalize(mean, std, inplace=False)
#因为有三个通道所以有三个mean\std?
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
download=True, transform=transform)
#这里的获取的trainset不是numpy也不是tensor,是单独的一个CIFAR类
Train the network
主要说一下网络训练这一部分的代码
for epoch in range(2): # loop over the dataset multiple times
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
#这里dataloader被enumerate之后,i就是index,data为一个list,包含x和y,也就是inputs和labels
#每次迭代抛出一个iteration的数据?也就是说i是iteration的index,每个iteration用一个batch的数据
# get the inputs; data is a list of [inputs, labels]
inputs, labels = data
# zero the parameter gradients
optimizer.zero_grad()
# forward + backward + optimize
outputs = net(inputs)#输入数据得到输出
loss = criterion(outputs, labels)计算损失函数
loss.backward()#梯度后向传播
optimizer.step()#优化
# print statistics
running_loss += loss.item()
if i % 2000 == 1999: # print every 2000 mini-batches
print('[%d, %5d] loss: %.3f' %
(epoch + 1, i + 1, running_loss / 2000))
running_loss = 0.0
print('Finished Training')
CLASS torchvision.transforms.Compose(transforms)
Compose就是把很多种transforms集合在一起,参数为transorms类的list,比如上面示例中的transforms.ToTensor和transforms.Normalize
torchvision.utils.make_grid(imagelist)
把多个图像做成一个表格tensor
iter()与enumerate()函数
iter()
生成迭代器,返回迭代器对象
迭代器可以用.next()返回下一个,也可以用for循环遍历
eg.
for i in iter(lst):
print(i)
enumerate()
将一个可遍历的数据对象变为(索引,对象)的序列
eg.
>>>seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
>>> list(enumerate(seasons, start=1)) # 下标从 1 开始
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
因为有索引,所以用for遍历时要for i,element in enumerate(seq)
torch.max()
(1)torch.max(tensor)
返回tensor中的最大值
(2)torch.max(tensor,dim)
返回tensor中的最大值及他们对应的index
eg.
>> a
0.0692 0.3142 1.2513 -0.5428
0.9288 0.8552 -0.2073 0.6409
1.0695 -0.0101 -2.4507 -1.2230
0.7426 -0.7666 0.4862 -0.6628
torch.FloatTensor of size 4x4]
>>> torch.max(a, 1)
(
1.2513
0.9288
1.0695
0.7426
[torch.FloatTensor of size 4x1]#每行的最大值
,
2
0
0
0
[torch.LongTensor of size 4x1]#最大值对应的索引
)
torch.squeeze(input, dim=None, out=None)
将tensor的shape中的1去除,比如输入形状为: (A×1×B), squeeze(input, 0) 将会保持张量不变,只有用 squeeze(input, 1),形状会变成 (A×B)。
第五章 DATA PARALLELISM
如何让模型使用多GPU
model = nn.DataParallel(model)
这是最基本的用法