0 绪论
使用 caffe 的步骤:
(1) convert data(run a script)
(2) Define net(edit prototxt) 网络结构
(3) Define solver(edit prototxt) 超参数
(4) Train(witjh pretrained weights)(run a script)
1. 数据打包:VOC 格式,lmdb 封装
1.1构造VOC 格式数据集:图片,xml标注
VOC 含3个文件夹,Annotations、ImageSets、JPEGImages。其中Annotations存放xml格式的标注信息。ImageSets/Main目录存放文件名列表,train.txt、val.txt、test.txt。JPEGImages存放图片。
VOC 中的图片仅拷贝即可。而标注数据,将真值文件解析成xml格式。人脸业务调用:writexml(filename,saveimg,bboxes,xmlpath)。
xml文件采取节点-子节点的数据结构。
1.1.1 write_xml
from xml.dom.minidom import Document
(1)doc = Document() # 创建文件对象
(2)doc.createElement() # 用文件对象创建元素
(3)doc.createTextNode() # 用文件对象创建文本
(4)node.appendChild() # 在node之后追加对象
(5)node.setAttribute('A','B') # 节点内 A = "B"
(6)f.write(doc.toprettyxml()) # 写入xml文件
凡是写节点或者写文本,都要遵循先创建元素,再添加的步骤。
详情参考:https://www.cnblogs.com/wcwnina/p/7222180.html
1.1.2 解析原标注数据,生成VOC格式
从数据集提供的标注文件中,解析出 write_xml 函数所需的入参,按照 VOC 格式进行封装。
1.2修改数据打包脚本的相关路径并运行,获得lmdb
在路径 caffe-ssd/data/widerface 下:
(1)修改labelmap,VOC原本含21个类别,人脸业务含2个类别,人脸和背景
(2)修改文件 create_list.sh 并执行 :让 dataset_file 指向 Imageset/Main 下 trainval.txt 和 test.txt。对这两个列表文件进行随即排序、复制,在 widerface 这个目录下生成 trian.txt、test.txt 和 test_name_size.txt。
(3)修改文件 create_data.sh 并执行:让 mapfile 指向 caffe-ssd/data/widerface/labelmap_voc.prototxt。这个shell脚本执行了 caffe-ssd/scripts/create_annoset.py ,在存储原VOC格式数据的widerface文件夹下生成一个lmdb文件夹存放数据。
2. caffe 源码解读及优化
2.1 主干网络 : python/caffe/model_libs.py
这个文件中提供了多个定义主干网络结构的函数。
2.2 模型训练配置: examples/ssd/ssd_pascal.py
在 "# Create train/test net"之后,通过调用 model_libs.py 中的不同函数,选择主干网络结构。
2.3 模型优化:提速
(1)减小模型: 修改 model_libs.py 定义网络结构中每一层的输出大小。
(2)去掉一些卷积层
3. caffe-ssd 测试
(1) 测试网络模型需要使用:deploy.prototxt 、 face.caffemodel
(2) 实例化 caffe 模型:
net = caffe.Net(model_def,model_weight,caffe.TEST)
(3) 处理输入数据层:
image_data = caffe.io.load_image(img_path)
tranformer = caffe.io.Transformer({'data':net.blobs['data'].data.shape})
tranformer.set_transpose('data',(2,0,1))
tranformer.set_channel_swap('data',(2,1,0))
tranformer.set_mean('data',np.array([128,128,128]))
tranformer.set_raw_scale('data',255)
tranformer_image = tranformer.preprocess('data',image_data)
net.blobs['data'].reshape(1,3,300,300)
net.blobs['data'].data[...] = tranformer_image
(4) 解析并显示结果:
detect_out = net.forward()['detection_out']
# print(detect_out)
det_label = detect_out[0,0,:,1]
det_conf = detect_out[0,0,:,2]
det_xmin = detect_out[0,0,:,3]
det_ymin = detect_out[0,0,:,4]
det_xmax = detect_out[0,0,:,5]
det_ymax = detect_out[0,0,:,6]
top_indices = [i for i,conf in enumerate(det_conf) if conf >= 0]
top_conf = det_conf[top_indices]
top_xmin = det_conf[top_indices]
top_ymin = det_conf[top_indices]
top_xmax = det_conf[top_indices]
top_ymax = det_conf[top_indices]
[height,width,_] = image_data.shape
for i in range(min(5,top_conf.shape[0])):
xmin = int(top_xmin[i] * width)
ymin = int(top_ymin[i] * height)
xmax = int(top_xmax[i] * width)
ymax = int(top_ymax[i] * height)
cv2.rectangle(image_data,(xmin,ymin),(xmax,ymax),(255,0,0),2)
cv2.imshow("face",image_data)
cv2.waitKey(0)