完整代码:https://download.csdn.net/download/weixin_55771290/87432778
项目基于darknet开发了一系列的快速启动脚本,旨在让图像识别新手或者开发人员能够快速的启动一个目标检测(定位)的项目。 如果有没有讲清楚的地方,欢迎提issue和PR,希望能和大家共同完善!
本项目分为两个部分:
- 提供两个目标检测(单分类和多分类点选验证码)的例子,你可以通过例子熟悉定位yolo3定位网络的使用方式
- 基于darknet提供一系列API,用于使用自己的数据进行目标检测模型的训练,并提供web server的代码
1.1项目结构
项目分为darknet、extent、app三部分
- darknet: 这部分是darknet项目源码,没有作任何改动。
- extent: 扩展部分,包含生成配置、生成样本、训练、识别demo、api程序。
- app: 每一个新的识别需求都以app区分,其中包含配置文件、样本和标签文件等。
1.2开始一个例子:单类型目标检测
以点选验证码为例 darknet实际上给我们提供了一系列的深度学习算法,我们要做的就是使用比较简单的步骤来调用darknet训练我们的识别模型。
推荐使用的操作系统是ubuntu,遇到的坑会少很多。
- 如果使用windowns系统,需要先安装cygwin,便于编译darknet。(参考我的博客:安装cygwin)
下面的步骤都已经通过ubuntu16.04测试。
1.下载项目
git clone https://github.com/nickliqian/darknet_captcha.git
2.编译darknet
进入darknet_captcha目录,下载darknet项目,覆盖darknet目录:
cd darknet_captcha git clone https://github.com/pjreddie/darknet.git
进入darknet目录,修改darknet/Makefile配置文件
1. cd darknet 2. vim Makefile
- 如果使用GPU训练则下面的GPU=1
- 使用CPU训练则下面的GPU=0
1. GPU=1 2. CUDNN=0 3. OPENCV=0 4. OPENMP=0 5. DEBUG=0
然后使用make编译darknet:
make
不建议使用CPU进行训练,因为使用CPU不管是训练还是预测,耗时都非常久。
如果你需要租用临时且价格低的GPU主机进行测试,后面介绍了一些推荐的GPU云服务。
如果在编译过程中会出错,可以在darknet的issue找一下解决办法,也可以发邮件找我要旧版本的darknet。
3.安装python3环境
使用pip执行下面的语句,并确保你的系统上已经安装了tk:
1. pip install -r requirement.txt 2. sudo apt-get install python3-tk
4.创建一个应用
进入根目录,运行下面的程序生成一个应用的基本配置:
1. cd darknet_captcha 2. python3 extend/create_app_config.py my_captcha 1
这里的类别默认生成classes_1,你可以修改类别名称;
打开app/my_captcha/my_captcha.names修改classes_1为主机想要的名称即可。
如何查看create_app_config.py的命令行参数解释?
直接运行python create_app_config.py便可以在控制台查看,下面的程序也是如此。
如果你对darknet相关配置有一定的了解,可以直接打开文件修改参数的值,这里我们保持原样即可。
5.生成样本
生成样本使用另外一个项目 nickliqian/generate_click_captcha
这里我已经集成进去了,执行下面的命令生成样本和对应标签到指定应用中yolo规定的目录:
python3 extend/generate_click_captcha.py my_captcha
运行python generate_click_captcha.py查看参数解释。
6.划分训练集和验证集
运行下面的程序,划分训练集和验证集,同时将标签的值转换为yolo认识的格式:
python3 extend/output_label.py my_captcha 1
这里填写的种类需要与上面一致。 运行python output_label.py查看参数解释。
7.开始训练
到这里,我们要准备的东西还差一样,我们需要下载darknet提供的预训练模型放在darknet_captcha目录下:
wget https://pjreddie.com/media/files/darknet53.conv.74
在darknet_captcha目录下,执行下面的命令开始训练:
./darknet/darknet detector train app/my_captcha/my_captcha.data app/my_captcha/my_captcha_train.yolov3.cfg darknet53.conv.74
训练过程中模型会每一百次迭代储存一次,储存在app/my_captcha/backup/下,可以进行查看。
8.识别效果
使用GTX 1060训练大概1.5小时,训练迭代到1000次,会有比较明显的效果。
我们找一张验证集的图片使用不同进度下的模型进行识别测试,执行下面的语句开始识别:
python3 extend/rec.py my_captcha 100
这里的100是选择app/my_captcha/images_data/JPEGImages目录下的第一百张图片进行识别。
运行python rec.py查看参数解释。
迭代300次:
迭代800次:
迭代1000次:
迭代1200次:
9.图片切割
这部分比较简单,网上有很多示例代码,可以调用darknet_interface.cut_and_save方法把定位到的字符切割下来。
10.分类器
到分类这一步就比较容易了,可以使用darknet自带的分类器,也可以使用cnn_captcha一个使用卷积神经网络识别验证码的项目。
11.总结
我们识别点选验证码的大致流程如下:
- 搜集样本
- 打标签(标注坐标和字符)
- 训练定位器
- 检测位置,切割图片
- 训练分类器
- 使用定位器+分类器识别点选验证码上字符的位置和字符类别
1.3第二个例子:多类型目标检测
步骤和上面基本上一致,直接把命令列出来:
# 生成配置文件python3extend/create_app_config.pydummy_captcha2# 生成图片python3extend/generate
2.训练自己的数据
下面的过程教你如何训练自己数据。
假定我们要创建一个识别路上的车和人的应用,因此类别数量为2。
假定你现在有一些原始图片,首先你需要给这些图片打上标签,推荐使用labelImg进行打标工作。
使用教程可以自行谷歌,软件界面大致如下:
给图片中的人和车分别打上person和car的标签,会生成xml标签文件。
接下来,我们创建一个应用,应用名称是car,类别为2类,同时生成一些配置文件:
python3 extend/create_app_config.py car 2
然后把你的原始图片放到指定的路径app/car/JPEGImages,把xml标签文件放在app/car/Annotations
yolo训练的时候需要图片中目标的相对坐标,所以这里需要把xml的坐标计算为相对坐标的形式。
同时car.data中需要分别定义训练集和验证集的样本路径,这里会划分出训练集和验证集,同时生成两个txt文件记录其路径。
python3 extend/output_label.py car 2
要提到的是,这里可以打开car.names,把里面的class_1和class_2分别修改为car和person,这里识别结果就会输出car和person。 然后就可以开始训练了:
./darknet/darknet detector train app/car/car.data app/car/car_train.yolov3.cfg darknet53.conv.74
识别测试和上面也没有上面区别:
1. # 识别测试 2. python3 extend/rec.py car 100
3.web服务
启动web服务:
python3 extend/web_server.py
启动前需要按需修改配置参数:
# 生成识别对象,需要配置参数app_name="car"# 应用名称config_file="app/{}/{}_train.yolov3.cfg".format(app_name,app_name)# 配置文件路径model_file="app/{}/backup/{}_train.backup".format(app_name,app_name)# 模型路径data_config_file="app/{}/{}.data".format(app_name,app_name)# 数据配置文件路径dr=DarknetRecognize(config_file=config_file,model_file=model_file,data_config_file=data_config_file)save_path="api_images"# 保存图片的路径
使用下面的脚本request_api.py进行web服务的识别测试(注意修改图片路径):
python3 extend/request_api.py
返回响应,响应包含目标类别和中心点位置:
接口响应:{"speed_time(ms)":16469,"time":"15472704635706885","value":[["word",0.9995613694190979,[214.47508239746094,105.97418212890625,24.86412811279297,33.40662384033203]],...}
4.项目说明
4.1使用阿里云OSS加速下载
如果你使用国外云主机进行训练,训练好的模型的下载速度确实是一个问题。
这里推荐使用阿里云oss,在云主机上把文件上传上去,然后使用oss下载下来。
配置秘钥:
# 从环境变量获取密钥AccessKeyId=os.getenv("AccessKeyId")AccessKeySecret=os.getenv("AccessKeySecret")BucketName=os.getenv("BucketName")
上传图片:
python3 extend/upload2oss.py app/my_captcha/images_data/JPEGImages/1_15463317590530567.jpg python3 extend/upload2oss.py text.jpg
4.2GPU云推荐
使用租用 vectordash GPU云主机,ssh连接集成了Nvidia深度学习环境的ubuntu16.04系统
包含以下工具或框架:
CUDA 9.0, cuDNN, Tensorflow, PyTorch, Caffe, Keras
vectordash提供了一个客户端,具备远程连接、上传和下载文件、管理多个云主机等。
下面是几种显卡的租用价格:
创建实例后,面板会提供一个秘钥,输入秘钥后,就可以使用客户端操作了:
# 安装客户端 pip install vectordash --upgrade # 登录 vectordash login # 列出主机 vectordash list # ssh登录 vectordash ssh <instance_id> # 打开jupyter vectordash jupyter <instance_id> # 上传文件 vectordash push <instance_id> <from_path> <to_path> # 下载文件 vectordash pull <instance_id> <from_path> <to_path>
由于vectordash主机在国外,所以上传和下载都很慢,建议临时租用一台阿里云竞价突发型实例(约7分钱一小时)作为中转使用。
4.3CPU和GPU识别速度对比
GTX 1060, 识别耗时1s
[load model] speed time: 4.691879987716675s [detect image - i] speed time: 1.002530813217163s
CPU, 识别耗时13s
1. [load model] speed time: 3.313053846359253s 2. [detect image - i] speed time: 13.256595849990845s
5.报错解决办法
- UnicodeEncodeError: 'ascii' codec can't encode character '\U0001f621' in posit
参考链接
- pip install, locale.Error: unsupported locale setting
参考链接
5.1错误描述及分析
最近跑程序遇到一个很神奇的问题,程序在输出的时候,前面都是正常的,但是中间同样的code在执行的时候却报错: UnicodeEncodeError: ‘ascii’ codec can’t encode character ‘\U0001f621’ in posit
在本地打印出’\U0001f621’,显示是一个愤怒的表情:
import sys sys.getdefaultencoding() 'utf-8' 但是同样的code,在服务器上就会报上面的错误; 一开始以为是读写文件的问题,改了超级久,所有编码都改成了utf8,还是不行; 而且提示是ascii,比较好奇这是哪里的编码…
5.2系统编码
报错的字符是一个Unicode字符,查了下发现是python3,只有str和Unicode两种编码,去查了python3的系统编码:
import sys sys.getdefaultencoding() 'utf-8' 1 2 3 4 系统编码就是utf8, 所以再去设置什么系统编码,文件开头加上‘# coding=utf8’ 对我的问题是没啥帮助;
5.3输入输出编码
既然不是系统编码,而且前面输出都没有问题,所以可能也不是之前读写文件的编码错误,可能是print的时候,也就是标准输入输出的时候编码问题了;那么print的时候做了什么,用的是什么编码呢? 我们已经知道在python3中,输出的时候,会把str/Unicode 变成utf8的编码;来看一下环境中的输出编码是什么:
import sys sys.stdout.encoding 'ANSI_X3.4-1968' 1 2 3 4 emmmm…..果然!!!居然是ansi…
5.4解决方法
这样看来应该就是输入输出print的锅了,那么如何解决呢? 也就是如何修改标准输出编码方式呢? 有如下解决方法:、
PYTHONIOENCODING 运行程序的时候加上: PYTHONIOENCODING=utf-8 python code.py
重新定义输出标准 import codecs sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach()) sys.stdout.write("Your content....")
5.5Python3 编码学习
默认读者已经了解编码/Unicode/utf8/ASCII/GBK 的基础知识和区别;
在最新的python 3版本中,字符串的类型是str, 在内存中都是以Unicode表示,一个字符对应若干个字节; 如果要在网络上传输,或者保存到磁盘上,就需要把str变为以字节为单位的bytes。
以Unicode表示的str通过encode()方法可以编码为指定的bytes,例如:
'ABC'.encode('ascii') b'ABC' '中文'.encode('utf-8') b'\xe4\xb8\xad\xe6\x96\x87' '中文'.encode('ascii') Traceback (most recent call last): File "", line 1, in UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
在操作字符串时,我们经常遇到str和bytes的互相转换。为了避免乱码问题,应当始终坚持使用UTF-8编码对str和bytes进行转换。
TODO
- 支持多类别检测的识别和训练 Done
- WebServer API调用 Done
- 分类器