项目地址:https://github.com/kerlomz/captcha_trainerpython
编译版下载地址: https://github.com/kerlomz/captcha_trainer/releases/tag/v1.0linux
注意:若使用云服务器 (Windows Server版) 遇到闪退,请按照步骤:个人电脑——属性——管理——添加角色和功能——勾选桌面体验,点击安装,安装以后重启便可。git
想必各位只是偶然间搜到这篇文章,网上文章良莠不齐,标题党不少,能跑起来的开源代码不多,对于能跑起来的代码,也常常遇到如下问题如:内存泄漏,网络参数写死致使更换训练集报错,网络跑其余样本识别率低,没有调用示例等等。es6
再往下看以前,我能够向大家保证,它绝对会是你所见过的全部验证码有关的文章中最实用,最接近生产水平的。github
由于小编打算转行了,离开这个行业以前总要留下点什么证实本身来过,总有人和我说的这个部署不会调用,可能大家想要的是一行pip就搞定环境的,因此今天给大家安排了麻瓜OCR(MuggleOCR)。
https://pypi.org/project/muggle-ocr
它整合了简单验证码识别通用模型+印刷文字通用识别,而且支持调用本文框架训练的模型。调用只须要三行核心代码:正则表达式
import time # STEP 1 import muggle_ocr import os # STEP 2 sdk = muggle_ocr.SDK(model_type=muggle_ocr.ModelType.OCR) root_dir = r"./imgs" for i in os.listdir(root_dir): n = os.path.join(root_dir, i) with open(n, "rb") as f: b = f.read() st = time.time() # STEP 3 text = sdk.predict(image_bytes=b) print(i, text, time.time() - st)
这真的很简单,应付通常的文字识别和验证码都足够了。(文字识别过几天会更新一下新模型,毕竟0601模型就跑了半天。sql
本项目适用于Python3.7,GPU>=NVIDIA GTX1050Ti,原master分支新增了GUI配置界面以及编译版本了,是时候写一篇新的文章了。json
长话短说,开门见山,网络上现有的代码以教学研究为主,本项目是为实用主义者定制的,只要基本的环境安装常识,即可很好的训练出指望的模型,重定义几个简单的参数任何人都能使用深度学习技术训练一个商业化成品。flask
笔者选用的时下最为流行的CNN+BLSTM+CTC(CRNN)进行端到端的不定长验证码识别,代码中预留了CNNX(搜不到由于是小编本身拼凑的)/MobileNet/DenseNet121/ResNet50等选项,能够在配置界面中直接选用。首先,介绍个大概吧。
ubuntu
网格结构 | predict-CPU | predict-GPU | 模型大小 |
---|---|---|---|
CNN5+Bi-LSTM+H64+CTC | 15ms | 8ms | 2mb |
CNN5+CrossEntropy | 8ms | 2ms | 1.5mb |
H16/H64指的是Bi-LSTM的隐藏神经元个数UnitsNum,因此本项目使用GPU训练,使用CPU进行预测。预测服务部署项目源码请移步此处:https://github.com/kerlomz/captcha_platform
部署项目的编译版下载地址:https://github.com/kerlomz/captcha_platform/releases
花了超长篇幅介绍了训练环境的基本搭建,主要是给还没有入门的读者看的,老鸟们随便跳过,若不但愿在环境上面浪费时间的,欢迎使用编译版,可在文章开头找到下载地址。
关于CUDA和cuDNN版本的问题,很多人很纠结,这里就列出官方经过pip安装的TensorFlow的版本对应表:
Version | Python version | Compiler | Build tools | cuDNN | CUDA |
---|---|---|---|---|---|
tensorflow_gpu-1.14.0 | 3.7 | GCC 4.8 | Bazel 0.15.0 | 7.6 | 9 |
Version | Python version | Compiler | Build tools | cuDNN | CUDA |
---|---|---|---|---|---|
tensorflow_gpu-1.14.0 | 3.7 | MSVC 2015 update 3 | Bazel 0.15.0 | 7.6 | 10 |
若是但愿使用上面对应以外的搭配的CUDA和cuDNN,能够自行编译TensorFlow,或者去Github上搜索TensorFlow Wheel
找到第三方编译的对应版本的whl安装包。提早预警,如果本身编译将会苦难重重,坑不少,这里就不展开了。
目前在如下主流操做系统平台均测试经过:
操做系统 | 最低支持版本 |
---|---|
Ubuntu | 16.04 |
Windows | 7 SP1 |
MacOS | N/A |
本训练项目主要的环境依赖清单以下
依赖 | 最低支持版本 |
---|---|
Python | 3.7 |
TensorFlow-GPU | 1.14.0 |
Opencv-Python | 4.1.2.30 |
Numpy | 1.16.0 |
Pillow | 4.3.0 |
PyYaml | 3.13 |
tqdm | N/A |
1)先安装Python环境(有Python 3.7环境的能够忽略)
sudo apt-get install openssl sudo apt-get install libssl-dev sudo apt-get install libc6-dev gcc sudo apt-get install -y make build-essential zlib1g-dev libbz2-dev libreadline-dev $ libsqlite3-dev wget curl llvm tk-dev wget https://www.python.org/ftp/python/3.7.6/Python-3.7.6.tgz tar -vxf Python-3.7.6.tar.xz cd Python-3.7.6 ./configure --prefix=/usr/local --enable-shared make -j8 sudo make install -j8
通过上面指令就安装好Python3.7环境了,若是提示找不到libpython3.7m.so.1.0
就到/usr/local/lib路径下将该文件复制一份到/usr/lib和/usr/lib64路径下。
2)安装相关依赖(这一步Windows和Linux通用)
能够直接在项目路径下执行pip3 install -r requirements.txt
安装全部依赖,注意这一步是安装在全局Python环境下的,强烈建议使用虚拟环境进行项目间的环境隔离,如Virtualenv或Anaconda等等。
我通常使用的是Virtualenv,有修改代码须要的,建议安装PyCharm做为Python IDE
virtualenv -p /usr/bin/python3 venv # venv is the name of the virtual environment. cd venv/ # venv is the name of the virtual environment. source bin/activate # to activate the current virtual environment. cd captcha_trainer # captcha_trainer is the project path. pip3 install -r requirements.txt
网上看到过不少教程,我本身也部署过不少次,Ubuntu 16.04遇到的坑仍是比较少的。14.04支持就没那么好,若是主板不支持关闭SecureBoot的话千万不要安装Desktop版,由于安装好以后必定会无限循环在登录界面没法进入桌面。
网上教程说要加驱动黑名单什么的我直接跳过了,亲测没那个必要。就简单的几步:
1. 下载好安装包
注意下载runfile类型的安装包,deb安装会自动安装默认驱动,极有可能致使登录循环
NVIDIA 驱动下载:https://www.geforce.cn/drivers
CUDA 下载地址:https://developer.nvidia.com/cuda-downloads
cuDNN 下载地址:https://developer.nvidia.com/cudnn (须要注册NVIDIA帐号且登录,下载deb安装包)
2. 关闭图形界面
Ctrl+alt+F1进入字符界面,关闭图形界面
sudo service lightdm stop
3. 安装Nvidia Driver
命令中的版本本身对应下载的版本改,在上面的下载地址根据本身的显卡型号下载最新版,切记是runfile格式的安装包。
sudo chmod a+x NVIDIA-Linux-x86_64-384.90.run //获取执行权限 sudo ./NVIDIA-Linux-x86_64-384.90.run –no-x-check –no-nouveau-check –no-opengl-files //安装驱动
安装成功之后使用如下命令验证,若是显示显卡信息则表示安装成功
nvidia-smi
4. 安装CUDA
1)先安装一些系统依赖库
sudo apt-get install freeglut3-dev build-essential libx11-dev libxmu-dev libxi-dev libgl1-mesa-glx libglu1-mesa libglu1-mesa-dev
sudo sh cuda_9.0.176_384.81_linux.run
安装完若是环境变量没配上去,就写到 ~/.bashrc 文件的尾部
export PATH=/usr/local/cuda-9.0/bin${PATH:+:${PATH}} export LD_LIBRARY_PATH=/usr/local/cuda-9.0/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
而后在终端执行 sudo ldconfig
更新,安装完毕就能够重启机器重启图形界面了。
sudo service lightdm start
在Windows其实简单不少,只要到官网下载安装包无脑安装就能够了,下载链接同Ubuntu,先安装Python,显卡驱动,CUDA,而后下载对应的cuDNN替换到对应路径便可。
在训练以前,有很多群友常常问我“训练4位数英文数字须要多少样本?”诸如此类的问题,我这里统一作个回复,样本数量主要是看样本的特征复杂度而定。
这里能够提供几个参考依据: 是否变形?是否旋转?是否有复杂背景干扰?是否多种字体?字符集(分类数)多大?位数(标签数)多少?
注:只准备一百个不到样本的亲们,千万不要尝试训练测试,由于根本跑不起来。
入手的第一步环境搭建好了,那就是准备跑代码了,仍是有几个必要的条件,巧妇难为无米之炊,首先,既然是训练,要先有训练集,有一个新手尝鲜的训练集,是mnist手写识别的例子,能够在腾讯云下载:https://share.weiyun.com/5pzGF4V
,如今万事俱备,只欠东风。
本项目基于参数化配置,不须要改动任何代码,能够经过可视化界面操做训练几乎任何字符型图片验证码。训练框架界面能够大体划分为几个部分:
依此类推的训练配置的步骤以下:
如若使用CrossEntropy做为解码器须要注意标签数LabelNum和图片尺寸须要知足的关系,由于网络为多标签而设计(通常的多标签采用直接链接多个分类器),卷积层的输出 outputs 通过了如下变换:
Reshape([label_num, int(outputs_shape[1] / label_num)])
为了保证运算 int(outputs_shape[1] / label_num) 可以取得正整数,也意味着他们之间存在某种关系,对于CNN5+Cross Entropy的网络结构,Conv2D层的步长皆为1,那么须要保证如下关系成立:
因此有时候须要Resize网络输入的Shape
网络 | 池化步长^池化层数 | 输出层参数 |
---|---|---|
CNN5 | 16 | 64 |
CNNX | 8 | 64 |
ResNet50 | 16 | 1024 |
DenseNet | 32 | 2048 |
例如使用CNN5+CrossEntropy组合,则输入宽度与输入高度须要知足:
同理若是CNN5+RNN+CTC,卷积层以后的输出通过如下变换:
Reshape([-1, outputs_shape[2] * outputs_shape[3]])
原输出(batch_size, outputs_shape[1], outputs_shape[2], outputs_shape[3]),RNN层的输入输出要求为(batch, timesteps, num_classes),为了接入RNN通过以上操做,那么又引出一个Time Step的概念,因此timesteps的值也是 outputs_shape[1],而CTC Loss要求的输入为 [batch_size, frames, num_labels],如果 timesteps 小于标签数则没法计算损失,也就没法找损失函数中找到极小值,梯度何如下降。timesteps 最合理的值通常是标签数的2倍,为了达到目的,也能够经过Resize网络输入的Shape解决,通常状况timesteps直接关联于图片宽度,大多状况只要按比例放大宽度便可。
注意:若是训练集的命名格式和我提供的新手训练集不同,请根据实际状况修改ExtractRegex的正则表达式。目前只支持在yaml配置文件中直接修改,还没有提供GUI界面修改的支持。 DatasetPath 和SourcePath参数容许多个路径,这种操做适用于须要将多种样本训练为一个模型,或者但愿训练一套通用泛化模型的人。
字符集Category其实大多数状况下不须要修改,通常的图形验证码离不开数字和英文,并且通常来讲是大小写不敏感的,不区分大小写,由于打码平台收集的训练集质量良莠不齐,有些大写有些小写,不如所有统一为小写,默认ALPHANUMERIC_LOWER则会自动将大写的转为小写,字符集可定制化很灵活,除了配置备注上提供的几种类型,还能够训练中文,自定义字符集用list表示,示例以下:
Category: ['常', '世', '宁', '慢', '南', '制', '根', '难']
若是是单标签分类,能够配合LabelNum=1,例如:
Category: ["航母", "雨靴", "毛线", "安全帽", "调色板", "海鸥", "日历", "网球拍", ......]
其文件名示例:航母_1231290424123.png
若是是多标签分类,能够配合LabelSplit=&,例如:
Category: ["航母", "雨靴", "毛线", "安全帽", "调色板", "海鸥", "日历", "网球拍", ......]
其文件名示例:航母&雨靴&毛线_1231290424123.png
能够本身根据收集训练集的实际字符集使用率来定义,也能够无脑网上找3500经常使用字来训练,注意:中文字符集通常比数字英文大不少,刚开始收敛比较慢,须要更久的训练时间,也须要更多的样本量,请量力而行
形如上图的图片能轻松训练到95%以上的识别率。
ImageWidth、ImageHeight只要和当前图片尺寸匹配便可,其实这里的配置主要是为了方便后面的部署智能策略。
该参数是用来作图片预处理的,例如形如如下的GIF动图,
可使用ConcatFrames参数选取帧对两帧进行水平拼接,适用于处理滚动型GIF,而闪烁型GIF可使用BlendFrames参数进行融合。
按照上面的介绍,配置只要修改极少数的参数对应的值,就能够开启正式的训练之旅了,具体操做以下:
能够直接使用 PyCharm 的 Run,执行 trains.py,也能够在激活Virtualenv下使用终端亦或在安装依赖的全局环境下执行,但本文建议全程使用GUI界面进行操做,使用GUI仅需启动 app.py 便可。
python3 trains.py
剩下的就是等了,看过程,等结果。
正常开始训练的模样应该是这样的:
训练结束会在项目的out路径下生成一个包含pb文件的graph目录和包含yaml文件的model目录,下面该到部署环节了。
真的颇有必要认真的介绍一下部署项目,比起训练,这个部署项目倾注了笔者更多的心血,为何呢?
项目地址:https://github.com/kerlomz/captcha_platform
如但愿将本系统集成于本身的项目中的能够参考python-sdk的使用:
https://pypi.org/project/muggle-ocr/
该项目的核心基于 captcha_platform/sdk/pb/sdk.py 能够根据须要自行修改,抑或直接使用MuggleOCR 调用训练框架生产的模型。(具体调用方法可点击上面连接有对应的文档介绍)
编译版:https://github.com/kerlomz/captcha_platform/releases,使用编译版无需安装Python和TensorFlow环境。
首先笔者重写了TensorFlow的Graph会话管理,设计会话池,容许同时管理多模型,实现多模型动态部署方案。
1) 训练好的 pb模型只要放在部署项目的graph路径下,yaml模型配置文件放在model, 便可被服务发现并加载。(用SDK调用时,二者置于同一目录下)
2) 若是须要卸载一个正在服务的模型,只须要在model中删除该模型的yaml配置文件,在graph中删除对应的pb模型便可。
3) 若是须要更新一个已经服务中的模型,只需修改新版的模型yaml配置文件的版本号高于原模型的版本号,按先放pb后放yaml的顺序,服务便会自动发现新版的模型并加载使用,旧的模型将因版本低于新版模型不会被调用,能够按照上述的卸载方法卸载已被弃用的模型释放内存。
上面的操做中无需重启服务,彻底的无缝切换
其次,一套服务想要服务于各式各样的图像识别需求,能够定义一套策略,训练时将全部尺寸同样的图片训练成一个模型,服务根据图片尺寸自动选择使用哪一个模型,这样的设计使定制化和通用性共存,等积累到必定多样的训练集时能够将全部的训练集合到一块儿训练一个通用模型,亦能够彼此独立,每一个模型的叠加仅仅增长了少许的内存或显存,网上的方案大可能是不一样的模型单独部署一套服务,每一个进程加载了一整套TensorFlow框架势必是过于庞大和多余的。
用到批量识别需求的人相对少不少这里就不展开介绍了。可是这里给出一个12306的例子:
FieldParam: CorpParams: [ { "start_pos": [118, 0], "interval_size": [0, 0], "corp_num": [1, 1], "corp_size": [60, 30] }, { "start_pos": [5, 40], "interval_size": [5, 5], "corp_num": [4, 2], "corp_size": [66, 66] } ] OutputCoord: True
该参数能够用于大图的裁剪组成一批小图做为一个批次的输入,改用法能够避免屡次调用。
可是识别项目提供了多套可选的服务有:gRPC,Flask,Tornado,Sanic,其中Flask和Tornado提供了加密接口,相似于微信公众号开发接口的SecretKey和AccessKey接口,感兴趣的能够在demo.py中阅读调用源码了解。
部署的使用能够通过package.py编译为可执行文件,这样能够免去更换机器环境安装的烦恼,部署项目安装流程同训练项目,项目中提供的requirements.txt已经将所需的依赖都列清楚了,强烈建议部署项目安装cpu版TensorFlow。
本项目部署推荐使用Tornado版,功能最齐全,性能最为稳定。
Linux:
# 端口 19952 python3 tornado_server.py
# 方案1,裸启动, 端口 19951 python flask_server.py # 方案2,使用gunicorn,端口 5000 pip install gunicorn gunicorn -c deploy.conf.py flask_server:app
# 端口 19953 python3 sanic_server.py
# 端口 50054 python3 grpc_server.py
# 前台运行 ./captcha_platform_tornado #后台运行 nohup ./captcha_platform_tornado &
Windows:
Windows平台下都是经过python3 xxx_server.py
启动对应的服务,注意,Tornado、Flask、Sanic的性能在Windows平台都大打折扣,gRPC是Google开源的RPC服务,有较为优越的性能。
编译版直接运行编译后的exe可执行文件便可。
1. Tornado服务:
请求地址 | Content-Type | 参数形式 | 请求方法 |
---|---|---|---|
http://localhost:19952/captcha/v1 | application/json | JSON | POST |
具体参数:
参数名 | 必选 | 类型 | 说明 |
---|---|---|---|
image | Yes | String | Base64 编码 |
model_name | No | String | 模型名,yaml配置中可绑定 |
need_color | No | String | 颜色过滤,black/red/blue/yellow/green/white |
output_split | No | String | 多标签分割字符 |
请求为JSON格式,形如:{"image": "base64编码后的图像二进制流"}
返回结果:
参数名 | 类型 | 说明 |
---|---|---|
message | String | 识别结果或错误消息 |
code | String | 状态码 |
success | String | 是否请求成功 |
该返回为JSON格式,形如:{"message": "xxxx", "code": 0, "success": true}
2. Flask服务:
请求地址 | Content-Type | 参数形式 | 请求方法 |
---|---|---|---|
http://localhost:19951/captcha/v1 | application/json | JSON | POST |
请求参数和返回格式同上
3. Sanic服务:
请求地址 | Content-Type | 参数形式 | 请求方法 |
---|---|---|---|
http://localhost:19953/captcha/v1 | application/json | JSON | POST |
请求参数和返回格式同上
4. gRPC服务:
须要安装依赖,grpcio、grpcio_tools和对应的grpc.proto文件,能够直接从项目中的示例代码demo.py中提取。
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. ./grpc.proto
grpcio、grpcio_tools 是根据 grpc.proto 使用上述命令生成的。
class GoogleRPC(object): def __init__(self, host: str): self._url = '{}:50054'.format(host) self.true_count = 0 self.total_count = 0 def request(self, image, model_type=None, model_site=None): import grpc import grpc_pb2 import grpc_pb2_grpc channel = grpc.insecure_channel(self._url) stub = grpc_pb2_grpc.PredictStub(channel) response = stub.predict(grpc_pb2.PredictRequest( image=image, split_char=',', model_type=model_type, model_site=model_site )) return {"message": response.result, "code": response.code, "success": response.success} if __name__ == '__main__': result = GoogleRPC().request("base64编码后的图片二进制流") print(result)
该项目还能够直接用于识别带颜色的验证码,部署项目middleware/impl/color_extractor.py基于k-means实现了颜色分离模块,可用于处理以下形式的验证码:
还有一种方案是同时预测验证码和每一个字符对应的颜色,不过这须要修改现有的神经网络进行支持,在最后一层修改成双输出,一个输出颜色,一个输出对应字符,这对于样本标注的要求较高,也提升的成本,因此若是能用无限生成样本,那问题就迎刃而解了,好比上图,笔者就写了样本生成代码,感兴趣的能够移步:
https://www.jianshu.com/p/da1b972e24f2
其实还有不少不少技巧,例如,用生成的样本代替训练集,其实网上的图片验证码大可能是采用开源的,稍做修改而已,大多数状况都能被近似生成出来,上述展现的验证码图片不表明任何实际的网站,若有雷同,纯属巧合,该项目只能用于学习和交流用途,不得用于非法用途。
若是文章描述不够详尽或须要技术支持的,能够加群 857149419 咨询,或在开源项目中提issue,很荣幸能为开源社区贡献绵薄之力。