Pytorch官方教程【Deep Learning with PyTorch: A 60 Minute Blitz】学习笔记

Tensor基础

pytorch中的数据以tensor的形式存在,类似于numpy中的ndarrays。可以更好地利用GPU加速运算。

torch.empty(): 定义了一个未被初始化的张量,会被随机初始化为内存中的值。

torch.random() 定义一个值为随机数的张量。

torch.zeros(行数,列数,dtype=torch.long) 定义一个值为0的张量

torch.tensor([1,2,3,4]) 根据给出的数据定义一个张量

还可以从已有的张量(x)中定义一个新的张量,如果不进行指定会复用输入张量的属性(如dtype)

x = x.new_ones(5, 3, dtype=torch.double)      # new_* methods take in sizes
print(x)

x = torch.randn_like(x, dtype=torch.float)    # override dtype!
print(x)                                      # result has the same size

x.size() 会输入一个张量大小的元组,支持所有元组的操作。

加法操作:

  x+y 或 torch.add(x,y,output=...),指定output参数则将结果赋给该参数

  y.add_(x) ,y本身的值会改变

  操作后加上下划线“_”表示进行的是in-place操作,会改变本身的值。例如 x.copy_(y), x.t_()

可以像numpy一样对张量进行索引

resize/reshape:

  使用 torch.view() 函数,会根据指定参数从原张量中按顺序取元素重组。

x = torch.randn(4, 4)
y = x.view(16)
z = x.view(-1, 8) #-1表示该维根据另一维计算得到。

.item() 可以以数字的形式取出只有一个元素的张量

张量各种操作参考:https://pytorch.org/docs/stable/torch.html

与numpy转换

  使用 .numpy() 可以得到一个张量对应的numpy数组。

  使用torch.from_numpy() 可以得到numpy数组对应的张量。

  并且如果是在CPU中,张量和numpy数组共享同一个内存,改变一个的值会影响另一个。

  在CPU中除了CharTensor之外,所有Tensor都支持与NumPy的互相转换。

CUDA Tensor

if torch.cuda.is_available():
    device = torch.device("cuda")          # a CUDA device object
    y = torch.ones_like(x, device=device)  # directly create a tensor on GPU
    x = x.to(device)                       # or just use strings ``.to("cuda")``
    z = x + y
    print(z)
    print(z.to("cpu", torch.double))       # ``.to`` can also change dtype together!

Autograd

官方文档:https://pytorch.org/docs/stable/autograd.html#function

Tensor类的属性 .requires_grad 如果被设置为 True (默认为 False ),所有对这个tensor的操作都会被记录下来。在调用 .backward() 函数时,梯度就会被自动计算。计算后的梯度会被累加到属性 .grad 中。如果需要清零梯度,可以使用 .zero_grad()

只有标量可以使用 .backward()求梯度,如果不是标量可以在该函数中传入一个矩阵进行点积得到标量。

所有非用户定义的(通过操作产生的)tensor都会有一个 grad_fn 属性,记录定义这个tensor的Function的引用(由用户定义的为None)。

如果某些操作不需要算入求梯度的步骤中,可以使用 with torch.no_grad(): 或是使用 .detach() 得到一个新的tensor

torch.nn

官方文档:https://pytorch.org/docs/stable/nn.html

自定义的神经网络需要继承nn.Module类, __init__ 函数中定义网络的结构, forward() 函数中定义输入到输出的计算过程。

训练一个神经网络的步骤为:

  • 定义包含可学习参数(或权重)的神经网络
  • 在数据集或输入上进行迭代
  • 通过网络处理输入
  • 计算损失
  • 将梯度传播回网络的参数
  • 更新网络的权重,通常是使用 weight = weight - learning_rate * gradient

通过 .parameters() 可以得到网络中的参数,属于nn.Parameter类。

nn package中自带了许多损失函数,可以直接进行调用,网络的输出结果和目标结果作为参数。

当对损失值(loss)调用 .backward() 网络中所有 requires_grad=True 的tensor都会关于loss计算梯度并累加到 grad 参数中。

反向传播时先清零梯度,调用loss的 .backward() 函数

torch.optim 中预先定义了许多优化函数用于权重的更新,定义好优化函数后每次更新时调用 .step() 函数

# 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

可以为不同层指定不同的学习参数

optim.SGD([
                {'params': model.base.parameters()},
                {'params': model.classifier.parameters(), 'lr': 1e-3}
            ], lr=1e-2, momentum=0.9)

数据读取

针对计算机视觉,pytorch还提供了 torchvision 包,其中 torchvision.datasets 中还包含了众多常用的数据集如 Imagenet, CIFAR10, MNIST等

数据集中的图片都是取值为$[0,1]$类型为PIL Image 的图片。

可以使用 torchvision.transforms 包含对数据的多种操作, .Compose() 函数则是用于将多个transform组合。

读取数据集举例:

transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]) 
#表示第一步将数据集中数据转为tensor,第二步进行规范化。第一个参数表示(R,G,B)的均值,第二个参数为方差 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')

pytorch中有两种类型的数据集,map-style和Iterable-style。

Iterable-style的数据集可以调用 iter(dataset)会返回一个读数据库的数据流。

Map-style的数据集可以使用 torch.utils.data.Sampler 类指定数据读取时的下标序列。

collate_fn 函数在automatic batching关闭时,传入的参数是单个数据,功能是将其从numpy数组形式转为tensor。如果在automatic batching开启时,会添加一维存储class信息。