用SSD訓練自己的資料集
1構建 資料集
先來看一下我們構建資料集合應該是什麼樣的,假設總資料為1000張。
為了方便,我們將資料放在/home/bingolwang/data 資料夾下。/home/bingolwang/data/VOCdevkit 這個目錄下是VOC2007
VOC2007/
|-- Annotations #1000個xml檔案。
|-- ImageSets
| `-- Main
| |-- test.txt #測試集
| `-- trainval.txt #訓練集
`-- JPEGImages #1000個jpg檔案
仔細看看 test.txt ,trainval.txt 這兩個檔案的格式,
test.txt
00002 #其實就是去掉了對應的 .jpg
00003
00100
00012
.....
trainval.txt #圖片的名字到底有什麼要求?不一定是6位碼,也不一樣定是從00000開始,只要
00000 #區分的開各個圖片即可
00001
00004
00005
.....
JPEGImages ,Annotations資料夾中的內容
#Annotations dir 下的內容
00000.xml
00001.xml
00002.xml
00003.xml
......xml
01000.xml
#JPEGImages dir 下的內容
00000.jpg
00001.jpg
00002.jpg
00003.jpg
......jpg
01000.jpg
在來看看xml中的內容,這舉例00005.xml。
<annotation>
<folder>images</folder>
<filename>00005.jpg</filename>
<source>
<database>bingolwangDataSet</database>
</source>
<size>
<width>435</width>
<height>363</height>
<depth>3</depth >
</size>
<object>
<name>Object</name>
<difficult>0</difficult>
<bndbox>
<xmin>37</xmin>
<ymin>318</ymin>
<xmax>428</xmax>
<ymax>358</ymax>
</bndbox>
</object>
</annotation>
注意:實際上在ssd官方(github:https://github.com/weiliu89/caffe/tree/ssd)的檔案中,使用的create_list.sh 建立了生成lmdb所需要的各種檔案。這裡,我們手動建立,因為根本用不了那麼複雜的指令碼。
create_data.sh 就是建立訓練輸入的lmdb。他的輸入是 labelmap_voc.prototxt | test.txt | trainval.txt ,這三個檔案。
還是得看一下,這三個檔案都是什麼格式。
# trainval.txt
VOC2007/JPEGImages/105df.jpg VOC2007/Annotations/105df.xml
VOC2007/JPEGImages/ww231.jpg VOC2007/Annotations/ww231.xml
VOC2007/JPEGImages/763005.jpg VOC2007/Annotations/763005.xml
#test.txt
VOC2007/JPEGImages/0b73.jpg VOC2007/Annotations/0b73.xml
VOC2007/JPEGImages/c5ccbe1.jpg VOC2007/Annotations/c5ccbe1.xml
VOC2007/JPEGImages/ec5f0.jpg VOC2007/Annotations/ec5f0.xml
VOC2007/JPEGImages/a0341.jpg VOC2007/Annotations/a0341.xml
#labelmap_voc.prototxt #single object
item {
name: "none_of_the_above"
label: 0
display_name: "background"
}
item {
name: "Object"
label: 1
display_name: "Object"
}
準備好了上述檔案,就可以git clone https://github.com/weiliu89/caffe/tree/ssd 編譯,然後到我們的caffe_root目錄下,找到data 下,然後看到 ILSVRC2016 VOC0712 cifar10 coco ilsvrc12 moist 這幾個資料夾,然後進入VOC0712 目錄下,可以看到 create_data.sh create_list.sh labelmap_voc.prototxt test.txt trainval.txt , 然後執行 create_data.sh 指令碼。
附件
–這個xml檔案是怎麼生成的。這裡推薦用python指令碼
#coding=utf-8
import os
from lxml import etree
import math
anno_file = "imageInfo.txt"
save_root = "/data1/user/bingolwang/data/VOCdevkit/VOC2007/Annotations/"
f = open(anno_file,'r')
for line in f:
data = line.strip().split(" ")
fname = data[0]
img_width = int(float(data[1]))
img_height = int(float(data[2]))
save_file = save_root + fname[:-3] + "xml"
fout = open(save_file, 'w')
# creat XML
root = etree.Element("annotation")
# folder info
folder = etree.SubElement(root, "folder")
folder.text = "GeneraOcr_WeiYun_Det_imgs"
# file name
filename = etree.SubElement(root, "filename")
filename.text = str(fname)
# source
source = etree.SubElement(root, "source")
database = etree.SubElement(source, "database")
database.text = "GeneraOcr_WeiYun_Det"
# image size
size = etree.SubElement(root, "size")
width = etree.SubElement(size, "width")
width.text = str(img_width)
height = etree.SubElement(size, "height")
height.text = str(img_height)
depth = etree.SubElement(size, "depth")
depth.text = "3"
# object
object_count = 2
while object_count < data.__len__():
object = etree.SubElement(root, "object")
name = etree.SubElement(object, "name")
name.text = "text"
difficult = etree.SubElement(object, "difficult")
difficult.text = "0"
bndbox = etree.SubElement(object, "bndbox")
xminv = max(1,int(float(data[object_count + 1])) + 1)
yminv = max(1,int(float(data[object_count + 2])) +1)
xmaxv = min(int(float(data[object_count + 3])) ,img_width-2)
ymaxv = min(int(float(data[object_count + 4])) ,img_height-2)
xmin = etree.SubElement(bndbox, "xmin")
xmin.text = str(xminv)
ymin = etree.SubElement(bndbox, "ymin")
ymin.text = str(yminv)
xmax = etree.SubElement(bndbox, "xmax")
xmax.text = str(xmaxv)
ymax = etree.SubElement(bndbox, "ymax")
ymax.text = str(ymaxv)
object_count += 5
ss = etree.tostring(root, encoding='utf8',pretty_print=True)
fout.write(ss.decode('utf-8'))
fout.close()
# source end
#s = etree.tostring(root, encoding='utf8',pretty_print=True)
#print(str(s))
f.close()
訓練自己的資料集時候報錯:
Check failed: background_label_id != label (0 vs. 0) “Found background label in the dataset.”
檢查失敗: background_label_id != label
但是現在二者相等(0 vs 0)
主要原因:在dataset的label中,發現了背景類
也就是某些圖片為純背景,而且 標註為 0
編譯器出錯:
json_parser_read.hpp:257:264: error: ‘type name’ declared as function returning an array escape
// 解決步驟:
// 1- vi /usr/include/boost/property_tree/detail/json_parser_read.hpp
// 2- 註釋掉 json_parser_read.hpp:257:264 之間的程式碼
// 3- 儲存。然後重新編譯即可。
// 出現這種情況的原因往往是由於: 我們的gcc 與cuda版本不匹配, 可以選擇升級gcc 或者降級 cuda,但是很麻煩。
執行時出錯:
Check failed: error == cudaSuccess (8 vs. 0) invalid device function
// 可能執行時候的cuda lib 與 編譯時候的 nvcc 版本對不上
// 或者 直接copy了一個已經在其他平臺上已經編譯好的cuda 但是本平臺與其他平臺的 gcc版本不一致。
訓練時loss為nan
兩種可能:
1 在生成lmdb的時候,沒有選擇設定尺寸。就是resize選項。
2 在已有的模型上finetune,沒有設定好學習率。