tensorflow之验证码生成与训练

思路

1.数据
2.模型
3.数据训练模型
4.验证模型

1。数据

验证码数据需要生成验证码,而python中有相关的模块生成验证码图片

  • captcha包用于验证码图生成
  • PIL包用于图像处理和展现

来个例子:

from captcha.image import ImageCaptcha
ic=ImageCaptcha()
d=ic.generate('G8iY')
from PIL import  Image
Image.open(d).show()

效果如下:
在这里插入图片描述
确定验证码范围

import string
char_set=list(string.ascii_letters+string.digits) #英文大小写+数字
char_num=4 #一个验证码图片有多少字符,这里4个

生成验证码

import numpy as np
from captcha.image import ImageCaptcha
from PIL import Image
char2index=dict(zip(char_set,range(len(char_set)))) #字符和顺序号的键值对
def generate_captcha():
    single_captcha=np.random.choice(char_set,size=char_num)
    single_text=''.join(single_captcha) #连接成char_num个字母为要生成图片的字符串
    ic=ImageCaptcha()
    captcha=ic.generate(single_text) #已经生成了验证码
    a=Image.open(captcha) #把图片转换为数组
    s=np.array(a.convert('L')).flatten()/255 #彩色图片转换为灰色,并且归一化数组中的数字,这已经获得了图片数据
    #将验证码字符转换向量的形式,向量数字0和1代表有无,char_num个字符的向量拼接成一个长向量,就是一个验证码的向量数据y
    u=np.zeros(len(char_set)*char_num)
    k=0
    for i in single_captcha:
        u[char2index[i]+k*len(char_set)]=1
        k+=1
    return s,u  #s是图片数据,u是图片标签

批量生成验证码

def batch_data_gen(batch_size=128): #将batch_size个图片和标签存分别存放在在列表中
    batch_x=[]
    batch_y=[]
    for i in range(batch_size):
        ran=generate_captcha()
        batch_x.append(ran[0])
        batch_y.append(ran[1])
    return np.array(batch_x),np.array(batch_y) #数组形式,每个样本是一个行向量
2。定义模型

网络结构:
conv -> relu6 -> max_pool -> conv -> relu6 -> max_pool -> dropout -> conv -> relu6 -> max_pool -> full connection -> full connection

import tensorflow as tf
def cnn_(x,height=60,width=160):
    x=tf.reshape(x,shape=[-1,height,width,1]) #将每行行数据转换为图片尺寸的数据,方便做2维窗口卷积,1表示通道数,黑白图片就1个通道
    #第一层定义随机参数,然后卷积
    w_c1=tf.Variable(tf.random_normal([3,3,1,32],dtype="float64"))
    b_c1=tf.Variable(tf.random_normal([32],dtype="float64"))
    cv=tf.nn.conv2d(x,w_c1,strides=[1,1,1,1],padding='SAME')
    #线性变换加偏执项,得到输出卷积过程的输出
    outcv=tf.nn.bias_add(cv,b_c1)
    #激活
    conv1=tf.nn.relu6(outcv)
    #最大池化层
    conv1=tf.nn.max_pool(conv1,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
    #第二层定义卷积层参数然后卷积
    w_c2=tf.Variable(tf.random_normal([3,3,32,64],dtype="float64"))
    b_c2=tf.Variable(tf.random_normal([64],dtype="float64"))
    cv2=tf.nn.conv2d(conv1,w_c2,strides=[1,1,1,1],padding='SAME')
    #偏执项
    outcv2=tf.nn.bias_add(cv2,b_c2)
    #激活
    conv2=tf.nn.relu6(outcv2)
    #最大池化
    conv2=tf.nn.max_pool(conv2,[1,2,2,1],strides=[1,2,2,1],padding='SAME')
    #dropout
    conv2=tf.nn.dropout(conv2,keep_prob=0.5)
    #第三层卷积
    w_c3=tf.Variable(tf.random_normal([3,3,64,64],dtype="float64"))
    b_c3=tf.Variable(tf.random_normal([64],dtype="float64"))
    cv3=tf.nn.conv2d(conv2,w_c3,strides=[1,1,1,1],padding='SAME')
    #激活
    conv3=tf.nn.relu6(tf.nn.bias_add(cv3,b_c3))
    #最大池化
    conv3=tf.nn.max_pool(conv3,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
    #全连接
    w_f1=tf.Variable(tf.random_normal([8*20*64,512],dtype="float64"))
    b_f1=tf.Variable(tf.random_normal([512],dtype="float64"))
    #注意这里,每个点是一个神经元,2维拉成1维
    dense= tf.reshape(conv3, [-1, 8*20*64])
    #全连接的参数,设mxn个,m是前面一层的神经元,n是后面一层的神经元,理解成w_f1每列是神经元连接前面一层的神经元参数,
    es=tf.add(tf.matmul(dense,w_f1),b_f1)
    es=tf.nn.sigmoid(es)
    #第二层全连接
    w_f2=tf.Variable(tf.random_normal([512,248],dtype="float64"))
    b_f2=tf.Variable(tf.random_normal([248],dtype="float64"))
    out=tf.add(tf.matmul(es,w_f2),b_f2)
    return out

3。数据训练模型流程
def target(x,y):
    #引用模型
    output=cnn_(x)
    #定义损失
    loss=tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=output,labels=y))
    #定义优化损失的方法
    optimizer=tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)
    #模型评价指标先对输出做处理,使其格式和标签shape一致,方便对比
    predict=tf.reshape(output,[-1,4,62])
    idx_p=tf.argmax(predict,2)#取行中值最大的一个将与标签对比
    idx_l=tf.argmax(tf.reshape(y,[-1,4,62]),2)#将y变量重置回一个字符一个向量的格式
    accu=tf.reduce_mean(tf.cast(tf.equal(idx_l,idx_p),tf.float32)) #tf.equal是True/False,转换为数字0/1,匹配上的概率
    saver=tf.train.Saver()
    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        for i in range(500000):
            bax, bay = batch_data_gen()
            _, los, acc = sess.run([optimizer, loss, accu], feed_dict={x: bax, y: bay})
            print('第',i,'次',f'loss:{los},acc:{acc}')
            if acc > 0.2:
                # 持久化
                saver.save(sess, "./model.model")
                break
        saver.save(sess, './model.ckpt')
4。使用模型

需要训练几十万次才能得到高精度的模型,设备不够不提供模型

saver = tf.train.Saver()
saver.restore(sess, './model.ckpt')
sess.run(predict) #还不能理解,后期解释

完整代码

#-*-coding:utf-8-*-
import string
'''
确定验证码范围
'''
char_set=list(string.ascii_letters+string.digits) #英文大小写+数字
char_num=4 #一个验证码图片有多少字符,这里4个
'''
生成验证码
'''
import numpy as np
from captcha.image import ImageCaptcha
from PIL import Image
char2index=dict(zip(char_set,range(len(char_set)))) #字符和顺序号的键值对
def generate_captcha():
    single_captcha=np.random.choice(char_set,size=char_num)
    single_text=''.join(single_captcha) #连接成char_num个字母为要生成图片的字符串
    ic=ImageCaptcha()
    captcha=ic.generate(single_text) #已经生成了验证码
    a=Image.open(captcha) #把图片转换为数组
    s=np.array(a.convert('L')).flatten()/255 #彩色图片转换为灰色,并且归一化数组中的数字,这已经获得了图片数据
    #将验证码字符转换向量的形式,向量数字0和1代表有无,char_num个字符的向量拼接成一个长向量,就是一个验证码的向量数据y
    u=np.zeros(len(char_set)*char_num)
    k=0
    for i in single_captcha:
        u[char2index[i]+k*len(char_set)]=1
        k+=1
    return s,u  #s是图片数据,u是图片标签
'''
批量生成验证码
'''
def batch_data_gen(batch_size=128): #将batch_size个图片和标签存分别存放在在列表中
    batch_x=[]
    batch_y=[]
    for i in range(batch_size):
        ran=generate_captcha()
        batch_x.append(ran[0])
        batch_y.append(ran[1])
    return np.array(batch_x),np.array(batch_y) #数组形式,每个样本是一个行向量
'''
定义模型
网络结构:
 conv -> relu6 -> max_pool -> conv -> relu6 -> max_pool -> dropout -> conv -> relu6 -> max_pool -> full connection -> full connection
'''
import tensorflow as tf
def cnn_(x,height=60,width=160):
    x=tf.reshape(x,shape=[-1,height,width,1]) #将每行行数据转换为图片尺寸的数据,方便做2维窗口卷积,1表示通道数,黑白图片就1个通道
    #第一层定义随机参数,然后卷积
    w_c1=tf.Variable(tf.random_normal([3,3,1,32],dtype="float64"))
    b_c1=tf.Variable(tf.random_normal([32],dtype="float64"))
    cv=tf.nn.conv2d(x,w_c1,strides=[1,1,1,1],padding='SAME')
    #线性变换加偏执项,得到输出卷积过程的输出
    outcv=tf.nn.bias_add(cv,b_c1)
    #激活
    conv1=tf.nn.relu6(outcv)
    #最大池化层
    conv1=tf.nn.max_pool(conv1,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
    #第二层定义卷积层参数然后卷积
    w_c2=tf.Variable(tf.random_normal([3,3,32,64],dtype="float64"))
    b_c2=tf.Variable(tf.random_normal([64],dtype="float64"))
    cv2=tf.nn.conv2d(conv1,w_c2,strides=[1,1,1,1],padding='SAME')
    #偏执项
    outcv2=tf.nn.bias_add(cv2,b_c2)
    #激活
    conv2=tf.nn.relu6(outcv2)
    #最大池化
    conv2=tf.nn.max_pool(conv2,[1,2,2,1],strides=[1,2,2,1],padding='SAME')
    #dropout
    conv2=tf.nn.dropout(conv2,keep_prob=0.5)
    #第三层卷积
    w_c3=tf.Variable(tf.random_normal([3,3,64,64],dtype="float64"))
    b_c3=tf.Variable(tf.random_normal([64],dtype="float64"))
    cv3=tf.nn.conv2d(conv2,w_c3,strides=[1,1,1,1],padding='SAME')
    #激活
    conv3=tf.nn.relu6(tf.nn.bias_add(cv3,b_c3))
    #最大池化
    conv3=tf.nn.max_pool(conv3,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
    #全连接
    w_f1=tf.Variable(tf.random_normal([8*20*64,512],dtype="float64"))
    b_f1=tf.Variable(tf.random_normal([512],dtype="float64"))
    #注意这里,每个点是一个神经元,2维拉成1维
    dense= tf.reshape(conv3, [-1, 8*20*64])
    #全连接的参数,设mxn个,m是前面一层的神经元,n是后面一层的神经元,理解成w_f1每列是神经元连接前面一层的神经元参数,
    es=tf.add(tf.matmul(dense,w_f1),b_f1)
    es=tf.nn.sigmoid(es)
    #第二层全连接
    w_f2=tf.Variable(tf.random_normal([512,248],dtype="float64"))
    b_f2=tf.Variable(tf.random_normal([248],dtype="float64"))
    out=tf.add(tf.matmul(es,w_f2),b_f2)
    return out

'''
数据训练模型流程
'''
def target(x,y):
    #引用模型
    output=cnn_(x)
    #定义损失
    loss=tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=output,labels=y))
    #定义优化损失的方法
    optimizer=tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)
    #模型评价指标先对输出做处理,使其格式和标签shape一致,方便对比
    predict=tf.reshape(output,[-1,4,62])
    idx_p=tf.argmax(predict,2)#取行中值最大的一个将与标签对比
    idx_l=tf.argmax(tf.reshape(y,[-1,4,62]),2)#将y变量重置回一个字符一个向量的格式
    accu=tf.reduce_mean(tf.cast(tf.equal(idx_l,idx_p),tf.float32)) #tf.equal是True/False,转换为数字0/1,匹配上的概率
    saver=tf.train.Saver()
    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        for i in range(500000):
            bax, bay = batch_data_gen()
            _, los, acc = sess.run([optimizer, loss, accu], feed_dict={x: bax, y: bay})
            print('第',i,'次',f'loss:{los},acc:{acc}')
            if acc > 0.8:
                # 持久化
                saver.save(sess, "./model.ckpt")
                break
        saver.save(sess, './model.ckpt')


if __name__ == '__main__':
    x=tf.placeholder(dtype=tf.float64,shape=[None,60*160])
    y=tf.placeholder(dtype=tf.float64,shape=[None,62*4])
    target(x,y)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值