1. 课程学习

本节课主要对于大白AI课程:https://mp.weixin.qq.com/s/STbdSoI7xLeHrNyLlw9GOg
《Pytorch 模型推理及多任务通用范式》课程中的第二节课进行学习。
本课程的重点有:

  • 载入torchvision.models中的模型
  • 加载本地模型权重文件
  • 通过 model.state_dict()这个函数,以字典的方式查看模型网络层的名称、形状和具体数值。
  • 利用 thop 包统计模型的参数量,以及给定输入大小下的计算量。
  • 将训练好的模型(包括结构和权重)保存成 onnx。

    2. 作业题目

    2.1 必做题

    (1) 从 torchvision 中加载 resnet18 模型结构,并载入预训练好的模型权重 ‘resnet18-5c106cde.pth’ (在物料包的 weights 文件夹中)。

    实现代码如下: ```python import torch

    加载resnet模型,并载入权重。

    import torchvision.models as models

model = models.resnet18()

读取预训练好的模型权重

pretrained_state_dict = torch.load(‘./weights/resnet18-5c106cde.pth’)

将读取的权重载入model

model.load_state_dict(pretrained_state_dict, strict=True)

  1. Note
  2. - 通过 model.**state_dict**()这个函数,以字典的方式查看模型网络层的名称、形状和具体数值。
  3. - 与其对应的model.**load_state_dict**(pretrained_state_dict, strict=True)函数,可以将之前训练好的模型参数载入到当前模型中。此处的pretrained_state_dict可通过torch.load得到。
  4. <a name="vWVOq"></a>
  5. #### (2) 将(1)中加载好权重的 resnet18 模型,保存成 onnx 文件。
  6. 转好的文件为45648kb。实现代码如下:
  7. ```python
  8. import torch
  9. import torchvision.models as models
  10. model = models.resnet18()
  11. # 读取预训练好的模型权重
  12. pretrained_state_dict = torch.load('./weights/resnet18-5c106cde.pth')
  13. # 将读取的权重载入model
  14. model.load_state_dict(pretrained_state_dict, strict=True)
  15. # 模型放置CPU
  16. model.to(torch.device('cpu'))
  17. # 模型变为推理状态
  18. model.eval()
  19. # 构建一个项目推理时需要的输入大小的单精度Tensor,并且放置模型所在的设备(CPU或CUDA)
  20. inputs = torch.ones([1, 3, 224, 224]).type(torch.float32).to(torch.device('cpu'))
  21. # 生成onnx
  22. torch.onnx.export(model, inputs, './weights/resnet18.onnx', verbose=False)

Note:

  • torch中图像的分量分别代表:(1,C,H,W)

(3) 以 torch.rand([1,3,224,224]).type(torch.float32)作为输入,求 resnet18 的模型计算量和参数量。

Model: 1.82 GFLOPs and 11.69M parameters
代码实现如下:

  1. import torch
  2. from thop import profile
  3. import torchvision.models as models
  4. model = models.resnet18()
  5. # 构建一个适合模型输入大小的单精度Tensor
  6. inputs = torch.ones([1, 3, 224, 224]).type(torch.float32)
  7. # 统计计算量和参数量
  8. flops, params = profile(model=model, inputs=(inputs,))
  9. print('Model: {:.2f} GFLOPs and {:.2f}M parameters'.format(flops / 1e9, params / 1e6))

(4) 以 torch.rand([1,3,448,448]).type(torch.float32)作为输入,求 resnet18 的模型计算量和参数


Model: 7.27 GFLOPs and 11.69M parameters【实现代码同上】

2.2 思考题

(1) 比较必做题中的(3)和(4)的结果,有什么规律?

回答:

  • 由于模型输入的像素数量相差4倍(输入图像宽高均放大两倍),所以经过resnet18网络(卷积)之后,得到的输入特征的大小也相差4倍。
  • 但是网络结构不变,所以参数量不变。

(2) 尝试用 netron 可视化 resnet18 的 onnx 文件 。

见文章最后

(3) model 作为 torch.nn.Module 的子类,除了用 model.state_dict()查看网络层外,还 可以用 model.named_parameters()和 model.parameters()。它们三儿有啥不同?

参考文章:https://blog.csdn.net/u013548568/article/details/84311099
回答:

  • model.named_parameters()将会打印每一次迭代元素的名字和param
  • model.parameters()将会打印每一次迭代元素的param而不会打印名字,这是他和named_parameters的区别。上面两者都可以用来改变requires_grad的属性,因此多见于优化器的初始化
  • model.state_dict() 会打印所有的name和param,但是这里的所有的param都是requires_grad=False,没有办法改变requires_grad的属性。该函数多见于模型的保存。

(4) 加载模型权重时用的 model.load_state_dict(字典, strict=True),里面的 strict 参数什 么情况下要赋值 False?

参考文章:https://blog.csdn.net/t20134297/article/details/110533007
回答:当加载的模型和载入的模型参数中的key不匹配时,设strict=True会报错。但是将strict=False之后,模型会根据模型参数文件中保存的内容有针对性的读取,而不会报错。

其他:resnet18 的 onnx 文件可视化
resnet18.onnx.png