完整项目代码:https://github.com/SPECTRELWF/pytorch-cnn-study

ResNet网络结构

ResNet是何恺明大神在CVPR2016的工作,也拿到了当年的最佳论文。是为了解决深层网络的梯度消失的问题,引入了残差块连接。
论文地址:https://arxiv.org/pdf/1512.03385.pdf
其实我自己刚开始看这篇文章的时候不是很明白,有很多细节并不能很清楚,比如怎么去实现shortcut,每个阶段的输出到下一阶段时候的特征通道并不一致,在这里推荐大神李沐在哔哩哔哩的讲解,讲解得非常牛逼。
ResNet34的网络结构图:

图是来自论文中的,Pytorch中可以很方便的使用自带的model模块实现ResNet,但是有些细节是看不明白的,还是得自己去实现才能了解。

这是不同的ResNet的具体细节,本代码完全按照上面的细节来搭建的。

可以使用Pytorch中的torchvision模块的方法去初始化一个网络,查看一下网络结构,照着实现。代码如下:

# !/usr/bin/python3
# -*- coding:utf-8 -*-
# Author:WeiFeng Liu
# @Time: 2021/11/5 下午3:55
import torch
import torchvisionnet = torchvision.models.resnet34()
print(net)

会输出一个标准的网络信息,我在复现这些基本的backbone的时候喜欢这么做,直接看着代码敲可能会少一些思考和对细节的理解,得到的结果如下:

ResNet((conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)(layer1): Sequential((0): BasicBlock((conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(1): BasicBlock((conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(2): BasicBlock((conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)))(layer2): Sequential((0): BasicBlock((conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)(bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(downsample): Sequential((0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)(1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)))(1): BasicBlock((conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(2): BasicBlock((conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(3): BasicBlock((conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)))(layer3): Sequential((0): BasicBlock((conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(downsample): Sequential((0): Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2), bias=False)(1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)))(1): BasicBlock((conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(2): BasicBlock((conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(3): BasicBlock((conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(4): BasicBlock((conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(5): BasicBlock((conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)))(layer4): Sequential((0): BasicBlock((conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)(bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(downsample): Sequential((0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)(1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)))(1): BasicBlock((conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(2): BasicBlock((conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)))(avgpool): AdaptiveAvgPool2d(output_size=(1, 1))(fc): Linear(in_features=512, out_features=1000, bias=True)
)Process finished with exit code 0

其实只能得到具体每个块和每层的具体参数,怎么去实现还是的自己去思考,可能我太菜了,搞了一早上。

数据集描述

数据集使用的网上一个公开的汽车数据集,包含十个类别的汽车。


包含大巴,面包车等一些类别。需要数据集的私聊我发你百度链接。

网络结构

# !/usr/bin/python3
# -*- coding:utf-8 -*-
# Author:WeiFeng Liu
# @Time: 2021/11/16 上午10:40import torch
import torchvision
import torch.nn as nn
import torch.nn.functional as Fclass BasicBlock(nn.Module):def __init__(self, in_channels,out_channels,stride=(1,1),downsample=None):super(BasicBlock, self).__init__()self.Block = nn.Sequential(nn.Conv2d(in_channels, out_channels,kernel_size=3,stride=stride,padding=1),nn.BatchNorm2d(out_channels),nn.ReLU(inplace=True),nn.Conv2d(out_channels,out_channels,kernel_size=3,stride=1,padding=1),nn.BatchNorm2d(out_channels),)self.downsample = downsampledef forward(self,x):out = self.Block(x)if self.downsample is not None:residual = self.downsample(x)else:residual = xout += residualreturn outclass ResNet34(nn.Module):def __init__(self,num_classes=1000):super(ResNet34, self).__init__()self.head = nn.Sequential(nn.Conv2d(3,64,kernel_size=7,stride=2,padding=3),nn.BatchNorm2d(64),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=3,stride=2,padding=1))self.layer1 = self.make_layer(64,64,3)self.layer2 = self.make_layer(64,128,4,strides=2)self.layer3 = self.make_layer(128,256,6,strides=2)self.layer4 = self.make_layer(256,512,3,strides=2)self.avg_pool = nn.AdaptiveAvgPool2d(1)self.fc1 = nn.Linear(512,256)self.fc2 = nn.Linear(256,num_classes)def make_layer(self,in_channels,out_channels,block_num,strides=1):downsample = nn.Sequential(nn.Conv2d(in_channels, out_channels, kernel_size=1,stride=strides,bias=False),nn.BatchNorm2d(out_channels),)layer = []layer.append(BasicBlock(in_channels,out_channels,strides,downsample))for i in range(1,block_num):layer.append(BasicBlock(out_channels,out_channels))return nn.Sequential(* layer)def forward(self,x):x = self.head(x)x = self.layer1(x)x = self.layer2(x)x = self.layer3(x)x = self.layer4(x)x = self.avg_pool(x)x = x.view(x.size(0),-1)x = self.fc1(x)x = self.fc2(x)return x

train

使用Adam优化器来训练的网络

# !/usr/bin/python3
# -*- coding:utf-8 -*-
# Author:WeiFeng Liu
# @Time: 2021/11/5 下午4:37import torch
from torch.utils.data import DataLoader
from torchvision.transforms import transforms as transforms
import torch.optim as optim
from dataload.car_dataload import CAR_DATASET
from resnet34 import ResNet34
import torch.nn as nn
from utils import plot_curvedevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
epochs = 200
batch_size = 32
lr = 0.001
transform = transforms.Compose([transforms.Resize([224, 224]),transforms.ToTensor(),transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]),
])
train_dataset = CAR_DATASET(r'dataset/train', transform=transform)
train_loader = DataLoader(train_dataset,batch_size=batch_size,shuffle=True,
)model = ResNet34(10).to(device)
opt = optim.Adam(model.parameters(),lr=lr,betas=(0.9,0.999))
cri = nn.CrossEntropyLoss()train_loss = []
for epoch in range(epochs):sum_loss = 0for batch_idx, (x, y) in enumerate(train_loader):x = x.to(device)y = y.to(device)pred = model(x)opt.zero_grad()loss = cri(pred, y)loss.backward()opt.step()train_loss.append(loss.item())print('[epoch : %d  ,batch : %d  ,loss : %.3f]' %(epoch,batch_idx,loss.item()))torch.save(model.state_dict(), 'model/model.pth')
plot_curve(train_loss)

但是在测试集上也没有特别好,也就是0.8这个样子的正确率。

Pytorch:手撕ResNet34实现汽车分类相关推荐

  1. 手撕python_GitHub - caishiqing/manual: 手撕机器学习

    手撕机器学习 用腻了开源框架,尝试下手撕机器学习模型?写这个手撕机器学习系列,旨在不使用任何开源框架的条件下手推实现各种模型,同时保证高性能. Requirements 适用于python2.7与py ...

  2. 手撕 CNN 经典网络之 VGGNet(PyTorch实战篇)

    大家好,我是红色石头! 在上一篇文章: 手撕 CNN 经典网络之 VGGNet(理论篇) 详细介绍了 VGGNet 的网络结构,今天我们将使用 PyTorch 来复现VGGNet网络,并用VGGNet ...

  3. 手撕 CNN 之 AlexNet(PyTorch 实战篇)

    大家好,我是红色石头! 在上一篇文章: 手撕 CNN 经典网络之 AlexNet(理论篇) 详细介绍了 AlexNet 的网络结构,今天我们将使用 PyTorch 来复现AlexNet网络,并用Ale ...

  4. 关键点检测之直接回归(逐行手撕Pytorch)

    直接回归的整个流程如下: 用卷积提特征 用全连接层进行回归得到关键点 与标签做损失并优化损失 当图像很大的时候,神经网络是在整张图像中去寻找一个像素点,所以直接回归这一解决办法让神经网络的工作是非常难 ...

  5. 手撕 CNN 经典网络之 VGGNet(理论篇)

    2014年,牛津大学计算机视觉组(Visual Geometry Group)和Google DeepMind公司一起研发了新的卷积神经网络,并命名为VGGNet.VGGNet是比AlexNet更深的 ...

  6. 深度学习之手撕深度神经网络DNN代码(基于numpy)

    声明 1)本文仅供学术交流,非商用.所以每一部分具体的参考资料并没有详细对应.如果某部分不小心侵犯了大家的利益,还望海涵,并联系博主删除. 2)博主才疏学浅,文中如有不当之处,请各位指出,共同进步,谢 ...

  7. 手撕图机器学习,图神经网络

    手撕图机器学习,图神经网络 写在前面 & 配套链接(访者必读) 图的基本表示 图的基本参数 图的类别 节点连接数(Node degree) 图的矩阵表示(邻接矩阵) 连接列表和邻接列表 其他图 ...

  8. predict函数 R_RROC三剑客(一)使用R语言手撕ROC曲线

    之前因工作需要绘制ROC曲线,所以对该曲线的计算细节进行了一番摸索.刚开始我搜索ROC曲线一般跟机器学习相关联,导致我对它的概念有了曲解,理所当然地以为它只是一个用于机器学习的分类器评估标准,所以在绘 ...

  9. 机器学习算法之手撕SVM-线性(理论)

    感谢Jack-Cui大佬的知识分享 机器学习专栏点击这里 目录 感谢Jack-Cui大佬的知识分享 0. 什么是SVM? 概述 1. 线性SVM 1.1 相关概念:决策面,分类间隔,最优决策面(最优解 ...

最新文章

  1. 扩展资源服务器解决oauth2 性能瓶颈
  2. [architecture]-ARMV7架构下Linux Kernel的Userspace进程切换时保存和恢复哪些寄存器
  3. 脉冲宽度测量程序 c51 c语言,基于C51单片机和LCD1602显示的超声波测距仪C语言程序...
  4. python几乎无所不能 只有你不知道的,如何通过Python玩转小视频
  5. Android隐藏状态栏和标题栏
  6. 英伟达 | 深度学习GPU最新情况
  7. Angular.js学习-入门
  8. iOS CoreData (一) 增删改查
  9. android studio怎么设置log保存txt_【Stata写论文】log命令的使用和分析结果导出
  10. Web应用工作原理、动态网页技术
  11. 编译安装Nginx-1.0.1
  12. [转载] Java中使用new构造数组时会不会自动调用类的默认构造函数
  13. 中断python快捷键_python的快捷键
  14. SpringBoot PageOffice 在线编辑 (完整版、有源码)
  15. 什么是GPU,GPU怎么工作的,什么是图形的渲染,渲染怎么完成的。
  16. 量子计算机和神威计算机哪个快,神威 计算机 IBM的量子计算机真的可以秒杀中国超算吗?(2)...
  17. 堆排序 ← 改编自《啊哈!算法》
  18. 三刺激值计算公式_颜色三刺激值的计算方法及其比较
  19. 34、查询课程名称为数学,且分数低于60的学生姓名和分数(不重点)(自己做出)
  20. Ubuntu18.04 Sublime Text3

热门文章

  1. 提升沟通效率,增强企业执行力-中小企业融合通信解决方案
  2. 并查集解决朋友圈问题
  3. 海思3559kernel移植(一):一路next的默认模式
  4. 系统资源查看与进程管理
  5. 如果用计算机计算带有大括弧的数学题,小学一年级数学上册图画大括号应用题doc...
  6. Unity中游戏存档方式
  7. 使用uglifyjs压缩JS文件
  8. 35岁离开互联网,35岁真的是职场分水岭吗?
  9. SAP一共有多少模块?
  10. 产品经理的修炼:怎样把梳子卖给和尚