參考自:
https://blog.csdn.net/weixin_39750664/article/details/82502302
目錄
1.把labelmap_voc.prototxt複製到工程文件下
3.將labelmap_voc .prototxt改名爲labelmap.prototxt
4.將VOC2007_test_lmdb改名爲test_lmdb
5.將VOC2007_trainval_lmdb改名爲trainval_lmdb
8.進入examples文件夾,打開編輯MobilNetSSD_train.prototxt(MobileNetSSD_test.prototxt文件類似地方也改下)
1.下載Mobilnet ssd
git下載:
git clone https://github.com/chuanqi305/MobileNet-SSD.git
網站下載:https://github.com/chuanqi305/MobileNet-SSD
2.製作VOC數據集
目錄結構是這樣的
|--VOCseahorse
|--VOC2007
|--Annotations
|--ImageSets
|--Layout
|--Main
|--Segmentation
|--JPEGImages
·這裏解釋下Annotations是放xml的,就是放置標註(物體位置 類別)好了的文件,用的labelImg軟件標註的。
·ImageSets下面的Main放的是文本,裏面有4個文件 test.txt val,txt train.txt trainval.txt,分別爲測試圖片,驗證圖片,訓練圖片,訓練驗證圖片的文件名。其他Layout和Segmentation佔時用不到,可以放Main中一樣的文件進去。
·JPEGImages是放置圖片的
這個目錄結構的文件我會提供,裏面也包含了標註好的圖片。下面說說如何製作。
我修改過的工程文件:https://download.csdn.net/download/ourkix/12076480
標註軟件下載:https://github.com/tzutalin/labelImg
我用的編譯好的,上面的是源碼,你們也可以去下載編譯好的。
想知道如何標註,可以自己查查 研究研究,比較簡單,看看應該會(就選好圖片文件夾路徑,右鍵選擇方框,左鍵拉框,標上label值,保存xml文件即可)
這裏默認標定好了數據 xml放入到annotations文件夾裏面了。
按照上面的目錄結構建立好文件夾,去到caffe的根目錄,切換到data/VOC0712/,將裏面的create_data.sh create_list.sh labelmap_voc.prototxt文件複製到你建立的目錄的VOC2007下面
接下來進入imagesets文件夾的main
修改 test.txt 和 trainval.txt文件
trainval是要訓練的圖片,test是測試圖片,這裏直接填上圖片的名字就行了。圖片多的話可以用腳本來生成。
修改create_list.sh
#!/bin/bash
#你數據的路徑
root_dir=$HOME/caffe/caffe-ssd/data/VOCseahorse
sub_dir=ImageSets/Main
bash_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
for dataset in trainval test
do
dst_file=$bash_dir/$dataset.txt
if [ -f $dst_file ]
then
rm -f $dst_file
fi
for name in VOC2007
do
if [[ $dataset == "test" && $name == "VOC2012" ]]
then
continue
fi
echo "Create list for $name $dataset..."
dataset_file=$root_dir/$name/$sub_dir/$dataset.txt
img_file=$bash_dir/$dataset"_img.txt"
cp $dataset_file $img_file
sed -i "s/^/$name\/JPEGImages\//g" $img_file
sed -i "s/$/.jpg/g" $img_file
label_file=$bash_dir/$dataset"_label.txt"
cp $dataset_file $label_file
sed -i "s/^/$name\/Annotations\//g" $label_file
sed -i "s/$/.xml/g" $label_file
paste -d' ' $img_file $label_file >> $dst_file
rm -f $label_file
rm -f $img_file
done
# Generate image name and size infomation.
if [ $dataset == "test" ]
then
$HOME/caffe/caffe-ssd/build/tools/get_image_size $root_dir $dst_file $bash_dir/$dataset"_name_size.txt"
fi
# Shuffle trainval file.
if [ $dataset == "trainval" ]
then
rand_file=$dst_file.random
cat $dst_file | perl -MList::Util=shuffle -e 'print shuffle(<STDIN>);' > $rand_file
mv $rand_file $dst_file
fi
done
修改create_data.sh
cur_dir=$(cd $( dirname ${BASH_SOURCE[0]} ) && pwd )
#咖啡根目錄路徑
root_dir=$HOME/caffe/caffe-ssd
cd $root_dir
redo=1
#你的數據的路徑
data_root_dir="$HOME/caffe/caffe-ssd/data/VOCseahorse"
dataset_name="VOC2007"
#labelmap路徑
mapfile="$root_dir/data/VOCdevkits/$dataset_name/labelmap_voc.prototxt"
anno_type="detection"
db="lmdb"
min_dim=0
max_dim=0
width=300 #0
height=300 #0
extra_cmd="--encode-type=jpg --encoded"
if [ $redo ]
then
extra_cmd="$extra_cmd --redo"
fi
for subset in test trainval
do
python $root_dir/scripts/create_annoset.py --anno-type=$anno_type --label-map-file=$mapfile --min-dim=$min_dim --max-dim=$max_dim --resize-width=$width --resize-height=$height --check-label $extra_cmd $data_root_dir $root_dir/data/VOCseahorse/$dataset_name/$subset.txt $data_root_dir/$dataset_name/$db/$dataset_name"_"$subset"_"$db examples/$dataset_name
done
#如果你路基不同的話 上面這裏面的路徑也要改
修改labelmap_voc.prototxt文件(背景層爲0,有幾個類就寫幾個item)
item {
name: "none_of_the_above"
label: 0
display_name: "background"
}
item {
name: "seahorse"
label: 1
display_name: "seahorse"
}
修改好後,生成lmdb數據庫
chmod +x creat_list.sh creat_data.sh
./creat_list.sh
./creat_data.sh
執行完成後會創建出lmdb文件夾進入此文件夾
訓練前準備
1.把labelmap_voc.prototxt複製到工程文件下
2.把上面兩個lmdb數據庫複製到工程下
3.將labelmap_voc .prototxt改名爲labelmap.prototxt
4.將VOC2007_test_lmdb改名爲test_lmdb
5.將VOC2007_trainval_lmdb改名爲trainval_lmdb
6.如下圖
7.運行gen_model.sh腳本
執行命令:./gen_model.sh 2
數字爲類別數,注意,實際類別+1,有個默認的背景類
之後,生成examples文件夾,裏面的3個prototxt就是從模板生成的正式網絡定義,根據作者設置,其中的deploy文件是已經合併過bn層的,需要後面配套使用。
8.進入examples文件夾,打開編輯MobilNetSSD_train.prototxt(MobileNetSSD_test.prototxt文件類似地方也改下)
#找到這個,改成你自己的數據庫路徑
#batch_size 爲批量大小,根據自己的平臺內存大小來 4 和 8 都可以
data_param {
source: "trainval_lmdb/"
batch_size: 4
backend: LMDB
}
#找到這個,改成你自己的labelmap路徑
label_map_file: "/home/ubuntuq/mobilenet/MobileNet-SSD/labelmap.prototxt"
9.回到上一層目錄,編輯train.sh文件
/home/ubuntuq/caffe/caffe-ssd/build/tools/caffe 是你的caffe的路徑
solver="solver_train.prototxt" 這個是訓練參數文件
weights="mobilenet_iter_73000.caffemodel" 這個是預訓練模型
#!/bin/sh
if ! test -f example/MobileNetSSD_train.prototxt ;then
echo "error: example/MobileNetSSD_train.prototxt does not exist."
echo "please use the gen_model.sh to generate your own model."
exit 1
fi
mkdir -p snapshot
/home/ubuntuq/caffe/caffe-ssd/build/tools/caffe train -solver="solver_train.prototxt" \
-weights="mobilenet_iter_73000.caffemodel" \
-gpu 0
10.修改solver_train.prototxt文件
#訓練網絡的文件路徑
train_net: "example/MobileNetSSD_train.prototxt"
#基礎學習率
base_lr: 0.0005
display: 10
#最大訓練迭代次數
max_iter: 5000
lr_policy: "multistep"
gamma: 0.5
weight_decay: 0.00005
#訓練多少次一次快照
snapshot: 2500
#快照模型保存路徑
snapshot_prefix: "snapshot/mobilenet"
#訓練方式 GPU 還是 CPU
solver_mode: GPU
debug_info: false
snapshot_after_train: true
test_initialization: false
average_loss: 10
stepvalue: 20000
stepvalue: 40000
iter_size: 1
type: "RMSProp"
eval_type: "detection"
ap_version: "11point"
訓練
./train.sh
訓練完成後,運行檢測
如果下載我的上傳的文件,進入testmodel文件夾,裏面是我之前訓練好的,你把裏面的文件換成你自己的
deploy.prototxt文件是example文件夾裏面的MobileNetSSD_deploy.prototxt,複製過來改名即可
labelmap.prototxt就是我們之前改的那個,複製進來
mobilenet_iter_5000.caffemodel是訓練完的模型文件,在snapshot文件夾裏面複製過來
image裏面是測試圖片
裏面的demo.py也修改下。
import numpy as np
import sys,os
import cv2
#caffe路徑 根目錄
caffe_root = '/home/ubuntuq/caffe/caffe-ssd/'
sys.path.insert(0, caffe_root + 'python')
import caffe
#部署文件路徑
net_file= 'deploy.prototxt'
#模型文件路徑
caffe_model='mobilenet_iter_5000.caffemodel'
#測試圖片路徑
test_dir = "image"
if not os.path.exists(caffe_model):
print(caffe_model + " does not exist")
exit()
if not os.path.exists(net_file):
print(net_file + " does not exist")
exit()
net = caffe.Net(net_file,caffe_model,caffe.TEST)
#分類顯示名字修改
CLASSES = ('background',
'seahorse')
def preprocess(src):
img = cv2.resize(src, (300,300))
img = img - 127.5
img = img * 0.007843
return img
def postprocess(img, out):
h = img.shape[0]
w = img.shape[1]
box = out['detection_out'][0,0,:,3:7] * np.array([w, h, w, h])
cls = out['detection_out'][0,0,:,1]
conf = out['detection_out'][0,0,:,2]
return (box.astype(np.int32), conf, cls)
def detect(imgfile):
origimg = cv2.imread(imgfile)
img = preprocess(origimg)
img = img.astype(np.float32)
img = img.transpose((2, 0, 1))
net.blobs['data'].data[...] = img
out = net.forward()
box, conf, cls = postprocess(origimg, out)
#print("box is ",box)
for i in range(len(box)):
p1 = (box[i][0], box[i][1])
p2 = (box[i][2], box[i][3])
cv2.rectangle(origimg, p1, p2, (0,255,0))
p3 = (max(p1[0], 15), max(p1[1], 15))
#print("---",i)
title = "%s:%.2f" % (CLASSES[int(cls[i])], conf[i])
cv2.putText(origimg, title, p3, cv2.FONT_ITALIC, 0.6, (0, 255, 0), 1)
cv2.imshow("SSD", origimg)
k = cv2.waitKey(0) & 0xff
#Exit if ESC pressed
if k == 27 : return False
return True
for f in os.listdir(test_dir):
if detect(test_dir + "/" + f) == False:
break
測試(回車下一張,esc退出)
python demo.py
測試報錯解決
原因是caffe-ssd缺少了relu6層,要修改caffe源碼重新編輯就行了。
下載這兩個文件
下載地址:https://github.com/chuanqi305/MobileNetv2-SSDLite/tree/master/src
去到你的caffe根目錄,進入src/caffe/layers將這兩個文件複製進去覆蓋掉原來的文件。
然後去到你的caffe構建目錄,我的是build目錄
make -j4
make pycaffe
make install
完成後重新打開終端,運行demo.py