2025年resnet网络代码(resnet34代码)

resnet网络代码(resnet34代码)来源 计算机视觉工坊 作者 K Fire 添加 v dddvision 备注 深度学习 拉你入群 文末附行业细分群 完整代码在 github SqueezNet Pytorch 随着深度学习这一概念的兴起 越来越多的研究人员投身到深度神经网络搭建的浪潮中 各种各样的网络层出不穷 给定一个精度级别 通常存在多个达到该精度级别的 CNN 架构 但是在同等精度下 具有较少参数的 CNN 有三大优势

大家好,我是讯享网,很高兴认识大家。



来源:计算机视觉工坊,作者:K.Fire

添加v:dddvision,备注:深度学习,拉你入群。文末附行业细分群

完整代码在github:SqueezNet-Pytorch

随着深度学习这一概念的兴起,越来越多的研究人员投身到深度神经网络搭建的浪潮中,各种各样的网络层出不穷。给定一个精度级别,通常存在多个达到该精度级别的CNN架构,但是在同等精度下,具有较少参数的CNN有三大优势:

  1. 更高效的分布式训练:分布式训练的数据并行方法在每个服务器上保留整个模型的副本,处理训练数据集的不同子集。因此通信开销与模型中的参数数成正比,换而言之,越小的模型,训练更快。虽然随着GPU等硬件架构的发展,很多时候我们并不需要再进行分布式训练,但如果你搭建的网络很深,训练数据集很大,分布式训练也是很有意义的。
  2. 在实际应用过程中,将新模型导出到客户端时,开销较小:Over-the-air update(OTA)是特斯拉等企业常用的技术,是指移动终端通过无线网络下载远程服务器上的升级包,对系统或应用进行升级的技术。训练的模型越小,需要的通信更少,因此可以实现更频繁更快速地更新。
  3. 更容易在嵌入式设备上部署:芯片存储空间有限,较小的模型让芯片(FPGA)嵌入式设备存储,部署神经网络更加可行,在SLAM领域,随着技术的成熟,越来越多的SLAM框架倾向于与神经网络相结合,但有很多时候苦恼于神经网络训练和运行时太耗时间,无法满足实时性需求,而小的网络往往更容易满足实时性。

因此,基于此,SqueezeNet期望探寻一种能保持相同精度,但是参数量更少的模型。

它是以AlexNet为基础进行的改进,AlexNet是当时ImageNet比赛的冠军,而且远超第二名,给了后世很多启发,但是它的不足之处(它的论文中也提到了)就是模型过大,参数过多,训练时间过长,它有5个卷积层,3个池化层,3个全连接层,模型大小为:*4/1024/1024=240M,下图为AlexNet的模型结构:

而通过我的实验,我训练完的SqueezeNet模型,只有2.97M,确实是实现了很大程度的压缩!

总的来说,Squeeze有以下几点主要贡献:

  • 概述了使用很少参数进行CNN架构设计的策略,这一点不仅仅是针对SqueezeNet,而是对今后所有的网络设计都很有指导意义
  • 引入了Fire Module作为网络基本构成单元,Fire模块在后来也有很多人引用借鉴,比如做点云物体语义识别的SqueezeSeg等
  • 以Fire Module为基础,构建了SqueezeNet轻量级网络,就是本文的网络架构

我们在进行网络参数精简时,主要可以想到也是最直观的有三个策略:

  1. 用1x1卷积滤波器替换3x3卷积过滤器,1x1的参数比3x3少9倍。
  2. 减少输入通道的数量
  3. 提前下采样,当网络层数很深时,提前进行下采样,可以得到更小的特征图,后面的网络训练时就会有更少的参数

第1,2条策略一般不会过多减少得到结果的精度,而第三条策略已经有研究人员证明了会降低网络的精度,延迟下采样会得到更高的精度,Fire模块就是基于此设计的。

Fire模块如下图所示,

这是论文中给出的图,其实容易产生误导,作者的意思是:先将图像输入一个1X1的卷积网络(称为squeeze),通道数为3(图中的3个),然后将输出分别输入给4通道(图中)的1X1的卷积层和4个(图中)3X3的卷积层(称为expand),将得到的结果按通道的维度进行拼接,作为最后的输出。


讯享网

注意在实际实现时,卷积后要接ReLU函数,也要注意ReLU和拼接的顺序,我的实验结果是拼接后再ReLU比较好。具体代码如下:

class Fire(nn.Module):    def init(self, in_channels, squeeze_channels, expand1x1_channels, expand3x3_channels, version=1):        super(Fire, self).init()        self.in_channels = in_channels        self.version = version        self.squeeze = nn.Conv2d(in_channels, squeeze_channels, kernel_size=1)        self.bn_squeeze = nn.BatchNorm2d(squeeze_channels)        self.expand1x1 = nn.Conv2d(squeeze_channels, expand1x1_channels, kernel_size=1)        self.activation = nn.ReLU(inplace=True)        self.expand3x3 = nn.Conv2d(squeeze_channels, expand3x3_channels, kernel_size=3, padding=1)        self.bn_out = nn.BatchNorm2d(expand1x1_channels + expand3x3_channels)    def forward(self, x):        # x1 = self.squeeze_activation(self.squeeze(x))        # e1 = self.expand1x1(x1)        # e2 = self.expand3x3(x1)        x1 = self.activation(self.bn_squeeze(self.squeeze(x)))        e1 = self.expand1x1(x1)        e2 = self.expand3x3(x1)        y = torch.cat([e1, e2], 1)        if self.version == 1:            y = self.activation(self.bn_out(y))        elif self.version == 2:            # y = self.expand_activation(y + x)            y = self.activation(self.bn_out(y + x))        return y

讯享网

在这个代码中有两点需要注意(比较坑):

  1. 在squeeze或expand后需要进行Batch Bormalization操作,不然训练不动,结果精度极差
  2. 我在代码中通过version参数,实现了两种不同的Fire架构,第二种是ResNet启发的残差网络的模式,如下图:

搭建好Fire模块,就可以按照论文的架构去搭建整个Squeeze模型,我主要实现了这两种架构:

讯享网class SqueezeNet(nn.Module):    def init(self, version=1, num_classes=10):        super(SqueezeNet, self).init()        self.num_classes = num_classes        self.version = version        self.net = nn.Sequential(            nn.Conv2d(3, 96, kernel_size=7, stride=2, padding=2),            nn.ReLU(inplace=True),            nn.MaxPool2d(kernel_size=3, stride=2),            Fire(96, 16, 64, 64),            Fire(128, 16, 64, 64),            Fire(128, 32, 128, 128),            nn.MaxPool2d(kernel_size=3, stride=2),            Fire(256, 32, 128, 128),            Fire(256, 48, 192, 192),            Fire(384, 48, 192, 192),            Fire(384, 64, 256, 256),            nn.MaxPool2d(kernel_size=3, stride=2),            Fire(512, 64, 256, 256),        )        self.classifier = nn.Sequential(            nn.Dropout(p=0.5),            nn.Conv2d(512, self.num_classes, kernel_size=1),            nn.ReLU(inplace=True),            nn.AdaptiveAvgPool2d((1, 1)),    # 自适应平均池化,指定输出(H,W)        )    def forward(self, x):        x = self.net(x)        x = self.classifier(x)        y = torch.flatten(x, 1)        return ydef test():    test_model = SqueezeNet(version=2, num_classes=10)    y = test_model(torch.randn(1, 3, 224, 224))    print(y.size())    summary(test_model, (1, 3, 224, 224))if name == ‘main’:    test()

注意几点:

  1. 加入了Dropout层增强泛化性
  2. 下面定义的test函数主要是为了测试查看网络参数是否出错

在搭建模型时也可以根据作者在论文中提供的表,但是要注意,第一个卷积层是需要padding=2才能实现作者提到的尺寸,可以自己算一下:

完整代码在github:SqueezNet-Pytorch

训练时,先通过argparse包加载终端参数:

import argparseparser = argparse.ArgumentParser()parser.add_argument(‘–batch_size’, type=int, default=128, help=‘input batch size’)parser.add_argument(‘–lr’, type=float, default=0.1, help=‘learning rate’)parser.add_argument(‘–m’, type=float, default=0.09, help=‘momentum’)parser.add_argument(‘–wd’, type=float, default=0.0005, help=‘weight decay’)parser.add_argument(‘–epoch’, type=int, default=10, help=‘train epoch’)parser.add_argument(‘–version’, type=int, default=1, help=‘squeezenet version(12)’)opt = parser.parse_args()

然后加载数据集,我这里使用CIFAR10为例:

讯享网# 数据集转换参数transform = transforms.Compose([    transforms.ToTensor(),    # transforms.RandomCrop(224),    transforms.Resize(224),    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])# 下载训练集与测试集train_data = datasets.CIFAR10(    root=‘https://www.bilibili.com/read/cv31480642/CIFAR10/',    train=True,         # 是 train 集    download=True,      # 如果该路径没有该数据集,就下载    transform=transform # 数据集转换参数)test_data = datasets.CIFAR10(    root='https://www.bilibili.com/read/cv31480642/CIFAR10/',    train=False,    download=True,    transform=transform)train_loader = DataLoader(train_data, shuffle=True, batch_size=opt.batch_size)test_loader = DataLoader(test_data, shuffle=True, batch_size=opt.batch_size)

然后我这里是定义了一个训练器类对训练流程进行了封装:

class Trainer:    def init(self, opt, model, train_loader):        self.opt = opt        self.model = model        self.train_loader = train_loader        self.losses = []    def train(self):        loss_fn = nn.CrossEntropyLoss()        learning_rate = opt.lr        optimizer = torch.optim.SGD(            model.parameters(),            lr=learning_rate,            momentum=opt.m,            weight_decay=opt.wd        )        scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.5)        for epoch in tqdm(range(opt.epoch)):            scheduler.step()            for i, (X, Y) in enumerate(self.train_loader):                X, Y = X.to(’cuda:0‘), Y.to(’cuda:0‘)                Pred = self.model(X)                loss = loss_fn(Pred, Y)                optimizer.zero_grad()                loss.backward()                optimizer.step()                if i % opt.epoch == 0:                    self.losses.append(loss.item())                    print(’训练误差为: {:.4f}‘.format(loss.item()))    def printParamters(self):        # 打印模型的 state_dict        print(“Model’s state_dict:”)        for param_tensor in self.model.state_dict():            print(param_tensor, “ ”, self.model.state_dict()[param_tensor].size())    def saveParameters(self, root=‘https://www.bilibili.com/read/cv31480642/'):        try:            os.makedirs(root)        except OSError:            pass        # state_dict()表示只保存训练好的权重        torch.save(self.model.state_dict(), root + 'squeeze_model_' + 'version' + str(opt.version) + '_epoch' + str(opt.epoch) + '.pt')    def plotLoss(self):        Fig = plt.figure()        plt.plot(range(len(self.losses)), self.losses)        plt.show()

调用其中的train()方法进行训练,命令如下:

讯享网python train_SqueezeNet.py –batch_size=128 –epoch=20 –lr=0.1 –m=0.9 –version=1 –wd=0.001

然后进行测试:

correct = 0total = 0model = model.eval()with torch.no_grad():    for i, (X, Y) in enumerate(testloader):        X, Y = X.to(’cuda:0‘), Y.to(’cuda:0‘)        Pred = model(X)        , predicted = torch.max(Pred.data, dim=1)        correct += torch.sum((predicted==Y))        total += Y.size(0)        print(f’第 {blue(str(i))} 批测试精准度: {100*correct/total} %‘)

启动测试的代码如下:

讯享网python test_SqueezeNet.py –batch_size=128 –epoch=20 –version=1

训练结果:

放一下version2的损失曲线如下:

迭代5次:

迭代20次:

迭代20次的精度:

与我自己用pytorch搭建的AlexNet精度基本一致,甚至有超过AlexNet的趋势!

下载

在公众号「计算机视觉工坊」后台,回复「3dcv」,即可获取工业3D视觉、SLAM、自动驾驶、三维重建、事件相机、无人机等近千余篇最新顶会论文;巴塞罗那自治大学和慕尼黑工业大学3D视觉和视觉导航精品课件;相机标定、结构光、三维重建、SLAM,深度估计、模型部署、3D目标检测等学习资料。

3D视觉方向交流群成立啦

目前工坊已经建立了3D视觉方向多个社群,包括SLAM、工业3D视觉、自动驾驶、三维重建、无人机方向,细分群包括:

[工业3D视觉]相机标定、立体匹配、三维点云、结构光、机械臂抓取、缺陷检测、6D位姿估计、相位偏折术、Halcon、摄影测量、阵列相机、光度立体视觉等。

[SLAM]视觉SLAM、激光SLAM、语义SLAM、滤波算法、多传感器融合、多传感器标定、动态SLAM、MOT SLAM、NeRF SLAM、机器人导航等。

[自动驾驶]深度估计、Transformer、毫米波|激光雷达|视觉摄像头传感器、多传感器标定、多传感器融合、自动驾驶综合群等、3D目标检测、路径规划、轨迹预测、3D点云分割、模型部署、车道线检测、Occupancy、目标跟踪等。

[三维重建]NeRF、多视图几何、OpenMVS、MVSNet、colmap、纹理贴图等

[无人机]四旋翼建模、无人机飞控等

除了这些,还有求职、硬件选型、视觉产品落地、最新论文、3D视觉最新产品、3D视觉行业新闻等交流群

大家可以添加小助理v: dddvisiona,备注:加群+方向+学校|公司, 小助理会拉你入群。

添加小助理v:dddvisiona,加群+方向+学校|公司,拉你入群

小讯
上一篇 2025-05-26 12:30
下一篇 2025-06-08 19:16

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/181908.html