pytorch入门教程
pytorch官方中文版教程
Tensors 类似 ndarrays,Tensors可以放到GPU上计算。
构造tensor:
x = torch.rand(5, 3) #5行3列的随机矩阵
x = torch.zeros(5, 3, dtype=torch.long) #数据类型为long的全0矩阵
x = torch.tensor([5.5, 3]) #直接用数据构造一个张量
查看tensor维度信息:
x.size() #torch.Size([5, 3])
改变 tensor 的形状:
x = torch.randn(4, 4)
y = x.view(16) #torch.Size([16])
z = x.view(-1, 8) #torch.Size([2, 8]) the size -1 is inferred from other dimensions
如果一个tensor只包含一个元素,则可以使用 .item() 来获得这个元素的 value:
x = torch.randn(1)
print(x) #tensor([ 0.9422])
print(x.item()) #0.9422121644020081
使用下面语句跟踪针对tensor烦所有操作,从而能够在backward()时自动计算梯度,将该tensor的梯度累积到它的 .grad属性中
tensor.requires_grad = True
tensor.gard
with torch.no_grad():
如果不想要对tensor求梯度更新,将代码块写在这里面
计算导数:
Tensor.backward()
一个例子:
x = torch.ones(2, 2, requires_grad=True)
#x=tensor([[1., 1.],[1., 1.]], requires_grad=True)
y = x + 2
#y=tensor([[3., 3.],[3., 3.]], grad_fn=)
z = y * y * 3
out = z.mean()
#z=tensor([[27., 27.],[27., 27.]], grad_fn=)
#out=tensor(27., grad_fn=)
out.backward() #out是一个标量,backward的时候不需要参数
print(x.grad)
#tensor([[4.5000, 4.5000],[4.5000, 4.5000]])
训练神经网络的过程:
定义神经网络的例子:
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, 5x5 square convolution
# kernel
self.conv1 = nn.Conv2d(1, 6, 5)
self.conv2 = nn.Conv2d(6, 16, 5)
# an affine operation: y = Wx + b
self.fc1 = nn.Linear(16 * 5 * 5, 120)
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))
# If the size is a square you can only specify a single number
x = F.max_pool2d(F.relu(self.conv2(x)), 2)
x = x.view(-1, self.num_flat_features(x))
x = F.relu(self.fc1(x)) #一般都在全连接层后面接一个激活函数
x = F.relu(self.fc2(x))#relu这些激活函数不包含参数,不需要写在init里
x = self.fc3(x)
return x
def num_flat_features(self, x):
size = x.size()[1:] # all dimensions except the batch dimension
num_features = 1
for s in size:
num_features *= s
return num_features
net = Net()
print(net) #print可以看到网络结构
训练过程:
input = torch.randn(1, 1, 32, 32) #获取输入数据
target=torch.randn(10) #输入数据的真实标签
target = target.view(1, -1) #与输出尺寸相同,都是1x10,其中batch_size=1
out = net(input) #将数据输入到模型中,模型自动执行forward函数,此时x=input,返回输出
criterion = nn.MSELoss() #设计or选择损失函数,MSELoss是均方误差
loss = criterion(output, target) #计算误差
net.zero_grad() #将模型net的所有参数梯度缓存器置零(grad=0.),不然会一直累积梯度导致梯度爆炸
loss.backward() #反向传播得到需要更新的张量的梯度
#最简单的更新方法(落后,不推荐),一般使用 torch.optim 包中的更新方法
learning_rate = 0.01 #随机梯度下降更新参数,weight = weight - learning_rate * gradient
for f in net.parameters():
f.data.sub_(f.grad.data * learning_rate)
loss的反向传播路径,整条路径上的requires_grad=True参数都即将得到更新。
print(loss.grad_fn)
input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d
-> view -> linear -> relu -> linear -> relu -> linear
-> MSELoss
-> loss
所以,当我们调用 loss.backward(),整个图都会微分,而且所有的在图中的requires_grad=True 的张量将会让他们的 grad 张量累计梯度,此时只是计算得到了梯度,未进行参数更新。
参数更新一般使用 torch.optim 包中的更新规则
import torch.optim as optim
# create your optimizer
optimizer = optim.SGD(net.parameters(), lr=0.01)
# in your training loop:
optimizer.zero_grad() # zero the gradient buffers
output = net(input)
loss = criterion(output, target)
loss.backward()
optimizer.step() # Does the update
数据处理方面,当要处理图像,文本,语音或者视频数据时,可以使用标准 python 包将数据加载成 numpy 数组格式,然后将这个数组转换成 torch.*Tensor
特别是对于视觉,pytorch已经有一个 torchvision 包,该包含有支持加载类似Imagenet,CIFAR10,MNIST 等公共数据集的数据加载模块 torchvision.datasets 和支持加载图像数据数据转换模块torch.utils.data.DataLoader。
使用CIFAR10数据集为例,包含10个类别。CIFAR-10 中的图像尺寸为3x32x32,也就是RGB的3层颜色通道,每层通道内的尺寸为32*32。
import torch
import torchvision
import torchvision.transforms as transforms
transform = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))])
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
shuffle=True, num_workers=2)
testset = torchvision.datasets.CIFAR10(root='./data', train=False,
download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4,
shuffle=False, num_workers=2)
classes = ('plane', 'car', 'bird', 'cat',
'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
查看图片
import matplotlib.pyplot as plt
import numpy as np
# functions to show an image
def imshow(img):
img = img / 2 + 0.5 # unnormalize
npimg = img.numpy()
plt.imshow(np.transpose(npimg, (1, 2, 0)))
plt.show()
# get some random training images
dataiter = iter(trainloader)
images, labels = dataiter.next() #拿出了一个batch的数据
# show images
imshow(torchvision.utils.make_grid(images)) #将若干幅图像拼成一幅图像
# print labels
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = x.view(-1, 16 * 5 * 5)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
net = Net()
import torch.optim as optim
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
for epoch in range(2): # loop over the dataset multiple times
running_loss = 0.0
for i, data in enumerate(trainloader, 0): #从索引0开始枚举
# get the inputs
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')
correct = 0
total = 0
with torch.no_grad():
for data in testloader:
images, labels = data
outputs = net(images)
_, predicted = torch.max(outputs.data, dim=1) #return (values, indices)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print('Accuracy of the network on the 10000 test images: %d %%' % (
100 * correct / total))
将神经网络转移到GPU上
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
#定义设备device为第一个可见的cuda设备
print(device) #cuda:0
net.to(device) #递归地遍历所有模块,并将它们的参数和缓冲器转换为CUDA张量。
出了网络要放到GPU上,记住必须在每一个步骤向GPU发送输入和目标:
inputs, labels = inputs.to(device), labels.to(device)
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.to(device) #将模型放上gpu 0
mytensor = my_tensor.to(device) #将张量复制到gpu 0
PyTorch 默认只会使用一个 GPU,想要多CPU运行则要用到 DataParallel
model = nn.DataParallel(model)
一个简单的DataSet类模板
class RandomDataset(Dataset):
def __init__(self, size, length):
self.len = length
self.data = torch.randn(length, size)
def __getitem__(self, index):
return self.data[index]
def __len__(self):
return self.len
rand_loader = DataLoader(dataset=RandomDataset(input_size, data_size), batch_size=batch_size, shuffle=True)
用nn.DataParallel包裹model,然后再放到多GPU上。
model = Model(input_size, output_size)
if torch.cuda.device_count() > 1:
print("Let's use", torch.cuda.device_count(), "GPUs!")
# dim = 0 [30, xxx] -> [10, ...], [10, ...], [10, ...] on 3 GPUs
model = nn.DataParallel(model)
model.to(device)
数据并行自动拆分数据,并且将任务单发送到多个 GPU 上。当每一个模型都完成自己的任务之后,DataParallel 收集并且合并这些结果,然后再返回给你。
一般是在第一个维度,即batch_size这个维度上拆分数据的。
for data in rand_loader:
input = data.to(device)
output = model(input)
print("Outside: input size", input.size(),
"output_size", output.size())
参数设置:
input_size = 5
output_size = 2
batch_size = 30
data_size = 100
如果有2个GPU:
In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
如果有3个GPU:
In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])