基于卷积神经网络的图像识别算法及其应用研究
毕业快一年了,拿出来分享给大家,我和网上唯一的区别就是,我能够同时实现两个方案(猫狗识别和狗品种识别),我当时也是网上各种查,花了2,3个月的时间,一个萝卜一个坑走过来的,深度学习真的是深似海呀,不过结果还好,知道过程和原理是怎么来的了。
希望这篇文章能帮助你,加油,祝你好运!!!
前言
随着图像识别以及机器视觉的不断发展,卷积神经网络(Convolutional Neural Network, CNN)逐渐成为一个热门的研究课题。
本文研究了基于卷积神经网络的图像识别的算法及其应用,实现了猫狗和狗品种的鉴别,主要的研究工作如下:
(1)首先,介绍了CNN的组成和工作原理,在此基础上对基于卷积神经网络的图像识别算法进行了深入研究。通过手动采集对Kaggle数据集和斯坦福大学犬类图像数据集进行预处理,作为输入网络的数据。
(2)其次,利用之前预处理好的图像数据来构建卷积神经网络模型,设计卷积神经网络算法,加入卷积层,采样层,池化层和全连接层等网络层,微调图像数据参数,优化模型,分别解决二分类模型和多分类模型的图像识别问题。
(3)最后,利用卷积神经网络训练好的模型预测图像结果,以网络模型作为区分预测猫狗和狗品种的鉴别标准,进行图像预测,验证实验结果。利用卷积神经网络技术对大量的复杂图像进行自我学习,提取图像的特征值,生成模型。再用此模型来判断图像,得出类别和准确率。
提示:以下是本篇文章正文内容,下面案例可供参考
一、卷积神经网络是什么?
卷积神经网络(Convolutional Neural Network, CNN)是一种前馈神经网络,处理图像数据。第一个卷积神经网络是由Alexander Waibel得出的时间延迟网络(TDNN),是一种用于语音识别的卷积神经网络,用FFT预处理的语音信号当作输入,两种一维卷积构成的隐含层,提取频率域上面的平移不变特征。当时语音识别的隐马尔可夫模型,在同等条件下的表现是落后于TDNN。
1988年,Wei Zhang推出了第一个二维卷积神经网络:平移不变人工神经网络(SIANN),并应用在医学影像检测领域。1989年,Yann LeCun也创建了图像分类的卷积神经网络领域,也就是LeNet的第一个版本。网络结构和当今的卷积神经网络十分接近。LeCun随机初始化权重,随后用随机梯度下降进行自我学习,这一方法被后来的深度学习研究进行广泛应用。“卷积”和“卷积神经网络”等词,最先在这网络结构中描述。LeNet-5往原先的网络模型中加入了池化层对输入特征进行筛选,现代卷积神经网络的基本结构就是这种模型,采用交替叠加卷积层-池化层结构,能有效提取出输入图像的平移不变特征。如人像识别、手势识别等基于卷积神经网络的应用研究也逐渐深入。
CNN前馈过程为往前传播输出计算,该过程只向前传播输出计算,后一层的输入当作前一层的输出,持续到最后一层输出最终结果。传播过程不会调整网络参数。反向传播过程为,计算损失函数,修改每层参数,使误差向前传播,从最后一层开始,调整全部网络参数权重。CNN的特点在于其每一层的特征都由上一层的局部区域通过共享权值的卷积核激励得到。总的来说CNN有两大特点:
(1)可以将超大的数据量图像有效的降维成小的数据量。
(2)较为可靠的保留特征图像,图像较为符合处理原则。
CNN是终端到终端的一种学习研究模型,模型参数的训练方法为,通过传统的梯度进行下降,训练后的卷积神经网络,可以学习提取图像特征和图像分类。
二、卷积神经网络结构及工作原理
1.卷积神经网络的结构
卷积神经网络的结构第一部分为输入层,第二部分是若干卷积层和采样层,采样层也称为池化层,第三部分为全连接层。
2 卷积神经网络的工作原理
CNN的工作原理为以下三个步骤:
1.卷积层的运算;2.池化层的下采样;3.全连接层的分类。池化层的下采样,大幅降低参数量级(降维);全连接层的分类,类似传统神经网络部分,输出预测结果。
1、 卷积层的工作原理
卷积层,负责运算和提取图像中的局部特征;比如使用一个Filter(过滤器,也叫卷积核)来过滤图像的各个小区域,从而得到这些小区域的特征值。多个二维平面类型的卷积核可以当作每个卷积层,多个神经元组成一个卷积核。CNN中的n个卷积核为每种卷积层,共享权重在特征图里,这样就可以大大减少神经网络的参数数目,加快运算速率。卷积神经网络[17]的每个神经元,在接收输入、执行点积和非线性跟随时,使得深度学习面临着数据过拟合的问题[18]。在无法获取更多训练数据的情况下,防止神经网络过拟合的常用方法有添加网络容量、添加权重正则化[19]、dropout处理[20]、数据增强[21]等。卷积核扫完整张图像(Image),得出卷积特征(Convolved Feature)。运算过程为对应相乘,再相加,卷积层的运算过程如下图所示:
在实际应用中,一般为有多个卷积核,每个图像特征代表每种卷积核。
当图像特征与卷积核卷积出的较大的值时,则图像特征非常接近于这个卷积核,如下图所示:
卷积核(kernel convolution)不止用于CNN,也是在其他许多视觉算法领域的关键纽带。卷积核相当于一个小小的数字矩阵(滤波器,英文叫法为kernel或filter)在图像上进行滚动,依据kernel的值,并转换图像矩阵的值。通过卷积操作后得到的图像输出为特征映射(feature map)。特征映射值的公式计算如下:
式中, f为输入图像, h为滤波器。矩阵结果行数为 n,列数为 n。
把kernel固定在像素上后,在kernel中依次拿出每一个值,并成对地与图像中的值相乘。最后将每种核运算后的最终元素结果相加,把求和结果放到特征图输出的合适位置中。假设想用多种kernel在同种图像上,可以分别对每种kernel执行卷积,然后将结果来叠加,最后组成一个整体。
卷积层为创建CNN的一种层,已经不是使用单一的矩阵乘法,而是用卷积计算。前向传播为一下两个步骤。
首先是计算中间值Z:将输入数据与张量W(包括滤波器)进行卷积计算,再把结果和偏差 加上。其次把中间值Z传输到非线性激活函数中(使用g表示该激活函数)。
卷积优化图像处理计算过程:将2D卷积可视化操作——把数字1-9标记为神经元构成的输入层,用来接收像素亮度的输入图像,字母A-D为通过卷积运算得到的特征映射。I-IV 为来自kernel的后续值,可以理解为拿来学习网络的值。
卷积层有两个关键的属性。可以从图中看出,并不是相邻层的全部神经元都应该互相连接。如A的值是受神经元1影响。还有我们可以看出有些神经元用相同的权重。这样我们需要学习的参数,在CNN中我们要少得多。所以任何的kernel值都将影响每一个元素的特征映射输出,是反向传播中是较为关键的过程。
如果卷积层的输入向量是 ,那么输出向量是 , 参数向量(卷积算子)就是 。从输入向量到输出向量的过程为:
3 池化层的工作原理
即便是完成了卷积,图像依然较大,直接原因是卷积核比较小,采用直接的方法进行下采样来降低数据维度。池化层可以是下采样,因为极大地降低数据维度,减小数据量的大小空间并加快运算速度。如下图所示:
从图中可以看出,原始图像为10×10,开始进行下采样,采样窗口为3×3,下采样后的特征图为一个2×2的大小。池化层是较为可靠的下降数据维度比起卷积层来说,极大减少运算量,来避免过拟合。
池化层(Pooling)和卷积层的数学计算原理是一样的,先压缩来对输入的Feature Map。选一个极值输出到下一层Feature Map 邻域内的值,称为Max-Pooling。最后2N×2N的Feature Map,可以压缩为N×N。
CNN较为基本的两个层为卷积层和池化层,一般情况下为一起使用,池化层紧挨着卷积层之后。包含三个级联函数,前向传播和后向传播如下图所示:
3 全连接层的工作原理
全连接层,在整个卷积神经网络中起到“分类器”的作用。
神经网络模型训练完成后,得出全连接层。它的每节点与上层每节点相互连接,全部综合起来前一层的输出特征,因此这层权值参数是极多的。可以用一个简单的网络模型数学原理来推导一下过程:
其中,x1、x2、x3 为全连接层的输入, a1、a 2、 a3为输出。
当池化层和卷积层处理后的数据,输入给全连接层,得出想要的效果。通过降维后,卷积层和池化层数据,全连接层才能“跑起来”,否则数据量大,计算成本高,效率低下。
全连接层模拟过程如下图所示:
先是从局部特征的图像片段进行分类、搜寻和对比。由小局部特征图像到大局部特征图像逐渐演进,最后找到整个猫的图像。如对猫头、猫尾巴、猫腿等进行分类,红色圆形表示这个特征被找到的神经元,已经激活了,当寻找到合适的特征图像时,确定为猫。再往前走一层,对子特征图像分类,如猫头有眼睛、耳朵等这些特征进行分类。直到发现最符合要求的图像,把这些找到的特征组合在一起,最后确定为猫。
啊啊啊啊啊说了这多,代码类勒?
嘿嘿,不急,安排
2.代码(猫狗识别和狗品种识别)
1 猫狗识别(tensorflow方法)
猫狗识别代码
restore.py模块代码:
import tensorflow as tf
import numpy as np
import tensorflow.contrib.slim as slim
from PIL import Image,ImageFont, ImageDraw
__global_times = 0
# 创建一个新的python程序并导入相关numpy、tensorflow等基础科学软件包。
#一共定义了4个类,
# def build_graph(top_k):
# 在这个类中,主要就是创建大量的权重和偏置项,进行卷积和池化。定义一个解析输入参数的函数,
# build_graph()来构建图表。创建大量的权重和偏置项,进行卷积和池化。
#调用tf.placeholder函数操作,定义传入图表中的shape参数,后续还会将实际的训练用例传入图表。在训练循环(train_op)的后续步骤中,传入的整个图像和标签数据集会被切片,以符合每一个操作所设置的shape参数值,占位符操作将会填补以符合这个shape参数值。然后使用feed_dict参数,将数据传入sess1.run()函数。
#构建好图表,满足促使神经网络向前反馈并做出预测的要求。往,图表中添加生成损失(loss)所需要的操作,往损失图表中添加计算并应用梯度,所需的操作。定义Weight变量、biase变量、卷积层、池化层。
#定义卷积,传入x和参数,slim..conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None)
#定义池化,传入x, pooling, slim..max_pool(value, ksize, strides, padding, name=None)
#loss()函数通过添加所需的损失操作,进一步构建图表。
# def predictPrepare():
#将build_graph()函数构建好的图层,就是图表。进行加工,然后保存在当前文件夹checkpoint中。
# def imagePrepare(image_path):
#这个函数是对图像数据,进行统一处理,深加工。
# def Recognize(__test_image_file):
#这个函数主要是对处理好的测试图像,进行识别、分类和预测。
def build_graph(top_k):
keep_prob = tf.placeholder(dtype=tf.float32, shape=[], name='keep_prob')
images = tf.placeholder(dtype=tf.float32, shape=[None, 64, 64, 3], name='image_batch')
labels = tf.placeholder(dtype=tf.int64, shape=[None], name='label_batch')
conv_1 = slim.conv2d(images, 64, [3, 3], 3, padding='SAME', scope='conv1')
max_pool_1 = slim.max_pool2d(conv_1, [2, 2], [2, 2], padding='SAME')
conv_2 = slim.conv2d(max_pool_1, 128, [3, 3], padding='SAME', scope='conv2')
max_pool_2 = slim.max_pool2d(conv_2, [2, 2], [2, 2], padding='SAME')
conv_3 = slim.conv2d(max_pool_2, 256, [3, 3], padding='SAME', scope='conv3')
max_pool_3 = slim.max_pool2d(conv_3, [2, 2], [2, 2], padding='SAME')
conv_4 = slim.conv2d(max_pool_3, 512, [3, 3], padding='SAME', scope='conv4')
conv_5 = slim.conv2d(conv_4, 512, [3, 3], padding='SAME', scope='conv5')
max_pool_4 = slim.max_pool2d(conv_5, [2, 2], [2, 2], padding='SAME')
flatten = slim.flatten(max_pool_4)
fc1 = slim.fully_connected(slim.dropout(flatten, keep_prob), 1024, activation_fn=tf.nn.tanh, scope='fc1')
logits = slim.fully_connected(slim.dropout(fc1, keep_prob), 2, activation_fn=None, scope='fc2')
loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=labels))
accuracy = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(logits, 1), labels), tf.float32))
global_step = tf.get_variable("step", [], initializer=tf.constant_initializer(0.0), trainable=False)
rate = tf.train.exponential_decay(2e-4, global_step, decay_steps=2000, decay_rate=0.97, staircase=True)
train_op = tf.train.AdamOptimizer(learning_rate=rate).minimize(loss, global_step=global_step)
probabilities = tf.nn.softmax(logits)
tf.summary.scalar('loss', loss)
tf.summary.scalar('accuracy', accuracy)
merged_summary_op = tf.summary.merge_all()
predicted_val_top_k, predicted_index_top_k = tf.nn.top_k(probabilities, k=top_k)
accuracy_in_top_k = tf.reduce_mean(tf.cast(tf.nn.in_top_k(probabilities, labels, top_k), tf.float32))
return {
'images': images,
'labels': labels,
'keep_prob': keep_prob,
'top_k': top_k,
'global_step': global_step,
'train_op': train_op,
'loss':