基于简化版python+VGG+MiniGoogLeNet的智能43类交通标志识别—深度学习算法应用(含全部python工程源码)+数据集+模型(二)

目录

  • 前言
  • 总体设计
    • 系统整体结构图
    • 系统流程图
  • 运行环境
  • 模块实现
    • 1. 数据预处理
    • 2. 模型构建
      • 1)VGG模型简化版
      • 2)GoogLeNet简化版——MiniGoogLeNet
    • 3. 模型训练及保存
  • 相关其它博客
  • 工程源代码下载
  • 其它资料下载


在这里插入图片描述

前言

本项目专注于解决出国自驾游特定场景下的交通标志识别问题。借助Kaggle上的丰富交通标志数据集,我们采用了VGG和GoogLeNet等卷积神经网络模型进行训练。通过对网络架构和参数的巧妙调整,致力于提升模型在不同类型交通标志识别方面的准确率。

首先,我们选择了Kaggle上的高质量交通标志数据集,以确保训练数据的多样性和丰富性。接着,采用VGG和GoogLeNet等先进的卷积神经网络模型,这些模型在图像分类任务上表现卓越。

通过巧妙的网络架构和参数调整,本项目致力于提高模型的准确率。我们深入研究了不同交通标志的特征,使网络更有针对性地学习这些特征,从而增强模型在复杂场景下的泛化能力。

最终,本项目旨在为出国自驾游的用户提供一个高效而准确的交通标志识别系统,以提升驾驶安全性和用户体验。这一创新性的解决方案有望在自动驾驶和智能导航等领域产生深远的影响。

总体设计

本部分包括系统整体结构图和系统流程图。

系统整体结构图

系统整体结构如图所示。

在这里插入图片描述

系统流程图

系统流程如图所示。

在这里插入图片描述

运行环境

本部分包括 Python 环境、Anaconda环境。

详见博客。

模块实现

本项目包括3个模块:数据预处理、模型构建、模型训练及保存。下面分别给出各模块的功能介绍及相关代码。

1. 数据预处理

本项目使用德国交通标志识别基准数据集(GTSRB),此数据集包含50000张在各种环境下拍摄的交通标志图像,下载地址为:https://www.kaggle.com/datasets/meowmeowmeowmeowmeow/gtsrb-german-traffic-sign。数据集下载完成后,导入数据并进行预处理。

详见博客。

2. 模型构建

本部分包括VGG模型和GoogLeNet模型简化版。

1)VGG模型简化版

通过测试各种简化版模型,发现多减少网络的深度(卷积层、池化层、全连接层的层数),少减少网络的宽度(卷积层输出通道数),效果更好。由于本项目的图像尺寸较小,此版模型的卷积层输出通道数只减少为VGG-11的一半。输入图像经过3个卷积层、2个最大池化层、1个全连接层和1个Softmax层。卷积层的步幅为1,通过填充使输出的宽和高与输入相同,前2个卷积层调整为5×5,最后一个卷积层保持3×3不变,3个卷积层的输出通道数依次为32、64和64。2个最大池化层分别位于第2和第3个卷积层后,池化窗口均为2×2,步幅为2,无填充,使输出的宽和高减半,每个最大池化层后接一个参数为0.25的Dropout层防止过拟合。最后是一个输出通道数为256的全连接层和1个Softmax层,全连接层后接1个参数为0.5的Dropout层防止过拟合。

相关代码如下:

#导入需要的包
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import BatchNormalization
from tensorflow.keras.layers import Conv2D
from tensorflow.keras.layers import MaxPooling2D
from tensorflow.keras.layers import Activation
from tensorflow.keras.layers import Flatten
from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Dense
class VGGN:def build(width, height, depth, classes):#使用Keras框架的Sequential模式编写代码model = Sequential()inputShape = (height, width, depth)chanDim = -1#卷积核大小为5*5,步幅为1,输出通道数32,填充使得输出的宽和高与输入相同model.add(Conv2D(32, (5, 5), padding="same",input_shape=inputShape))#Relu激活函数+批量归一化model.add(Activation("relu"))model.add(BatchNormalization(axis=chanDim))  #卷积核大小为5*5,步幅为1,输出通道数64,填充使得输出的宽和高与输入相同 model.add(Conv2D(64, (5, 5), padding="same"))model.add(Activation("relu"))model.add(BatchNormalization(axis=chanDim))#池化窗口为2*2,步幅为2,不填充,输出的宽和高减半(变为16*16)model.add(MaxPooling2D(pool_size=(2, 2)))#最大池化层后接一个参数为0.25的Dropout层防止过拟合model.add(Dropout(0.25))#卷积核大小为3*3,步幅为1,输出通道数64,填充使得输出的宽和高与输入相同model.add(Conv2D(64, (3, 3), padding="same"))model.add(Activation("relu"))model.add(BatchNormalization(axis=chanDim))#池化窗口为2*2的最大池化层,步幅为2,不填充,输出的宽和高减半(变为8*8)model.add(MaxPooling2D(pool_size=(2, 2)))#最大池化层后接一个参数为0.25的Dropout层防止过拟合model.add(Dropout(0.25))model.add(Flatten())#输出通道数为256的全连接层model.add(Dense(256))model.add(Activation("relu"))model.add(BatchNormalization())#全连接层后接一个参数为0.5的Dropout层防止过拟合model.add(Dropout(0.5))#最后是一个softmax层输出各类别的概率model.add(Dense(classes))model.add(Activation("softmax"))       return model

2)GoogLeNet简化版——MiniGoogLeNet

MiniGoogLeNet由Inception模块、Downsample模块和卷积模块组成,卷积模块包括卷积层、激活函数和批量归一化;Inception模块由两个卷积核大小分别为1×1和3×3的卷积模块并联组成,这两个卷积模块都通过填充使输入输出的高和宽相同,便于通道合并;Downsample模块由一个卷积核大小为3×3的卷积模块和一个池化窗口为3×3的最大池化层并联组成,卷积模块和最大池化层不填充,步幅均为2,使得输入经过后宽和高减半。MiniGoogLeNet的输入图片经过一个卷积模块后输出通道数不同的Inception模块,最后是一个全局平均池化层和一个Softmax层,全局平均池化层将每个通道的高和宽变为1,有效地减少了过拟合。

相关代码如下:

#导入需要的包
from tensorflow.keras.layers import BatchNormalization
from tensorflow.keras.layers import Conv2D
from tensorflow.keras.layers import AveragePooling2D
from tensorflow.keras.layers import MaxPooling2D
from tensorflow.keras.layers import Activation
from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Flatten
from tensorflow.keras.layers import Input
from tensorflow.keras.models import Model
from tensorflow.keras.layers import concatenate
from tensorflow.keras import backend as K
class MiniGoogLeNet:#定义卷积模块,x表示输入数据,K表示输出通道的数量,KX、KY表示卷积核的大小def conv_module(x,K,KX,KY,stride,chanDim,padding="same"):#卷积+激活函数+批量归一化,默认填充使得输出的宽和高不变x = Conv2D(K, (KX, KY), strides=stride, padding=padding)(x)x = Activation("relu")(x)x = BatchNormalization(axis=chanDim)(x)return x#定义Inception模块,x表示输入数据,numK1_1,numK3_3表示两个卷积模块输出通道数量def inception_module(x,numK1_1,numK3_3,chanDim):#并联的两个卷积模块,卷积核大小分别为1*1和3*3conv1_1=MiniGoogLeNet.conv_module(x,numK1_1,1,1,(1,1),chanDim)    conv3_3=MiniGoogLeNet.conv_module(x,numK3_3,3,3,(1,1),chanDim)    x=concatenate([conv1_1,conv3_3],axis=chanDim)return x#定义Downsample模块,x表示输入数据,K表示卷积模块的输出通道数def downsample_module(x,K,chanDim):  #并联的卷积模块和最大池化层,均使用3*3窗口,步幅2,不填充,输出的宽和高减半
conv3_3=MiniGoogLeNet.conv_module(x,K,3,3,(2,2),chanDim,padding='valid')pool=MaxPooling2D((3,3),strides=(2,2))(x)        x=concatenate([conv3_3,pool],axis=chanDim)return x#定义模型def build(width, height, depth, classes):        inputShape = (height, width, depth)chanDim = -1   #如果通道在前,将chanDim设为1         if K.image_data_format() == "channels_first":            inputShape = (depth, height, width)            chanDim = 1  #使用Keras的Model模式编写代码             inputs = Input(shape=inputShape)#输入图片先经过一个卷积核大小3*3,输出通道数96的卷积模块x = MiniGoogLeNet.conv_module(inputs, 96, 3, 3, (1, 1),chanDim)    #2个Inception模块(输出通道数32+32、32+48)+1个Downsample模块x = MiniGoogLeNet.inception_module(x, 32, 32, chanDim)        x = MiniGoogLeNet.inception_module(x, 32, 48, chanDim)       x = MiniGoogLeNet.downsample_module(x, 80, chanDim)           #4个Inception模块(输出通道数112+48、96+64、80+80、48+96)+1Downsample模块x = MiniGoogLeNet.inception_module(x, 112, 48, chanDim)        x = MiniGoogLeNet.inception_module(x, 96, 64, chanDim)        x = MiniGoogLeNet.inception_module(x, 80, 80, chanDim)        x = MiniGoogLeNet.inception_module(x, 48, 96, chanDim)        x = MiniGoogLeNet.downsample_module(x, 96, chanDim)         #2个Inception模块+1个Downsample模块+1个全局平均池化层+1个Dropout层x = MiniGoogLeNet.inception_module(x, 176, 160, chanDim)        x = MiniGoogLeNet.inception_module(x, 176, 160, chanDim)
#输出7*7*(160+176)经过平均池化之后变成了1*1*376        x = AveragePooling2D((7, 7))(x)  x = Dropout(0.5)(x)         #特征扁平化 x = Flatten()(x)#softmax层输出各类别的概率       x = Dense(classes)(x)       x = Activation("softmax")(x)        #创建模型        model = Model(inputs, x, name="googlenet")               return model   

3. 模型训练及保存

通过随机旋转等方法进行数据增强,选用Adam算法作为优化算法,随着迭代的次数增加降低学习速率,经过尝试,速率设为0.001时效果最好。调用之前的模型,以交叉熵为损失函数,使用Keras的fit_generator()方法训练模型,最后评估并保存到磁盘。

相关代码如下:

#设置初始学习速率、批量大小和迭代次数
INIT_LR = 1e-3
BS = 64
NUM_EPOCHS = 10
#使用随机旋转、缩放,水平/垂直移位、透视变换、剪切等方法进行数据增强(不用水平或垂直翻转
aug = ImageDataGenerator(rotation_range=10,zoom_range=0.15,width_shift_range=0.1,height_shift_range=0.1,shear_range=0.15,horizontal_flip=False,vertical_flip=False,fill_mode="nearest")
print("[INFO] compiling model...")
#选用Adam作为优化算法,初始学习速率0.001,随着迭代次数增加降低学习速率
opt = Adam(lr=INIT_LR, decay=INIT_LR / (NUM_EPOCHS * 0.5))
#调用MiniGoogLeNet,使用VGG网络时把MiniGoogLeNet更改为VGGN
model = MiniGoogLeNet.build(width=32, height=32, depth=3,classes=numLabels)
#编译模型,使用交叉熵作为损失函数
model.compile(loss="categorical_crossentropy", optimizer=opt,metrics=["accuracy"])
#使用Keras的fit_generator方法训练模型
print("[INFO] training network...")
H = model.fit_generator(aug.flow(trainX, trainY, batch_size=BS),validation_data=(testX, testY),steps_per_epoch=trainX.shape[0] ,epochs=NUM_EPOCHS,verbose=1)
#评估模型,打印分类报告
print("[INFO] evaluating network...")
predictions = model.predict(testX, batch_size=BS)
print(classification_report(testY.argmax(axis=1),predictions.argmax(axis=1), target_names=labelNames))
#将模型存入磁盘
print("[INFO]serializing network to'{}'...".format('output/testmodel.pb'))
model.save('output/testmodel.pb')
#绘制loss和accuracy随迭代次数变化的曲线
N = np.arange(0, NUM_EPOCHS)
plt.style.use("ggplot")
plt.figure()
plt.plot(N, H.history["loss"], label="train_loss")
plt.plot(N, H.history["val_loss"], label="val_loss")
plt.plot(N, H.history["acc"], label="train_acc")
plt.plot(N, H.history["val_acc"], label="val_acc")
plt.title("Training Loss and Accuracy on Dataset")
plt.xlabel("Epoch #")
plt.ylabel("Loss/Accuracy")
plt.legend(loc="lower left")
plt.savefig('output/test.png')

相关其它博客

基于简化版python+VGG+MiniGoogLeNet的智能43类交通标志识别—深度学习算法应用(含全部python工程源码)+数据集+模型(一)

基于简化版python+VGG+MiniGoogLeNet的智能43类交通标志识别—深度学习算法应用(含全部python工程源码)+数据集+模型(三)

工程源代码下载

详见本人博客资源下载页


其它资料下载

如果大家想继续了解人工智能相关学习路线和知识体系,欢迎大家翻阅我的另外一篇博客《重磅 | 完备的人工智能AI 学习——基础知识学习路线,所有资料免关注免套路直接网盘下载》
这篇博客参考了Github知名开源平台,AI技术平台以及相关领域专家:Datawhale,ApacheCN,AI有道和黄海广博士等约有近100G相关资料,希望能帮助到所有小伙伴们。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/589908.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#中string.ToUpper()和string.ToLower()的用法

目录 一、关于ToUpper()和ToLower() 1.ToUpper() 2.ToLower() 3.小结 二、实例 三、生成效果 一、关于ToUpper()和ToLower() 1.ToUpper() 使用字符串对象的ToUpper方法可以将字符串中的字母全部转换为大写。 string P_str_book "mingribook".ToUpper()…

AD教程 (二十一)模块化布局规划

AD教程 (二十一)模块化布局规划 原理图是按照我们的功能模块去进行排布划分的 利用交叉选择模式分屏快速进行模块化布局 分屏,选中任意文档,右击,点击垂直分割 交叉选择模式,点击工具,交叉选…

【Java进阶篇】JDK新版本中的新特性都有哪些

JDK新版本中的新特性都有哪些 ✔️经典解析✔️拓展知识仓✔️本地变量类型推断✔️Switch 表达式✔️Text Blocks✔️Records✔️封装类✔️instanceof 模式匹配✔️switch 模式匹配 ✅✔️虚拟线程 ✔️经典解析 JDK 8中推出了Lambda表达式、Stream、Optional、新的日期API等…

2023-12-12LeetCode每日一题(下一个更大元素 IV)

2023-12-12每日一题 一、题目编号 2454. 下一个更大元素 IV二、题目链接 点击跳转到题目位置 三、题目描述 给你一个下标从 0 开始的非负整数数组 nums 。对于 nums 中每一个整数,你必须找到对应元素的 第二大 整数。 如果 nums[j] 满足以下条件,那…

「网络编程」其他重要的协议或技术_ DNS协议 | ICMP协议 | NAT技术

「前言」文章内容是DNS协议、ICMP协议、NAT技术的讲解。 「归属专栏」网络编程 「主页链接」个人主页 「笔者」枫叶先生(fy) 目录 一、DNS协议1.1 背景1.2 域名简介1.3 域名解析的过程 二、ICMP协议2.1 ICMP简介2.2 ping命令2.3 traceroute命令 三、NAT技术3.1 NAT技术背景3.2 …

【算法提升—力扣每日一刷】五日总结【12/25--12/29】

文章目录 LeetCode每五日一总结【12/25--12/29】2023/12/25今日数据结构:双锁实现阻塞队列 2023/12/26每日力扣:[215. 数组中的第K个最大元素(堆实现)](https://leetcode.cn/problems/kth-largest-element-in-an-array/) 2023/12/…

uniapp中的uview组件库丰富的Form 表单用法

目录 基本使用 #Form-item组件说明 #验证规则 #验证规则属性 #uView自带验证规则 #综合实战 #校验错误提示方式 #校验 基本使用 此组件一般是用于表单验证使用,每一个表单域由一个u-form-item组成,表单域中可以放置u-input、u-checkbox、u-radio…

伺服电机:原点复位

一、原点复位概念 原点复位指的是,在驱动器使能时,触发原点复位功能后,电机将主动查找零点,完成定位功能。 那么问题来了,什么是原点,什么是零点? 原点:即机械原点,可…

基于JAVA的独居老人物资配送系统 开源项目

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示四、核心代码4.1 查询社区4.2 新增物资4.3 查询物资4.4 查询物资配送4.5 新增物资配送 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的独居老人物资配送系统,包含了社区档案、…

【解决问题】pyinstaller打包python应用进行快速分发

pyinstaller打包python应用进行快速分发 问题起因先利其器再善其事试用运行 问题起因 有同学问我要接口的应用,于是试了一下python打包成exe的过程。 先利其器 主要使用pyinstaller,可以通过pip安装 pip install pyinstaller安装过程如图 再善其事…

B+树的插入删除

操作 插入 case2的原理,非叶子节点永远和最右边的最左边的节点的值相等。 case3:的基本原理 非叶子节点都是索引节点 底层的数据分裂之后 相当于向上方插入一个新的索引(你可以认为非叶子节点都是索引),反正第二层插入160 都要分裂,然后也需要再插入(因为索引部分不需要重…

2023-12-27 LeetCode每日一题(保龄球游戏的获胜者)

2023-12-27每日一题 一、题目编号 2660. 保龄球游戏的获胜者二、题目链接 点击跳转到题目位置 三、题目描述 给你两个下标从 0 开始的整数数组 player1 和 player2 ,分别表示玩家 1 和玩家 2 击中的瓶数。 保龄球比赛由 n 轮组成,每轮的瓶数恰好为…

数据分析工具 Top 8

你能想象一个没有工具箱的水管工吗? 没有,对吧? 数据从业者也是如此。如果没有他们的数据分析工具,数据从业者就无法分析数据、可视化数据、从数据中提取价值,也无法做数据从业者在日常工作中做的许多很酷的事情。 根据你最感兴趣的数据科学职业——数…

前后台分离开发

前后台分离开发 简介 前后台分离开发,就是在项目开发过程中,对于前端代码的开发由专门的前端开发人员负责,后端代码则由后端开发人员负责,这样可以做到分工明确、各司其职,提高开发效率,前后端代码并行开…

SpringBoot 日志打印

一. 自定义打印日志 开发者自定义打印日志实现步骤: • 在程序中得到日志对象 • 使用日志对象的相关语法输出要打印的内容. 得到日志对象: //日志工厂需要将需要打印的类的类型传递进去,这样我们才知道日志的归属类,才能更方便的定位到文体类 private static Logger logger …

js_常用事件演示

✨前言✨ 1.如果代码对您有帮助 欢迎点赞👍收藏⭐哟 后面如有问题可以私信评论哟🗒️ 2.博主后面将持续更新哟😘🎉文章目录 🍔一、在JavaScript中什么是事件?🍟二、为什么要使用事件&#x…

杂文月刊投稿方式论文发表要求

《杂文月刊》是由国家新闻出版总署批准的正规文学类期刊。主要内容取向:杂文、散文、小说、诗歌、漫画、文学评论、艺术评论、戏剧文化、地方文化、非遗文化、美学艺术、教育等历史、文化、文学、艺术类的文章。是广大专家、学者、教师、学子发表论文、交流信息的重…

gzip引入后node_modules中.cache compression-webpack-plugin占用内存过多

1.Gzip Gzip(GNU zip)是一种常见的文件压缩格式和压缩算法,通常用于在 Web 服务器上对静态资源文件进行压缩,以减小文件大小并加快文件传输速度。在前端开发中,经常会使用 Gzip 压缩来优化网站的性能。 Gzip 压缩通过…

前端八股文(CSS篇)二

目录 1.css中可继承与不可继承属性有哪些 2.link和import的区别 3.transition和animation的区别 4.margin和padding的使用场景 5.::before和:after的双冒号和单冒号有什么区别? 6.display:inline-block什么时候会显示间隙 7…

Spring Boot案例-员工分页查询

准备工作: 数据库的连接: #驱动类名称 spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver #数据库连接的url spring.datasource.urljdbc:mysql://localhost:3306/tlias #连接数据库的用户名 spring.datasource.usernameroot #连接数据库的密码 spring.datasource.p…