CNN卷积神经网络  与验证码之间的联系

        本文主要介绍CNN卷积神经网络  与验证码之间的联系  我们可以应用CNN自动提取验证码之间的内容  下面我来主要介绍:

数据集样式 前面为标签 后面为.jpg  .

此代码应用到的数据集地址:https://download.csdn.net/download/duyibo123/12755468,有兴趣的可以自行下载。

先倒入的相关的包 以及简单的设置了几个参数

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2020/8/25 15:01
# @Author : DYB
# @Site : 
# @File : 11-1-vcode练习.py
# @Software: PyCharm

import tensorflow as tf
import random
import os
import numpy as np
from PIL import Image

tf.set_random_seed(777)#设置随机种子
#获取数据集
train_num=1000
test_num=100

#设置压缩之后的图片的高和宽
IMG_HEIGHT=60# 高
IMG_WIDTH=160#宽
char_num=4 #四个验证码
characters=range(10)    #十个
labellen=char_num*len(characters)#40

此函数为返回验证码的数字

拿 1327作为例子 进行了循环  运用枚举的方法 第一次 i=0 num=1 责idx=1所以第一个位置为1 所以为1 第二次 i=1,num=3那么循环里面为13 则 idx=13 即第十三个位置为1 十个一循环所以为3 依次类推即可以推算出 1327 即所有的数字都可以这样推算出来。

def label2vec(label):
    '''
    将验证码的标签转为40维的向量
    param label: 1327
                  0123
        [0,1,0,0,0,0,0,0,0,0,
        0,0,0,1,0,0,0,0,0,0,
        0,0,1,0,0,0,0,0,0,0,
        0,0,0,0,0,0,0,1,0,0]
    '''
    label_vec=np.zeros(char_num*len(characters))#生成一个一维的一行40列的矩阵
    for i,num in enumerate(label):#通过循环枚举的方式  把验证码循环导出 1: i为0 num为 1  2: i为1 num为3
        idx= i *len(characters)+int(num)
        label_vec[idx]=1
    return label_vec

进行图片恢复处理

此函数为图片的灰度处理,可以不尽兴处理但是运行起来彩色图片相对慢一些 所以建议转换为灰色图片

如果通道数大于2 则需要转换 0,1,2分别为第一层,第二层,第三层 因为彩色图片为三通道。然后把数据传入r,g,b.

三个小数自己设定就好,加起来小于等于1即可

def concert2gray(img):
    if len(img.shape)>2:
        r,g,b= img[:,:,0],img[:,:,1],img[:,:,2]#3通到  层数
        gray=0.2989*r +0.5870*g+0.1140*b
        return gray
    else:
        return img

 此函数为获取图片的路径,返回的为样本的特征和标签

先创建了两个存放的列表 然后进行循环 此循环用os定位图片地址 用Image库打开 再进行了逐一灰度处理,进行归一化 方便数据计算

然后把图片的分辨率转化为统一格式 此数据因为图片分辨率统一,所以可有可无.再然后定位图片,再进行切割把前面的特征切割出来。

最后把特征数值逐一取出添加到列表中   最后返回一个二维数组

def get_all_files(file_path,num):#获取图片路径及其标签
    image_list=[]
    label_list=[]
    i=0
    for item in os.listdir(file_path):
        item_path=file_path+'\\'+item  #获取图片的路径
        image=Image.open(item_path) #打开图片的路径 得到每一张图片
        image=concert2gray(np.array(image))#  进行灰度处理
        image_array=np.array(image)/255#归一化
        image_list.append(image_array.reshape(IMG_HEIGHT,IMG_WIDTH,1))#把图片的分辨率改变 然后加入到image_list 列表中
        label=os.path.splitext(item)[0] #标签  寻找路径然后 切割 前面为标签
        label_list.append(label2vec(label))  #把标签上的特征数值传入到列表中
        i+=1
        if i>=num:# 如果 超过数值 退出循环
            break
    return  np.array(image_list),np.array(label_list)# 返回图片 标签

通过之前的函数把训练集,测试集的特征,标签 运行出来 

#数据集地址
img_dir = r'E:\第十一个月 深度一\第十一个月 深度一\Protect\8 25\train'
test_dir=r'E:\第十一个月 深度一\第十一个月 深度一\Protect\8 25\test'
#返回训练集 测试集的标签特征
imgArr,Y_one_hot,=get_all_files(img_dir,train_num)
imgArrtest,Y_test=get_all_files(test_dir,test_num)
print(imgArr.shape,len(Y_one_hot))

next_batch函数 每次返回一批数据的X,Y

定义全局变量g_b ,然后每次都加长度为size 

g_b=0
#每次返回一批数据的 x y
def next_batch(size):
    global g_b
    xb=imgArr[g_b:g_b+size]
    yb=Y_one_hot[g_b:g_b+size]
    g_b=g_b+size
    return xb,yb

后续需要的参数值 

learning_rate=0.001
training_epochs=100
batch_size=100

 卷积操作的基本流程

定义占位符->两层卷积->维度转换 转换成一维->全联接层->softmax层

#定义占位符
X=tf.placeholder('float',shape=[None,IMG_HEIGHT,IMG_WIDTH,1])
Y=tf.placeholder('float',shape=[None,labellen])

#第一层卷积
W1=tf.Variable(tf.random_normal([3,3,1,32]))
L1=tf.nn.conv2d(X,W1,strides=[1,1,1,1],padding='SAME')
L1=tf.nn.relu(L1)#激活函数
L1=tf.nn.max_pool(L1,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')#最大池化

#第二层卷积
W2=tf.Variable(tf.random_normal([3,3,32,64]))
L2=tf.nn.conv2d(L1,W2,strides=[1,1,1,1],padding='SAME')
L2=tf.nn.relu(L2)
L2=tf.nn.max_pool(L2,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')

#转换为一维数组
dim=L2.get_shape()[1].value * L2.get_shape()[2].value *L2.get_shape()[3].value
L2_flg=tf.reshape(L2,[-1,dim])
print( L2.get_shape())

#全联接层
W3=tf.get_variable(name='w3',shape=[dim,1024],dtype=tf.float32, initializer=tf.contrib.layers.xavier_initializer())
b3=tf.Variable(tf.random_normal([1024]))
L3=tf.nn.relu(tf.matmul(L2_flg,W3)+b3)

#softmax层
W4=tf.get_variable('w4',shape=[1024,labellen],dtype=tf.float32,initializer=tf.contrib.layers.xavier_initializer())
b4=tf.Variable(tf.random_normal([labellen]))
logtis=tf.matmul(L3,W4)+b4

代价函数和优化器

为什么这里不用softmax_cros:

sigmod_cross适用于每个类别相互独立但不互斥,如图中可以有字母和数字
       softmax_cross适用于每个类别独立且排斥的情况,如数字和字母不可以同时出现

cost=tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=logtis,labels=Y))
optimzer=tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)

 准确率计算

首先把预测模型的维度转换成 4*10的矩阵  方便进行一一比较

预测值的最大值下标  这里好多人问为什么是2 因为括号里是对predict 进行操作 2代表的是10的位置 即是列的意思 按照列逐一进行比较 必须满足四个数字每个数字的位置都相同 才能算对, 如果仅仅是四个数字一样但是位置不同,也是不对的。所以这里是对列进行操作比较。

再就是进行预测值跟真实值比较 

最后计算准确率  求平均转换为float类型

predict=tf.reshape(logtis,[-1,4,10])# 预测数据转换维度  四行十列
max_idx_p = tf.argmax(predict,2)  #
max_idx_y = tf.argmax(tf.reshape(Y,[-1,4,10]),2)

correct_pred = tf.equal(max_idx_p,max_idx_y)
accuracy= tf.reduce_mean(tf.cast(correct_pred,tf.float32))

  创建会话,进行数据传递操作

 双层循环: 外部循环为循环周期 意思就是 整体数据循环的次数 咱们定义的周期数为100次,然后定义平均代价avg_cost,循环批次total_batch,全局变量g_b,特别注意:这里的g_b一定要进行初始化为0,因为内部循环循环完一次 再进行外部循环,整体的数据要初始化。否则运行结果会错误。

                 内部循环:用next_batch函数把数据倒入 ,进行数据传入 得出数据计算每个周期的平均代价 

每十个周期循环一次  输出代价跟准确率

#创建会话
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print('开始学习')
    for epoch in range(training_epochs):#循环周期
        avg_cost=0
        g_b=0
        total_batch=int(train_num/batch_size)#批次
        for i in range(total_batch):#循环多少次
            batch_x,batch_y=next_batch(batch_size)
            c_,_=sess.run([cost,optimzer],feed_dict={X:batch_x,Y:batch_y})
            avg_cost+=c_/total_batch
        if epoch %10 ==0:#十次输出一次
            print('Epoch:',(epoch+1),'cost=',avg_cost,'acc',sess.run(accuracy,feed_dict={X:imgArrtest,Y:Y_test}))
    print('学习完成')

测试模型的准确率

传入测试集的数据

 #测试模型检查准确率
    print('正确率',sess.run(accuracy,feed_dict={X:imgArrtest,Y:Y_test}))

 在测试集中随机抽取一个样本进行测试

首先规定r的取值范围,再用真实测试集的Y值取到r 然后维度转换成4*10的数据 进行最大下标输出 最后用预测模型来查看的预测数据,把测试集的X传入。最后 结束。

    #在测试集中随机抽一个样本进行测试
    r=int(random.randint(0,test_num-1))
    print('标签:',sess.run(tf.argmax(Y_test[r:r+1].reshape(4,10),1)))
    per=sess.run([tf.argmax(tf.reshape(logtis,[4,10]),1)],feed_dict={X:imgArrtest[r:r+1]})
    print('预测',per)

 最后运行结果

建议大家运行用GPU,因为cpu运行一次需要时间太长,效率太低。

正确率有点低 大家可以尝试更换优化器 或者激活函数进行改进。

再简单的介绍一下整体的流程以及代码:整体思路其实就是三步走:第一步就是数据的处理 。第二步就是卷积操作。第三步就是创建会话完成会话的各项内容。整体内部流程思路大概就是这样,其中有好多的小细节需要大家注意。不然出一点错都不好找。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

忘川之水&

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

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

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

打赏作者

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

抵扣说明:

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

余额充值