P4 pytorch基本开发框架_哔哩哔哩_bilibili

通知

大家好,我的《人工智能开发基础》第二次内容大纲见:https://www.yuque.com/xlpr/doai/session4

本次分享会
1、首先会简单回顾下第一次讲了哪些python基础内容,再做一点简单的补充扩展。

我补充了一个题目,有时间的同学可以试做一下https://www.yuque.com/xlpr/doai/session2最后面的那道doctest考题。复习完第一次分享会内容后,我会讲这题答案。

2、第二次分享会,我先过一下环境配置https://www.yuque.com/xlpr/doai/install-pytorch,然后主要讲pytorch开发一个分类任务的基本框架,和几个组件常见的变种写法 https://www.yuque.com/xlpr/doai/session5

3、上次其实讲了本来规划两次分享会的内容,我想想组会分享还是讲慢点,要录屏留给以后的新人看。但文档我会尽快写好大家可以提前看。下次组会准备讲的图像分类框架基本完成了https://www.yuque.com/xlpr/doai/session6,有需要的可以结合海礼写的,我们团队的分类框架 https://www.yuque.com/xlpr/code/hrvtof 先学习。

1 整体框架、流程概览

image.png

按照研发时间从上到下,分三个阶段:训练、评价、部署。对于大部分研究生而言,掌握前两个阶段即可。
按照程序运行从左到右,也分三个阶段:(加载)数据、(运行)模型、特定阶段操作。

一般拿到个新项目,都是从左上到右下的顺序逐步完成五个组件的功能代码:
① 数据 ② 模型 ③ 损失 ④ 优化器 ⑤ 评价指标

因为是二维结构,从左上到右下其实有很多种走法,具体问题具体分析。
总之做任何一个单元格里的组件时,必须要确保其左边、上面的所有工作都已完成。

2 直播写代码

我们来照着这个表格,实现一个数值二分类的代码。

net:forward、仿函数call
跳转看torch源码,Structure
演示断点调试

3 完整代码:numcls1_basic.py

数值二分类任务

  1. """ pytorch做分类任务的基本框架(基础版) """
  2. from tqdm import tqdm # pip install tqdm,进度条工具
  3. import numpy as np
  4. import torch
  5. from torch import nn, optim
  6. def build_dataloader(n):
  7. """ 生成n个数据样本,每个样本是 5个 [0, 6) 的整数
  8. 按照数值和分成两类, 10<sum(x)<20是1类,其他是0类
  9. """
  10. data = np.random.randint(0, 6, [n, 5])
  11. dataset = [(np.array(x, dtype='float32'), int(10 < sum(x) < 20)) for x in data]
  12. return torch.utils.data.DataLoader(dataset, batch_size=16, shuffle=True)
  13. class NumNet(nn.Module):
  14. def __init__(self):
  15. super().__init__()
  16. self.classifier = nn.Sequential(
  17. nn.Linear(5, 10),
  18. nn.ReLU(),
  19. nn.Linear(10, 5),
  20. nn.ReLU(),
  21. nn.Linear(5, 2),
  22. nn.ReLU(),
  23. )
  24. def forward(self, batched_inputs):
  25. x, y = batched_inputs
  26. logits = self.classifier(x)
  27. if self.training:
  28. loss = nn.functional.cross_entropy(logits, y)
  29. return loss
  30. else:
  31. y_hat = logits.argmax(dim=1)
  32. return y_hat
  33. def train(epochs=10):
  34. # 1 数据、模型、优化器
  35. train_num = 5000
  36. train_loader = build_dataloader(train_num)
  37. model = NumNet()
  38. optimizer = optim.SGD(model.parameters(), lr=0.01)
  39. # 2 训练
  40. for epoch in tqdm(range(epochs), 'epoch'):
  41. for batched_inputs in train_loader:
  42. loss = model(batched_inputs) # 前向传播
  43. optimizer.zero_grad() # 清空之前梯度
  44. loss.backward() # 进行该轮梯度反传
  45. optimizer.step() # 按指定学习策略,更新网络权重的梯度
  46. # 3 保存
  47. torch.save(model.state_dict(), 'model.pth')
  48. def eval():
  49. # 1 数据
  50. val_num = 1000
  51. val_loader = build_dataloader(val_num)
  52. # 2 加载模型
  53. model = NumNet() # 初始化模型结构
  54. model.load_state_dict(torch.load('model.pth')) # 加载模型权重
  55. model.eval() # 进入推断模式
  56. # 3 检查分类精度
  57. with torch.no_grad():
  58. correct_num = 0
  59. for batched_inputs in val_loader:
  60. y_hat = model(batched_inputs)
  61. correct_num += sum(batched_inputs[1] == y_hat)
  62. print(f'正确率: {correct_num} / {val_num} ≈ {correct_num / val_num:.2%}')
  63. if __name__ == '__main__':
  64. np.random.seed(4102)
  65. torch.manual_seed(4102) # torch也有随机数种子
  66. train()
  67. eval()
  68. # 在我们自己十卡服务器上运行的结果
  69. # epoch: 100%|████████████████████████████████████| 10/10 [00:03<00:00, 3.22it/s]
  70. # 正确率: 886 / 1000 ≈ 88.60%

4 总结

实现的代码中,依次对应整体框架中的如下模块
image.png