利用captcha_trainer 进行验证码训练

captcha_trainer 验证码识别-训练 使用记录

在爬数据的时候,网站出现了验证码,那么我们就得去识别验证码了。目前有两种方案

  1. 接入打码平台(花钱,慢)
  2. 自己训练(费时,需要GPU环境,快)

那么我采用的是使用开源训练框架 https://github.com/kerlomz/captcha_trainer

训练集准备

图片示例:

geetest seesion 验证码池_验证码

  1. 请求网站验证码具体接口,训练集(2w张) 测试集(1k张)
  2. 从打码平台进行标注
  3. 提交验证码给网站 检测 打码平台正确性
  4. 保存验证码图片格式为 {结果}_{md5(文件)}.jpg
  5. 打包训练集 测试集
    在projects/项目名/model.yaml 文件中配置训练集位置
Trains:
DatasetPath:
  Training: 
    # 训练集打包结果路径
    - ./projects/wacai-model-CNN5-GRU-H64-CTC-C1/dataset/Trains.0.tfrecords
  Validation: 
    # 测试集打包结果路径
    - ./projects/wacai-model-CNN5-GRU-H64-CTC-C1/dataset/Validation.0.tfrecords
SourcePath:
  Training: 
    # 训练集图片路径
    - D:/PyCode/XiaoXiangDemo/APPCheck/WaCaiCaptchaTraining/images
  Validation: 
    # 测试集图片路径
    - D:/PyCode/XiaoXiangDemo/APPCheck/WaCaiCaptchaTraining/images2

最后在项目主目录下 运行 python make_dataset.py 项目名 方式打包

设置训练配置

根据项目作者的参数说明,配置了符合我自己项目的要求

# - requirement.txt  -  GPU: tensorflow-gpu, CPU: tensorflow
# - If you use the GPU version, you need to install some additional applications.
# MemoryUsage: 显存占用率,推荐0.6-0.8之间
System:
  MemoryUsage: {MemoryUsage}
  Version: 2

# CNNNetwork: [CNN5, ResNet50, DenseNet] 
# RecurrentNetwork: [CuDNNBiLSTM, CuDNNLSTM, CuDNNGRU, BiLSTM, LSTM, GRU, BiGRU, NoRecurrent]
# - 推荐配置为 不定长问题:CNN5+GRU ,定长:CNN5/DenseNet/ResNet50
# UnitsNum: RNN层的单元数 [16, 64, 128, 256, 512] 
# - 神经网络在隐层中使用大量神经元,就是做升维,将纠缠在一起的特征或概念分开。
# Optimizer: 优化器算法 [AdaBound, Adam, Momentum]
# OutputLayer: [LossFunction, Decoder]
# - LossFunction: 损失函数 [CTC, CrossEntropy] 
# - Decoder: 解码器 [CTC, CrossEntropy] 
NeuralNet:
  CNNNetwork: {CNNNetwork}
  RecurrentNetwork: {RecurrentNetwork}
  UnitsNum: {UnitsNum}
  Optimizer: {Optimizer}
  OutputLayer:
    LossFunction: {LossFunction}
    Decoder: {Decoder}


# ModelName: 模型名/项目名,同时也对应编译后的pb模型文件名
# ModelField: 模型处理的数据类型,目前只支持图像 [Image, Text]
# ModelScene: 模型处理的场景类型,目前只支持分类场景 [Classification]
# - 目前只支持 “图像分类” 这一种场景.
Model:
  ModelName: {ModelName}
  ModelField: {ModelField}
  ModelScene: {ModelScene}

# FieldParam 分为 Image, Text 两种,不同数据类型时可配置的参数不同,目前只提供 Image 一种。
# ModelField 为 Image 时:
# - Category: 提供默认的内置解决方案:
# -- [ALPHANUMERIC(含大小写英文数字), ALPHANUMERIC_LOWER(小写英文数字), 
# -- ALPHANUMERIC_UPPER(大写英文数字),NUMERIC(数字), ALPHABET_LOWER(小写字母), 
# -- ALPHABET_UPPER(大写字母), ALPHABET(大小写字母), 
# -- ALPHANUMERIC_CHS_3500_LOWER(小写字母数字混合中文常用3500)]
# - 或者可以自定义指定分类集如下(中文亦可):
# -- ['Cat', 'Lion', 'Tiger', 'Fish', 'BigCat']
# - Resize: 重置尺寸,对应网络的输入: [ImageWidth, ImageHeight/-1, ImageChannel]
# - ImageChannel: 图像通道,3为原图,1为灰度 [1, 3]
# - 为了配合部署服务根据图片尺寸自动选择对应的模型,由此诞生以下参数(ImageWidth,ImageHeight):
# -- ImageWidth: 图片宽度.
# -- ImageHeight: 图片高度.
# - MaxLabelNum: 该参数在使用CTC损失函数时将被忽略,仅用于使用交叉熵作为损失函数/标签数固定时使用
# ModelField 为 Text 时:
# - 该类型暂时不支持
FieldParam:
  Category: {Category}
  Resize: {Resize}
  ImageChannel: {ImageChannel}
  ImageWidth: {ImageWidth}
  ImageHeight: {ImageHeight}
  MaxLabelNum: {MaxLabelNum}
  OutputSplit: {OutputSplit}


# 该配置应用于数据源的标签获取.
# LabelFrom: 标签来源,目前只支持 从文件名提取 [FileName, XML, LMDB]
# ExtractRegex: 正则提取规则,对应于 从文件名提取 方案 FileName:
# - 默认匹配形如 apple_20181010121212.jpg 的文件.
# - 默认正则为 .*?(?=_.*\.)
# LabelSplit: 该规则仅用于 从文件名提取 方案:
# - 文件名中的分割符形如: cat&big cat&lion_20181010121212.png,那么分隔符为 &
# - The Default is null.
Label:
  LabelFrom: {LabelFrom}
  ExtractRegex: {ExtractRegex}
  LabelSplit: {LabelSplit}


# DatasetPath: [Training/Validation], 打包为TFRecords格式的训练集/验证集的本地绝对路径。
# SourcePath:  [Training/Validation], 未打包的训练集/验证集源文件夹的本地绝对路径。
# ValidationSetNum: 验证集数目,仅当未配置验证集源文件夹时用于系统随机抽样用作验证集使用。
# - 该选项用于懒人训练模式,当样本极度不均衡时建议手动设定合理的验证集。
# SavedSteps: 当 Session.run() 被执行一次为一步(1.x版本),保存训练过程的步数,默认为100。
# ValidationSteps: 用于计算准确率,验证模型的步数,默认为每500步验证一次。
# EndAcc: 结束训练的条件之准确率 [EndAcc*100]% 到达该条件时结束任务并编译模型。
# EndCost: 结束训练的条件之Cost值 EndCost 到达该条件时结束任务并编译模型。
# EndEpochs: 结束训练的条件之样本训练轮数 Epoch 到达该条件时结束任务并编译模型。
# BatchSize: 批次大小,每一步用于训练的样本数量,不宜过大或过小,建议64。
# ValidationBatchSize: 验证集批次大小,每个验证准确率步时,用于验证的样本数量。
# LearningRate: 学习率 [0.1, 0.01, 0.001, 0.0001] fine-tuning 时选用较小的学习率。
Trains:
  DatasetPath:
    Training: {DatasetTrainsPath}
    Validation: {DatasetValidationPath}
  SourcePath:
    Training: {SourceTrainPath}
    Validation: {SourceValidationPath}
  ValidationSetNum: {ValidationSetNum}
  SavedSteps: {SavedSteps}
  ValidationSteps: {ValidationSteps}
  EndAcc: {EndAcc}
  EndCost: {EndCost}
  EndEpochs: {EndEpochs}
  BatchSize: {BatchSize}
  ValidationBatchSize: {ValidationBatchSize}
  LearningRate: {LearningRate}

# 以下为数据增广的配置
# Binaryzation: 该参数为 list 类型,包含二值化的上界和下界,值为 int 类型,参数为 -1 表示未启用。
# MedianBlur: 该参数为 int 类型,参数为 -1 表示未启用。
# GaussianBlur: 该参数为 int 类型,参数为 -1 表示未启用。
# EqualizeHist: 该参数为 bool 类型。
# Laplace: 该参数为 bool 类型。
# WarpPerspective: 该参数为 bool 类型。
# Rotate: 该参数为大于 0 的 int 类型,参数为 -1 表示未启用。
# PepperNoise: 该参数为小于 1 的 float 类型,参数为 -1 表示未启用。
# Brightness: 该参数为 bool 类型。
# Saturation: 该参数为 bool 类型。
# Hue: 该参数为 bool 类型。
# Gamma: 该参数为 bool 类型。
# ChannelSwap: 该参数为 bool 类型。
# RandomBlank: 该参数为大于 0 的 int 类型,参数为 -1 表示未启用。
# RandomTransition: 该参数为大于 0 的 int 类型,参数为 -1 表示未启用。
DataAugmentation:
  Binaryzation: {DA_Binaryzation}
  MedianBlur: {DA_MedianBlur}
  GaussianBlur: {DA_GaussianBlur}
  EqualizeHist: {DA_EqualizeHist}
  Laplace: {DA_Laplace}
  WarpPerspective: {DA_WarpPerspective}
  Rotate: {DA_Rotate}
  PepperNoise: {DA_PepperNoise}
  Brightness: {DA_Brightness}
  Saturation: {DA_Saturation}
  Hue: {DA_Hue}
  Gamma: {DA_Gamma}
  ChannelSwap: {DA_ChannelSwap}
  RandomBlank: {DA_RandomBlank}
  RandomTransition: {DA_RandomTransition}
  
# 以下为预处理的配置 
# Binaryzation: 该参数为 list 类型,包含二值化的上界和下界,值为 int 类型,参数为 -1 表示未启用。
# ReplaceTransparent: 使用白色替换透明背景
# HorizontalStitching: 水平拆分拼接,适用于上下分层
# ConcatFrames: 根据帧索引列表水平合并帧
# BlendFrames: 根据帧索引列表融合帧内容
Pretreatment:
  Binaryzation: {Pre_Binaryzation}
  ReplaceTransparent: {Pre_ReplaceTransparent}
  HorizontalStitching: {Pre_HorizontalStitching}
  ConcatFrames: {Pre_ConcatFrames}
  BlendFrames: {Pre_BlendFrames}

开始训练

执行 python trains.py 项目名 方式训练。然后就开始等待训练完成,生成 .pb文件

调用 pb 文件进行识别

采用作者提供的 muggle_ocr 项目来进行调用 pb 文件,进行验证码识别

import muggle_ocr
yaml_path = 'xx.pb'
sdk = muggle_ocr.SDK(model_type=muggle_ocr.ModelType.Captcha,conf_path=yaml_path)
url = 'http://www.xxx/image/11.jpg'
response = requests.get(url, verify=False)
text = self.sdk.predict(image_bytes=response.content)

结语

这样简单的操作就完成了验证码识别了,是不是太方便了。