• Pytorch速成教程


    目录

    0 简介

    1 张量的概念和生成

    2 自动微分

    2.1 Tensor类

    2.2 梯度

    3 神经网络

     3.1 定义网络

    3.2 查看模型参数

    3.3 测试网络

    3.4 损失函数更新权重

    4 训练分类器

    4.1 数据处理生成Dataload

    4.2 定义卷积网络

    4.3 定义损失函数

    4.4 遍历DataLoader进行训练

    4.5 测试

    5 GPU训练


    0 简介

    跟numpy功能一样,但可以GPU加速,和numpy可以相互转化。

    1 张量的概念和生成

    张量是torch里的多维数组,和numpy中的ndarrays相似

    生成张量的方法:

    • 空张量
    1. # 这个是用来生成一个为未初始化的5*3的张量,切记不是全零
    2. x = torch.empty(5, 3
    • 随机化0-1张量
    1. # 这个是生成一个均匀分布的初始化的,每个元素从0~1的张量,与第一个要区别开,另外,还有其它的随机张量生成函数,如torch.randn()、torch.normal()、torch.linespace(),分别是标准正态分布,离散正态分布,线性间距向量
    2. x = torch.rand(5, 3)
    • 全0张量
    1. # 这个是初始化一个全零张量,可以指定每个元素的类型。
    2. x = torch.zeros(5, 3, dtype=torch.long)
    • 已有矩阵转化为张量
    x = torch.tensor([5.5, 3])
    • size函数来看它的shape
    print(x.size())
    • 张量加法
    print(torch.add(x, y))
    • 张量的大小
    print(x.item())
    • torch转numpy

    在使用Cpu的情况下,张量和array将共享他们的物理位置,改变其中一个的值,另一个也会随之变化。

    1. a = torch.ones(5)
    2. b = a.numpy()
    • numpy转torch
    1. a = np.ones(5)
    2. b = torch.from_numpy(a)
    • GPU下转化
    1. if torch.cuda.is_available():
    2. device = torch.device("cuda") # a CUDA device object
    3. y = torch.ones_like(x, device=device) # directly create a tensor on GPU
    4. x = x.to(device) # or just use strings ``.to("cuda")``
    5. z = x + y

    2 自动微分

    在pytorch中,神经网络的核心是自动微分

    2.1 Tensor类

    orch.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就会记录用于反向梯度计算的信息:

    1. x = torch.ones(2, 2, requires_grad=True)
    2. print(x)

    然后我们通过operation产生新的tensor:

    1. y = x + 2
    2. print(y)

    是通过operation产生的tensor,因此它的grad_fn不是None。

    1. print(y.grad_fn)
    2. #

    再通过y得到z和out 

    1. z = y * y * 3
    2. out = z.mean()
    3. print(z, out)
    4. # z = tensor([[ 27., 27.],[ 27., 27.]])
    5. # out = tensor(27.)

    requires_grad_()函数会修改一个Tensor的requires_grad。

    1. a = torch.randn(2, 2)
    2. a = ((a * 3) / (a - 1))
    3. print(a.requires_grad)
    4. a.requires_grad_(True)
    5. print(a.requires_grad)
    6. b = (a * a).sum()
    7. print(b.grad_fn)
    8. 输出:
    9. False
    10. True
    11. object at 0x7f35766827f0>

    2.2 梯度

    现在我们里反向计算梯度。因为out是一个scalar,因此out.backward()等价于out.backward(torch.tensor(1))。

    1. v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
    2. y.backward(v)
    3. print(x.grad) #数量的梯度,即各个方向的导数的集合
    4. """
    5. tensor([1.0240e+02, 1.0240e+03, 1.0240e-01])
    6. """
    7. #停止计算微分
    8. print(x.requires_grad)
    9. print((x ** 2).requires_grad)
    10. with torch.no_grad():
    11. print((x ** 2).requires_grad)
    12. """
    13. True
    14. True
    15. False
    16. """

    3 神经网络

    神经网络定义过程

    • 定义神经网络及其参数;
    • 在数据集上多次迭代循环;
    • 通过神经网络处理数据集;
    • 计算损失(输出和正确的结果之间相差的距离);
    • 用梯度对参数反向影响;
    • 更新神经网络的权重,weight = weight - rate * gradient;

     3.1 定义网络

    1. import torch
    2. import torch.nn as nn
    3. import torch.nn.functional as F
    4. # 汉字均为我个人理解,英文为原文标注。
    5. class Net(nn.Module):
    6. #1、初始化定义
    7. def __init__(self):
    8. # 继承原有模型
    9. super(Net, self).__init__()
    10. # 1 input image channel, 6 output channels, 5x5 square convolution
    11. # kernel
    12. # 定义了两个卷积层
    13. # 第一层是输入1维的(说明是单通道,灰色的图片)图片,输出6维的的卷积层(说明用到了6个卷积核,而每个卷积核是5*5的)。
    14. self.conv1 = nn.Conv2d(1, 6, 5)
    15. # 第一层是输入1维的(说明是单通道,灰色的图片)图片,输出6维的的卷积层(说明用到了6个卷积核,而每个卷积核是5*5的)。
    16. self.conv2 = nn.Conv2d(6, 16, 5)
    17. # an affine operation: y = Wx + b
    18. # 定义了三个全连接层,即fc1与conv2相连,将16张5*5的卷积网络一维化,并输出120个节点。
    19. self.fc1 = nn.Linear(16 * 5 * 5, 120)
    20. # 将120个节点转化为84个。
    21. self.fc2 = nn.Linear(120, 84)
    22. # 将84个节点输出为10个,即有10个分类结果。
    23. self.fc3 = nn.Linear(84, 10)
    24. #2、搭建网络 我们只需要定义forward函数,而backward函数会自动通过autograd创建。
    25. def forward(self, x):
    26. # Max pooling over a (2, 2) window
    27. # 用relu激活函数作为一个池化层,池化的窗口大小是2*2,这个也与上文的16*5*5的计算结果相符(一开始我没弄懂为什么fc1的输入点数是16*5*5,后来发现,这个例子是建立在lenet5上的)。
    28. # 这句整体的意思是,先用conv1卷积,然后激活,激活的窗口是2*2。
    29. x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
    30. # If the size is a square you can only specify a single number
    31. # 作用同上,然后有个需要注意的地方是在窗口是正方形的时候,2的写法等同于(2,2)。
    32. # 这句整体的意思是,先用conv2卷积,然后激活,激活的窗口是2*2。
    33. x = F.max_pool2d(F.relu(self.conv2(x)), 2)
    34. # 实际上view()类似于reshape()的用法,将张量重新规划格式 -1代表待定
    35. x = x.view(-1, self.num_flat_features(x)) #一维化
    36. # 用一下全连接层fc1,然后做一个激活。
    37. x = F.relu(self.fc1(x))
    38. # 用一下全连接层fc2,然后做一个激活。
    39. x = F.relu(self.fc2(x))
    40. # 用一下全连接层fc3。
    41. x = self.fc3(x)
    42. return x
    43. def num_flat_features(self, x):
    44. # 承接上文的引用,这里需要注意的是,由于pytorch只接受图片集的输入方式(原文的单词是batch),所以第一个代表个数的维度被忽略。
    45. size = x.size()[1:] # all dimensions except the batch dimension
    46. num_features = 1
    47. for s in size:
    48. num_features *= s
    49. return num_features
    50. net = Net()
    51. print(net)
    52. """
    53. Net(
    54. (conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
    55. (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
    56. (fc1): Linear(in_features=400, out_features=120, bias=True)
    57. (fc2): Linear(in_features=120, out_features=84, bias=True)
    58. (fc3): Linear(in_features=84, out_features=10, bias=True)
    59. )
    60. """

    3.2 查看模型参数

    1. # 现在我们已经构建好模型了,但是还没有开始用bp呢,如果你对前面的内容有一些印象的话,你就会想起来不需要我们自己去搭建,我们只需要用某一个属性就可以了,autograd。
    2. # 现在我们需要来看一看我们的模型,下列语句可以帮助你看一下这个模型的一些具体情况。
    3. params = list(net.parameters())
    4. print(len(params))
    5. print(params[0].size()) # conv1's .weight
    6. """
    7. 10
    8. torch.Size([6, 1, 5, 5])
    9. """

    3.3 测试网络

    1. input = torch.randn(1, 1, 32, 32)
    2. out = net(input)
    3. print(out)
    4. # tensor([[-0.0198, 0.0438, 0.0930, -0.0267, -0.0344, 0.0330, 0.0664,
    5. 0.1244, -0.0379, 0.0890]])
    6. #默认的梯度会累加,因此我们通常在backward之前清除掉之前的梯度值:
    7. net.zero_grad()
    8. out.backward(torch.randn(1, 10))

    3.4 损失函数更新权重

    1. 1、计算损失
    2. # 这一部分是来搞定损失函数
    3. output = net(input)
    4. target = torch.randn(10) # a dummy target, for example
    5. target = target.view(1, -1) # make it the same shape as output
    6. criterion = nn.MSELoss()
    7. loss = criterion(output, target)
    8. print(loss)
    9. 2、查看结果
    10. print(loss.grad_fn) # MSELoss
    11. print(loss.grad_fn.next_functions[0][0]) # Linear
    12. print(loss.grad_fn.next_functions[0][0].next_functions[0][0]) # ReLU
    13. 3、计算梯度
    14. #在调用loss.backward()之前,我们需要清除掉tensor里之前的梯度,否则会累加进去。
    15. net.zero_grad()
    16. loss.backward()
    17. 4、更新权重 (梯度下降)
    18. learning_rate = 0.01
    19. for f in net.parameters():
    20. f.data.sub_(f.grad.data * learning_rate)
    • 使用优化包即使用optimizer,我们也需要清零梯度。但是我们不需要一个个的清除,而是用optimizer.zero_grad()一次清除所有。
    1. import torch.optim as optim
    2. # 创建optimizer,需要传入参数和learning rate
    3. optimizer = optim.SGD(net.parameters(), lr=0.01)
    4. # 清除梯度
    5. optimizer.zero_grad()
    6. output = net(input)
    7. loss = criterion(output, target)
    8. loss.backward()
    9. optimizer.step() # optimizer会自动帮我们更新参数

    4 训练分类器

    4.1 数据处理生成Dataload

    特别是对于视觉领域,我们写了一个叫做torchvision的包,他可以将很多知名数据的数据即涵盖在内。并且,通过torchvision.datasets 和 torch.utils.data.DataLoader 进行数据的转化。在本里中我们将会使用 CIFAR10 数据集,它有以下各类: ‘airplane’, ‘automobile’, ‘bird’, ‘cat’, ‘deer’, ‘dog’, ‘frog’, ‘horse’, ‘ship’, ‘truck’。在这个数据集中的图像尺寸都是33232的。

    1. import torch
    2. import torchvision
    3. import torchvision.transforms as transforms
    4. #数据归一化
    5. transform = transforms.Compose(
    6. [transforms.ToTensor(),
    7. transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
    8. #训练集
    9. trainset = torchvision.datasets.CIFAR10(root='/path/to/data', train=True,
    10. download=True, transform=transform)
    11. trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
    12. shuffle=True, num_workers=2)
    13. #测试集
    14. testset = torchvision.datasets.CIFAR10(root='/path/to/data', train=False,
    15. download=True, transform=transform)
    16. testloader = torch.utils.data.DataLoader(testset, batch_size=4,
    17. shuffle=False, num_workers=2)
    18. # 标签
    19. classes = ('plane', 'car', 'bird', 'cat',
    20. 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

    4.2 定义卷积网络

    1. import torch.nn as nn
    2. import torch.nn.functional as F
    3. class Net(nn.Module):
    4. def __init__(self):
    5. super(Net, self).__init__()
    6. self.conv1 = nn.Conv2d(3, 6, 5)
    7. self.pool = nn.MaxPool2d(2, 2)
    8. self.conv2 = nn.Conv2d(6, 16, 5)
    9. self.fc1 = nn.Linear(16 * 5 * 5, 120)
    10. self.fc2 = nn.Linear(120, 84)
    11. self.fc3 = nn.Linear(84, 10)
    12. def forward(self, x):
    13. x = self.pool(F.relu(self.conv1(x)))
    14. x = self.pool(F.relu(self.conv2(x)))
    15. x = x.view(-1, 16 * 5 * 5)
    16. x = F.relu(self.fc1(x))
    17. x = F.relu(self.fc2(x))
    18. x = self.fc3(x)
    19. return x
    20. net = Net()

    4.3 定义损失函数

    1. import torch.optim as optim
    2. #这里使用交叉熵损失函数,Optimizer使用带冲量的SGD。
    3. criterion = nn.CrossEntropyLoss()
    4. optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

    4.4 遍历DataLoader进行训练

    1. for epoch in range(2): # 这里只迭代2个epoch,实际应该进行更多次训练
    2. running_loss = 0.0
    3. #enumerate将其组成一个索引序列,利用它可以同时获得索引和值
    4. for i, data in enumerate(trainloader, 0):
    5. # 得到输入
    6. inputs, labels = data
    7. # 梯度清零
    8. optimizer.zero_grad()
    9. # forward + backward + optimize
    10. outputs = net(inputs)
    11. loss = criterion(outputs, labels)
    12. loss.backward()
    13. optimizer.step()
    14. # 定义统计信息
    15. running_loss += loss.item()
    16. if i % 2000 == 1999:
    17. print('[%d, %5d] loss: %.3f' %
    18. (epoch + 1, i + 1, running_loss / 2000))
    19. running_loss = 0.0
    20. print('Finished Training')

    4.5 测试

    • 取样测试
    1. #next() 返回迭代器的下一个项目。
    2. #next() 函数要和生成迭代器的iter() 函数一起使用。
    3. # 1 选取图片
    4. dataiter = iter(testloader)
    5. images, labels = dataiter.next()
    6. imshow(torchvision.utils.make_grid(images))
    7. print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))
    8. # 2 预测结果
    9. outputs = net(images)
    10. _, predicted = torch.max(outputs, 1)
    11. print('Predicted: ', ' '.join('%5s' % classes[predicted[j]]
    12. for j in range(4)))
    • 测试集一类测试
    1. correct = 0
    2. total = 0
    3. with torch.no_grad():
    4. for data in testloader:
    5. images, labels = data
    6. outputs = net(images)
    7. _, predicted = torch.max(outputs.data, 1)
    8. total += labels.size(0)
    9. correct += (predicted == labels).sum().item()
    10. print('Accuracy of the network on the 10000 test images: %d %%' % (
    11. 100 * correct / total))
    • 每类的测试
    1. class_correct = list(0. for i in range(10))
    2. class_total = list(0. for i in range(10))
    3. with torch.no_grad():
    4. for data in testloader:
    5. images, labels = data
    6. outputs = net(images)
    7. _, predicted = torch.max(outputs, 1)
    8. c = (predicted == labels).squeeze()
    9. for i in range(4):
    10. label = labels[i]
    11. class_correct[label] += c[i].item()
    12. class_total[label] += 1
    13. for i in range(10):
    14. print('Accuracy of %5s : %2d %%' % (
    15. classes[i], 100 * class_correct[i] / class_total[i]))
    16. Accuracy of plane : 52 %
    17. Accuracy of car : 66 %
    18. Accuracy of bird : 49 %
    19. Accuracy of cat : 34 %
    20. Accuracy of deer : 30 %
    21. Accuracy of dog : 45 %
    22. Accuracy of frog : 72 %
    23. Accuracy of horse : 71 %
    24. Accuracy of ship : 76 %
    25. Accuracy of truck : 55 %

    5 GPU训练

    1. device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    2. print(device)
    3. # cuda:0
    4. class Net2(nn.Module):
    5. def __init__(self):
    6. super(Net2, self).__init__()
    7. self.conv1 = nn.Conv2d(3, 6, 5).to(device)
    8. self.pool = nn.MaxPool2d(2, 2).to(device)
    9. self.conv2 = nn.Conv2d(6, 16, 5).to(device)
    10. self.fc1 = nn.Linear(16 * 5 * 5, 120).to(device)
    11. self.fc2 = nn.Linear(120, 84).to(device)
    12. self.fc3 = nn.Linear(84, 10).to(device)
    13. def forward(self, x):
    14. x = self.pool(F.relu(self.conv1(x)))
    15. x = self.pool(F.relu(self.conv2(x)))
    16. x = x.view(-1, 16 * 5 * 5)
    17. x = F.relu(self.fc1(x))
    18. x = F.relu(self.fc2(x))
    19. x = self.fc3(x)
    20. return x
    21. net = Net2()
    22. criterion = nn.CrossEntropyLoss()
    23. optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
    24. for epoch in range(20):
    25. running_loss = 0.0
    26. for i, data in enumerate(trainloader, 0):
    27. # 得到输入
    28. inputs, labels = data
    29. inputs, labels = inputs.to(device), labels.to(device)
    30. # 梯度清零
    31. optimizer.zero_grad()
    32. # forward + backward + optimize
    33. outputs = net(inputs)
    34. loss = criterion(outputs, labels)
    35. loss.backward()
    36. optimizer.step()
    37. # 定义统计信息
    38. running_loss += loss.item()
    39. if i % 2000 == 1999:
    40. print('[%d, %5d] loss: %.3f' %
    41. (epoch + 1, i + 1, running_loss / 2000))
    42. running_loss = 0.0
    43. print('Finished Training')

  • 相关阅读:
    机器学习11—原型聚类之学习向量量化(LVQ)
    这份工具清单,令Python 提速N倍,简直太好用了
    《The Art of InnoDB》第二部分|第4章:深入结构-磁盘结构-撕裂的页面(doublewrite buffer)
    SpringMVC学习---第二课
    基于Java毕业设计学生选课咨询系统源码+系统+mysql+lw文档+部署软件
    【短道速滑十一】标准的Gabor滤波器及Log_Gabor滤波器的实现、解析、速度优化及其和Halcon中gen_gabor的比较。
    Zookeeper初识及安装配置
    vue09
    TypeScript 泛型
    nodejs爬虫 测试 modi
  • 原文地址:https://blog.csdn.net/HUASHUDEYANJING/article/details/126452106