从零手写Resnet50实战篇——权值另存为

​大家好啊,我是董董灿。

这是《从零手写Resnet50实战》的第二篇文章。

往期文章列表:
从零手写Resnet50,chatGPT是我的第一个合伙伙伴

权值怎么处理

在制定了不用第三方库和框架,从零手写Resnet50的前提下,面临的第一个问题就是网络的权值怎么处理。

网上有不少教程是基于已有的模型和推理框架来加载权值,然后完成的推理运算。

而如果不依赖已有的框架,就需要对模型中的权值做一次自定义的格式转存。

权值转存成文本文件

第一步,把模型中的权值,另存为一个可以随意被操控的文件格式——最常见的 txt 文本格式。

这样做的好处就是,以txt文件存储的模型参数,可以随时随地的,以读文件的方式随意加载。

由于不再是结构化的数据,而是我们可以随意操控的数据(甚至可以修改),也方便神经网络中每一层的调试。

于是,我写了个脚本,用来将参数数据保存下来。

import torch
import torchvision
import numpy as np
from torchvision import models
resnet50 = models.resnet50(pretrained=True)
print(resnet50)def save(data, file):
  d = np.array(data.weight.data.cpu().numpy())
  np.savetxt(file+str(".txt"), d.reshape(-1, 1))
  
save(resnet50.conv1, "resnet50_conv1")
save(resnet50.bn1, "resnet50_bn1")def save_bottle_neck(layer, layer_index):
  bottle_neck_idx = 0
  layer_name = "resnet50_layer" + str(layer_index) + "_bottleneck"
  for bottleNeck in layer:
    save(bottleNeck.conv1, layer_name + str(bottle_neck_idx) + "_conv1")
    save(bottleNeck.bn1, layer_name + str(bottle_neck_idx) + "_bn1")
    save(bottleNeck.conv2, layer_name + str(bottle_neck_idx) + "_conv2")
    save(bottleNeck.bn2, layer_name + str(bottle_neck_idx) + "_bn2")
    save(bottleNeck.conv3, layer_name + str(bottle_neck_idx) + "_conv3")
    save(bottleNeck.bn3, layer_name + str(bottle_neck_idx) + "_bn3")
    if bottleNeck.downsample:
      save(bottleNeck.downsample[0], layer_name + str(bottle_neck_idx) + "_downsample_conv2d")
      save(bottleNeck.downsample[1], layer_name + str(bottle_neck_idx) + "_downsample_batchnorm")
    bottle_neck_idx = bottle_neck_idx + 1
​
save_bottle_neck(resnet50.layer1, 1)
save_bottle_neck(resnet50.layer2, 2)
save_bottle_neck(resnet50.layer3, 3)
save_bottle_neck(resnet50.layer4, 4)
​
save(resnet50.fc, "resnet50.fc")

这个脚本可以自动地从网上下载已经训练好的模型,然后打印出Resnet50的网络结构,并且将有参数的层(主要是卷积层和BN层和FC层)中的参数保存下来。
保存的每一层参数

简单验证存储的权值对不对

Resnet50中的第一层卷积,卷积核大小为 7x7,channel 数是3,共 64 个卷积核,因此这一层的权值参数有 64x7x7x3 = 9408个。

Resnet50中最后一层全连接层,将通道 2048 转为通道 1000,算法上为一个简单地 [m, k] x [k, n] = [m, n] 的矩阵乘法。
最后一层的矩阵乘法
这一层的权值参数个数为 2048 x 1000 = 2048000个。

查看保存的 resnet50_conv1.txt 和 resnet50_fc.txt 的行数:

$ wc -l resnet50_conv1.txt
9408 resnet50_conv1.txt
​
$ wc -l resnet50_fc.txt
2048000 resnet50_fc.txt

txt文件每一行保存一个参数,可以看到参数个数是正确的。

这样就完成了Resnet50权值的格式转存,转存到txt中,无论python环境,还是C++环境,都可以很友好的读入文件数据,然后进行计算。

代码和保存的权值参数文件已经上传到了仓库——从零手写Resnet50。

说明:txt文件中的数据类型都是浮点型,浮点型能确保整个神经网络推理的精度达标,不至于误差太大,后续算法实现,也需要是浮点运算。

猜你喜欢

转载自blog.csdn.net/dongtuoc/article/details/130000500