tensorflow 訓練 think-captcha 圖片驗證碼自動識別

抄你碼科技有限公司發表於2022-07-14

原文:www.e4rl.com/archives/198.html
原文已無法訪問 ,所以特意從百度快照搬運過來。

ThinkPHP:github.com/top-think/framework
think-captcha:github.com/top-think/think-captcha
captcha_trainer (訓練):github.com/kerlomz/captcha_trainer
captcha_platform (部署):github.com/kerlomz/captcha_platfor...
MuggleOCR:pypi.org/project/muggle-ocr
captcha_trainer 作者介紹:www.jianshu.com/p/80ef04b16efc
矩池雲 GPU伺服器:matpool.com/

  1. 使用 ThinkPHP 呼叫 think-captcha 生成驗證碼

    composer create-project topthink/think tp
    cd tp
    composer require topthink/think-captcha
    php think run
  2. 修改 think-captcha 原始碼,將驗證碼儲存到 Session
    vendor/topthink/think-captcha/src/Captcha.php:195 插入以下程式碼

    Session::set('captcha', implode('', $code), '');
  3. 在控制器內列印驗證碼

    public function code() {
     $code = Session::get('captcha', '');
     echo $code;
    }
  4. 使用 Python 抓取圖片驗證碼樣本,按照 captcha_trainer 預設規則重新命名儲存

    import requests
    import threading
    import os
    import hashlib
    #
    def md5(s, salt=''):
     new_s = str(s) + salt
     m = hashlib.md5(new_s.encode())
     return m.hexdigest()
    #
    def get_captcha():
     session = requests.session()
     for i in range(0, 100000):
         try:
             content = session.get('http://x.com/captcha?'+str(i))
             if content.status_code != 200:
                 continue
             code = session.get('http://x.com/index/Home/code')
             if code.status_code != 200:
                 continue
             filename = '{}_{}.png'.format(code.text, md5(content.content))
             with open(os.path.join('captcha_images', filename), 'wb') as f:
                 f.write(content.content)
                 f.close()
         except Exception as e:
             print(str(e))
    #
    for i in range(1, 20):
     t = threading.Thread(target=get_captcha, args=())
     t.start()
  5. 租用矩池雲 RTX 2080 Ti 的GPU伺服器進行訓練
    ThinkPHP驗證碼類庫 think-captcha 圖片驗證碼識別

  6. 使用 captcha_trainer 進行訓練
    配置訓練環境及專案

    pip3 install -r requirements.txt
    pip3 install tensorflow-gpu # tensorflow模組需獨立安裝
    mkdir -p projects/{project name}/
    vi projects/{project name}/model.yaml

model.yaml 模板引數介紹請參考 captcha_trainer 專案介紹,可以用 Windows 編譯版生成後上傳至伺服器,需保持專案名一致。

專案名 TP-CNNX-GRU-H64-CTC-C1
./projects/TP-CNNX-GRU-H64-CTC-C1/model.yaml

# - requirement.txt  -  GPU: tensorflow-gpu, CPU: tensorflow
# - If you use the GPU version, you need to install some additional applications.
System:
  MemoryUsage: 0.8
  Version: 2

# CNNNetwork: [CNN5, ResNet, DenseNet]
# RecurrentNetwork: [CuDNNBiLSTM, CuDNNLSTM, CuDNNGRU, BiLSTM, LSTM, GRU, BiGRU, NoRecurrent]
# - The recommended configuration is CNN5+GRU
# UnitsNum: [16, 64, 128, 256, 512]
# - This parameter indicates the number of nodes used to remember and store past states.
# Optimizer: Loss function algorithm for calculating gradient.
# - [AdaBound, Adam, Momentum]
# OutputLayer: [LossFunction, Decoder]
# - LossFunction: [CTC, CrossEntropy]
# - Decoder: [CTC, CrossEntropy]
NeuralNet:
  CNNNetwork: CNNX
  RecurrentNetwork: GRU
  UnitsNum: 64
  Optimizer: RAdam
  OutputLayer:
    LossFunction: CTC
    Decoder: CTC

# ModelName: Corresponding to the model file in the model directory
# ModelField: [Image, Text]
# ModelScene: [Classification]
# - Currently only Image-Classification is supported.
Model:
  ModelName: TP-CNNX-GRU-H64-CTC-C1
  ModelField: Image
  ModelScene: Classification

# FieldParam contains the Image, Text.
# When you filed to Image:
# - Category: Provides a default optional built-in solution:
# -- [ALPHANUMERIC, ALPHANUMERIC_LOWER, ALPHANUMERIC_UPPER,
# -- NUMERIC, ALPHABET_LOWER, ALPHABET_UPPER, ALPHABET, ALPHANUMERIC_CHS_3500_LOWER]
# - or can be customized by:
# -- ['Cat', 'Lion', 'Tiger', 'Fish', 'BigCat']
# - Resize: [ImageWidth, ImageHeight/-1, ImageChannel]
# - ImageChannel: [1, 3]
# - In order to automatically select models using image size, when multiple models are deployed at the same time:
# -- ImageWidth: The width of the image.
# -- ImageHeight: The height of the image.
# - MaxLabelNum: You can fill in -1, or any integer, where -1 means not defining the value.
# -- Used when the number of label is fixed
# When you filed to Text:
# This type is temporarily not supported.
FieldParam:
  Category: ['2', '3', '4', '5', '6', '7', '8', 'a', 'b', 'c', 'd', 'e', 'f', 'h', 'i', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'T', 'U', 'V', 'W', 'X', 'Y']
  Resize: [224, 70]
  ImageChannel: 1
  ImageWidth: 224
  ImageHeight: 70
  MaxLabelNum: 4
  OutputSplit: 
  AutoPadding: True

# The configuration is applied to the label of the data source.
# LabelFrom: [FileName, XML, LMDB]
# ExtractRegex: Only for methods extracted from FileName:
# - Default matching apple_20181010121212.jpg file.
# - The Default is .*?(?=_.*\.)
# LabelSplit: Only for methods extracted from FileName:
# - The split symbol in the file name is like: cat&big cat&lion_20181010121212.png
# - The Default is null.
Label:
  LabelFrom: FileName
  ExtractRegex: .*?(?=_)
  LabelSplit: 

# DatasetPath: [Training/Validation], The local absolute path of a packed training or validation set.
# SourcePath:  [Training/Validation], The local absolute path to the source folder of the training or validation set.
# ValidationSetNum: This is an optional parameter that is used when you want to extract some of the validation set
# - from the training set when you are not preparing the validation set separately.
# SavedSteps: A Session.run() execution is called a Step,
# - Used to save training progress, Default value is 100.
# ValidationSteps: Used to calculate accuracy, Default value is 500.
# EndAcc: Finish the training when the accuracy reaches [EndAcc*100]% and other conditions.
# EndCost: Finish the training when the cost reaches EndCost and other conditions.
# EndEpochs: Finish the training when the epoch is greater than the defined epoch and other conditions.
# BatchSize: Number of samples selected for one training step.
# ValidationBatchSize: Number of samples selected for one validation step.
# LearningRate: [0.1, 0.01, 0.001, 0.0001]
# - Use a smaller learning rate for fine-tuning.
Trains:
  DatasetPath:
    Training: 
      - ./projects/TP-CNNX-GRU-H64-CTC-C1/dataset/Trains.0.tfrecords
    Validation: 
      - ./projects/TP-CNNX-GRU-H64-CTC-C1/dataset/Validation.0.tfrecords
  SourcePath:
    Training: 
      - /root/captcha_images
    Validation: 
  ValidationSetNum: 300
  SavedSteps: 100
  ValidationSteps: 500
  EndAcc: 0.95
  EndCost: 0.5
  EndEpochs: 2
  BatchSize: 64
  ValidationBatchSize: 300
  LearningRate: 0.001

# Binaryzation: The argument is of type list and contains the range of int values, -1 is not enabled.
# MedianBlur: The parameter is an int value, -1 is not enabled.
# GaussianBlur: The parameter is an int value, -1 is not enabled.
# EqualizeHist: The parameter is an bool value.
# Laplace: The parameter is an bool value.
# WarpPerspective: The parameter is an bool value.
# Rotate: The parameter is a positive integer int type greater than 0, -1 is not enabled.
# PepperNoise: This parameter is a float type less than 1, -1 is not enabled.
# Brightness: The parameter is an bool value.
# Saturation: The parameter is an bool value.
# Hue: The parameter is an bool value.
# Gamma: The parameter is an bool value.
# ChannelSwap: The parameter is an bool value.
# RandomBlank: The parameter is a positive integer int type greater than 0, -1 is not enabled.
# RandomTransition: The parameter is a positive integer int type greater than 0, -1 is not enabled.
DataAugmentation:
  Binaryzation: -1
  MedianBlur: -1
  GaussianBlur: -1
  EqualizeHist: False
  Laplace: False
  WarpPerspective: False
  Rotate: -1
  PepperNoise: -1.0
  Brightness: False
  Saturation: False
  Hue: False
  Gamma: False
  ChannelSwap: False
  RandomBlank: -1
  RandomTransition: -1
  RandomCaptcha: 
     Enable: False
     FontPath: 

# Binaryzation: The parameter is an integer number between 0 and 255, -1 is not enabled.
# ReplaceTransparent: Transparent background replacement, bool type.
# HorizontalStitching: Horizontal stitching, bool type.
# ConcatFrames: Horizontally merge two frames according to the provided frame index list, -1 is not enabled.
# BlendFrames: Fusion corresponding frames according to the provided frame index list, -1 is not enabled.
# - [-1] means all frames
Pretreatment:
  Binaryzation: -1
  ReplaceTransparent: True
  HorizontalStitching: False
  ConcatFrames: -1
  BlendFrames: -1
  ExecuteMap: {}

打包訓練集後開始訓練

python3 make_dataset.py TP-CNNX-GRU-H64-CTC-C1
python3 trains.py TP-CNNX-GRU-H64-CTC-C1
  1. Linux 訓練環境強制結束任務
    因為 think-captcha 隨機呼叫系統字型生成圖片驗證碼,部分字型顯示只有大寫字母,與 think-captcha 生成的驗證碼存在大小寫偏差,導致 captcha_trainer 訓練正確率只能維持在 0.6 左右,無法滿足結束訓練任務的 0.95 正確率,但忽略大小寫後的正確率已滿足需求,所以需要強制結束訓練任務,編譯模型。

Windows 環境下可以直接點選 Stop 按鈕結束任務後再點選 Compile 按鈕編譯模型。

ThinkPHP驗證碼類庫 think-captcha 圖片驗證碼識別

Linux 環境結束任務需要修改 trains.py 程式碼,簡單分析後發現 trains.py 共有兩處正確率判斷

# trains.py:308
# 滿足終止條件但尚未完成當前epoch時跳出epoch迴圈
if self.achieve_cond(acc=accuracy, cost=batch_cost, epoch=epoch_count):
    break
# trains.py:314
if self.achieve_cond(acc=accuracy, cost=batch_cost, epoch=epoch_count):
    # sess.close()
    tf.compat.v1.keras.backend.clear_session()
    sess.close()
    self.compile_graph(accuracy)
    tf.compat.v1.logging.info('Total Time: {} sec.'.format(time.time() - start_time))

找到程式碼後直接簡單粗暴的把判斷條件改成 1==1 讓條件成立即可結束任務

# trains.py:308
# 滿足終止條件但尚未完成當前epoch時跳出epoch迴圈
if 1==1:
    break
# trains.py:314
if 1==1:
    # sess.close()
    tf.compat.v1.keras.backend.clear_session()
    sess.close()
    self.compile_graph(accuracy)
    tf.compat.v1.logging.info('Total Time: {} sec.'.format(time.time() - start_time))

captcha_trainer 支援中斷任務恢復,修改程式碼後按 Ctrl+C 結束任務,重新執行 python3 trains.py,初始化後將直接結束訓練任務,編譯模型。

使用 captcha_platform 專案進行 docker 部署

  1. 將 captcha_trainer 訓練後編譯生成的模型複製到 captcha_platform 專案中

    mv -rf captcha_trainer/out/* captcha_platform/
  2. 構建並啟動 docker

    cd captcha_platform/
    docker build . 
    docker run -d -p 19952:19952 [image:tag]

13萬 think-captcha 圖片驗證碼樣本經過約 11 個小時的訓練後,使用未經過訓練的新樣本進行識別測試,識別成功率在 95% 左右

ThinkPHP驗證碼類庫 think-captcha 圖片驗證碼識別

使用 Python 指令碼進行識別測試

import requests
import base64
import os
import re
#
dir = 'test-1' # 未經過訓練的圖片驗證碼樣本目錄
success = 0
error = 0
count = 0
file_list = os.listdir(dir)
#
for i in range(0, 1000):
    filename = file_list[i]
    origin = re.match(r'.*?(?=_.*\.)', filename).group()
    if not origin:
        continue
    src = os.path.join(dir, filename)
    img = base64.b64encode(open(src, 'rb').read())
    post_data = {
        'image': img,
        'model_name': 'TP-CNNX-GRU-H64-CTC-C1'
    }
    res = requests.post('http://localhost:19952/captcha/v1', data=post_data)
    json_res = res.json()
    # 忽略大小寫
    if json_res['code'] == 0 and str(json_res['message']).upper() == origin.upper():
        print('Sample: {}, Identify: {}, Status: {}'.format(org, json_res['message'], 'success'))
        success += 1
    else:
        print('Sample: {}, Identify: {}, Status: {}'.format(org, json_res['message'], 'error'))
        error += 1
    count += 1
print('Count: {}, Success: {}, Error: {}'.format(count, success, error))

ThinkPHP驗證碼類庫 think-captcha 圖片驗證碼識別

模型下載

連結: pan.baidu.com/s/1e0quRSqMV8lP6XXoS... 提取碼:sg6c

本作品採用《CC 協議》,轉載必須註明作者和本文連結
CV專員在靜靜的抄你碼

相關文章