基于深度学习的车型识别系统的设计与实现

~~

目录

~~
摘 要 1

  1. 引言 3
    1.1. 研究背景与意义 3
    1.2. 主要研究内容 3
    1.3. 论文组织结构 4
  2. 车型识别系统总体设计 5
    2.1. 系统需求分析 5
    2.2. 环境介绍 5
    2.3. 整体方案设计 5
    2.4. 原理概述 6
  3. 相关技术介绍 8
    3.1. ResNet-50网络架构介绍 8
    3.2. 前后端技术介绍 9
  4. 数据集设计与制作 11
    4.1. 数据集介绍 11
    4.2. 数据爬取与整理 11
  5. ResNet-50训练与调试 15
    5.1. 图像预处理 15
    5.2. 全连接层设计 16
    5.3. 损失函数与优化器设计 19
    5.4. 模型训练 20
    5.5. 泛化能力测试及结果分析 22
  6. 模型应用 23
    6.1. 分类程序设计 23
    6.2. 图像识别网站设计 24
  7. 总结与展望 25
    7.1. 本文总结 25
    7.2. 设想与展望 25
    致谢 26
    参考文献 27
    附件1:程序源码 28

摘 要

随着城市化建设的不断发展,我国对交通建设的需求也不断增长。发展智能交通是一项重要的任务,而汽车车型的识别在智能交通领域又起着极其重要的作用。本文采用PyTorch这一深度学习框架,利用ResNet-50预训练模型为基础训练得到了用于车型识别的模型,通过分析比对全连接层中的各项参数与各类函数,对该模型的全连接层进行了修改与调优以适应本模型。除此之外,本文通过编写爬虫脚本采集迁移学习时所需要的样本图片以完成训练集的制作。经过不断尝试与挑选得到了训练完成的最优模型并将其应用到实际场景中,分别设计了一个汽车图片分类程序以及一个以html为前端、python为后端的车型识别网站。
关键字:深度学习、车型识别、迁移学习、PyTorch。

Abstract
With the continuous development of urbanization construction, China’s demand for transportation construction is growing at the same time. Developing intelligent transportation is an significant task, and the identification of vehicle type plays an very important role in the field of intelligent transportation. In this paper, we use PyTorch as the deep learning framework, and use the ResNet-50 pre-training model as the basis for training to obtain a model for vehicle type identification. The full-connection layer has been modified and tuned to suit this model. In addition, this article completes the production of the training set by writing a crawler script to collect the sample pictures needed for training with migration learning. After continuous trial and selection, we obtain a trained optimal model and apply to the actual scene:we design a car picture classification program and a vehicle identification website whitch with html as the front end and python as the back end.
Key words: Deep learning, model recognition, transfer learning, PyTorch.

1. 引言

1.1.研究背景与意义
1.1.1.研究背景
随着城市化建设不断发展,我国对交通建设的需求也不断增长,我国成为了世界上在交通领域基础设施建设最快的国家之一[1],但车辆管控问题、道路交通问题、车辆违章问题等层出不穷,很难做到全面、有效的管理。目前,计算机技术不断提高,在大数据、物联网和机器学习等技术的支持下,人类社会日渐趋于智能化,智能地管理城市交通正是目前急需发展的,即智能交通。智能交通指的是将计算机技术、物联网、机器学习等技术综合运用于交通体系,能够有效、准确、全面地管理交通[2]。目前,智能交通在国外一些发达国家已经得到了广泛地使用,在我国也快速地发展着。
汽车车型的识别在智能交通领域有着极其重要的作用,它采用图像处理等技术,根据不同汽车车型的图像特征,对其进行分类。我国从九十年代已经开始了这方面的研究,社会上很多人才已经在这一方面投入了大量的研究,对交通智能化领域的发展提供了巨大的帮助。
对于车辆的智能识别来说,深度学习提供了一种高效可靠的解决方案,其中卷积神经网络在车型识别中得到了广泛的应用[3]。近几年来,随着大数据的发展,传统机器学习的发展并未随着数据量的增多而发展,深度学习却有了很好的表现。运用大量数据来提高自身性能的深度学习迅速被应用到各种场合,并发挥了独特的作用。从2017年1月Facebook AI 研究团队发布PyTorch以来的三年的时间,PyTorch发展迅速,在深度学习领域不断发光发热,为深度学习爱好者提供了一个优秀的深度学习框架。
1.1.2.研究意义
一方面,汽车车型识别能有效地简化一些交通管理问题,减小了交通规划所需的成本,提升管理效率。例如,有些路段禁止大货车通行,要严格管控违章车辆需要投入大量人力成本,但智能化识别车型便能方便有效地管理这些交通问题。另一方面,也有利于道路车辆信息实时地采集,通过对采集到的这些数据进行统计分析,有利于之后对不同路段道路交通的规划建设。除此之外,车型识别对于数据集的管理也有重要的意义,对于其他汽车智能定损项目的数据集的筛选制作提供了便捷的方法,极大地提升了素材管理的人力成本。
1.2.主要研究内容
本文开发了一个以python为后台,以html为前台用于车型识别的网站系统。系统后台通运用 PyTorch深度学习框架,根据性能及需求选择并搭建了一个适合的神经网络,通过采集大量素材,制作了训练数据集、验证数据集及测试数据集对网络不断训练和测试,根据结果不断进行优化和完善,最终得到了一个可靠的识别系统。
与此同时,本文开发一个了python程序,用于将文件夹中的汽车图片按照车型分入不同的文件夹中,该程序可以用于到一些实际项目中,帮助项目整理车型类图像样本素材,节约素材整理时间,提高效率。

1.3.论文组织结构
本文将分为六个章节,讲述车型识别系统的设计与实现,内容如下:
第一章引言:该章节介绍该项目的研究背景与意义、主要研究内容以及论文组织结构。
第二章车型识别系统总体设计:该章节用于总述该项目的需求及设计方案,其中包括需求分析、相关的电脑环境介绍、整体方案设计以及原理概述
第三章相关技术介绍:该章节具体介绍了所以用的卷积神经网络技术以及前后端交互技术。
第四章数据集设计与介绍:该章节包括数据集介绍和数据集的爬取与整理。
第五章ResNet-50训练与调试:该章节讲述了对ResNet-50进行训练与调试的具体工作,其中讲述了图像预处理、全连接层设计、损失函数与优化器、模型训练、最优模型泛化能力测试。
第六章模型应用:该章节讲述了模型的具体应用,包括图像分类程序设计和图像识别网站设计,分别介绍了其目的与意义以及实现方案。
第七章总结与展望:总结了课题研究期间的所有工作和心得体会,并针对本课题中存在的问题提出了改善思路。

2.车型识别系统总体设计

2.1.系统需求分析
以杭州某公司为例,该公司的车辆保险项目是利用机器学习方法,仅需通过车损照片就可以快速、智能、高效地判断赔损情况。由于定损过程中对车型具有限制,因此需要员工进行网络车型图片爬取并人工筛选制作数据集,效率低下且常常因为员工的失误导致车型数据集存在不属于该车型的杂质样本。本车型识别系统很好地可以应对这一需求,该系统能将车型图片进行快速有效地分类,即节约了该公司研发时间,又降低了研发成本,可以实现高度自动化。
除此之外,随着机器学习技术的快速进步,智慧交通这一概念不断被提起。实现交通智能化、管理高效化时钟离不开基于各项机器学习技术的一些识别系统,本车型识别系统就是其中的一个重要组成部分。利用本车型识别系统,可以实时监控路段车型情况,有效排查违规车型这一智能交通领域的基本需求。
综上所述,制作一个基于深度学习框架的车型识别系统无论对于相关企业或是交通智能管理都有着较大的需求和重要的意义。
2.2.环境介绍
操作系统:Windows 10
Python IDE(集成开发环境): JetBrains PyCharm+ Jupyter notebook
Python版本:Python3.7
深度学习框架:PyTorch
PyTorch框架介绍:深度学习框架可以有效简化神经网络搭建的代码,同时使代码有更好的可读性。相较其他较为常用的框架,PyTorch的性能更好,具体表现在模型的训练上有着更快的速度,这也是深度学习上一个重要的指标,主要由于PyTorch是由C语言开发。PyTorch框架的出现相对比较迟,目前的学习资源也相对来说较少,但由于该框架的实用性很高,目前也受到了很多人的关注。同时,PyTorch在学习上和使用上相对来说比较简单灵活。
CUDA版本:10.2(用于进行GPU运算,相较于CPU运算大大提高训练效率)
爬虫编写相关库:requests、urllib3
神经网络训练相关库:numpy、torch、torchvision、opencv、matplotlib
2.3.整体方案设计
本文分析了Pytorch和TensorFlow深度学习框架的优劣势和所适用的应用场景,结合车型识别这一实际目的,最终选择了灵活简易,易于应用的Pytorch框架。在深度学习网络的设计中,对经过不同层数的预训练的RestNet模型进行迁移学习实验。迁移学习是目前深度学习中的一个热点,主要也是为了解决目前很多情况下标注数据稀缺的问题[4],在素材较少的场合下也能达到满意的识别结果。本文用全链接神经网络代替RestNet网络最后一层,并将该输出经过Softmax函数进行分类判断得到预测结果。实验过程中还对预训练模型的最后一层进行了包括Loss函数、学习率及其动态变化方法、正则化函数、梯度下降算法及优化器等在内的算法和函数的调整以最优化适应本车型识别模型。
用于训练的车型被分为小汽车、越野车、面包车、大巴车、货车、SUV六类,通过爬虫技术采集该六类车型的图片素材,通过筛选和清洗之后制作包括训练集、验证集和测试集在内的完整数据集。训练集将输入到模型中用来训练和更新模型的参数,验证集则将在每一轮次的训练后对模型识别准确率进行验证,评估选择在迭代过程中的最优模型。根据分析验证集的准确率数值,与训练集的数据同时分析之后可以对模型最后一层的各项函数和参数进行人工调优后得到更适应车型识别的模型,最终可以将测试集输入到训练结果最好的模型中进行考核该模型的泛化能力。
模型训练测试完成之后,可以将这个模型应用于各种车辆图片的车型识别与分类。分类程序中,程序得到需要被分类的车型图片的文件夹路径之后将各图片输入到训练完的模型之中,根据测试模型输出的对应标签将各车型图片复制到该目录下生成的对应车型文件夹中,完成分类工作。此外,本文还设计了一个示意网站来与用户进行交互,用户将上传汽车图片到后端进行识别,识别结果将返还到用户界面上。
系统整体框架流程图如图1-1所示。
在这里插入图片描述

图1-1 系统整体框架图
2.4.原理概述
深度神经网络可以模拟出人体的神经结构,建立神经网络来解析数据进行学习。神经网络一般包括了输入层、隐藏层和输出层,深度神经网络一般含有较多数量的隐藏层,层与层之间进行输入与输出进行加权计算连接,加上偏置后,通过激活函数对输出按照激活函数进行变换,变换后即为该神经元的输出。神经网络的训练就是给网络输入大量的数据集进行训练,对神经元中未知的权重值通过反向传播进行计算和修正,使之总结出事物特征。
卷积深度神经网络是常用于图像识别的深度学习方法之一,其隐藏层较为复杂。一般来说,一个卷积网络的隐藏层包含了卷积层、池化层、全连接层。卷积层能够计算得到素材样本的局部特征,从而当图片本质未发生变化,只是位置发生变化时,能够依然保留图像的本质特征,如当图片进行旋转、镜像、变换位置时,依然使神经网络能提取出与原图类似的特征。
由于训练一个完全的卷积神经网络需要大量数据集,训练时长将无法预估,所以本文将应用到卷积神经网络中的ResNet网络模型进行迁移学习。迁移学习,就是将已经经过预训练的适用于大数据的模型及其参数迁移到自己的模型中,然后根据本身数据集的需求,对训练好的模型的输入层、输出层进行调整,使其适用于自己的数据集,再进行训练。车型识别系统总体设计。

3.相关技术介绍

3.1.ResNet-50网络架构介绍
四十多年前,多伦多大学的一位教授以及其所在的团队第一次展示了一种通过卷积计算的神经网络。2012年,Geofrey Hinton教授和他的团队,带着他们的AlexNet模型在Imagenet比赛取得了巨大的成功,极大地推动了图片识别领域的发展[5]。接着,牛津大学Visual Geometry团队以及谷歌的DeepMind公司一起提出一种名叫VGG的深度神经网络网络,在ILSVRC 2014上取得了杰出的成绩[6]。VGGNet在图像识别领域具有重要的意义,它容易迁移到其他图像识别的项目上,以至于目前很多卷积神经网络都以它为基础[6]。同年马里奥·塞格德等人提出了GoogLeNet深度卷积神经网络架构,相较于之前的AlexNet模型,参数少了12倍,但有着更高的精度,使内部计算资源的利用率大大提高,相较于VGGNet也加深了分类网络的深度[7]。2015年,微软提出了ResNet,解决了当网络性能达到最优时,若继续加深网络,准确率反而下降的问题,成功训练出了152层深度的网络,在深度学习的发展上有着重要的意义。
目前主流的ResNet网络通常分为ResNet-18、ResNet-34、ResNet-50、ResNet-101、ResNet-152这五种。ResNet-18和ResNet-34主要由BasicBlock构成,BasicBlock单元结构如图3-1所示[8]。而本文所应用的ResNet-50以及ResNet-101、ResNet-152主要由Bottleneck构成,Bottleneck单元结构如图3-2所示[8]。在pytorch的resnet.py文件中,我们可以通过ResNet网络的源代码很好地了解ResNet网络的组织架构。以ResNet-50为例,其首层为输入3通道,卷积核尺寸为的二维卷积层,该卷积层如下所示:
self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=7, stride=2, padding=3,bias=False)
网络第二层为bn层,常用于加快收敛速度,防止梯度爆炸。在bn层之后需要经过一个ReLU激活函数,网络的第四层是一个池化层用于对特征降维度,提高计算速度,提高特征鲁棒性。从网络的第五层开始,进入由Bottleneck组成的卷积层,也是ResNet的关键部分。从源代码中resnet50的返回值_resnet(‘resnet50’, Bottleneck, [3, 4, 6, 3], pretrained, progress,**kwargs)及源代码resnet函数中对layer1、layer2、layer3、layer4的定义可以看出,ResNet-50由3个planes为64的Bottleneck层,4个planes为128的Bottleneck层,6个planes为256的Bottleneck层,3个planes为512的Bottleneck层构成。在这些层是一个平均池化层,网络的最后一层为用于分类的全连接层,通常迁移学习中,常常通过修改这个全连接层来训练以适应自己的数据集。
在这里插入图片描述

图3-1 BasicBlock单元结构
在这里插入图片描述

图3-2 Bottleneck单元结构
3.2.前后端技术介绍
在web开发中,分为前端和后端两个环节,前端主要负责页面的布局,后端负责处理页面的逻辑,包括处理一些单击事件或提交的信息。
其中html(超文本标记语言)是前端常见的技术,是一种网页设计技术,具体结构如下:

标题 网页内容 标签用于定义文档的各种属性和信息,包括标题、文档编码格式、模块样式定义、客户端脚本定义等。 在标签下可以添加多个标签,用于组成网站的内容,例如,当我们打开一个网页,网页中显示的内容都是放于之间,其中常见的标签有、

、、 等。其中标签中可以添加一些文本框、文件上传、按钮等控件,用于向服务器传输数据。
标签用于制作表格通过 标签定义表格的行,
标签定义表格的单元格。

标签用于在网页中添加段落。标签可以在网页中添加超链接,通过点击可以事先页面跳转。 html结合CSS和JavaScript搭建前端,html作为主体,用于装载各种dom元素,CSS用于装饰,JavaScript用于控制dom元素,也可以连接前端和后端服务器,可以使得搭建的网站具有动态性。 后端采用Bottle框架开发,Bottle框架是一个微型的Python Web框架[9],内置HTTP服务器。Bottle框架主要路由系统、模板系统、公共组件、基于WSGI的服务组成。Bottle的路由系统可以分为静态路由、动态路由、请求方法路由、二级路由这四类,通过修饰器可以在用户打开对应url时用指定函数进行处理。其快捷方便的开发流程大大节约了开发Web的时间,在一些Web开发时常有着不宿的表现。

4.数据集设计与制作

4.1.数据集介绍
该系统包含识别的车型为六类,分别为大巴车、货车、小汽车、面包车、越野车、SUV,数据集被分为训练集、验证集和测试集。
训练集作用:训练集输入到神经网络中,使网络自动学习数据集中图片的特征,从而对神经元中未知的权重值通过反向传播进行计算和修正,使之能总结出图片额的特征。
验证集作用:验证集将在每一轮次的训练后对模型识别准确率进行验证,评估选择在迭代过程中的最优模型。根据分析验证集的准确率数值和变化趋势,根据准确率的收敛和发散情况,可以对模型最后一层的各项函数和参数进行人工调优后得到更适应车型识别的模型。
测试集作用:用于对最终的模型进行测试与评估。
训练集、验证集、测试集分别放入三个文件夹内,分别命名为train、valid、test。每个文件夹内包含六个文件夹:0_BUS、1_TRUCK、2_CAR、3_MINIBUS、4_JEEP、5_SUV,每个文件夹对应一类车型。将相应车型的图片放入相应的文件夹,用来给图片打上标签。
4.2.数据爬取与整理
4.2.1.数据爬取
由于深度神经网络的训练需要大量的图像素材,所以本文使用python编写爬虫脚本,进行多线程爬取百度图库中相关的车型的搜索结果图片,关键代码如下:
1)对输入的搜索关键字进行url编码,urllib库中的urllib.parse用于url解析:
queryEnc = urllib.parse.quote(keyword)
2)为了提高图片爬取的效率,需要进行多线程工作。将进程池设为5,当有新的请求被提交时,如果进程池中的进程数未到最大,则为提交的请求创建一个新的进程,直至进程数到达上限,其余的请求则需要等待池中其中一个进程结束。在多线程中对图片进行读取和保存的相关代码,首先需要导入相关的库,设置进程池的大小,通过异步非阻塞的方式对图片进行读取和存储:
from multiprocessing import Pool
p = Pool(5)
p.apply_async(func=get_and_save, args=(real_urls,))
3)在百度图库中搜索关键字面包车之后,可以查看到ajax请求信息及其url,如图4-1所示。
在这里插入图片描述

图4-1 包含ajax请求信息的示意图
如图4-2所示,%E9%9D%A2%E5%8C%85%E8%BD%A6该字符串是搜索的关键字“面包车”的url编码形式。
在这里插入图片描述

图4-2 ajax请求响应信息
所以在编写爬取图片时的ajax请求的url,需要使用queryEnc(上文中对中文的关键字进行url编码后的结果)代替%E9%9D%A2%E5%8C%85%E8%BD%A6,同时对pn=30根据输入的所需图片数进行修改,主函数代码如下:
def main():
keyword = input('输入爬取的图片名: ')
page = int(input(“请输入爬取的页数(每页30张图): “))
queryEnc = urllib.parse.quote(keyword)
p = Pool(5)
for i in range(page):
url=“https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=2013 26592&is=&fp=result&queryWord=”+queryEnc+”&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=&hd=&latest=&copyright=&word=”+queryEnc+“&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&expermode=&force=&pn=”+str(i*30)+“&rn=30&gsm=1e&1582816234965=”
html = get_page_html(url)
real_urls = parse_result(html)
p.apply_async(func=get_and_save, args=(real_urls,))
p.close()
p.join()
4)def get_page_html(url)函数用于获取该ajax请求返回的文本,文本内容包含了多张请求图片的信息,并以json格式封装,响应文本信息的json格式如图4-3所示。
在这里插入图片描述

图4-3 json格式下的响应文本内容
其中data展开后,包了含所有请求图片的信息,以其中的一张图片为例,该图片所包含的信息如图4-4所示。
在这里插入图片描述

图4-4 data中某图片信息
5)def parse_result(html)函数则是通过正则表达式从文本上一步获取的文本中提取每一张图片的真实url,代码如下:
url_real = re.findall(‘“thumbURL”:“(.*?)”,’, html)
该正则表达式用来匹配"thumbURL":“和”,中间的数据,即每一张图片的真实url。此外,re.findall()方法用来返回所有捕获组的列表。
6)对列表中获取的图片url,发送request get请求获取返回的数据包,代码如下:
r = requests.get(url_real, headers=headers)
在上述代码中,首先对响应包中的http状态码进行判断,如果状态码值为200,即响应一切正常,则将图片的信息以二进制形式写入,代码如下:
if r.status_code == 200:
r.encoding = r.apparent_encoding
将图片的content写入到指定路径下面,代码如下:
with open(path, ‘wb’) as f:
f.write(content)
4.2.2.数据整理
由于爬取的图像中存在大量不符合训练要求的图像,因此需要对爬取到的图像进行筛选和清洗。这些不规范的图像包括图像中同时包含多种车型的多辆车、车辆较不完整、非爬取类型的车型等情况。反复清洗核验之后每种车型各取大巴车277张、货车211张、小汽车127张、面包车210张、越野车133张、SUV214张作为验证集。取每种车型各取40张车型图像组成测试集。其余图像作为训练集,最终完成的数据集的训练集中拥有大巴车样本654个、货车样本931个、小汽车样本632个、面包车样本513个、越野车样本861、SUV样本722个。取数据集中的每类样本样例展示如图4-5所示,统计结果如表4-1所示。
在这里插入图片描述

图4-5.数据集展示

表4-1 数据集样本数量统计表
数据集
类型 样本数量(个)
BUS TRUCK CAR MINIBUS JEEP SUV
训练集 654 931 632 513 861 722
验证集 227 211 127 210 133 214
测试集 40 40 40 40 40 40

5.ResNet-50训练与调试

5.1.图像预处理
当出现训练模型过于复杂,训练数据集样本少,特征的维度过多等一些情况时,训练结束得到的模型常常会出现过拟合现象。从数据上通俗地来说就是训练集得到的训练准确率远远大于验证集和测试集的准确率。过拟合是神经网络模型训练过程中比较常见的一个现象,除了加入Dropout函数或正则化算法等方法之外,还可以通过上一章中提到的数据集清洗来清洗掉噪音过多的训练样本的方法,以及本小结所介绍的图像预处理(数据增强)的方法来尽可能改善训练完成的模型过拟合程度,保证模型有较好的泛化能力,使模型的识别率更高。
在将图片输入到Resnet网络进行训练、验证、测试之前,都需要对图像进行一定的数据增强。实验表明[10],数据增强有一定的抗过拟合问题,一定程度上增加了样本的随机性。在本文的数据增强方法中,先对训练集的图片进行按随机的长宽比例裁剪,输出分辨率为224,裁剪照片为原照片的80%100%,随机长宽比范围为0.81.2,由于原图片的长宽比与输出图片不一致,在长宽比变化时需要进行插值,本文选用了RandomResizedCrop函数的默认插值法,即双线性插值,代码如下:
transforms.RandomResizedCrop(size=224, scale=(0.8, 1.0), ratio=(0.8, 1.2))
双线性差值法能使处理完的图像更平滑,双线性差值法举例说明如下:如果对某一图片进行长宽变化得到新图,需要计算该新图的某一坐标对应的RGB值,该点在原图的坐标为,如图5-1所示。则与P点最接近的四个相邻整数点分别为、、、。用表示点的RGB值。记为点A,为点B。则A的RGB值为、B的RGB值为,计算方式如下:

则点的RGB值可根据A、B两点计算,计算如下:

将和带入计算得,计算如下:
在这里插入图片描述

图5-1 某点坐标
完成随机长宽比例裁剪之后需要将图片进行随机旋转,参数degree设置为15度,即将图像在范围内随机旋转。重采样方法采用RandomRotation函数默认的最邻近法。该方法处理简单,处理速度快。其原理为变换后得点得RGB值为取原图对应点得最近邻整数坐标得RGB值。随机旋转代码如下:
transforms.RandomRotation(degrees=15)
为了增加图像的随机性,使上述处理完成的图像有50%的可能性会发生水平方向上的翻转,代码如下:
transforms.RandomHorizontalFlip()
然后将图片进行中心裁剪为224224像素的训练图像,代码为:
transforms.CenterCrop(size=224)
完成图像的一些随机处理之后,需要将图转换为张量以便输入给神经网络。最后将图片进行标准化操作,即将图片的RGB三通道减去均值(0.485, 0.456, 0.406),再除以标准差(0.229, 0.224, 0.225),这里的均值和标准差是由数百万张图像数据计算得到,本文使用的时ResNet-50预训练神经网络,因此可以使用该计算完成的均值和标准差。转换为张量和标准化的代码如下:
transforms.ToTensor()
transforms.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225))
对于验证集和测试集而言,数据预处理方法较为简单,其顺序为:最邻近法重置图像分辨率;224
224像素中心裁剪;转换为张量;标准化。
在加载训练集、验证集和测试集的图片时,都需要使用Pytorch库中的ImageFolder函数。以加载训练集为例,设置训练集的路径root以及数据增强方式,该数据增强方式为上述的所有训练集数据增强方式的按序组合,具体代码如下:
train=datasets.ImageFolder(root=‘mydata/train’,transform=train)
完成Dataset对象的创建之后,需要用到DataLoader函数。该函数用于在Dataset对象中随机取batch_size个样本放入到DataLoader中,以便进行训练、验证、测试时分批输入到深度学习网络中,在本设计中,batch_size设计为32。以训练集为例,具体代码如下:
train_loader=torch.utils.data.DataLoader(train,batch_size=batch_size,shuffle=True)
5.2.全连接层设计
残差神经网络的末层通常都是一个全连接层。卷积神经网络的重点在于局部特征,而全连接层则可以将卷积计算得到的局部特征进整合与归一,最终将末层的输出经过分类函数进行图像的预测和识别。由于全连接层的输出值的范围在整个实数域,因此需要对这些输出值取指数,然后用归一化的思想进行概率计算,这便是分类函数Softmax的计算思路。Softmax的数学表达式如下:

而将Softmax函数取对数的LogSoftmax则是在Softmax计算之后将其取对数,表达式如下:

由于本文选取的分类函数为ogSoftmax,为了避免对Softmax值进行两次取对数导致模型多样本的惩罚变轻,从而使模型准确率下降,因此选择的损失函数为NLLLoss而非CrossEntropyLoss。
在全连接层的设计中,全连接层层数的确定、各层神经元个数的确定、每一层的激活函数的选择、Dropout防止过拟合函数的选择[11]等这些都是需要认真考虑的[12]。由于单层的全连接层在解决非线性问题时往往效果不佳,而两层及以上的全连接层在保证数据集数量足够的情况下可以改善这一问题,但随着层数的增加,模型就会越复杂,训练的用时也会有一定程度的增加。在各层神经元个数分析上可以得到:神经元个数如果过大则会使模型训练速度变慢;神经元个数如果过小又会使模型准确度得不到保证。Dropout函数可以是前向传播过程中某个神经元以设置的Dropout函数参数的概率不进行训练和运算,也就是跳过这个神经元,这无论对加快训练速度还是对防止过拟合而言,都有着比较重要的作用。
在全连接层层数,本文分别测试对比了2层、3层以及4层全连接层层数对应的不同的效果。全连接层的输出有6个,经过分类函数计算后对应了某一个样本分别是六种分类类型的概率。保证激活函数和Dropout函数不变,对这三种模型各进行三次训练并将最优模型进行测试,将准确率和训练单次迭代耗时结果分别进行求平均(结果保留两位小数),得到了如表5-1所示的结果,可以看到,四层全连接层在准确率上较为有优势,且训练时间合适,因此选择四层全连接层。
表5-1 不同全连接层数对应的准确率和训练时间
全连接层层数 训练集正确率 验证集正确率 训练耗时(s)
2层 94.60% 92.50% 241.42
3层 94.09% 92.41% 242.08
4层 94.60% 92.58% 245.06

神经元个数选择上,本文在四层全连接层的基础上进行一定的实验,固定首层输出的神经元个数为256个,第二层的输出分别测试对比了128、256、512个,对这三种模型各进行三次训练并将最优模型进行测试,将准确率和训练单次迭代耗时结果分别进行求平均(结果保留两位小数),结果如表5-2所示。在综合了准确率和训练时间之后,最终选择第二层的输出有256个神经元。
表5-2 不同神经元个数对应的准确率和训练时间
神经元个数 训练集正确率 验证集正确率 训练耗时(s)
64 93.67% 91.98% 241.88
128 93.72% 91.98% 244.56
256 94.60% 92.58% 245.06

在全连接层中,常见可以选择的激活函数有Sigmoid函数、Tanh函数、ReLU函数、PReLU函数、ELU函数等[13],各激活函数的表达式见表5-3。在文献[13]的实验分析中,在训练次数有限时,ReLU函数在损失函数值和测试精度上都有着最好的表现。文献[13]的实验结果指出在迭代次数小于4000代时,激活函数ReLU函数在损失函数值和测试精度上都排名第一,而相对最差的激活函数为Sigmoid函数。本文也在全连接层分别使用上上述五个激活函数进行测试,也得到了激活函数ReLU函数最适合本设计的实验结果。因此,本文最后选择的激活函数为ReLU函数。
表5-3 常见激活函数及其数学表达式
激活函数名称 数学表达式
Sigmoid
Tanh
ReLU
PReLU
ELU

Dropout函数的概率参数可以根据实际模型来进行选择,如果过拟合现象严重,可适当增加神经元不进行训练和计算的概率。本文对比分析了分别在不加入Dropout函数、概率为0.4、概率为0.8三种情况下的模型准确率,分析了过拟合和欠拟合情况,发现本模型过拟合现象较小,分析可能的原因为训练集的训练样本数量足够,卷积层对喂入网络的训练样本特点提取较为充分。另外,当Dropout参数过大时,系统的整体准确率明显下降,出现欠拟合现象。经过综合考虑,最终选择了概率为0.4,即每个神经元有40%的概率不工作。实验结果入表5-4所示。
表5-4 Dropout函数对准确率的影响
Dropout参数 训练集准确率 验证集准确率 训练耗时(s)
0 93.83% 91.30% 246.54
0.4 94.60% 92.58% 245.96
0.8 84.44% 86.18% 245.88

最后,全连接层设置为:
fc_inputs = resnet50.fc.in_features
resnet50.fc = nn.Sequential(
nn.Linear(fc_inputs, 256),
nn.ReLU(),
nn.Linear(256,256),
nn.ReLU(),
nn.Linear(256,64),
nn.ReLU(),
nn.Dropout(0.4),
nn.Linear(64,6),
nn.LogSoftmax(dim=1)
)
5.3.损失函数与优化器设计
损失函数作为评估每一代模型的预测能力的函数,指导着模型学习。在本车型识别的模型中,损失函数选择负对数似然损失函数NLLLoss,该损失函数常与Softmax分类函数结合使用,等效于常用于多分类任务的交叉熵损失函数CrossEntropyLoss。NLLLoss损失函数将Softmax分类函数对每个样本图像的处理结果与标签相对应,计算每个样本对应的实际标签下的Softmax处理结果取对数再取相反数,最后将所有样本该计算值求和取平均,得到NLLLoss值,科学地评估了模型的预测能力。在实验调试时,发现于与其他损失函数相比,用NLLLoss损失函数更适合本车型识别模型,设置代码如下:
loss_f = nn.NLLLoss()
在优化器的选择中,我们选择了随机梯度下降算法,并加入了动量参数进行优化。在Pytorch库中,对应函数torch.optim.SGD。普通的无动量SGD算法,是将训练集的所有样本分为n个大小为batch_size的样本集,在训练的过程中,根据该样本集进行更新。由于样本集远小于训练集,利用样本集进行更新可以减少大量计算量,加快收敛。但样本集往往不能囊括整个训练集,只利用样本集进行更新有着不稳定的缺点。Pytorch中的torch.optim.SGD可以通过设置动量来优化传统的SGD算法。有动量的加入,能使梯度下降过程时以上次的更新为依据进行本次更新,相当于本次样本集的更新建立在上次的基础上,大大弥补了SGD的更新不稳定的缺点。在本模型中,学习率参数设置为0.001,动量参数设置为0.95,代码如下:
optimizer = optim.SGD(resnet50.parameters(), lr=0.001, momentum=0.95)
对于优化器中的重要参数之一,学习率在一定程度上可以理解为跟新幅度。在训练的前期,较大的学习率有助于模型更快收敛;而在训练的后期,为了让模型更新更加稳定防止震荡,可以适当减小学习率。本模型采用的时一种阶跃下降的学习率下降算法StepLR,步长设置为8,衰减因子设置为0.5,即每循环五次学习率变为上一次的50%。对应训练100代。学习率曲线方式如图5-1所示,代码如下所示:
scheduler = lr_scheduler.StepLR(optimizer, step_size=8, gamma=0.5)
在这里插入图片描述

图5-1学习率下降图
5.4.模型训练
设置模型总共训练100代,每代训练完之后计算该代平均准确率和损失值,用以评估模型、更新模型。完成一代训练之后,更新学习率,保存改代模型,并利用验证集对该代模型的泛化性进行简单的评估,可以有效验证是否过拟合以及为选择最优模型提供参考依据。每代的训练流程图如图5-2所示。在每代的循环中,利用to()函数将每次的训练样本的tensor变量复制到GPU并在GPU上训练,加快训练速度。模型参数更新的方法往往有两种,一种是每一个banch计算一次梯度更新一次参数,另一种是对每个banch的梯度进行累加,最后根据累加的梯度更新模型参数。后者往往有更好的效果,但由于计算机的限制,本文采用了前者。Pytorch在每次计算完成梯度之后会对梯度进行累加,因此,在每次反向传播更新网络参数之前,需要利用zero_grad()函数将梯度清零。在每次的训练中,将样本输入至模型,得到预测结果的标签与概率,根据负对数似然损失函数NLLLoss计算损失并将每个损失值与预测准确率进行累加。
验证集的程序较为简单,通过将拷贝到GPU的验证集样本输入值对应代训练完模型中进行标签与概率的计算,然后再与实际标签对比计算损失值与准确率,完成验证。
在通常的深度学习中,验证集准确率往往作为考量模型优良的标准以减少模型的过拟合影响。但是在本设计的训练与测试中我们发现,本设计的过拟合现象几乎不存在。并且,本设计中,用于验证集样本数量并不多,在经过一系列的测试和实验中后发现测试集的准确率也可以作为判断模型好坏的一个标准。所以在经过了100代的重复训练之后,本文采取了通过综合考量每代的训练准确率和验证集准确率的方式来选取最优模型。设训练集准确率为,验证集准确率为,则最优模型由如下公式(1)得到的最高准确率决定:
(1)
在这里插入图片描述

图5-2 每代训练流程图
5.5.泛化能力测试及结果分析
为了验证文中所训练的车型识别系统是否具有良好的泛化能力,本文将数据集中测试集的所有测试图片进行了模型泛化能力验证。最终的到测试集的240张样本图片的准确率为93.75%,即正确识别228个样本,预测错误结果统计如表5-1所示。通过对15张测试错误的图片进行统计发现,错误率最高的是面包车,共识别错误10张,其中有7张面包车样本被识别为小汽车;2张面包车样本被识别为大巴车;1张面包车样本被识别为货车。货车与小汽车均识别错误2张,越野车识别错误1张,大巴车和SUV识别均正确。从误识别的结果来看,将各图片样本错误地识别为大巴车、货车、小汽车的数量分别为4张、3张、8张,其余为0张。除面包车外,其余识别准确率基本满足要求。
表5-1 预测错误样本预测结果统计表
车型 预测错误数量 被识别为以下车型数量 准确率
大巴车 货车 小汽车 面包车 越野车 SUV
大巴车 0 0 0 0 0 0 0 100%
货车 2 1 0 1 0 0 0 95%
小汽车 2 1 1 0 0 0 0 95%
面包车 10 2 1 7 0 0 0 75%
越野车 1 0 1 0 0 0 0 97.5%
SUV 0 0 0 0 0 0 0 100%

6.模型应用

6.1.分类程序设计
6.1.1.目的与意义
该分类程序的目的是应用先前训练完成的识别效果较好的深度模型,设计完成一个批量车型图片自动化分类的程序。将批量图片文件夹的路径输入到程序中后,程序会在该文件夹中生成一个存放分类结果的文件夹,该文件夹中包含了六类车型对应的文件夹:bus、truck、car、minibus、jeep、suv,并根据每张图片的识别结果将图片分类放入对应的文件夹中。
随着智能化交通的发展,目前,许多车辆识别的项目对车型有指定要求,在训练素材和测试素材采集时,需要人工对杂乱的爬取的图像根据车型进行筛选和分类。由于图片的素材量是十分大,该车型分类程序可以十分有效地减少了人工成本,节省了素材管理事件,提升工作效率。除此之外,交通部门可以通过对采集的道路车辆图像进行分类分析,有利于之后对道路交通进行规划建设。
6.1.2.实现方案
本文挑选已训练完成识别效果较好的模型在分类程序中进行加载,用于识别输入的图片。由于版本兼容性问题需要重新声明池化层,代码如下:
model =torch.load(‘models/mydata_model_24.pt’)
首先,在程序中输入指定文件夹,通过os库中的os.makedirs()函数获取文件夹中的图片名,并采用os.path.join()函数获取图片的绝对路径,将加载的模型和图片绝对路径传入到函数def classify(model, test_image_name)中。该函数用于识别图片的类别,首先将需要识别的图像根据第三章图像预处理中所提到的方法,数据增强之后转换为张量再进行标准化,然后将图像张量输入到模型。CUDA为英伟达公司推出的运算平台,能够实现CPU+GPU并行计算从而提高计算速度[14],因为GPU在图片处理速度上远大于CPU,PyTorch中cuda()用于将变量传输到GPU上,在电脑环境配备的情况下,因选择使用GPU来运行模型。在分类程序中,不需要计算梯度也不需要进行反向传播,torch.no_grad()能够将这部分时间省略。model.eval()函数用于对输入图像进行测试。具体代码如下:
test_image_tensor = [test_image_tensor.view(1, 3, 224,224),test_image_tensor.view(1, 3, 224, 224).cuda()][torch.cuda.is_available()]
with torch.no_grad():
model.eval()
out =model(test_image_tensor)
ps = torch.exp(out)
模型对每个图像的输出结果如图6-1所示,torch.exp()可以对该结果张量中的元素求指数,将负数结果转化为正数,ps.topk(1, dim=1)用于获取最大指数值及其下标,即其对应的车型类别标签。

在这里插入图片描述

图6-1 图片对应张量示意图
将每一类车型文件夹通过os.path.join()函数结合用户输入的文件夹路径获取车型文件夹的绝对路径,并根据模型中每一类车型对应的位置将文件夹写入列表new_path[]中,若未存在文件夹,就在该路径创建对应文件夹。最终,根据classify函数返回的结果,将遍历的每一张图片复制到对应文件夹中,代码如下,其中i为遍历的每张图片的绝对路径:
shutil.copyfile(img_path,os.path.join(new_path[x],i) )
6.2.图像识别网站设计
该图像识别网站的开发主要用于将先前编写好的识别函数应用于网站上,用户可以在该网站上传汽车图片,上传界面如图6-2所示,后端将图片写入服务器中后调用车型识别函数,将函数返还的结果显示在前端界面上,识别结果如图6-3所示。
在这里插入图片描述

图6-2 上传界面
在这里插入图片描述

图6-3 识别结果
该网站是一个以html为前端,python为后端的图片识别网站,采用了bottle这一微型web框架。
前端采用html编写,元素定义html表单,表单中包含文件上传控件、按钮控件和文本框控件。将表单的action属性设为"/upload",即当鼠标点击上传按钮时,会将表单中的内容提交到upload中,并且界面将跳转到upload中显示识别结果。file控件放入表单中,客户端可以选择上传本地文件。用时file控件中的accept属性可以用于限制上传文件的类型,因该网站的目的是用于图片识别,可以将accept属性设为accept=”image/*”。
后端用了python进行编写,使用bottle框架实现前后端交互。前端提交表单数据传给后端后,后端接收数据并进行处理后返回一个新页面,通过 @app.route 装饰器中的POST方法返回一个新页面,页面路径为/upload,代码如下:
@route(‘/upload’, method=‘POST’)
在修饰器中加入do_upload()函数,该函数用于将表单中获取的图片数据存储到服务器文件夹中,使用request.files.get()函数获取图片数据,filedata.save()函数用于存储图片,调用先前编写好的图片识别函数def classify(model, filename)获取识别结果,该函数具体在5.1.2章节中介绍。

7.总结与展望

7.1.本文总结
本文通过查阅大量文献资料,分析该系统在目前社会背景下的研究意义,以及国内外深度学习和图像识别应用的发展情况,确定了该课题。同时,本文通过有目的地研究不同深度学习方法的利弊,将迁移学习运用到了该系统中,因此,通过查阅一些文献资料和影像资料,分析并选择了比较先进、效果较好的深度学习网络模型——ResNet,进行实验比对,尽量提高识别准确率。
因深度学习的网络模型在不同应用场景下的检测效果会有偏差,本文根据训练完成模型的测试结果,查找有利于提升准确率的方法,考虑了如下参数的选择与调优: Loss函数选择、学习率、选择何种Regularization、选择何种梯度下降算法……除此,本文也研究学习了卷积神经网络的卷积过程,从而能够对这些模型有自己的认识和理解,在参数调优过程中能针对性地解决测试中出现的问题。
本文主要工作工作如下:
1) 深度学习框架搭建、训练与测试,其中包括:数据集的采集和数据集的清洗;
根据性能及需求选择并搭建深度学习网络(PyTorch)、反复调整网络参数并进行训练;网络的测试并与其他网络对比、分析及总结。
2) 系统人机交互的设计,其中包括:前后端交互,数据传输;界面与功能设计;Python办公自动化实现。
3) 其它内容包括:编写爬虫程序爬取训练素材和测试素材;对各类结果的统计进行分析来设计优化模型,使用较少的数据得到较好的模型;具体应用于公司车型分类工作中的可行性及优缺点的调查分析。
通过本次对车型识别系统的设计与应用,我自学掌握了一些深度学习的知识,也对人工智能技术有了更多的了解。虽然深度学习只是人工智能的一小个分支,但它给我们的生活与工作带来了很大的便捷。目前,行业中已有许多科学家研究者在这一领域打造了良好的基础,为我们学习者提供了非常好的学习环境,同时,借助一些深度学习的框架和一些预训练模型,我们在应用深度学习时也十分方便快捷。在接下来的工作与生活中,我也会学习并结合一些先进技术解决工作中一些繁杂问题,极大程度上提高了效率,享受人工智能带来的便捷。
7.2.设想与展望
本文设计的深度学习模型在准确率上,通过模型的对比选择和参数的反复调整,准确率到达了93%以上,对比人工识别的准确率来说还需要进一步优化,在接下来也会就提高准确率这一目的,做更多的学习和改进。除此之外,设计的车型识别目前只适用于简单识别普通图片,在使用上还是十分局限的,还有许多需要研究和改进的空间,我们可以结合目标跟踪,拓展其对动图、视频等的识别。更进一步,可以将其与物联网技术相结合,将该系统运用到一些智能摄像头上面,随着智能摄像头对路况信息实时采集,同时也能对过路车型进行实时识别,这将在实际运用中发挥更大的作用。

致谢

大学这四年,对我的人生有很重要的意义。我十分感谢大学中的每一位老师,每一位同学,给我的大学生活和学习带来了很大的帮助,我会永远铭记大学这一段美好的时光,记得你们对我的帮助和鼓励。
毕业设计对于每一位毕业生来说都是一次考验,是对大学四年所学的总结,因此,我想特别感谢我的唐老师。唐老师是我的毕业设计导师,在我为毕业设计而发愁的时候,唐老师对我进行了选题的指导和任务的规划。每当我在制作毕业设计的过程中遇到了困难,唐老师总是会耐心知道我,给我提出解决方案或者建议。在唐老师的指导下,我很好地完成了我的毕业设计,让我各方面的能力得到了锻炼。
同时,我十分感谢我的班主任林老师,在大学生活期间一直陪伴着我们,不论是在学习上还是生活上时刻关注着我们,引导我们朝着更好的方向努力。当我即将毕业,感到迷茫的时候,林老师为我分析了考研与就业的选择,帮助我解开心中的困惑。还有徐嬴颖老师,是我们很多专业课的任课老师,同时是我参加网络技术挑战赛的指导老师。正是在徐嬴颖老师的指导和鼓励下,以及队友们的共同努力下,我们获得了好成绩。
还有很多任课老师,无论在学业上、生活上还是就业上都为我们默默付出着,为我们提供了很大的帮助,感谢所有教导过我的老师们!

参考文献

[1]林荣安.2019年交通基础设施建设市场形势分析[J].筑路机械与施工机化,2019,36(02):15-21.
[2]曾俊东. 基于卷积神经网络的监控视频车型识别系统设计与实现[D]. 2017.
[3]裴月玲,张涛.基于人工智能的车牌号与车型识别系统[J].公路,2019,64(08):277-281.
[4]龙明盛. 迁移学习问题与方法研究[D].清华大学,2014.
[5]何西麟. 基于深度学习的手写体字符识别研究与实现[D].中山大学,2015.
[6]Simonyan K , Zisserman A . Very Deep Convolutional Networks for Large-Scale Image Recognition[J]. Computer Science, 2014.
[7]Szegedy C , Liu W , Jia Y , et al. Going Deeper with Convolutions[J]. 2014.
[8]戴加明. 基于深度卷积神经网络的星系形态分类研究[D]. 2018.
[9]余斌.基于Bottle的Python网络应用开发[J].无线互联科技,2014(06):29+103.
[10]赵江洪,张晓光,杨璐,马思宇,王殷瑞,董岩,孙铭悦,陈朝阳.深度学习的遥感影像舰船目标检测[J].测绘科学,2020,45(03):110-116+134.
[11]Krizhevsky A , Sutskever I , Hinton G . ImageNet Classification with Deep Convolutional Neural Networks[C]// NIPS. Curran Associates Inc. 2012.
[12]郭慧丰. 基于用户行为关系挖掘的个性化推荐模型及算法[D].哈尔滨工业大学,2018.
[13]田娟,李英祥,李彤岩.激活函数在卷积神经网络中的对比研究[J].计算机系统应用,2018,27(07):43-49.
[14]吴辉,罗清海,彭文武.GPU并行计算的CUDA架构浅析[J].教育教学坛,2019(06):277-278.

附件1:程序源码
训练与模型筛选程序:
import torch
from torch.optim import lr_scheduler
from torch.utils.data import DataLoader
import torchvision
from torchvision import datasets, models, transforms
import torchvision.transforms
import torch.nn as nn
import torch.optim as optim
import time
import cv2
import numpy as np
import matplotlib.pyplot as plt
import os
import random

train = transforms.Compose([
transforms.RandomResizedCrop(size=224, scale=(0.8, 1.0)),
transforms.RandomRotation(degrees=15),
transforms.RandomHorizontalFlip(),
transforms.CenterCrop(size=224),
transforms.ToTensor(),
transforms.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225))

]) # 修改的位置
valid = transforms.Compose([
transforms.Resize(size=224),
transforms.CenterCrop(size=224),
transforms.ToTensor(),
transforms.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225))
])

batch_size = 24
num_classes = 6
epochs_sum = 100

train = datasets.ImageFolder(root=‘mydataf/train’, transform=train)
valid = datasets.ImageFolder(root=‘mydataf/valid’, transform=valid)

train_loader = torch.utils.data.DataLoader(train, batch_size=batch_size, shuffle=True)
valid_loader = torch.utils.data.DataLoader(valid, batch_size=batch_size, shuffle=True)

train_lenth = len(train)
valid_lenth = len(valid)
print(train_lenth, valid_lenth)

def train_mydata(model, optimizer, loss_f, scheduler, epoch):
loss_train = 0.0
acc_train = 0.0

print('*' * 15)
print('Epoch {}/{}'.format(epoch + 1, epochs_sum))

model.train()  # 启用BatchNormalization和Dropout

for i, (inputs, labels) in enumerate(train_loader):

    inputs = inputs.to(device)
    labels = labels.to(device)

    optimizer.zero_grad()  # 梯度清0

    with torch.set_grad_enabled(True):  # 计算导数
        outputs = model(inputs)  # 将图片输入至网络中得到对应输出
        ret, preds = torch.max(outputs, 1)  # ret:预测标签 preds:预测概率对应值
        loss = loss_f(outputs, labels)  # 计算损失
        loss.backward()
        optimizer.step()  # 更新网络参数

    loss_train += loss.item() * inputs.size(0)

    right_sum = preds.eq(labels.data.view_as(preds))  # 对比统计预测正确数量,得到布尔型
    acc = torch.mean(right_sum.type(torch.FloatTensor))  # 转换为tensor并计算平均得到正确率
    acc_train += acc.item() * inputs.size(0)  # 正确率累加

scheduler.step()  # 更新学习率
print("1" * 20)
print(optimizer)
print("1" * 20)

return model, loss_train, acc_train

def valid_mydata(model, optimizer, loss_f, scheduler, epoch):
loss_valid = 0.0
acc_valid = 0.0

model.train()  # 启用BatchNormalization和Dropout

for i, (inputs, labels) in enumerate(valid_loader):
    inputs = inputs.to(device)
    labels = labels.to(device)
    outputs = model(inputs)  # 将图片输入至网络中得到对应输出

    ret, preds = torch.max(outputs, 1)  # ret:预测标签 preds:预测概率对应值
    loss = loss_f(outputs, labels)  # 计算损失
    loss_valid += loss.item() * inputs.size(0)

    right_sum = preds.eq(labels.data.view_as(preds))  # 对比统计预测正确数量,得到布尔型
    acc = torch.mean(right_sum.type(torch.FloatTensor))  # 转换为tensor并计算平均得到正确率
    acc_valid += acc.item() * inputs.size(0)  # 正确率累加

return loss_valid, acc_valid

device = torch.device(“cuda:0”)

history = []
acc_max = 0.0
acc_max_epoch = 0

resnet50 = models.resnet50(pretrained=True)

for param in resnet50.parameters():
param.requires_grad = False

fc_inputs = resnet50.fc.in_features
resnet50.fc = nn.Sequential(
nn.Linear(fc_inputs, 256),
nn.ReLU(),
nn.Linear(256,128),
nn.ReLU(),
nn.Linear(128,64),
nn.ReLU(),
nn.Dropout(0.4),
nn.Linear(64,6),
nn.LogSoftmax(dim=1)
)

resnet50 = resnet50.to(‘cuda:0’ )

loss_f = nn.NLLLoss()
optimizer = optim.SGD(resnet50.parameters(), lr=0.001, momentum=0.95)

optimizer = optim.RMSprop(resnet50.parameters())

scheduler = lr_scheduler.StepLR(optimizer, step_size=8, gamma=0.5)

for epoch in range(epochs_sum):

tstart = time.time()

model, loss_train, acc_train = train_mydata(resnet50, optimizer, loss_f, scheduler, epoch)

with torch.no_grad():
    model.eval()
    loss_valid, acc_valid = valid_mydata(resnet50, optimizer, loss_f, scheduler, epoch)

avgloss_train = loss_train / train_lenth
avgacc_train = acc_train / train_lenth
avgloss_valid = loss_valid / valid_lenth
avgacc_valid = acc_valid / valid_lenth
avgacc = avgacc_valid * 0.7 + avgacc_train * 0.3
if acc_max < avgacc:
    acc_max = avgacc
    acc_max_epoch = epoch + 1

history.append([avgloss_train, avgloss_valid, avgacc_train, avgacc_valid])

tend = time.time()
print(
    "Epoch: {:03d}, Training: Loss: {:.4f}, Accuracy: {:.4f}%, \n\t\tValidation: Loss: {:.4f}, Accuracy: {:.4f}%, Time: {:.4f}s".format(
        epoch + 1, avgloss_train, avgacc_train * 100, avgloss_valid, avgacc_valid * 100,
        tend - tstart))
print("Best Accuracy for validation : {:.4f} at epoch {:03d}".format(acc_max, acc_max_epoch))

torch.save(model, 'models/' + 'mydata' + '_model_' + str(epoch + 1) + '.pt')

图像识别函数:
def classify(model, test_image_name):
image_transforms = {
‘test’: transforms.Compose([
transforms.Resize(size=224),
transforms.CenterCrop(size=224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406],
[0.229, 0.224, 0.225])
])
}
num_classes = 6
transform = image_transforms[‘test’]
test_image = Image.open(test_image_name)
test_image_tensor = transform(test_image)
test_image_tensor = [test_image_tensor.view(1, 3, 224, 224), test_image_tensor.view(1, 3, 224, 224).cpu()][torch.cuda.is_available()]
with torch.no_grad():
model.eval()
out = model(test_image_tensor)
ps = torch.exp(out)
print(out)
topk, topclass = ps.topk(1, dim=1)
num=topclass.cpu().numpy()[0][0]
return num

本地图片批量分类程序代码:
model = torch.load(‘models/mydata_model_25.pt’, map_location=lambda storage, loc: storage)
model.avgpool = nn.AvgPool2d(kernel_size=7, stride=1, padding=0)
print(“请输入本地路径:”)
path=input()

path = eval(repr(s).replace(‘\’, ‘/’))

root_path=[‘classify_finish\dabache’,‘classify_finish\huoche’,‘classify_finish\xiaoqiche’,‘classify_finish\mianbaoche’,‘classify_finish\yueyeche’,‘classify_finish\SUV’]
new_path=[]
for i in root_path:
new_path.append(os.path.join(path,i))
for i in new_path:
if not os.path.exists(i):
os.makedirs(i)
lsdir = os.listdir(path)
geshi=[‘jpg’,‘png’,‘tif’,‘bmp’]
print(lsdir)
for i in lsdir:
img_path=os.path.join(path,i)
if ‘.’ in img_path:
if i.split(‘.’)[1] in geshi:
x=classify(model,img_path)
shutil.copyfile(img_path,os.path.join(new_path[x],i) )

车型识别网页代码:
#!/usr/bin/env python

-- coding: utf-8 --

import os
from bottle import *
from classify import classify
import torch
import torch.nn as nn
from torchvision import datasets, transforms
HTML = “”"

车型识别

请上传车辆图片

""" model = torch.load('models/mydata_model_25.pt', map_location=lambda storage, loc: storage) model.avgpool = nn.AvgPool2d(kernel_size=7, stride=1, padding=0) base_path = os.path.dirname(os.path.realpath(__file__)) # 获取脚本路径 upload_path = os.path.join(base_path, 'upload') # 上传文件目录 if not os.path.exists(upload_path): os.makedirs(upload_path) @route('/', method='GET') @route('/upload', method='GET') def index(): return HTML result_name=['大巴车','货车','小汽车','面包车','越野车','SUV'] @route('/upload', method='POST') def do_upload(): filedata = request.files.get('filepic') if filedata.file: file_name = os.path.join(upload_path, filedata.filename) try: filedata.save(file_name) except IOError: return '文件上传失败' result=classify(model,file_name) if (os.path.exists(file_name)): # 判断文件是否存在 os.remove(file_name) return '
文件上传成功, 分类结果: {}     返回
'.format(result_name[result]) else: return '文件上传失败' @route('/favicon.ico', method='GET') def server_static(): return static_file('favicon.ico', root=base_path) @error(404) def error404(error): return '404 发生页面错误, 未找到内容' run(port=6080, reloader=False)

多线程爬虫脚本:
import os
import re
import requests
import urllib

from multiprocessing import Pool

def get_page_html(page_url):
headers = {
‘Referer’: ‘https://image.baidu.com/search/index?tn=baiduimage’,
‘User-Agent’: ‘Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36’
}
try:
r = requests.get(page_url, headers=headers)
if r.status_code == 200:
r.encoding = r.apparent_encoding
return r.text
else:
print(‘请求失败’)
except Exception as e:
print(e)

def parse_result(text):
url_real = re.findall(‘“thumbURL”:“(.*?)”,’, text)
return url_real

def get_image_content(url_real):
headers = {
‘Referer’: url_real,
‘User-Agent’: ‘Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36’
}
try:
r = requests.get(url_real, headers=headers)
if r.status_code == 200:
r.encoding = r.apparent_encoding
return r.content
else:
print(‘请求失败’)
except Exception as e:
print(e)

def save_pic(url_real, content):
root = ‘D:\xiaojiaoche\’
path = root + url_real.split(‘/’)[-1]
if not os.path.exists(root):
os.mkdir(root)
if not os.path.exists(path):
with open(path, ‘wb’) as f:
f.write(content)
print(‘图片{}保存成功,地址在{}’.format(url_real, path))
else:
pass

def get_and_save(real_urls):
for real_url in real_urls:
try:
content = get_image_content(real_url)
save_pic(real_url, content)
except:
print(‘Error:’, real_url)

def main():
keyword = input('请输入你要查询的关键字: ')
keyword_quote = urllib.parse.quote(keyword)
depth = int(input("请输入要爬取的页数(每页30张图): "))
p = Pool(10)
for i in range(depth):
url = ‘https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord+=&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&word={}&z=&ic=0&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&step_word={}&pn={}&rn=30&gsm=1e&1541136876386=’.format(
keyword_quote, keyword_quote, i * 30)
html = get_page_html(url)
real_urls = parse_result(html)
p.apply_async(func=get_and_save, args=(real_urls,))
p.close()
p.join()
if name == ‘main’:
main()

目标识别是计算机视觉一个重要的研究领域,由此延伸出的车辆型号识别具有重 要的实际应用价值,特别是在当今交通状况复杂的大城市,智能交通系统成为发展趋 势,这离不开对车辆型号进行识别和分类的工作,本文围绕如何利用计算机视觉的方 法进行车辆型号的识别和分类展开了一系列研究: 本文对当前的目标识别和分类的特征和算法做了总结和归纳。分析比较了作为图 像特征描述常见的特征算子,总结归纳了他们的提取方法、特征性能以及相互之间的 关联。另外,介绍了在目标识别工作中常用的分类方法,阐述了他们各自的原理和工作 方法。研究了深度神经网络的理论依据,分析比较了深度神经网络不同的特征学习方 法,以及卷积神经网络的训练方法。分析比较不同特征学习方法的特点选取 k-means 作为本文使用的特征学习方法,利用卷积神经网络结构搭建深度学习模型,进行车辆 车型识别工作。 本文为了测试基于深度学习的车辆型号分类算法的性能在 30 个不同型号共 7158 张图片上进行实验;并在相同数据上利用改进了的 SIFT 特征匹配的算法进行对比实验; 进过实验测试,深度学习方法在进行车型分类的实验中取得 94%的正确率,并在与 SIFT 匹配实验结果对比后进一步证实:深度学习的方法能够应用在车辆型号识别领域
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_1406299528

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值