Pytorch学习
一些简单记录
一、基本语法
1.Tensor
-
创建Tensor:
#创建未初始化矩阵
x = torch.empty(5,3)#创建零初始化矩阵
x = torch.zeros(5,3 dtype=torch.long) #dtype是参数类型,可以更改#创建一初始化矩阵
x = x.new_ones(5, 3, dtype=torch.double)#从已有Tensor生成Tensor
x = torch.randn_like(x, dtype=torch.float) #此处dtype可以随意更改 -
Tensor计算:
y = torch.rand(5, 3)
#用add函数来实现加法
torch.add(x, y)#可以给加法提供返回值(而不是生成一个新的返回值)
result = torch.empty(5, 3)
torch.add(x, y, out=result) # x + y的结果放到result里。#可以把相加的结果直接修改第一个被加数
#把x加到y
y.add_(x) -
Tensor变换:
#打印x的第一列
print(x[:, 1])#想resize或者reshape一个Tensor,我们可以使用torch.view
x = torch.randn(4, 4)
y = x.view(16)
z = x.view(-1, 8) # -1的意思是让PyTorch自己推断出第一维的大小。
print(x.size(), y.size(), z.size())#如果一个tensor只有一个元素,可以使用item()函数来把它变成一个Python number
x = torch.randn(1)
print(x)
#输出的是一个Tensor
tensor([-0.6966])
print(x.item())
#输出的是一个数
-0.6966081857681274#把NumPy数组转成Torch Tensor
torch.from_numpy(a) -
CUDA Tensor
#如果有CUDA
#我们会使用torch.device来把tensors放到GPU上
if torch.cuda.is_available():
device = torch.device(“cuda”) #一个CUDA device对象。
y = torch.ones_like(x, device=device) # 直接在GPU上创建tensor
x = x.to(device) # 也可以使用.to(“cuda”)把一个tensor从CPU移到GPU上
z = x + y
print(z)
print(z.to(“cpu”, torch.double)) # .to也可以在移动的过程中修改dtype#输出:
tensor([ 0.3034], device=‘cuda:0’)
tensor([ 0.3034], dtype=torch.float64)
2、自动求导Autograd
-
torch.Tensor 是这个包的核心类。如果它的属性
requires_grad是True
,那么PyTorch就会追踪所有与之相关的operation
。当完成(正向)计算之后, 我们可以调用backward()
,PyTorch会自动的把所有的梯度都计算好
。与这个tensor相关的梯度都会累加到它的grad属性里。 -
如果不想计算这个tensor的梯度,我们可以
调用detach()
,这样它就不会参与梯度的计算
了。为了阻止PyTorch记录用于梯度计算相关的信息(从而节约内存),我们可以使用 with torch.no_grad()。这在模型的预测时非常有用,因为预测的时候我们不需要计算梯度,否则我们就得一个个的修改Tensor的requires_grad属性,这会非常麻烦。 -
关于autograd的实现还有一个很重要的Function类。Tensor和Function相互连接从而形成一个有向无环图, 这个图记录了计算的完整历史。
每个tensor有一个grad_fn属性来引用创建这个tensor的Function
(用户直接创建的Tensor,这些Tensor的grad_fn是None)。 -
如果你想计算梯度,可以对一个Tensor调用它的backward()方法。如果这个Tensor是一个scalar(只有一个数),那么调用时不需要传任何参数。如果Tensor多于一个数,那么需要传入和它的shape一样的参数,表示反向传播过来的梯度。
#创建tensor时设置属性requires_grad=True,PyTorch就会记录用于反向梯度计算的信息:
x = torch.ones(2, 2, requires_grad=True)
#然后通过operation产生新的tensor:
y = x + 2
#y是通过operation产生的tensor,因此它的grad_fn不是None#requires_grad_()函数会修改一个Tensor的requires_grad
a.requires_grad_(True)
print(a.requires_grad)
二、创建神经网络
1、创建网络
可以通过torch.nn包来创建,nn会使用autograd来定义模型以及求梯度,一个nn.Module对象包括了许多网络层(layer),并且有一个forward(input)方法来返回output
#创建网络
class Net(nn.Module):
#定义网络层
def __init__(self):
super(Net, self).__init__()
# 输入是1个通道的灰度图,输出6个通道(feature map),使用5x5的卷积核
self.conv1 = nn.Conv2d(1, 6, 5)
# 第二个卷积层也是5x5,有16个通道
self.conv2 = nn.Conv2d(6, 16, 5)
、、、
#前向传播
def forward(self, x):
# 32x32 -> 28x28 -> 14x14
x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
# 14x14 -> 10x10 -> 5x5
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))
x = self.fc3(x)
return x
def num_flat_features(self, x):
size = x.size()[1:] # 除了batch维度之外的其它维度。
num_features = 1
for s in size:
num_features *= s
return num_features
net = Net()
#使用网络:
out = net(input)
#默认的梯度会累加,因此我们通常在backward之前清除掉之前的梯度值
net.zero_grad()
out.backward(torch.randn(1, 10))
注意:torch.nn只支持mini-batches的输入。整个torch.nn包的输入都必须第一维是batch,即使只有一个样本也要弄成batch是1的输入。
比如,nn.Conv2d的输入是一个4D的Tensor,shape是nSamples x nChannels x Height x Width。如果你只有一个样本(nChannels x Height x Width),那么可以使用input.unsqueeze(0)来增加一个batch维。
2、损失函数
损失函数的参数是(output, target)对,output是模型的预测,target是实际的值。
criterion = nn.MSELoss()
loss = criterion(output, target)
当调用loss.backward()时,PyTorch会计算这个图中所有requires_grad=True的tensor关于loss的梯度
3、计算梯度
在调用loss.backward()之前,我们需要清除掉tensor里之前的梯度,否则会累加进去。
net.zero_grad()
loss.backward()
4、更新参数
使用torch.optim包:
import torch.optim as optim
# 创建optimizer,需要传入参数和learning rate
optimizer = optim.SGD(net.parameters(), lr=0.01)
# 清除梯度
optimizer.zero_grad()
output = net(input)
loss = criterion(output, target)
loss.backward()
optimizer.step() # optimizer会自动帮我们更新参数
三、使用技巧
1、指定GPU
import torch
dtype = torch.float
#device = torch.device("cpu")
device = torch.device("cuda:0")
2、创建网络过程中的问题:
# N是batch size;D_in是输入大小
# H是隐层的大小;D_out是输出大小。
N, D_in, H, D_out = 64, 1000, 100, 10
-
输入和输出需要的requires_grad=False(默认),因为我们不需要计算loss对它们的梯度。
x = torch.randn(N, D_in, device=device, dtype=dtype) y = torch.randn(N, D_out, device=device, dtype=dtype)
-
建weight的Tensor,需要设置requires_grad=True
w1 = torch.randn(D_in, H, device=device, dtype=dtype, requires_grad=True)
w2 = torch.randn(H, D_out, device=device, dtype=dtype, requires_grad=True)