1 课程学习
本节课主要对于大白AI课程:
《Pytorch模型推理及多任务通用范式》课程中的第二节课进行学习。
2 作业题目
题目描述
必做题:
(1) 从torchvision中加载resnet18模型结构,并载入预训练好的模型权重 'resnet18-5c106cde.pth' (在物料包的weights文件夹中)。
(2) 将(1)中加载好权重的resnet18模型,保存成onnx文件。
(3) 以torch.rand([1,3,224,224]).type(torch.float32)作为输入,求resnet18的模型计算量和参数量。
(4) 以torch.rand([1,3,448,448]).type(torch.float32)作为输入,求resnet18的模型计算量和参数量。
思考题:
(1) 比较必做题中的(3)和(4)的结果,有什么规律?
(2) 尝试用netron可视化resnet18的onnx文件
(3) model作为torch.nn.Module的子类,除了用 model.state_dict()查看网络层外,还可以用model.named_parameters()和model.parameters()。它们三儿有啥不同?
(4) 加载模型权重时用的model.load_state_dict(字典, strict=True),里面的strict参数什么情况下要赋值False?
实现及结果
from thop import profile
from torchvision.models import resnet18
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model = resnet18(num_classes=1000).to(device)
pretrained_state_dict = torch.load('./weights/resnet18-5c106cde.pth')
model.load_state_dict(pretrained_state_dict, strict=True)
inputs = torch.ones([1, 3, 224, 224]).type(torch.float32).to(torch.device('cuda:0'))
torch.onnx.export(model, inputs, './weights/resnet18.onnx', verbose=False)
inputs1 = torch.rand([1, 3, 224, 224]).type(torch.float32).to(torch.device('cuda:0'))
inputs2 = torch.rand([1, 3, 448, 448]).type(torch.float32).to(torch.device('cuda:0'))
flops1, params1 = profile(model=model, inputs=(inputs1,))
flops2, params2 = profile(model=model, inputs=(inputs2,))
print('Model([1, 3, 224, 224]): {:.2f} GFLOPs and {:.2f}M parameters'.format(flops1/1e9, params1/1e6))
print('Model([1, 3, 448, 448]): {:.2f} GFLOPs and {:.2f}M parameters'.format(flops2/1e9, params2/1e6))
生成的resnet18.onnx文件为45M 以torch.rand([1,3,224,224]).type(torch.float32)作为输入,ResNet18的模型计算量为1.82 GFLOPs,参数量为11.69M 以torch.rand([1,3,448,448]).type(torch.float32)作为输入,ResNet18的模型计算量为7.27 GFLOPs,参数量为11.69M
思考
1 模型计算量和参数量的分析
模型的参数量与网络结构本身相关,但与输入图片无关,因此对于前面分别以torch.rand([1,3,224,224]).type(torch.float32)和torch.rand([1,3,448,448]).type(torch.float32)作为输入而言,resnet18的参数量都是一致的,即都为11.69M;但模型计算量与输入图片相关,且可以看到,torch.rand([1,3,448,448]).type(torch.float32)比torch.rand([1,3,224,224]).type(torch.float32)作为输入,要多4倍计算量,因此结果分别为7.27 GFLOPs和1.82 GFLOPs。
2 netron可视化resnet18的onnx文件
3 model.state_dict()、model.named_parameters()、model.parameters()三者的比较
model.named_parameters()返回list中,每个元组包含两个内容,分别是layer-name和layer-param model.parameters()返回list中,只包含layer-param
model.named_parameters()的结果测试
from torchvision.models import resnet18
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model = resnet18(num_classes=1000).to(device)
for layer_name, layer_param in model.named_parameters():
print('layer_name: ', layer_name)
print('layer_param: ', layer_param)
model.parameters()的结果测试
from torchvision.models import resnet18
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model = resnet18(num_classes=1000).to(device)
for layer_param in model.parameters():
print('layer_param: ', layer_param)
model.state_dict()的结果测试
from torchvision.models import resnet18
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model = resnet18(num_classes=1000).to(device)
for layer_name, layer_param in model.state_dict().items():
print('layer_name: ', layer_name)
print('layer_param: ', layer_param)
model.named_parameters()与model.state_dict()的不同
(1)返回值类型不同 model.named_parameters():将layer_name和layer_param打包成一个元组然后再存到list当中,因此遍历方式为for layer_name, layer_param in model.named_parameters() model.state_dict():将layer_name和layer_param以键值对信息的形式存储,因此遍历方式为for layer_name, layer_param in model.state_dict().items() (2)存储的模型参数的种类不同 model.named_parameters():只保存可学习、可被更新的参数 model.state_dict():存储model中包含的所有layer中的所有参数 (3)返回的值的require_grad属性不同 model.named_parameters():require_grad属性都是True model.state_dict():require_grad属性都是False
4 model.load_state_dict(字典, strict=True)中,strict的作用?
这个字典一般就是权重文件,strict即严格的意思。 若strict=True,说明权重文件的参数值要跟该model严格匹配 若strict=False,则允许只将model内需要加载的参数,用权重文件进行加载;无需让权重文件的参数和model的参数严格对应
学习心得
本节课主要通过加载模型、权重文件等方式,来了解模型参数量、计算量等内容,进而为后续的模型训练和测试打下基础。
参考
https://blog.csdn.net/weixin_41712499/article/details/110198423
|