无人驾驶项目——交通标志识别

2023-05-16

在无人驾驶项目中, 实现交通标志识别是一项重要工作。本文以德国交通标志数据集为训练对象, 采用深度神经网络LeNet架构处理图像,实现交通标志识别。具体处理过程包括包括:
  • 数据导入

  • 探索和可视化数据集

  • 数据预处理

  • 构建、训练和测试模型架构

  • 采用该模型对新图片进行预测

  • 分析新图片的softmax概率

1.数据导入

下载数据 "traffic-signs-data.zip"

读取文件" train.p" and "test.p"

import pickle

training_file = '../traffic-signs-data/train.p'
testing_file = '../traffic-signs-data/test.p'

with open(training_file, mode='rb') as f:train = pickle.load(f)
with open(testing_file, mode='rb') as f:test = pickle.load(f)
    
X_train, y_train = train['features'], train['labels']
X_test, y_test = test['features'], test['labels']

2.探索和可视化数据集

分析数据集中训练集数量,测试集数量,图片特征以及分类数量。
n_train = X_train.shape[0]

# TODO: Number of testing examples.
n_test = X_test.shape[0]

# TODO: What's the shape of an traffic sign image?
image_shape = X_train.shape[1:]

# TODO: How many unique classes/labels there are in the dataset.
n_classes = len(set(y_train))

print("Number of training examples =", n_train)
print("Number of testing examples =", n_test)
print()
print("Image data shape =", image_shape)
print("Number of classes =", n_classes)
结果如下所示:

Number of training examples = 34799
Number of testing examples = 12630
Image data shape = (32, 32, 3)
Number of classes = 43  

随机显示数据集的一张图片:

3.数据预处理

数据预处理过程中用到的技术包括图片灰度处理、数据归一化、数据增强、数据分割等。

1.图片灰度处理

在交通标志识别过程中,颜色并非图片等主要特征,将彩色图片转换为灰度图片依然可以识别,且单通道数图片迭代更快。图片灰度处理代码如下:

X_train_rgb = X_train
X_train_gry = np.sum(X_train/3, axis=3, keepdims=True)
X_test_rgb = X_test
X_test_gry = np.sum(X_test/3, axis=3, keepdims=True)

print('RGB shape:', X_train_rgb.shape)
print('Grayscale shape:', X_train_gry.shape)

2.数据归一化

归一化输入图片,将输入特征处理到相似的范围内,使得代价函数优化起来更简单更快捷,该项目中将训练集和测试集归一化到(-1,1)范围。具体代码如下:

X_train_normalized = (X_train - 128.)/128. 
X_test_normalized = (X_test - 128.)/128.

3.数据增强

在交通标志识别训练过程中,对原始数据进行训练,结果显示训练集准确率挺高但是验证集的准确率偏低,表现为过拟合。出现过拟合时训练集准确率高表明算法充分学习到了原始数据的特征;验证集准确率偏低表明原始数据的特征不够充分,使算法在新验证集中泛化性表现较差。解决方式是对原始数据在数据预处理阶段进行数据增强,增加训练集数据。具体代码如下:

from scipy import ndimage
def expend_training_data(X_train, y_train):
    """
    Augment training data
    """
    expanded_images = np.zeros([X_train.shape[0] * 5, X_train.shape[1], X_train.shape[2]])
    expanded_labels = np.zeros([X_train.shape[0] * 5])

    counter = 0
    for x, y in zip(X_train, y_train):

        # register original data
        expanded_images[counter, :, :] = x
        expanded_labels[counter] = y
        counter = counter + 1

        # get a value for the background
        # zero is the expected value, but median() is used to estimate background's value
        bg_value = np.median(x)  # this is regarded as background's value

        for i in range(4):
            # rotate the image with random degree
            angle = np.random.randint(-15, 15, 1)
            new_img = ndimage.rotate(x, angle, reshape=False, cval=bg_value)

            # shift the image with random distance
            shift = np.random.randint(-2, 2, 2)
            new_img_ = ndimage.shift(new_img, shift, cval=bg_value)

            # register new training data
            expanded_images[counter, :, :] = new_img_
            expanded_labels[counter] = y
            counter = counter + 1

    return expanded_images, expanded_labels

X_train_normalized = np.reshape(X_train_normalized,(-1, 32, 32))
agument_x, agument_y = expend_training_data(X_train_normalized[:], y_train[:])
agument_x = np.reshape(agument_x, (-1, 32, 32, 1))

print(agument_y.shape)
print(agument_x.shape)

print('agument_y mean:', np.mean(agument_y))
print('agument_x mean:',np.mean(agument_x))
#print(y_train.shape)

4.数据分割

将扩增之后的数据重新分割为训练集和验证集,分割比例极代码如下:

from sklearn.model_selection import train_test_split

X_train, X_validation, y_train, y_validation = train_test_split(agument_x, agument_y,test_size=0.10,random_state=42)

4.定义LeNet函数

交通标志识别项目中,其图形特征明显,识别任务比较简单,分类输出数固定,对于该类任务采用该架构较简单的LeNet(X)就可以实现。所以项目算法架构采用LeNet(X),算法架构如下图所示:

LeNet(X)是交通标志识别中非常经典的算法结构。但是要实现交通标志识别还需要对该算法的初始结构进行调整。比如输出层的分类数调整为43;Subsampling layers 转为max pooling layers;增加Dropout 层,初始设置keep_prob=0.9;激活函数采用RELU。

改进后的架构流程如下表所示:

LayerDescription
Input32x32x1 gry image
Convolution 5x51x1 stride, VALID padding, outputs 28x28x6
RELUActivation
Max pooling2x2 stride, outputs 14x14x6
Convolution 5x51x1 stride, VALID padding, outputs 10x10x16
RELUActivation
Max pooling2x2 stride, outputs 5x5x16
FlattenOutputs 400
Fully connectedOutputs 120
RELUActivation
DropoutKeep_prob=0.5
Fully connectedOutputs 84
RELUActivation
DropoutKeep_prob = 0.5
Fully connectedOutputs = 43
具体代码如下:
from tensorflow.contrib.layers import flatten

def LeNet(x):    
    # Arguments used for tf.truncated_normal, randomly defines variables for the weights and biases for each layer
    mu = 0
    sigma = 0.1
    
    # SOLUTION: Layer 1: Convolutional. Input = 32x32x1. Output = 28x28x6.
    conv1_W = tf.Variable(tf.truncated_normal(shape=(5, 5, 1, 6), mean = mu, stddev = sigma))
    conv1_b = tf.Variable(tf.zeros(6))
    conv1   = tf.nn.conv2d(x, conv1_W, strides=[1, 1, 1, 1], padding='VALID') + conv1_b

    # SOLUTION: Activation.
    conv1 = tf.nn.relu(conv1)
    #conv1 = tf.nn.dropout(tf.nn.relu(conv1), keep_prob)

    # SOLUTION: Pooling. Input = 28x28x6. Output = 14x14x6.
    conv1 = tf.nn.max_pool(conv1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='VALID')

    # SOLUTION: Layer 2: Convolutional. Output = 10x10x16.
    conv2_W = tf.Variable(tf.truncated_normal(shape=(5, 5, 6, 16), mean = mu, stddev = sigma))
    conv2_b = tf.Variable(tf.zeros(16))
    conv2   = tf.nn.conv2d(conv1, conv2_W, strides=[1, 1, 1, 1], padding='VALID') + conv2_b
    
    # SOLUTION: Activation.
    conv2 = tf.nn.relu(conv2)
    #conv2 = tf.nn.dropout(tf.nn.relu(conv2), keep_prob)

    # SOLUTION: Pooling. Input = 10x10x16. Output = 5x5x16.
    conv2 = tf.nn.max_pool(conv2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='VALID')

    # SOLUTION: Flatten. Input = 5x5x16. Output = 400.
    fc0   = flatten(conv2)
    
    # SOLUTION: Layer 3: Fully Connected. Input = 400. Output = 120.
    fc1_W = tf.Variable(tf.truncated_normal(shape=(400, 120), mean = mu, stddev = sigma))
    fc1_b = tf.Variable(tf.zeros(120))
    fc1   = tf.matmul(fc0, fc1_W) + fc1_b
    
    # SOLUTION: Activation.
    #fc1    = tf.nn.relu(fc1)
    fc1 = tf.nn.dropout(tf.nn.relu(fc1), keep_prob)

    # SOLUTION: Layer 4: Fully Connected. Input = 120. Output = 84.
    fc2_W  = tf.Variable(tf.truncated_normal(shape=(120, 84), mean = mu, stddev = sigma))
    fc2_b  = tf.Variable(tf.zeros(84))
    fc2    = tf.matmul(fc1, fc2_W) + fc2_b
    
    # SOLUTION: Activation.
    #fc2 = tf.nn.relu(fc2)
    fc2 = tf.nn.dropout(tf.nn.relu(fc2), keep_prob)


    # SOLUTION: Layer 5: Fully Connected. Input = 84. Output = 43.
    fc3_W  = tf.Variable(tf.truncated_normal(shape=(84, 43), mean = mu, stddev = sigma))
    fc3_b  = tf.Variable(tf.zeros(43))
    logits = tf.matmul(fc2, fc3_W) + fc3_b
    
    return logits

5.训练流程及设置超参数

计算交叉熵,测量对数几率的分类结果和真实标签之间的差距。

计算训练集交叉熵平均值作为训练集的整体损失函数。训练过程使用Adam算法优化梯度下降,并最小化损失函数。超参数设置如下:

EPOCHS =10, BATCH_SIZE=128,sigma = 0.1,learning rate =0.001

具体代码如下:

logits = LeNet(x)  

cross_entropy = tf.nn.softmax_cross_entropy_with_logits(labels=one_hot_y,logits=logits)

loss_operation = tf.reduce_mean(cross_entropy) 
optimizer = tf.train.AdamOptimizer(learning_rate = rate) 
training_operation = optimizer.minimize(loss_operation) 

6.评估模型

在交通标志识别过程中,采用改进算法对数据增强数据进行训练,同时对算法Ddropout层调整参数,设置keep_prob=0.5,增加算法正则化效果。

算法的最终输出结果如下:

  • training set accuracy : 0.982

  • validation set accuracy : 0.976

  • test set accuracy : 0.945

7.测试新图片

下载8张德国交通标志图片,如图中所示:
将图片与训练集进行相同的处理,包括灰度化,归一化等。

8.分析新图片的softmax概率

对训练后的模型进行测试,输出各个图片识别softmax概率的前三位。


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

无人驾驶项目——交通标志识别 的相关文章

  • FreeRTOS之TCB

    FreeRTOSMini实现了最小任务调度 现在分开介绍进程调度重要部分 进程调度的基础首先是定义任务调度的数据结构 xff0c 来保存任务堆栈结构和任务状态所在状态列表 xff0c 然后就是任务的优先级唯一号等 最小Mini内核参照 Fr
  • FreeRTOS任务调度主要变量

    之前介绍的和FreeRTOS任务调度相关的数据结构即内存分配实现 xLIST heap 4 TCB结构体 任务调度就是基于这些结构体实现 这次介绍调度相关的主要变量 代码在FreeRTOSMini c文件签名部分 span class to
  • Base64串介绍

    以前写winform时候没接触过Base64 刚开始接触时候还不知道是个啥 最开始接触Base64串时候是仪器出图 很长一段时间我还真以为Base64就是表示图的 xff0c 很多人也是这么认为的 xff0c 这次介绍一下什么是Base64
  • FreeRTOS创建任务

    CPU有这些寄存器 R0 R12为通用寄存器 R13为栈顶指针 xff0c 在OS时候中断函数的R13使用MSP的指针 xff08 内核态 xff09 非中断里面使用PSP指针 xff08 用户态 xff09 正是有双堆栈指针可以保证OS切
  • FreeRTOS任务调度最后篇

    FreeRTOS开启任务调度 一篇说到启动任务调度最后启动Systick定时器 xff0c 通过SVC中断引导第一个任务执行 然后系统就在Systick的定时中断下调度任务执行 xff0c 这次介绍最后的部分 xff0c Systick和P
  • 从STM32-FreeRTOS到linux

    之前买的STM32的开发板学习裸机开发 了解裸机之后学习FreeRTOS来作为小型操作系统学习 xff0c 理解操作系统调度实现 一直想学习一下linux的内核 xff0c 之前下载源码和初步看了下感觉无从下手 有了RTOS的基础后 xff
  • C#实现图片旋转

    C 绘图正常是不涉及到旋转的 有时候会有旋转画笔的情况 比如条码打印字竖着打印 旋转图片一定角度绘制 或者斜着画水印 这时候就涉及到旋转画笔了 源码地址 通过graphics TranslateTransform Pcenter X Pce
  • C#调C++库返回字符串

    用C 调C 43 43 库函数返回字符串 xff0c 由于C 43 43 本身方法之间调用返回字符串都是一般都是申明void或int返回的方法 xff0c 然后通过char变量带出返回值 在C 43 43 调用这种之前自己先初始化char空
  • Asp.NetCore在CentOS网站卡死

    最近碰到项目的网站在高峰期卡死的现象 刚开始以为是数据库问题导致的卡死 xff0c 就排查和改了数据的设置 然后观察几天发现网站还是会在高峰期卡死 xff0c 然后改了点网站设置 xff0c 准备第二天观察一下 xff0c 星期二竟然又没出
  • 使用IRIS碰到的坑

    最近换新电脑了 xff0c 然后直接不安装cache2016了 xff0c 直接上IRIS啊 然后碰到几个坑 xff0c 一是在win11不知道是兼容性不好还是怎么了 每次重启电脑后数据库就无法启动 xff0c 为此祭出多年保存的方子 xf
  • K8s 配置高可用提示Configuration file ‘/etc/keepalived/keepalived.conf‘ is not a regular non-executable file

    k8s配置keepalived高可用 xff0c systemctl start keepalived提示 检查keepalived配置文件 xff0c 查询配置也正常 从报错提示显示keepalived conf 配置文件是一个非执行的文
  • Std数据M的荣光

    对检验的上线 xff0c 实施和开发的大部分时间都用在做基础数据和联设备对通道这些 对相同的仪器每次都有做项目数据 xff0c 对通道那些我一直深有感触 xff0c 一直在构思怎么减少仪器对通道这些做数据的工作量 奈何以前只是浅显的使用M
  • matlab从图表中提取数据

    有如下的波形图 xff0c 如何从中精确提取出全部的数据 1 将波形图片 截图 保存为test png或test jpg xff0c 并将图片放于matlab工作目录中 xff0c 如下图示例所指定的目录中 xff1a 2 xff0c 新建
  • STM32 基础系列教程 1- CubeMX+GPIO

    前言 学习stm32 GPIO 的使用 xff0c 设置某一GPIO引脚为输出功能 xff0c 将对应引脚拉高或拉低输出 xff0c 同时学会初步认识STM32最新的HAL库的使用 xff0c 用代码实现控制GPIO引脚输出产生周期出1s
  • STM32 基础系列教程 29 - FreeRTOS

    前言 学习stm32 中 FreeRTOS嵌入式实时操作系统的使用 xff0c 学会在FreeRTOS时行任务创建与任务运动 xff0c 学习在嵌入式实时操作系统下编程 xff0c 用串口打印相应信息 xff0c 并控制LED闪烁 示例详解
  • 对本地的代码进行修改后,直接git pull会提示本地代码和github代码冲突,需要先commit本地代码,或者stash他们

    对本地的代码进行修改后 xff0c 直接git pull会提示本地代码和github代码冲突 xff0c 需要先commit本地代码 xff0c 或者stash他们 对本地的代码进行修改后 xff0c 直接git pull会提示本地代码和g
  • linux查询内存、CPU、硬盘等系统信息的命令

    一 linux CPU大小 root 64 idc cat proc cpuinfo grep 34 model name 34 amp amp cat proc cpuinfo grep 34 physical id 34 model n

随机推荐

  • ubuntu无法更新的问题,提示错误Err http://mirrors.163.com trusty Release.gpg Could not resolve 'mirrors.163.com

    最近在安装使用ubuntu xff0c 并且配置源文件下载相应gcc xff0c gdb时候 xff0c 出现错误 xff0c 提示报错内容为 Err http mirrors 163 com trusty Release gpg Coul
  • 在 GitHub 下载某个程序的特定版本代码

    情况 github中某个项目已经更新到2 1 0版本 但是想要它的1 0 1版本怎么办 方法一 xff1a 首先点击这个repository下的这个branch按钮 点开了以后你会看到这个 xff0c 然后点tags 选择你想要下载的版本
  • Pixhawk之姿态控制

    原文地址 xff1a http blog csdn net qq 21842557 1 写在前面 无人机控制部分主要分为两个部分 xff0c 姿态控制部分和位置控制部分 xff1b 位置控制可用远程遥控控制 xff0c 而姿态控制一般由无人
  • Android注册表文件

    data system packages plist com google android ears 10043 0 data data com google android ears default 3003 1028 1015 com
  • Java 爬虫系列丨(一)爬虫介绍

    1 简介 1 1 背景 随着互联网的迅速发展 xff0c 网络资源越来越丰富 xff0c 信息需求者如何从网络中抽取信息变得至关重要 目前 xff0c 有效的获取网络数据资源的重要方式 xff0c 便是网络爬虫技术 简单的理解 xff0c
  • 基于龙伯格观测器的永磁同步电机仿真与实现

    摘 要 xff1a 在永磁同步电动机控制系统中 xff0c 使用转子位置传感器不仅会增加设计和制造的成本 xff0c 还会使系统的可靠性降低 因此 xff0c 无位置传感器技术已成为永磁同步电机控制领域的研究热点之一 本文对龙伯格观测器技术
  • 拷贝cp大文件报错“文件太大”

    问题 xff1a 今天在centos7系统下 xff0c u盘位vfat格式16个G xff0c 拷贝7个G大小的问文件 xff0c 无论是用dd还是cp都在拷贝到4 3G大小的时候显示失败 故写下这篇博客 无论什么系统 xff0c 只要分
  • CMakeList.txt

    一 Cmake 简介 cmake 是一个跨平台 开源的构建系统 它是一个集软件构建 测试 打包于一身的软件 它使用与平台和编译器独立的配置文件来对软件编译过程进行控制 二 常用命令 1 指定 cmake 的最小版本 cmake minimu
  • 安装centos7 卡在 “正在安装引导装载程序”界面

    今天系统突然起不来 xff0c 不知道什么原因删掉了一些文件 修复太浪费时间 xff0c 还是重新装一个系统 xff08 原来的分区有很多个人资料 xff0c 所以一定不能格调 xff0c 在无用的分区上装新的系统 所以你装系统的时候尽量不
  • insmod: ERROR: could not insert module: Invalid module format

    root 64 zn pc home zn sedriver 5000 new sedriver 5000 span class token comment insmod wst se echip drv ko span insmod ER
  • LoongArch上正常使用`pip install`

    原创 xff1a 你在使用loongarch架构操作系统时 xff0c 是否遇到pip install 安装失败的情况 xff1f 刷到这篇文章 xff0c 大家可添加评论或者私信我 xff0c 及时满足大家的需求 那么 xff0c 下面讲
  • python SOABI兼容性问题

    首先说明一点 xff1a 龙芯发布的仓库都是基于configure ac 中包含loongarch64 linux gnu定义的python所构建 https blog csdn net zhangna20151015 article de
  • python中为什么加上中文注释就会报错

    由于Python源代码也是一个文本文件 xff0c 所以 xff0c 当你的源代码中包含中文的时候 xff0c 在保存源代码时 xff0c 就需要务必指定保存为UTF 8编码 当Python解释器读取源代码时 xff0c 为了让它按UTF
  • 关于在linux操作系统下打不出汉字或者在敲打汉字时无法显示拼音的问题

    在linux下出现问题不比在window下形象 在window下 你发现哪个软件有问题了 xff0c 点击几下鼠标就完事了 xff1b 要是在linux系统下 xff0c 不懂代码 xff0c 可修复不了 打不出汉字 xff0c 在这我就说
  • 解析/etc/hosts文件

    1 xff0c etc hosts xff0c 主机名和ip配置文件 hosts The static table lookup for host name 主机名查询静态表 linux 的 etc hosts是配置ip地址和其对应主机名的
  • c++语法大全

    c 43 43 语法大全 一 变量和简单数据类型 1 变量名只能包含字母 数字和下划线 可以以字母和下划线开头 xff0c 但是不能从数字开头 xff1b 变量名不能包含空格 2 数据类型 字符串 字符串可以用双引号或者单引号括起来 xff
  • libxml2的安装及使用

    本文着重介绍解析xml的libxml2库的安装及使用 xff0c 举例说明创建和解析xml的过程 是针对C语言开发人员使用 你若想详细学习前端的一套东西 xff0c 即xml html css javascript JS 等 xff0c 可
  • dd 与cp的区别

    dd命令和cp命令的区别 cp与dd的区别在于cp可能是以字节方式读取文件 xff0c 而dd是以扇区方式记取 显然dd方式效率要高些 dd最大的用处是他可以进行格式转换和格式化 dd是对块进行操作的 xff0c cp是对文件操作的 比如有
  • 畸变校正与极线校正(具体原理+Matlab代码)

    附 xff1a 相关需要的工具函数源代码 xff08 投影函数 校正矩阵计算等 xff09 见最下面 1 畸变校正 1 1 形成原因 图像畸变一般有两种 xff0c 第一种是透镜本身的形状有问题 xff0c 使得图像发生径向畸变 xff1b
  • 无人驾驶项目——交通标志识别

    在无人驾驶项目中 xff0c 实现交通标志识别是一项重要工作 本文以德国交通标志数据集为训练对象 xff0c 采用深度神经网络LeNet架构处理图像 xff0c 实现交通标志识别 具体处理过程包括包括 xff1a 数据导入 探索和可视化数据