<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path> </svg>
讯享网
前言
最近在看经典的卷积网络架构,打算自己尝试复现一下,在此系列文章中,会参考很多文章,有些已经忘记了出处,所以就不贴链接了,希望大家理解。
完整的代码在最后。
本系列必须的基础
python基础知识、CNN原理知识、pytorch基础知识
本系列的目的
一是帮助自己巩固知识点;
二是自己实现一次,可以发现很多之前的不足;
三是希望可以给大家一个参考。
目录结构
1. 前言与参考资料:
本来是没打算再更新图像分类算法的实现的,因为前面alexnet、vgg已经很好的给出了例子,大家只需要按照流程来基本都可以实现。
不过,之所以出这篇文章,是因为在看pytorch实现resnet那篇文章的时候,发现很多地方都写错了,所以这里来纠正一下,顺带再次复习一下图像分类算法实现流程,并且尽力做到全面(主要是调整学习率训练和采取预训练模型试试)。
数据参考资料
B站的一个up主的GitHub仓库,链接为:
讯享网
这个up不仅提供了数据集,也提供了相关代码和讲解视频,大家可以自己去学习,但是建议大家自己先实现一次,体验下难点在哪里。
2. 数据集介绍与下载:
数据集下载
方法一:从GitHub中下载,然后还需要自己处理一下。
方法二:从下面的百度云下载:
数据集介绍
这个数据集也是来自于网上公开的数据集的子集,是一个花分类的数据集,总共有5个类别,分别为。
从百度网盘获取的数据集,分为两个文件夹,一个为train、一个为test,train中每个类别都有200张图片,共1000张图片;test中每个类别100张图片,共500张图片。
3. ResNet构建与完善:
之前已经写过了怎么构建resnet,当时的完整代码为:
讯享网
不过,后来在实际运行的时候,才发现很多地方写错了。不过改错也是一种基本能力,毕竟你拿来别人的代码,一般很少可以一次性跑成功,总是需要修改的。(如果不看改错的部分,直接跳到后面的完整代码即可,这里写出来,主要是为了纠正前面文章的错误)
首先,来纠错:
- 有四行关于make_layers的,本来应该为_make_layer写为了make_layers
- 也是上面这四行代码,字典self.layers_dic居然少些了个t
讯享网
- 还是上面的问题,最后传入的字典,把3写为了1
- 有两个地方in_planes与planes写岔了:
讯享网
- 另外,layers变量重复了,需要添加一个temp_layers变量
- 参数初始化部分,kaiming初始化中的参数写错
讯享网
完成上面修改后,新的resnet代码为:
4. 数据加载器构建:
这一部分我直接把前面复制过来了,本来想跳过的,但是方便读者就复制过来了
这里,我们需要自己实现Dataset类(用来获取数据和标签,配合Dataloader使用)。

目录结构
在介绍如何写代码前,先说明一下我的目录结构:
讯享网
基本框架
首先,根据pytorch基础知识,写出Dataset类的基本框架:
init()填写
我们需要定义两个基本的参数:
讯享网
而在init方法中,我们需要获取到我们的图像路径和相应标签,因此我们定义一个函数来实现该想法:
operate_file方法实现
由于我们的图片存在于多个文件夹中,因此决定了我们的filename参数应该是一个文件夹路径,在我的目录结构中应该为:
讯享网
因此,可以这么写代码(看注释)
这里,我必须解释一下:为什么np那里需要声明为int64类型?因为你训练的时候,使用损失函数计算那里,必须要求int类型为int64。
len方法填写
这个简单,直接按照固定套路写即可:
讯享网
getitem方法填写
实现的思路:
具体代码为:(看注释)
完整代码
讯享网
5. 训练代码:
在完成了模型创建、Dataset类构建,就可以开始着手实现训练过程了。
这里,我将训练过程放入了一个名为的函数中进行。
前期准备
首先,创建我们的模型,并将模型放入GPU中:
讯享网
声明,为了简便,后面不会写重复的部分,只会写新多出来的部分。
接着,我们定义损失函数,这里采取分类任务常用的交叉熵损失函数:
然后,定义优化器,这里采取Adam优化器:
讯享网
下一步,定义每批训练的数据个数并加载数据:
训练中
假设训练20次,并定义一个临时变量来存储损失值:
讯享网
接着,批量批次接收数据:
首先,把数据放入GPU中:
讯享网
接着,便是丝滑小连招:
当内层结束循环时,打印一下这次的平均损失值:

讯享网
最后,我们添加一个训练完成后模型保存的函数即可完成整个训练部分的代码:
完整代码:
讯享网
6. 训练与调整:
第一次尝试:GPU报错
我首先尝试使用batch_size=32,SGD优化器,学习率为0.02进行训练。结果果然不出我所料,报错了,还是vgg那篇的原因,GPU逊爆了,不过这方面我也不懂,所以我决定用我懂的方法解决它,减小batch_size大小。
第二次尝试:SGD、学习率0.02,batch_size=10
于是,我将batch_size改为了10,继续尝试:
第三次尝试:在上面模型的基础上,改小学习率,变为0.002
从上面的训练应该可以猜测,模型还没有收敛,因此可以继续训练。此时已经保存了模型参数,于是我修改了训练部分的代码:
讯享网
并且将学习率改为0.002,结果为:
效果似乎还不错,毕竟损失值在逐渐变小。好在我们把模型保存了,后面把测试代码写完了可以用来验证一下效果如何。
7. 加载预训练模型:
我们在网上找到resnet50的预训练模型,下载到本地保存,我保存的路径为:
讯享网
如果你想下载,可以直接在网上搜resnet预训练模型下载,这个网上很多,我就不贴链接了。
由于自己写的模型总会与官方有出入,因此加载预训练模型,建议采用官方提供的resnet50模型:
然后,需要把一些代码注释掉,然后加入预训练的代码:
讯享网
因为我们需要将我们的模型和预训练模型对比,所以在运行之前,记得改一下模型保存部分的路径,这样避免文件名重叠被覆盖了。
运行结果如下:
可以看到,结果比我们自己训练的好多了,不过,这也是我们本身没有训练好有关。
8. 测试代码:
测试部分的代码,需要写两个部分,一是测试集数据的加载,二是测试过程代码。
数据集加载的代码,可以仿照训练集加载来写 ,我直接把代码放在这里,大家可以自行参考:
讯享网
另外,就是测试过程的代码,也很简单,可以看注释:
最后,我们定义一个运行测试函数的代码,主要作用是加载我们已经训练好的模型:
讯享网
9. 测试:
我们来测试一下自己训练的和预训练模型的结果差别。
woc,怎么回事?这个准确率怎么这么低?
我表示很纳闷,因为之前VGG16训练的时候损失值降低到0.8左右也有58%左右的准确率呀,而预训练的ResNet-50好歹也降低到0.2左右,怎么准确率这么低呢?
我看了下代码,发现一个问题,就是我预训练模型,没有修改输出个数,大家都知道ImageNet比赛的输出为1000个,因此我怀疑是这个的问题,但是VGG16当时也忘记修改了也没有低呀。
本着试试的态度,我修改了代码:
讯享网
再次运行:
准确率:
讯享网
??这下我有点蒙蔽了,我想了很久没有想到为什么?难道是过拟合了?
这个问题我暂时不清楚,后面如果有机会再来解决吧,我的想法是如果过拟合了,那么可以使用数据增强试试,看看能不能提高精度。
10. 总结:
这篇文章,主要目的是纠正之前那篇文章的笔误,其次就是尝试调整学习率训练,不过说是调整,其实就是训练一次,改变一次学习率。我觉得应该可以随时暂停,然后调整学习率,再训练。不过,怎么实现我不清楚。
另外,这次文章还留下一个问题,就是准确率为什么这么低?希望后面可以解决。
完整代码

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