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)
Note:- 通过 model.**state_dict**()这个函数,以字典的方式查看模型网络层的名称、形状和具体数值。- 与其对应的model.**load_state_dict**(pretrained_state_dict, strict=True)函数,可以将之前训练好的模型参数载入到当前模型中。此处的pretrained_state_dict可通过torch.load得到。<a name="vWVOq"></a>#### (2) 将(1)中加载好权重的 resnet18 模型,保存成 onnx 文件。转好的文件为45648kb。实现代码如下:```pythonimport torchimport torchvision.models as modelsmodel = models.resnet18()# 读取预训练好的模型权重pretrained_state_dict = torch.load('./weights/resnet18-5c106cde.pth')# 将读取的权重载入modelmodel.load_state_dict(pretrained_state_dict, strict=True)# 模型放置CPUmodel.to(torch.device('cpu'))# 模型变为推理状态model.eval()# 构建一个项目推理时需要的输入大小的单精度Tensor,并且放置模型所在的设备(CPU或CUDA)inputs = torch.ones([1, 3, 224, 224]).type(torch.float32).to(torch.device('cpu'))# 生成onnxtorch.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
代码实现如下:
import torchfrom thop import profileimport torchvision.models as modelsmodel = models.resnet18()# 构建一个适合模型输入大小的单精度Tensorinputs = torch.ones([1, 3, 224, 224]).type(torch.float32)# 统计计算量和参数量flops, params = profile(model=model, inputs=(inputs,))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 文件可视化
