溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何使用Tensorflow構(gòu)建和訓(xùn)練自己的CNN來(lái)做驗(yàn)證碼識(shí)別方式

發(fā)布時(shí)間:2021-07-01 11:17:25 來(lái)源:億速云 閱讀:122 作者:小新 欄目:開發(fā)技術(shù)

這篇文章主要介紹如何使用Tensorflow構(gòu)建和訓(xùn)練自己的CNN來(lái)做驗(yàn)證碼識(shí)別方式,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

1. 準(zhǔn)備訓(xùn)練樣本

使用Python的庫(kù)captcha來(lái)生成我們需要的訓(xùn)練樣本,代碼如下:

import sys 

import os 
import shutil 
import random 
import time 
#captcha是用于生成驗(yàn)證碼圖片的庫(kù),可以 pip install captcha 來(lái)安裝它 
from captcha.image import ImageCaptcha 
 
#用于生成驗(yàn)證碼的字符集 
CHAR_SET = ['0','1','2','3','4','5','6','7','8','9'] 
#字符集的長(zhǎng)度 
CHAR_SET_LEN = 10 
#驗(yàn)證碼的長(zhǎng)度,每個(gè)驗(yàn)證碼由4個(gè)數(shù)字組成 
CAPTCHA_LEN = 4 
 
#驗(yàn)證碼圖片的存放路徑 
CAPTCHA_IMAGE_PATH = 'E:/Tensorflow/captcha/images/' 
#用于模型測(cè)試的驗(yàn)證碼圖片的存放路徑,它里面的驗(yàn)證碼圖片作為測(cè)試集 
TEST_IMAGE_PATH = 'E:/Tensorflow/captcha/test/' 
#用于模型測(cè)試的驗(yàn)證碼圖片的個(gè)數(shù),從生成的驗(yàn)證碼圖片中取出來(lái)放入測(cè)試集中 
TEST_IMAGE_NUMBER = 50 
 
#生成驗(yàn)證碼圖片,4位的十進(jìn)制數(shù)字可以有10000種驗(yàn)證碼 
def generate_captcha_image(charSet = CHAR_SET, charSetLen=CHAR_SET_LEN, captchaImgPath=CAPTCHA_IMAGE_PATH):   
  k = 0 
  total = 1 
  for i in range(CAPTCHA_LEN): 
    total *= charSetLen 
     
  for i in range(charSetLen): 
    for j in range(charSetLen): 
      for m in range(charSetLen): 
        for n in range(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() 
           
#從驗(yàn)證碼的圖片集中取出一部分作為測(cè)試集,這些圖片不參加訓(xùn)練,只用于模型的測(cè)試           
def prepare_test_set(): 
  fileNameList = []   
  for filePath in os.listdir(CAPTCHA_IMAGE_PATH): 
    captcha_name = filePath.split('/')[-1] 
    fileNameList.append(captcha_name) 
  random.seed(time.time()) 
  random.shuffle(fileNameList)  
  for i in range(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()

運(yùn)行上面的代碼,可以生成驗(yàn)證碼圖片,

生成的驗(yàn)證碼圖片如下圖所示:

如何使用Tensorflow構(gòu)建和訓(xùn)練自己的CNN來(lái)做驗(yàn)證碼識(shí)別方式

如何使用Tensorflow構(gòu)建和訓(xùn)練自己的CNN來(lái)做驗(yàn)證碼識(shí)別方式

2. 構(gòu)建CNN,訓(xùn)練分類器

代碼如下:

import tensorflow as tf 
import numpy as np 
from PIL import Image 
import os 
import random 
import time 
 
#驗(yàn)證碼圖片的存放路徑 
CAPTCHA_IMAGE_PATH = 'E:/Tensorflow/captcha/images/' 
#驗(yàn)證碼圖片的寬度 
CAPTCHA_IMAGE_WIDHT = 160 
#驗(yàn)證碼圖片的高度 
CAPTCHA_IMAGE_HEIGHT = 60 
 
CHAR_SET_LEN = 10 
CAPTCHA_LEN = 4 
 
#60%的驗(yàn)證碼圖片放入訓(xùn)練集中 
TRAIN_IMAGE_PERCENT = 0.6 
#訓(xùn)練集,用于訓(xùn)練的驗(yàn)證碼圖片的文件名 
TRAINING_IMAGE_NAME = [] 
#驗(yàn)證集,用于模型驗(yàn)證的驗(yàn)證碼圖片的文件名 

VALIDATION_IMAGE_NAME = [] 

#存放訓(xùn)練好的模型的路徑 
MODEL_SAVE_PATH = 'E:/Tensorflow/captcha/models/' 
 
def get_image_file_name(imgPath=CAPTCHA_IMAGE_PATH): 
  fileName = [] 
  total = 0 
  for filePath in os.listdir(imgPath): 
    captcha_name = filePath.split('/')[-1] 
    fileName.append(captcha_name) 
    total += 1 
  return fileName, total 
   
#將驗(yàn)證碼轉(zhuǎn)換為訓(xùn)練時(shí)用的標(biāo)簽向量,維數(shù)是 40   
#例如,如果驗(yàn)證碼是 ‘0296' ,則對(duì)應(yīng)的標(biāo)簽是 
# [1 0 0 0 0 0 0 0 0 0 
# 0 0 1 0 0 0 0 0 0 0 
# 0 0 0 0 0 0 0 0 0 1 
# 0 0 0 0 0 0 1 0 0 0] 
def name2label(name): 
  label = np.zeros(CAPTCHA_LEN * CHAR_SET_LEN) 
  for i, c in enumerate(name): 
    idx = i*CHAR_SET_LEN + ord(c) - ord('0') 
    label[idx] = 1 
  return label 
   
#取得驗(yàn)證碼圖片的數(shù)據(jù)以及它的標(biāo)簽     
def get_data_and_label(fileName, filePath=CAPTCHA_IMAGE_PATH): 
  pathName = os.path.join(filePath, fileName) 
  img = Image.open(pathName) 
  #轉(zhuǎn)為灰度圖 
  img = img.convert("L")     
  image_array = np.array(img)   
  image_data = image_array.flatten()/255 
  image_label = name2label(fileName[0:CAPTCHA_LEN]) 
  return image_data, image_label 
   
#生成一個(gè)訓(xùn)練batch   
def get_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 
  if trainOrTest == 'validate':     
    fileNameList = VALIDATION_IMAGE_NAME 
     
  totalNumber = len(fileNameList)  
  indexStart = step*batchSize   
  for i in range(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  
 
  return batch_data, batch_label 
   
#構(gòu)建卷積神經(jīng)網(wǎng)絡(luò)并訓(xùn)練 
def train_data_with_CNN(): 
  #初始化權(quán)值 
  def weight_variable(shape, name='weight'): 
    init = tf.truncated_normal(shape, stddev=0.1) 
    var = tf.Variable(initial_value=init, name=name) 
    return var 
  #初始化偏置   
  def bias_variable(shape, name='bias'): 
    init = tf.constant(0.1, shape=shape) 
    var = tf.Variable(init, name=name) 
    return var 
  #卷積   
  def conv2d(x, W, name='conv2d'): 
    return tf.nn.conv2d(x, W, strides=[1,1,1,1], padding='SAME', name=name) 
  #池化  
  def max_pool_2X2(x, name='maxpool'): 
    return tf.nn.max_pool(x, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME', name=name)    
   
  #輸入層 
  #請(qǐng)注意 X 的 name,在測(cè)試model時(shí)會(huì)用到它 
  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,防止過(guò)擬合 
  #請(qǐng)注意 keep_prob 的 name,在測(cè)試model時(shí)會(huì)用到它 
  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) 
  #全鏈接層 
  #每次池化后,圖片的寬度和高度均縮小為原來(lái)的一半,進(jìn)過(guò)上面的三次池化,寬度和高度均縮小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') 
  #預(yù)測(cè)結(jié)果 
  #請(qǐng)注意 predict_max_idx 的 name,在測(cè)試model時(shí)會(huì)用到它 
  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() 
  with tf.Session() as sess: 
    sess.run(tf.global_variables_initializer()) 
    steps = 0 
    for epoch in range(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}) 
      if steps % 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)) 
        if acc > 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) 
  #分成測(cè)試集 
  TRAINING_IMAGE_NAME = image_filename_list[ : trainImageNumber] 
  #和驗(yàn)證集 
  VALIDATION_IMAGE_NAME = image_filename_list[trainImageNumber : ] 
  train_data_with_CNN()   
  print('Training finished')

運(yùn)行上面的代碼,開始訓(xùn)練,訓(xùn)練要花些時(shí)間,如果沒有GPU的話,會(huì)慢些,

訓(xùn)練完后,輸出如下結(jié)果,經(jīng)過(guò)4100次的迭代,訓(xùn)練出來(lái)的分類器模型在驗(yàn)證集上識(shí)別的準(zhǔn)確率為99.5%

如何使用Tensorflow構(gòu)建和訓(xùn)練自己的CNN來(lái)做驗(yàn)證碼識(shí)別方式

生成的模型文件如下,在模型測(cè)試時(shí)將用到這些文件

如何使用Tensorflow構(gòu)建和訓(xùn)練自己的CNN來(lái)做驗(yàn)證碼識(shí)別方式

3. 測(cè)試模型

編寫代碼,對(duì)訓(xùn)練出來(lái)的模型進(jìn)行測(cè)試

import tensorflow as tf 

import numpy as np 
from PIL import Image 
import os 
import matplotlib.pyplot as plt  
 
CAPTCHA_LEN = 4 
 
MODEL_SAVE_PATH = 'E:/Tensorflow/captcha/models/' 
TEST_IMAGE_PATH = 'E:/Tensorflow/captcha/test/' 
 
def get_image_data_and_name(fileName, filePath=TEST_IMAGE_PATH): 
  pathName = os.path.join(filePath, fileName) 
  img = Image.open(pathName) 
  #轉(zhuǎn)為灰度圖 
  img = img.convert("L")     
  image_array = np.array(img)   
  image_data = image_array.flatten()/255 
  image_name = fileName[0:CAPTCHA_LEN] 
  return image_data, image_name 
 
def digitalStr2Array(digitalStr): 
  digitalList = [] 
  for c in digitalStr: 
    digitalList.append(ord(c) - ord('0')) 
  return np.array(digitalList) 
 
def model_test(): 
  nameList = [] 
  for pathName in os.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是在構(gòu)建graph時(shí)定義的(查看上面第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") 
  with tf.Session() as sess: 
    saver.restore(sess, tf.train.latest_checkpoint(MODEL_SAVE_PATH)) 
    count = 0 
    for fileName in nameList: 
      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) 
      if np.array_equal(predictValue, rightValue): 
        result = '正確' 
        count += 1 
      else:  
        result = '錯(cuò)誤'       
      print('實(shí)際值:{}, 預(yù)測(cè)值:{},測(cè)試結(jié)果:{}'.format(rightValue, predictValue, result)) 
      print('\n') 
       
    print('正確率:%.2f%%(%d/%d)' % (count*100/totalNumber, count, totalNumber)) 
 
if __name__ == '__main__': 
  model_test()

對(duì)模型的測(cè)試結(jié)果如下,在測(cè)試集上識(shí)別的準(zhǔn)確率為 94%

如何使用Tensorflow構(gòu)建和訓(xùn)練自己的CNN來(lái)做驗(yàn)證碼識(shí)別方式

下面是兩個(gè)識(shí)別錯(cuò)誤的驗(yàn)證碼

如何使用Tensorflow構(gòu)建和訓(xùn)練自己的CNN來(lái)做驗(yàn)證碼識(shí)別方式

以上是“如何使用Tensorflow構(gòu)建和訓(xùn)練自己的CNN來(lái)做驗(yàn)證碼識(shí)別方式”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI