CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)

这里面大多资料均为网上参阅,参考资料过多未能记住您的文章地址望见谅,如涉及您的文章,本文未声明的即可留言,我会将您的原文地址引入。

一、前言

项目代码:https://github.com/bao17634/cnn_captcha

本文主要是对DHL公司的验证码进行识别,如需识别其他验证码,需要找相关验证码进行训练。

  • 环境:Windows 10
  • 训练框架:tensorflow-gpu 1.15
  • 算法:CNN(卷积神经网络)
  • 图像识别库:PIL、OpenCV

二、相关概念

2.1、机器学习

机器学习是人工智能的一个子集,它是利用统计技术提供了向计算机“学习”数据的能力,而不需要复杂的编程。简单来说,机器学习可以被定义为一种科学,它使计算机像人类一样行动和学习,并通过以实际交互和观察的形式向他们提供信息和数据,以独立的方式提高他们的学习能力。机器学习鼓励各种行业的各种自动化跨度和任务,从分析恶意软件或数据安全公司到寻求有利交易的财务专家,都是机器学习的应用场景。常用的集中机器学习算法。例如:

  • Find-S
  • 决策树(Decision trees)
  • 随机森林(Random forests)
  • 人工神经网络(Artificial Neural Networks)

通常,有3类学习算法:

  1. 监督机器学习算法:该算法首先会进行预测。数据中含有标记好的标签,该算法会在在分配给数据点的值标签中搜索模式。
  2. 无监督机器学习算法:没有标签与数据关联。并且,这些 ML 算法将数据组成簇。此外,他需要描述其结构,并使复杂的数据看起来简单且能有条理的分析。
  3. 增强机器学习算法:我们使用这些算法选择动作。并且,我们能看到它基于每个数据点。一段时间后,算法改变策略来更好地学习。

2.2、深度学习(Deep Learning)

与特定于任务的算法不同,深度学习是基于学习数据的机器学习的子集。它的灵感来自被称为人工神经网络的功能和结构。深度学习通过学习将世界显示为更简单的概念和层次结构,以及基于不那么抽象的概念来计算更抽象的代表,从而获得巨大的灵活性和广泛性。

换言之,机器学习只关注解决现实问题,通过对大量数据的统计,然后分析结果做出预判;深度学生在通过对大量书籍分析后,能提取样本的特征,然后让机器自己“记住”样本的共同特征,从而让机器能有自己的“思想”,使其在遇到有此类特征的样本后自己判定出结果。

近几年深度学习被很多人工智能爱好大肆宣称所深度学习也越来来越受到开发者的广泛关注,尤其是在一些特定领域,例如在自然语言处理、图像识别等应用上。

为了理解上述概念,举一个动物识别器的例子,它用于识别给定的图像是狮子还是鹿。当我们将此解决为传统的机器学习问题时,我们将涉及特定的特征,比如说给定的动物是否有耳朵,是否有胡须或任何其他器官。简单来说,我们将定义面部特征,让系统识别动物。另一方面,在深度学习中,从第一步开始。深度学习将自动对关键特征进行定义和分类。深度学习将首先确定找出狮子或鹿的最相关因素。稍后它将开始识别形状和边缘的组合,以更深入地识别对象。例如,如果对象有耳朵或者有胡须。在定义了这些概念的连续分层识别之后,它将决定哪些特征负责找到正确的答案。

总结:

  • 使用机器学习算法来解析数据,学习数据,并根据数据做出理智预判;而深度学习用于创建可以自我学习和可理智判定的人工“神经网络”。

三、tensorflow

3.1、 tensorflow安装

  • 安装教程:https://juejin.im/post/5db66b99518825644402df4c
    注意:如果GPU性能比较好,建议安装GPU版本,因为GPU训练速度要比CPU快好多。

3.2、tensorflow 介绍

CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第1张图片
tensorflow是由谷歌开发,使用比较广泛的深度学习框架,主要用来深度学习(机器学习也用)以及其他涉及大量运算,也是Github上最受欢迎的深度学习;tensorflow在图像分类、音频处理,推荐系统和自然语言处理等领域应用十分广泛,谷歌几乎涉及深度学习或者机器学习的项目,都在使用tensorflow作为运算框架;tensorflow之所以能收到广大开发者的青睐,离不开tensorflow底层优秀的封装,让开发人员能在不了解底层原理的情况下快速上手并且能直接开发。

3.3、tensorflow运行原理

CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第2张图片
张量定义数据模型、把数据模型操作定义在计算图中,使用会话运行计算,然后把计算定义在图上

  • 张量(Tensor):
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第3张图片
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第4张图片
    在数学上,张量是N维向量,这也就意外着张量可以用来表示N维数据集。上图有点复杂,难以理解,可以看看简化版:
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第5张图片
    上图显示了一些简化的张量。随着维度的不断增加,数据表示将变得越来越复杂。例如,一个3x3的张量,我可以简单地称它为3行和列的矩阵。如果我选择另一个形式的张量(1000x3x3),我可以称之为一个向量或一组1000个3x3的矩阵。在这里我们将(1000x3x3)称为张量的形状或尺寸。张量可以是常数也可以是变量。
  • 计算图(流,flow):

流(Flow)是指一个计算图或简单的一个图,图不能形成环路,图中的每个节点代表一个操作,如加法、减法等。每个操作都会导致新的张量形成
CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第6张图片
上图展示了一个简单的计算图,所对应的表达式为:
e = (a+b) x (b + 1)

记算图具有以下属性:

  • 叶子顶点或起始顶点始终是张量。意即,操作永远不会发生在图的开头,由此我们可以推断图中的每个操作都应该接受一个张量并产生一个新的张量。同样,张量不能作为非叶子节点出现,这意味着它们应始终作为输入提供给操作/节点。

  • 计算图总是以层次顺序表达复杂的操作。通过将a + b表示为c,将b + 1表示为d,可以分层次组织上述表达式。 因此,我们可以将e写为:
    e = (c)x(d) 这里 c = a+b 且 d = b+1.
    以反序遍历图形而形成子表达式,这些子表达式组合起来形成最终表达式。

  • 当我们正向遍历时,遇到的顶点总是成为下一个顶点的依赖关系,例如没有a和b就无法获得c,同样的,如果不解决c和d则无法获得e。

  • 同级节点的操作彼此独立,这是计算图的重要属性之一。当我们按照图中所示的方式构造一个图时,很自然的是,在同一级中的节点,例如c和d,彼此独立,这意味着没有必要在计算d之前计算c。 因此它们可以并行执行。

计算图的并行

  • 上面提到的最后一个属性当然是最重要的属性之一。它清楚地表明,同级的节点是独立的,这意味着在c被计算之前不需空闲,可以在计算c的同时并行计算d。Tensorflow充分利用了这个属性

3.4、tensorflow应用

  • 处理数据挖掘任务
  • 处理机器学习任务
  • 处理深度学习任务
  • 进行并行化学习

3.5、tensorflow特点

  • 高度的灵活性
  • 真正的可移植性
  • 多语言支持
  • 丰富算法库
  • 完善的文档和成熟社区

3.6、其他深度学习框架

Caffa、MXNET、Torch、Theano、CNTK、PaddlePaddle(百度开发)

注: tensorflow更多了解请点击

四、卷积神经网络 CNN(Convolutional Neural Networks)

4.1、神经网络结构

  • 神经网络类别:
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第7张图片

神经网络是一种模拟人脑的神经网络以期能够实现类人工智能的机器学习技术,每一个神经网络都是由简单的神经元(处理单元)成的大规模并行处理器。
 下图是一个最基本的神经网(三层结构)的结构图:
 CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第8张图片
 CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第9张图片

  • 红色的是输入层,绿色的是输出层,紫色的是中间层(也称隐藏层),输入层有三个输入单元,隐藏层有四个运算单元,输出层有三个输出单元。

4.1.1 常用的神经网络模型

  1. 单层前馈网络
    输入节点的个数与输出节点个数相同:
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第10张图片
  2. 多层前馈网络
    有一层或者多层隐藏层,想应节点称之为隐藏神经元或者隐藏单元:
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第11张图片
  3. 递归网络
    递归为网络个前缀的区别是它至少有一个反馈环。
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第12张图片
    注意:
  4. 设计一个神经网络的时候, 输入层与输出层的节点往往是固定的,但中间层则可以自由指定;
  5. 神经网络结构图中的拓扑与箭头代表着预测过程的数据流向,跟训练时的数据有一定区别;
  6. 结构里面的关键不是圆圈(“神经元”),而是他们之间的连线(代表“神经元”之间的连接)。每一个连线对应一个不同的权重(其值称为权值),这是需要通过训练的到的。

4.1.1 神经元

  • 人体大脑神经元
  • CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第13张图片
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第14张图片
  • 神经网络神经元结构
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第15张图片
  • 权值: 神经元与神经元之间的权重或者强调特征。
  • 操作: 神经元输入值的乘、加操作。
  • 激活函数:用来限制神经元输出的振幅,将神经元输出值压制到允许的范围内的一定值。激活函数主要有:阈值函数,sigmiod、tanh函数。
    阈值函数:
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第16张图片
    sigmoid函数:
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第17张图片
  • 偏置biase:
    偏置b的作用是根据它的正直或者负值来响应的增加或者降低激活函数的网络输入。

4.1、CNN卷积神经网络

4.1.1 什么是卷积

  • 卷积的概念:
    卷积是对图像(不同的数据窗口数据)和滤波矩阵(一组固定的权重:因为每个神经元的多个权重固定,所以又可以看做一个恒定的滤波器filter)做内积(逐个元素相乘在求和)的操作就是所谓的卷积操作,也是卷积神经网络名字的来源。
    下图中红框框起来的部分变可以理解为一个滤波器(filter),即带着一组固定权重的神经元。多个滤波器叠加起来便成了卷积层。 CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第18张图片
    比如下图,左边部分是原始输入数据,图中中间部分是滤波器filter,图中右边是输出的新的二维数据。CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第19张图片
    中间滤波器filter与数据窗口做内积,其具体计算过程则是:4x0 + 0x0 + 0x0 + 0x0 + 0x1 + 0x1 + 0x0 + 0x1 + -4x2 = -8
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第20张图片

  • 图像上的卷积:
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第21张图片
    左边是图像输入,中间是滤波器filter(带着一组固定权重的神经元),不同的滤波器filter会得到不同的输出数据,比如颜色深浅、轮廓等特征。也是就是说如果想图区图像不同的特征,就需要不同的滤波器filter。

  • 卷积动图:
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第22张图片
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第23张图片

4.1.2 什么是CNN(卷积神经网络)

  • CNN的概念:
    CNN事故1998年LECun提出了卷积神经网络的金典模型LeNet-5,这是目前使用最广泛的模型之一。CNN是一种前馈神经网络,它的人工神经元可以响应一部分覆盖范围内的周围单元,对于大型图像处理有出色表现。CNN是由输入层卷积层(convolutional layer)、池化层(pooling layer,也称为去样层)、全连接层输出层构成。卷积层和池化层一般会取若干个,采用卷积层和池化层交替设置,即一个卷积层连接一个池化层,池化层再连接一个卷积层,以此类推。与其他深度学习结构相比,卷积神经网路在图像和语音识别方面具有很强的优势。
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第24张图片
  1. 卷积层: 通过卷积操作来提取图像特征
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第25张图片
    通过过滤器(卷积核)来过滤图像各个小区域,从而得到小区域的特征值。

说明: 再具体应用中,往往有很多卷积核,可以认为,每个卷积核代表一种图像模式,如果某个图像块与此卷积核卷积出的值大,则认为此图像块十分接近于此图像十分接近于此卷积核。如果我们设计了6个卷积核,可以理解为:我们认为这个图像有6种底层纹理模式,也就是我们6种基础模式就能描绘出一幅图像。下图就是25种不同的卷积核示例:
CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第26张图片

  • 总结:卷积层的通过卷积核的过滤提取出图片中局部的特征,跟上面提到的人类视觉的特征提取类似,卷积层输出值越高,就说明匹配程度越高,越能表现该图片的特征。
  1. 池化层: 下采样,数据降维,防止过拟合
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第27张图片
    可以从上图中看到,原始图片20x20的,对其进行下采样,采样的窗口为10x10,最终将其下采样称为一个2x2大小的特征图。
    这么做的主要目的是因为有时候及时做完卷积,图像任然很大(由于卷积核比较小),为了降低数据维度,就进行了下采样。
  • 总结:池化层相比卷积层可以更有效的降低数据维度,这么做不但可以大大减少运算量,还可以有效的避免过拟合。
  1. 全连接层: 输出结果。
    经过卷积层和池化层处理过后的数据输入到全连接层,得到最终想要的结果。
    经过卷积层和池化层降维过的数据,全连接层才能“跑得动”

  2. CNN金典网络架构图(以手写字体识别为例)
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第28张图片

  • 3D演示图:http://scs.ryerson.ca/~aharley/vis/conv/

4.1.2 CNN具体工作过程

  1. 设计的一个卷积核如下左图所示,想要识别如下右图的曲线:
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第29张图片
  2. 用上面的卷积核,来识别这个简化版的图片——一只漫画老鼠
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第30张图片
  3. 当机器识别到老鼠的屁股的时候,卷积核与真实区域数字矩阵作用后,输出较大:6600
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第31张图片
  4. 而用同一个卷积核,来识别老鼠的耳朵的时候,输出则很小:0
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第32张图片
    结论:现有的这个卷积核保存着曲线的特征,匹配识别出来了老鼠的屁股是曲线的。我们则还需要其他特征的卷积核,来匹配识别出来老鼠的其他部分。卷积层的作用其实就是通过不断的改变卷积核,来确定能初步表征图片特征的有用的卷积核是哪些,再得到与相应的卷积核相乘后的输出矩阵

四、利用CNN做验证码识别

因为验证码是图像验证码,所以可以将验证码识别过程理解为图像识别过程。

  • 训练环境:Windows 10
  • 显卡:GTX 1060
  • Tensorflow:tensorflow- gpu 1.15.0
  • 训练样本:50000张验证码(训练集:90%,验证集:5%,测试集:5%)

4.1 图像识别过程

可分为两个步骤:

  1. 图像处理
  2. 图像识别

4.1.1 图像处理

图像处理又分为:

  • 图像处理是指利用计算机对图像进行分析,已达到所需要的结果;
  • 图像处理可分为模拟图像处理和数字图像处理,而图像处理一般指的是数字图像处理
  • 图像处理的目的是去除图片的干扰、噪声、等不利于识别的影响因素,主要包括:图像采样图像标注图像增强图像复原图像编码与压缩图像分割

在验证码识别的项目中,在对图像处理的时候主要用的是:图像采样图像标注(也称打标签)图像增强图像分割

  • 图像采样: 自己写了一个程序,从所要识别网站上爬取验证码图片,采集的图片越多越好,训练的样本多了训练出的模型才能有很强的泛性,如果样本数太少模型容易出现过拟合现象,训练出的模型准确度就会很低。

  • 图片标注: 将采集到的图片进行标注,这里我主要是采用人工的方式将采集到的验证命名为图片验证码的内容,如下图:
    在这里插入图片描述
    例如上图中我将图片的名字命名为8hwa7_1573194299620671.png ,"_"前面的是验证码的内容,后面的是随机的字符串或数字;如果涉及其他图像识别人脸识别其图片标注就跟这个不一样,如下图所示:
    CNN(卷积神经网络)识别图形验证码(全网最通俗易懂,最全面的讲解)_第33张图片
    上图中使用专门的图片标注软件,在人脸上标注的年龄来达到通过人脸来识别年龄的目的。因为需要对大量的样本进行标注,而且大多都是人工标注,标注的是否准确直接想象生成模型的好坏,所以图片标注也是图像识别中最累最重要的一步,不光需要细心,还的有耐心。

  • 图像增强: 图像增强也就是通过相应的算法,去掉图像的干扰项,使图像尽量把所要识别的部分凸显出来;例如上述验证码的干扰项一个是背景颜色,一个是验证码的干扰线;由于干扰线太粗跟字母粘连在一起所以干扰线很难去掉,所以只将图片的背景去掉。在做图像处理的时候为了避免颜色的干扰,要对图像进行灰度处理或者二值化处理,我这里为了让字母更加清晰,先将图片进行灰度处理,然后再二值化并进行去噪,然后将二值化的图片进行裁剪,将多余的本分裁减掉,处理后的照片如下图所示:
    -在这里插入图片描述

1)图像灰度处理:

 img = cv.imread(image)
 gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

这里采用的是opencv图像处理库,image是图片路径,使用opencv中的 cvtColor(src, code, dst=None, dstCn=None) 将图像转为灰度图

2)图像二值化:

 ret, binary = cv.threshold(gray, 69.0, 255,cv.THRESH_BINARY) 

gray为灰度处理返回的数组,69.0为二值化法阈值,255表示高于(低于)阈值时赋予的新值,cv.THRESH_BINARY表示返会得到灰白二值图。
3) 图像降噪

def depoint(img):
   """传入二值化后的图片进行降噪"""
   pixdata = img.load()
   w, h = img.size
   for y in range(1, h - 1):
       for x in range(1, w - 1):
           count = 0
           if pixdata[x, y - 1] > 245:  # 上
               count = count + 1
           if pixdata[x, y + 1] > 245:  # 下
               count = count + 1
           if pixdata[x - 1, y] > 245:  # 左
               count = count + 1
           if pixdata[x + 1, y] > 245:  # 右
               count = count + 1
           if pixdata[x - 1, y - 1] > 245:  # 左上
               count = count + 1
           if pixdata[x - 1, y + 1] > 245:  # 左下
               count = count + 1
           if pixdata[x + 1, y - 1] > 245:  # 右上
               count = count + 1
           if pixdata[x + 1, y + 1] > 245:  # 右下
               count = count + 1
           if count > 4:
               pixdata[x, y] = 255
   return img

这里img是PIL库中Image.open(“图片路径”)方法返回的结果。

  • 图像分割: 通常图像分割是将图像中需要识别的个体分割开来,进行单独识别,但是对于本项目的验证码来说因为有的字母粘连在一起很进行分割,所以我这里只是将图片没有字母的那一部分进行了裁剪(所要训练的样本大小必须要一致),结果如下图所示:

裁剪后的图片

  • 图片裁剪
 img = Image.open(image_path)
 img = img.crop((0, 0, 200, 60))

将图片裁剪为200x60的大小

4.1.2 图像识别

图像识别是将处理后的图像进行特征提取和分类。识别方法中基本也是常用的方法有统计法(或决策理论法)、句法(或结构)方法、神经网络法模板匹配法几何变换法
在本项目中主要使用的是CNN卷积神经网络做为识别方法, 使用的CNN网络结构为:(卷积层 x 3)+(池化层 x 3)+ (全连接层 x 2)

  • 代码如下:
    def model(self):
    # self 为当前类对象
       x = tf.reshape(self.X, shape=[-1, self.image_height, self.image_width, 1])
       print(">>> input x: {}".format(x))

       # 卷积层1
       wc1 = tf.get_variable(name='wc1', shape=[3, 3, 1, 32], dtype=tf.float32,
                             initializer=tf.contrib.layers.xavier_initializer())
       bc1 = tf.Variable(self.b_alpha * tf.random_normal([32]))
       conv1 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(x, wc1, strides=[1, 1, 1, 1], padding='SAME'), bc1))
       conv1 = tf.nn.max_pool(conv1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
       conv1 = tf.nn.dropout(conv1, self.keep_prob)

       # # 卷积层2
       wc2 = tf.get_variable(name='wc2', shape=[3, 3, 32, 64], dtype=tf.float32,
                             initializer=tf.contrib.layers.xavier_initializer())
       bc2 = tf.Variable(self.b_alpha * tf.random_normal([64]))
       conv2 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(conv1, wc2, strides=[1, 1, 1, 1], padding='SAME'), bc2))
       conv2 = tf.nn.max_pool(conv2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
       conv2 = tf.nn.dropout(conv2, self.keep_prob)
       # 卷积层3
       wc3 = tf.get_variable(name='wc3', shape=[3, 3, 64, 128], dtype=tf.float32,
                             initializer=tf.contrib.layers.xavier_initializer())
       bc3 = tf.Variable(self.b_alpha * tf.random_normal([128]))
       conv3 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(conv2, wc3, strides=[1, 1, 1, 1], padding='SAME'), bc3))
       conv3 = tf.nn.max_pool(conv3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
       conv3 = tf.nn.dropout(conv3, self.keep_prob)
       print(">>> convolution 3: ", conv3.shape)
       next_shape = conv3.shape[1] * conv3.shape[2] * conv3.shape[3]

       # 全连接层1
       wd1 = tf.get_variable(name='wd1', shape=[next_shape, 1024], dtype=tf.float32,
                             initializer=tf.contrib.layers.xavier_initializer())
       bd1 = tf.Variable(self.b_alpha * tf.random_normal([1024]))
       dense = tf.reshape(conv3, [-1, wd1.get_shape().as_list()[0]])
       dense = tf.nn.relu(tf.add(tf.matmul(dense, wd1), bd1))
       dense = tf.nn.dropout(dense, self.keep_prob)

       # 全连接层2
       wout = tf.get_variable('name', shape=[1024, self.max_captcha * self.char_set_len], dtype=tf.float32,
                              initializer=tf.contrib.layers.xavier_initializer())
       bout = tf.Variable(self.b_alpha * tf.random_normal([self.max_captcha * self.char_set_len]))

       with tf.name_scope('y_prediction'):
           y_predict = tf.add(tf.matmul(dense, wout), bout)

       return y_predict

代码说明:

  • 1)tf.reshape(self.X, shape=[-1, self.image_height, self.image_width, 1])作用是将tensor变换为参数shape的形式。第一个参数表示值张量Tensor;第二这个参数也是一个张量Tensor,用于定义输出张量的形状类型必须是int32,int64;第三个参数表示操作名称(可选)
  • 2)tf.get_variable(name='wc1', shape=[3, 3, 1, 32], dtype=tf.float32, initializer=tf.contrib.layers.xavier_initializer()),创建名字为wc1,共享变量,shape为变量维度,dtype变量数据类型,initializer变量初始化方式tf.contrib.layers.xavier_initializer()是一种带权重的初始化方法,旨在使所有图层的渐变比例大致相同。
  • 3)tf.Variable(self.b_alpha * tf.random_normal([32])) 获取具有self.b_alpha * tf.random_normal([32])这些参数的新变量。
  • 4)tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(x, wc1, strides=[1, 1, 1, 1], padding='SAME'), bc1)) 激活函数,tf.nn.bias_add(tf.nn.conv2d(x, wc1, strides=[1, 1, 1, 1], padding='SAME')返回一个Tensor,作用是将偏差加到value(value:tf.nn.conv2d(x, wc1, strides=[1, 1, 1, 1], padding='SAME') 偏差:第三步返回的Tensorbc1)上;tf.nn.conv2d(x, wc1, strides=[1, 1, 1, 1], padding='SAME')将图像进行二维卷积,参数一:张量Tensor,参数二:卷积核参数,参数三:步长参数,参数四:卷积方式(可以取’VALID’ 或者’SAME’),返回一个Tensor。
  • 5)tf.nn.max_pool(conv1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') 池化操作,第一个参数:value(由第四步卷积后结果的代入),第二个参数:池化窗口大小,第三个参数:窗口每一个维度上滑动步长,低四个参数:池化方式(和卷及类似,可以取’VALID’ 或者’SAME’),结果返回一个Tensor。
  • 6)tf.nn.dropout(conv1, self.keep_prob)计算dropout,也可以通过修改dropout的方式类避免过拟合现象;第一个参数:将经过池化后的Tensor,第二个参数:dropout的概率。

4.1.3 图像训练结果

进过算法及不断增加样本数量会(最终样本数量达5w多)识别模型准确度为:

  • 训练集准确度:99%(每次训练会有浮动,但基本都在99%左右)
  • 验证集准确度:99%(训练的时候模型的准确度靠验证集的准确度来判定)
  • 测试集准确度:95%(每一次此时结果会略有浮动,但基本在保持在95%左右)

4.1.4 补充说明

上述文章中有一些概念上面没有解释,这里进行补充一下

  • 过拟合现象:因为模型过于复杂,或者训练数据不够,即训练数据无法对整个数据的分布进行估计的时候,或者在对模型进行过度训练时,很可能把一些训练样本自身的特性当成了所有潜在样本的共性了,这样一来模型的泛化性能就会下降,简而言之:训练集上表现很好,但是在测试集上表现很差,泛化性能差
    降低过拟合的方法:引入正则化、Dropout、提前终止训练、增加样本量
  • 训练集:用来拟合模型,通过设置分类器的参数,训练分类模型。后续结合验证集作用时,会选出同一参数的不同取值,拟合出多个分类器。
  • 验证集:当通过训练集训练出多个模型后,为了能找出效果最佳的模型,使用各个模型对验证集数据进行预测,并记录模型准确率。选出效果最佳的模型所对应的参数,即用来调整模型参数。如svm中的参数c和核函数等。
    -测试集:通过训练集和验证集得出最优模型后,使用测试集进行模型预测。用来衡量该最优模型的性能和分类能力。即可以把测试集当做从来不存在的数据集,当已经确定模型参数后,使用测试集进行模型性能评价。

你可能感兴趣的:(人工智能,tensorflow)