利用Tensorflow构建和训练自己的CNN来做简单的验证码识别方式
Tensorflow是目前最流行的深度学习框架,我们可以用它来搭建自己的卷积神经网络并训练自己的分类器,本文介绍怎样使用Tensorflow构建自己的CNN,怎样训练用于简单的验证码识别的分类器。本文假设你已经安装好了Tensorflow,了解过CNN的一些知识。
下面将分步介绍怎样获得训练数据,怎样使用tensorflow构建卷积神经网络,怎样训练,以及怎样测试训练出来的分类器
1.准备训练样本
使用Python的库captcha来生成我们需要的训练样本,代码如下:
importsys
importos
importshutil
importrandom
importtime
#captcha是用于生成验证码图片的库,可以pipinstallcaptcha来安装它
fromcaptcha.imageimportImageCaptcha
#用于生成验证码的字符集
CHAR_SET=['0','1','2','3','4','5','6','7','8','9']
#字符集的长度
CHAR_SET_LEN=10
#验证码的长度,每个验证码由4个数字组成
CAPTCHA_LEN=4
#验证码图片的存放路径
CAPTCHA_IMAGE_PATH='E:/Tensorflow/captcha/images/'
#用于模型测试的验证码图片的存放路径,它里面的验证码图片作为测试集
TEST_IMAGE_PATH='E:/Tensorflow/captcha/test/'
#用于模型测试的验证码图片的个数,从生成的验证码图片中取出来放入测试集中
TEST_IMAGE_NUMBER=50
#生成验证码图片,4位的十进制数字可以有10000种验证码
defgenerate_captcha_image(charSet=CHAR_SET,charSetLen=CHAR_SET_LEN,captchaImgPath=CAPTCHA_IMAGE_PATH):
k=0
total=1
foriinrange(CAPTCHA_LEN):
total*=charSetLen
foriinrange(charSetLen):
forjinrange(charSetLen):
forminrange(charSetLen):
forninrange(charSetLen):
captcha_text=charSet[i]+charSet[j]+charSet[m]+charSet[n]
image=ImageCaptcha()
image.write(captcha_text,captchaImgPath+captcha_text+'.jpg')
k+=1
sys.stdout.write("\rCreating%d/%d"%(k,total))
sys.stdout.flush()
#从验证码的图片集中取出一部分作为测试集,这些图片不参加训练,只用于模型的测试
defprepare_test_set():
fileNameList=[]
forfilePathinos.listdir(CAPTCHA_IMAGE_PATH):
captcha_name=filePath.split('/')[-1]
fileNameList.append(captcha_name)
random.seed(time.time())
random.shuffle(fileNameList)
foriinrange(TEST_IMAGE_NUMBER):
name=fileNameList[i]
shutil.move(CAPTCHA_IMAGE_PATH+name,TEST_IMAGE_PATH+name)
if__name__=='__main__':
generate_captcha_image(CHAR_SET,CHAR_SET_LEN,CAPTCHA_IMAGE_PATH)
prepare_test_set()
sys.stdout.write("\nFinished")
sys.stdout.flush()
运行上面的代码,可以生成验证码图片,
生成的验证码图片如下图所示:
2.构建CNN,训练分类器
代码如下:
importtensorflowastf
importnumpyasnp
fromPILimportImage
importos
importrandom
importtime
#验证码图片的存放路径
CAPTCHA_IMAGE_PATH='E:/Tensorflow/captcha/images/'
#验证码图片的宽度
CAPTCHA_IMAGE_WIDHT=160
#验证码图片的高度
CAPTCHA_IMAGE_HEIGHT=60
CHAR_SET_LEN=10
CAPTCHA_LEN=4
#60%的验证码图片放入训练集中
TRAIN_IMAGE_PERCENT=0.6
#训练集,用于训练的验证码图片的文件名
TRAINING_IMAGE_NAME=[]
#验证集,用于模型验证的验证码图片的文件名
VALIDATION_IMAGE_NAME=[]
#存放训练好的模型的路径
MODEL_SAVE_PATH='E:/Tensorflow/captcha/models/'
defget_image_file_name(imgPath=CAPTCHA_IMAGE_PATH):
fileName=[]
total=0
forfilePathinos.listdir(imgPath):
captcha_name=filePath.split('/')[-1]
fileName.append(captcha_name)
total+=1
returnfileName,total
#将验证码转换为训练时用的标签向量,维数是40
#例如,如果验证码是‘0296',则对应的标签是
#[1000000000
#0010000000
#0000000001
#0000001000]
defname2label(name):
label=np.zeros(CAPTCHA_LEN*CHAR_SET_LEN)
fori,cinenumerate(name):
idx=i*CHAR_SET_LEN+ord(c)-ord('0')
label[idx]=1
returnlabel
#取得验证码图片的数据以及它的标签
defget_data_and_label(fileName,filePath=CAPTCHA_IMAGE_PATH):
pathName=os.path.join(filePath,fileName)
img=Image.open(pathName)
#转为灰度图
img=img.convert("L")
image_array=np.array(img)
image_data=image_array.flatten()/255
image_label=name2label(fileName[0:CAPTCHA_LEN])
returnimage_data,image_label
#生成一个训练batch
defget_next_batch(batchSize=32,trainOrTest='train',step=0):
batch_data=np.zeros([batchSize,CAPTCHA_IMAGE_WIDHT*CAPTCHA_IMAGE_HEIGHT])
batch_label=np.zeros([batchSize,CAPTCHA_LEN*CHAR_SET_LEN])
fileNameList=TRAINING_IMAGE_NAME
iftrainOrTest=='validate':
fileNameList=VALIDATION_IMAGE_NAME
totalNumber=len(fileNameList)
indexStart=step*batchSize
foriinrange(batchSize):
index=(i+indexStart)%totalNumber
name=fileNameList[index]
img_data,img_label=get_data_and_label(name)
batch_data[i,:]=img_data
batch_label[i,:]=img_label
returnbatch_data,batch_label
#构建卷积神经网络并训练
deftrain_data_with_CNN():
#初始化权值
defweight_variable(shape,name='weight'):
init=tf.truncated_normal(shape,stddev=0.1)
var=tf.Variable(initial_value=init,name=name)
returnvar
#初始化偏置
defbias_variable(shape,name='bias'):
init=tf.constant(0.1,shape=shape)
var=tf.Variable(init,name=name)
returnvar
#卷积
defconv2d(x,W,name='conv2d'):
returntf.nn.conv2d(x,W,strides=[1,1,1,1],padding='SAME',name=name)
#池化
defmax_pool_2X2(x,name='maxpool'):
returntf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME',name=name)
#输入层
#请注意X的name,在测试model时会用到它
X=tf.placeholder(tf.float32,[None,CAPTCHA_IMAGE_WIDHT*CAPTCHA_IMAGE_HEIGHT],name='data-input')
Y=tf.placeholder(tf.float32,[None,CAPTCHA_LEN*CHAR_SET_LEN],name='label-input')
x_input=tf.reshape(X,[-1,CAPTCHA_IMAGE_HEIGHT,CAPTCHA_IMAGE_WIDHT,1],name='x-input')
#dropout,防止过拟合
#请注意keep_prob的name,在测试model时会用到它
keep_prob=tf.placeholder(tf.float32,name='keep-prob')
#第一层卷积
W_conv1=weight_variable([5,5,1,32],'W_conv1')
B_conv1=bias_variable([32],'B_conv1')
conv1=tf.nn.relu(conv2d(x_input,W_conv1,'conv1')+B_conv1)
conv1=max_pool_2X2(conv1,'conv1-pool')
conv1=tf.nn.dropout(conv1,keep_prob)
#第二层卷积
W_conv2=weight_variable([5,5,32,64],'W_conv2')
B_conv2=bias_variable([64],'B_conv2')
conv2=tf.nn.relu(conv2d(conv1,W_conv2,'conv2')+B_conv2)
conv2=max_pool_2X2(conv2,'conv2-pool')
conv2=tf.nn.dropout(conv2,keep_prob)
#第三层卷积
W_conv3=weight_variable([5,5,64,64],'W_conv3')
B_conv3=bias_variable([64],'B_conv3')
conv3=tf.nn.relu(conv2d(conv2,W_conv3,'conv3')+B_conv3)
conv3=max_pool_2X2(conv3,'conv3-pool')
conv3=tf.nn.dropout(conv3,keep_prob)
#全链接层
#每次池化后,图片的宽度和高度均缩小为原来的一半,进过上面的三次池化,宽度和高度均缩小8倍
W_fc1=weight_variable([20*8*64,1024],'W_fc1')
B_fc1=bias_variable([1024],'B_fc1')
fc1=tf.reshape(conv3,[-1,20*8*64])
fc1=tf.nn.relu(tf.add(tf.matmul(fc1,W_fc1),B_fc1))
fc1=tf.nn.dropout(fc1,keep_prob)
#输出层
W_fc2=weight_variable([1024,CAPTCHA_LEN*CHAR_SET_LEN],'W_fc2')
B_fc2=bias_variable([CAPTCHA_LEN*CHAR_SET_LEN],'B_fc2')
output=tf.add(tf.matmul(fc1,W_fc2),B_fc2,'output')
loss=tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(labels=Y,logits=output))
optimizer=tf.train.AdamOptimizer(0.001).minimize(loss)
predict=tf.reshape(output,[-1,CAPTCHA_LEN,CHAR_SET_LEN],name='predict')
labels=tf.reshape(Y,[-1,CAPTCHA_LEN,CHAR_SET_LEN],name='labels')
#预测结果
#请注意predict_max_idx的name,在测试model时会用到它
predict_max_idx=tf.argmax(predict,axis=2,name='predict_max_idx')
labels_max_idx=tf.argmax(labels,axis=2,name='labels_max_idx')
predict_correct_vec=tf.equal(predict_max_idx,labels_max_idx)
accuracy=tf.reduce_mean(tf.cast(predict_correct_vec,tf.float32))
saver=tf.train.Saver()
withtf.Session()assess:
sess.run(tf.global_variables_initializer())
steps=0
forepochinrange(6000):
train_data,train_label=get_next_batch(64,'train',steps)
sess.run(optimizer,feed_dict={X:train_data,Y:train_label,keep_prob:0.75})
ifsteps%100==0:
test_data,test_label=get_next_batch(100,'validate',steps)
acc=sess.run(accuracy,feed_dict={X:test_data,Y:test_label,keep_prob:1.0})
print("steps=%d,accuracy=%f"%(steps,acc))
ifacc>0.99:
saver.save(sess,MODEL_SAVE_PATH+"crack_captcha.model",global_step=steps)
break
steps+=1
if__name__=='__main__':
image_filename_list,total=get_image_file_name(CAPTCHA_IMAGE_PATH)
random.seed(time.time())
#打乱顺序
random.shuffle(image_filename_list)
trainImageNumber=int(total*TRAIN_IMAGE_PERCENT)
#分成测试集
TRAINING_IMAGE_NAME=image_filename_list[:trainImageNumber]
#和验证集
VALIDATION_IMAGE_NAME=image_filename_list[trainImageNumber:]
train_data_with_CNN()
print('Trainingfinished')
运行上面的代码,开始训练,训练要花些时间,如果没有GPU的话,会慢些,
训练完后,输出如下结果,经过4100次的迭代,训练出来的分类器模型在验证集上识别的准确率为99.5%
生成的模型文件如下,在模型测试时将用到这些文件
3.测试模型
编写代码,对训练出来的模型进行测试
importtensorflowastf
importnumpyasnp
fromPILimportImage
importos
importmatplotlib.pyplotasplt
CAPTCHA_LEN=4
MODEL_SAVE_PATH='E:/Tensorflow/captcha/models/'
TEST_IMAGE_PATH='E:/Tensorflow/captcha/test/'
defget_image_data_and_name(fileName,filePath=TEST_IMAGE_PATH):
pathName=os.path.join(filePath,fileName)
img=Image.open(pathName)
#转为灰度图
img=img.convert("L")
image_array=np.array(img)
image_data=image_array.flatten()/255
image_name=fileName[0:CAPTCHA_LEN]
returnimage_data,image_name
defdigitalStr2Array(digitalStr):
digitalList=[]
forcindigitalStr:
digitalList.append(ord(c)-ord('0'))
returnnp.array(digitalList)
defmodel_test():
nameList=[]
forpathNameinos.listdir(TEST_IMAGE_PATH):
nameList.append(pathName.split('/')[-1])
totalNumber=len(nameList)
#加载graph
saver=tf.train.import_meta_graph(MODEL_SAVE_PATH+"crack_captcha.model-4100.meta")
graph=tf.get_default_graph()
#从graph取得tensor,他们的name是在构建graph时定义的(查看上面第2步里的代码)
input_holder=graph.get_tensor_by_name("data-input:0")
keep_prob_holder=graph.get_tensor_by_name("keep-prob:0")
predict_max_idx=graph.get_tensor_by_name("predict_max_idx:0")
withtf.Session()assess:
saver.restore(sess,tf.train.latest_checkpoint(MODEL_SAVE_PATH))
count=0
forfileNameinnameList:
img_data,img_name=get_image_data_and_name(fileName,TEST_IMAGE_PATH)
predict=sess.run(predict_max_idx,feed_dict={input_holder:[img_data],keep_prob_holder:1.0})
filePathName=TEST_IMAGE_PATH+fileName
print(filePathName)
img=Image.open(filePathName)
plt.imshow(img)
plt.axis('off')
plt.show()
predictValue=np.squeeze(predict)
rightValue=digitalStr2Array(img_name)
ifnp.array_equal(predictValue,rightValue):
result='正确'
count+=1
else:
result='错误'
print('实际值:{},预测值:{},测试结果:{}'.format(rightValue,predictValue,result))
print('\n')
print('正确率:%.2f%%(%d/%d)'%(count*100/totalNumber,count,totalNumber))
if__name__=='__main__':
model_test()
对模型的测试结果如下,在测试集上识别的准确率为94%
下面是两个识别错误的验证码
以上这篇利用Tensorflow构建和训练自己的CNN来做简单的验证码识别方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。