Pytorch学习笔记(九)Learning PyTorch - Deep Learning with PyTorch: A 60 Minute Blitz

这篇博客瞄准的是 pytorch 官方教程中 Learning PyTorch 章节的 Deep Learning with PyTorch: A 60 Minute Blitz 部分,

完整网盘链接: https://pan.baidu.com/s/1L9PVZ-KRDGVER-AJnXOvlQ?pwd=aa2m 提取码: aa2m 

主要由以下四个部分组成:

  • Tensor
  • A Gentle Introduction to torch.autograd
  • Neural Networks
  • Training a Classifier

这个章节的教程打开后通常不会直接看到代码,而是需要往下拉看到类似于下图中红框部分的东西,点开后就是完整的示例:

在这里插入图片描述

这篇教程中包含了四个部分,为了保证笔记的结构与官网教程的一致,这里会压缩到一篇文章中。


Tensors

第一部分仍然是关于Tensor的一些基本操作,这一小节的内容与之前的笔记 Pytorch学习笔记(二)Learn the Basics - Tensors 中部分是重复的,如果你已经很熟练了可以选择性跳过一段。

  • 导入必要的包:
import torch
import numpy as np

Tensor 构造与初始化

  • 直接通过python数据类型初始化
data = [[1,2], [3,4]]
x_data = torch.tensor(data)
  • 通过其他tensor初始化
x_ones = torch.ones_like(x_data)
print(f"Ones Tensor:\n{x_ones}")

x_rand = torch.rand_like(x_data, dtype=torch.float)
print(f"Rand Tensor:\n{x_rand}")
  • 指定shape的变量与常量初始化:
shape = (2,3,)
rand_tensor = torch.rand(shape)
ones_tensor = torch.ones(shape)
zeros_tensor = torch.zeros(shape)

print(f"Random Tensor:\n{rand_tensor}")
print(f"Ones Tensor:\n{ones_tensor}")
print(f"Zeros Tensor:\n{zeros_tensor}")

Tensor 的三大属性

tensor对象最常用的三个属性为 shapedtypedevice

tensor = torch.rand(3, 4)

print(f"Shape: {tensor.shape}")
print(f"Dtype: {tensor.dtype}")
print(f"Device: {tensor.device}")

Tensor 的操作

  • 将tensor移动到cuda上
if torch.cuda.is_available():
    tensor = tensor.to('cuda')
    print(f"Device tensor is stored on : {tensor.device}")
  • 类似numpy形式的切片使用
tensor = torch.ones(4,4)
tensor[:,1] = 0
print(tensor)
  • 将两个tensor按照指定维度拼接
t1 = torch.cat([tensor, tensor], dim=1)
print(t1)
  • tensor按照元素 点乘
print(f"Tensor.mul:\n{tensor.mul(tensor)}")
print(f"Tensor *:\n{tensor * tensor}")
  • tensor 叉乘
print(f"Tensor.matmul:\n{tensor.matmul(tensor.T)}")
print(f"Tensor @:\n{tensor @ tensor.T}")
  • 就地操作:
print(f"Tensor:\n{tensor}")
tensor.add_(5)
print(f"Tensor:\n{tensor}")

Bridge with NumPy

  • Tensor -> Numpy
t = torch.ones(5)
print(f"t:\n{t}")
n = t.numpy()
print(f"n:\n{n}")
  • Numpy -> Tensor
n = np.array((2,4))
print(f"n:\n{n}")
t = torch.from_numpy(n)
print(f"t:\n{t}")

A Gentle Introduction to torch.autograd

这是该章节的第二部分,主要介绍了pytorch的自动梯度机制。torch.autograd 是 PyTorch 的自动微分引擎,为神经网络训练提供支持。


背景知识

神经网络 (NN) 是一些嵌套函数的集合,这些函数由参数(权重+偏置值)定义,参数存储在Tensor中。

训练 NN 分为两个步骤:

  • 前向传播:NN 对输出做出推理,通过每个函数运行输入数据以做出此猜测;
  • 反向传播:NN 根据推理中的误差调整参数,它通过从输出向后遍历、收集误差相对于函数参数的导数(梯度)并使用梯度下降优化来调整参数;

梯度传播演示

这里加载了一个 ResNet18 的参数并定义了一对无意义的sample用来掩饰pytorch是如进行梯度传播,运行后会自动下载 ResNet18 模型参数:

import torch
from torchvision.models import resnet18, ResNet18_Weights

加载模型及参数

model = resnet18(weights=ResNet18_Weights.DEFAULT)
data = torch.rand(1,3,64,64)
labels = torch.rand(1,1000)

执行推理:

prediction = model(data)

计算loss并反向传播

loss = (prediction - labels).sum()
loss.backward()

定义优化器并执行梯度优化

optimizer = torch.optim.SGD(model.parameters(), lr=1e-3)
optimizer.step()

具体梯度计算

这部分主要介绍了pytorch如和计算梯度,包含了一些数据概念,本质上就是对变量进行求导。

定义两个Tensor

a = torch.tensor([2.0, 3.0], requires_grad=True)
b = torch.tensor([6.0, 4.0], requires_grad=True)

定义另外一个Tensor为 Q = 3 a 3 − b 2 Q=3a^{3}-b^{2} Q=3a3b2

Q = 3*a**3 - b**2

手动计算Tensor Q的梯度:

external_grad = torch.tensor([1.0, 1.0])
Q.backward(gradient=external_grad)

print(9*a**2 == a.grad)
print(-2*b == b.grad)

Neural Networks

可以使用 torch.nn 构建神经网络。nn 依赖 autograd 来定义模型并对其进行区分。以经典的Alex Net模型为例:
在这里插入图片描述

神经网络的典型训练过程如下:

  1. 定义具有一些可学习参数(或权重)的神经网络;
  2. 迭代输入数据集;
  3. 模型处理输入;
  4. 计算损失(输出与正确的差值);
  5. 将梯度传播回网络参数;
  6. 更新网络权重,通常使用简单的更新规则:权重 = 权重 - 学习率 * 梯度

定义模型

导入依赖包

import torch 
import torch.nn as nn
import torch.nn.functional as F

定义模型结构

class Net(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1,6,5)
        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):
        c1 = F.relu(self.conv1(x))
        s2 = F.max_pool2d(c1, (2,2))
        c3 = F.relu(self.conv2(s2))
        s4 = F.max_pool2d(c3, 2)
        s4 = torch.flatten(s4, 1)
        f5 = F.relu(self.fc1(s4))
        f6 = F.relu(self.fc2(f5))
        output = self.fc3(f6)
        return output

实例化模型

net = Net()
print(net)

只需定义 前向函数反向函数(计算梯度的地方),autograd 会自动生成匹配的参数。

params = list(net.parameters())
print(len(params))
print(params[0].size())

模型计对随机数进行推理

input = torch.rand(1,1,32,32)
out = net(input)
print(out)

清空模型梯度并用随机数填充输出Tensor的梯度

net.zero_grad()
out.backward(torch.randn(1,10))

定义损失函数

损失函数采用(输出,目标)输入对,并计算一个值来估计输出与目标之间的差。nn 包下有几种不同的损失函数。最简单的损失函数是:nn.MSELoss 计算输出和目标之间的均方误差。

output = net(input)
target = torch.rand(10)
target = target.view(1, -1)
criterion = nn.MSELoss()

计算损失值:

loss = criterion(output, target)
print(loss)

查看部分层的损失梯度:

print(loss.grad_fn)
print(loss.grad_fn.next_functions[0][0])
print(loss.grad_fn.next_functions[0][0].next_functions[0][0])

只需执行 loss.backward() 就可以反向传播loss。但首先要清除现有梯度,否则梯度将累积到现有梯度中。

net.zero_grad()
print("conv1.bias.grad before backward")
print(net.conv1.bias.grad)

loss.backward()

print("conv1.bias.grad after backward")
print(net.conv1.bias.grad)

更新模型参数

手动对模型中的值进行一次修改

learning_rate = 0.01
for f in net.parameters():
    f.data.sub_(f.grad.data * learning_rate)

定义优化器

optimizer = torch.optim.SGD(net.parameters(), lr=0.01)

优化器根据loss值更新模型参数

optimizer.zero_grad()
output = net(input)
loss = criterion(output, target)
loss.backward()
optimizer.step()

Training a Classifier

当需要处理图像、文本、音频或视频数据时,可以将数据加载到 numpy 数组中的标准 python 包,然后转换为 torch.*Tensor

  • 对于图像:Pillow、OpenCV 等包;
  • 对于音频:scipy 和 librosa 等包;
  • 对于文本:原始 Python 或 Cython 的加载,或 NLTK 和 SpaCy 等包;

pytorch为于视觉提供了一个名为 torchvision 的包,内嵌了常见数据集(如 ImageNet、CIFAR10、MNIST 等)加载器,以及用于图像的数据转换器,即 torchvision.datasetstorch.utils.data.DataLoader

在这里将使用 CIFAR10 数据集。它有以下类别:‘airplane’, ‘automobile’, ‘bird’, ‘cat’, ‘deer’, ‘dog’, ‘frog’, ‘horse’, ‘ship’, ‘truck’. 。CIFAR-10 中的图像大小为 3x32x32,即 32x32 像素大小的 3 通道彩色图像。

按照下面的步骤训练图像分类神经网络:

  1. 使用 torchvision 加载并规范化 CIFAR10 训练和测试数据集;
  2. 定义卷积神经网络;
  3. 定义损失函数;
  4. 在训练数据上训练网络;
  5. 在测试数据上测试网络;

数据预处理

导入依赖包

import torch
import torchvision
import torchvision.transforms as transforms

定义图像数据转化器

transform = transforms.Compose(
    [
        transforms.ToTensor(),
        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
    ]
)

加载训练集与测试集

train_set = torchvision.datasets.CIFAR10(root="data", train=True, download=True, transform=transform)
test_set = torchvision.datasets.CIFAR10(root="data", train=True, download=True, transform=transform)

classes = ('plane', 'car', 'bird', 'cat',
           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

定义训练集与测试集加载器

batch_size = 4

train_loader = torch.utils.data.DataLoader(train_set, batch_size=batch_size, shuffle=True, num_workers=2)
test_loader = torch.utils.data.DataLoader(test_set, batch_size=batch_size, shuffle=True, num_workers=2)

抽看四张图像

import matplotlib.pyplot as plt
import numpy as np

def imshow(img):
    img = img/2 + 0.5
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1,2,0)))
    plt.show()

dataiter = iter(train_loader)
images, labels = next(dataiter)

imshow(torchvision.utils.make_grid(images))
print(' '.join(f'{classes[labels[j]]:5s}' for j in range(batch_size)))

定义神经网络

import torch.nn as nn
import torch.nn.functional as F

class Net(nn.Module):
    def __init__(self):
        super().__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 = torch.flatten(x,1)
        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):
    running_loss = 0.0
    for i, data in enumerate(train_loader, 0):
        inputs, labels = data
        optimzer.zero_grad()
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimzer.step()
        
        running_loss += loss.item()
        if i % 2000 == 1999:
            print(f"Epoch [{epoch+1}]: {i+1:5d} loss:{running_loss / 2000:3f}")
            runnling_loss = 0.0

print("Done")

在测试集上测试

dataiter = iter(test_loader)
images, labels = next(dataiter)

imshow(torchvision.utils.make_grid(images))
print('GroundTruth: ', ' '.join(f'{classes[labels[j]]:5s}' for j in range(4)))

outputs = net(images)

_, predicted = torch.max(outputs, 1)

print('Predicted: ', ' '.join(f'{classes[predicted[j]]:5s}'
                              for j in range(4)))

对整个测试集进行测试

correct = 0
total = 0

with torch.no_grad():
    for data in test_loader:
        images, labels = data
        outputs = net(images)
        _, predicted = torch.max(outputs, 1)
        total += labels.size(0)
        correct += (predict == labels).sum().item()
        
print(f'Accuracy of the network on the 10000 test images: {100 * correct // total} %')

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值