基于darknet实现mobilenet
基于darknet框架实现DepthwiseConvolutional层
深度学习(七十)darknet 实现编写mobilenet源码
下载
git clone https://github.com/eric612/MobileNet-YOLO
严格按照以下教程安装即可,注意 Opencv 版本
MobileNet-YOLO 安装教程
训练过程基本与MobileNet-SSD类似,只需配置好网络文件中的路径即可
以 yolov2 为例
labelmap_voc_cucumber.prototxt 修改内容:
item {
name: "none_of_the_above"
label: 0
display_name: "background"
}
item {
name: "sea cucumber"
label: 1
display_name: "cucumber"
}
create_list_cucumber.sh 修改内容:
root_dir=$HOME/MobileNet-YOLO/data/VOCdevkit/ # 修改此处
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 cucumber # 修改此处
create_data_cucumber.sh 修改内容:
data_root_dir="$HOME/MobileNet-YOLO/data/VOCdevkit"
dataset_name="cucumber"
mapfile="$root_dir/data/$dataset_name/labelmap_voc_cucumber.prototxt"
在 home/chris/MobileNet-YOLO/models/yolov2/ 目录下,修改mobilenet_yolo_solver.prototxt,mobilenet_yolo_test.prototxt 和 mobilenet_yolo_train.prototxt 文件
mobilenet_yolo_test.prototxt :
data_param {
source: "/home/chris/MobileNet-YOLO/data/VOCdevkit/cucumber/lmdb/cucumber_test_lmdb/"
batch_size: 1
backend: LMDB
}
annotated_data_param {
batch_sampler {
}
label_map_file: "/home/chris/MobileNet-YOLO/data/cucumber/labelmap_voc_cucumber.prototxt"
}
... ...
# 跳到最后
... ...
# 跟 darknet 下的 cfg 文件一样,将输出层的 num_output 和 classes 根据自己的情况修改
layer {
name: "conv22_indoor"
type: "Convolution"
bottom: "conv17"
top: "conv22"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 30 # 修改这里,若是yolov3,classes=1时,num_output = 18
kernel_size: 1
pad: 0
stride: 1
weight_filler {
type: "msra"
}
bias_filler {
value: 0
}
}
}
layer {
name: "conv23_indoor"
type: "Convolution"
bottom: "conv20"
top: "conv23"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 30 # 修改这里
kernel_size: 1
pad: 0
stride: 1
weight_filler {
type: "msra"
}
bias_filler {
value: 0
}
}
}
layer {
name: "detection_out"
type: "YoloDetectionOutput"
bottom: "conv22"
bottom: "conv23"
top: "detection_out"
include {
phase: TEST
}
yolo_detection_output_param {
num_classes: 1 # 修改这里
coords: 4
confidence_threshold: 0.25
nms_threshold: 0.45
biases: 1.08
biases: 1.19
biases: 3.42
biases: 4.41
biases: 6.63
biases: 11.38
biases: 9.42
biases: 5.11
biases: 16.62
biases: 10.52
}
}
layer {
name: "detection_eval"
type: "DetectionEvaluate"
bottom: "detection_out"
bottom: "label"
top: "detection_eval"
include {
phase: TEST
}
detection_evaluate_param {
num_classes: 2 # 修改这里( 背景 + 1 )
background_label_id: 0
overlap_threshold: 0.5
evaluate_difficult_gt: false
}
}
mobilenet_yolo_train.prototxt:
data_param {
source: "/home/chris/MobileNet-YOLO/data/VOCdevkit/cucumber/lmdb/cucumber_trainval_lmdb/"
batch_size: 2 # 调小,不然 CPU 内存不够用
backend: LMDB
}
annotated_data_param {
yolo_data_type : 1
yolo_data_jitter : 0.3
label_map_file: "/home/chris/MobileNet-YOLO/data/cucumber/labelmap_voc_cucumber.prototxt"
}
... ...
# 跳到最后
... ...
layer {
name: "conv22_indoor"
type: "Convolution"
bottom: "conv17"
top: "conv22"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 30 # 修改这里
kernel_size: 1
pad: 0
stride: 1
weight_filler {
type: "msra"
}
bias_filler {
value: 0
}
}
}
layer {
name: "conv23_indoor"
type: "Convolution"
bottom: "conv20"
top: "conv23"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 30 # 修改这里
kernel_size: 1
pad: 0
stride: 1
weight_filler {
type: "msra"
}
bias_filler {
value: 0
}
}
}
layer {
name: "Region_Loss1"
type: "RegionLoss"
bottom: "conv22"
bottom: "label"
top: "det_loss1"
loss_weight: 1
region_loss_param {
side: 13
num_class: 1 # 修改这里
coords: 4
num: 5
softmax: 1
jitter: 0.2
rescore: 1
object_scale: 5.0
noobject_scale: 1.0
class_scale: 1.0
coord_scale: 1.0
absolute: 1
thresh: 0.6
random: 0
biases: 1.08
biases: 1.19
biases: 3.42
biases: 4.41
biases: 6.63
biases: 11.38
biases: 9.42
biases: 5.11
biases: 16.62
biases: 10.52
}
}
layer {
name: "Region_Loss2"
type: "RegionLoss"
bottom: "conv23"
bottom: "label"
top: "det_loss2"
loss_weight: 1
region_loss_param {
side: 13
num_class: 1 # 修改这里
coords: 4
num: 5
softmax: 1
jitter: 0.2
rescore: 1
mobilenet_yolo_solver.prototxt:
train_net: "models/yolov2/mobilenet_yolo_train.prototxt"
test_net: "models/yolov2/mobilenet_yolo_test.prototxt"
test_iter: 4952
test_interval: 1000
base_lr: 0.0005
display: 10
max_iter: 120000
lr_policy: "multistep"
gamma: 0.5
weight_decay: 0.00005
snapshot: 1000
snapshot_prefix: "models/yolov2/mobilenet_yolo_deploy"
solver_mode: CPU # 修改为 CPU
debug_info: false
snapshot_after_train: true
test_initialization: false
average_loss: 10
stepvalue: 20000
stepvalue: 60000
iter_size: 1 # 修改为 1
type: "RMSProp"
eval_type: "detection"
ap_version: "11point"
show_per_class_result: true
返回至 MobileNet-YOLO 目录下,运行以下命令即可
sh train_yolo.sh
train_yolo.sh:去掉使用 GPU
#!/bin/bash
LOG=log/train-`date +%Y-%m-%d-%H-%M-%S`.log
./build/tools/caffe train --solver models/yolov2/mobilenet_yolo_solver.prototxt --weights models/MobileNet/mobilenet_iter_73000.caffemodel
修改网络结构时,注意卷积层间的链接,同时可将网络可视化以便于观察
# caffe网络可视化工具
http://ethereon.github.io/netscope/#/editor
注意:
layer {
name: "conv3/relu"
type: "ReLU"
bottom: "conv3"
top: "conv3"
}
layer {
name: "conv6/dw"
type: "DepthwiseConvolution"
bottom: "conv3" # 注意此处
top: "conv6/dw"
param {
lr_mult: 0.1
decay_mult: 0.1
}
小技巧:以上网络结构修改时也可使用 caffe 可视化工具辅助检查
比如:修改 num_output 时,即修改两个紫色层
安装的 CPU 版本,编译时 Opencv 报错,又卸载了原本安装的3.3.0,改为教程里的3.3.1 编译正常通过。
caffe_option(CPU_ONLY "Build Caffe without CUDA support" ON) # OFF 修改为 ON
caffe_option(USE_CUDNN "Build Caffe with cuDNN library support" OFF IF NOT CPU_ONLY)
caffe_option(USE_NCCL "Build Caffe with NCCL library support" OFF)
caffe_option(BUILD_SHARED_LIBS "Build shared libraries" ON)
caffe_option(BUILD_python "Build Python wrapper" ON)
set(python_version "2" CACHE STRING "Specify which Python version to use")
caffe_option(BUILD_matlab "Build Matlab wrapper" OFF IF UNIX OR APPLE)
caffe_option(BUILD_docs "Build documentation" ON IF UNIX OR APPLE)
caffe_option(BUILD_python_layer "Build the Caffe Python layer" ON)
caffe_option(USE_OPENCV "Build with OpenCV support" ON)
caffe_option(USE_LEVELDB "Build with levelDB" OFF)
caffe_option(USE_LMDB "Build with lmdb" ON)
caffe_option(ALLOW_LMDB_NOLOCK "Allow MDB_NOLOCK when reading LMDB files (only if necessary)" OFF)
caffe_option(USE_OPENMP "Link with OpenMP (when your BLAS wants OpenMP and you get linker errors)" OFF)
cd build
make uninstall
cd ..
sudo rm -r build
sudo rm -r /usr/local/include/opencv2 /usr/local/include/opencv /usr/include/opencv /usr/include/opencv2 /usr/local/share/opencv /usr/local/share/OpenCV /usr/share/opencv /usr/share/OpenCV /usr/local/bin/opencv* /usr/local/lib/libopencv
解决方法:仔细查看prototxt文件里面的各种路径
原因:CPU内存不足,将 batch_size 调小即可
参考:caffe调参中的batch_size和iter_size
报错内容:Check failed: target_blobs.size() == source_layer.blobs_size() (2 vs. 1) Incompatible number of blobs for layer conv0
原因分析:bias_term: false
The problem is with your bias term in conv1. In your train.prototxt it is set to false. But in your deploy.prototxt it is not and by default that is true. That is why weight loader is looking for two blobs.
解决办法:将 deploy.prototxt 中提示报错的层的 bias term = false
报错内容:图像中目标物体标签为 aeroplane,而不是自己设置的标签
原因分析:拆看脚本文件可知,他利用的是编译得到的 ssd_detect 进行检测的
./build/examples/ssd/ssd_detect models/yolov3_x/mobilenet_yolov3_lite_deploy.prototxt models/yolov3_x/mobilenet_yolov3_lite_deploy.caffemodel
但是在 MobileNet-YOLO/examples/ssd/ssd_detect.cpp 文件中,规定的类如下:
char* CLASSES[81] = { "__background__",
"person", "bicycle", "car", "motorcycle",
"airplane", "bus", "train", "truck", "boat",
"traffic light", "fire hydrant", "stop sign", "parking meter",
"bench", "bird", "cat",
"dog", "horse", "sheep", "cow",
"elephant", "bear", "zebra", "giraffe" ,
"backpack", "umbrella", "handbag", "tie" ,
"suitcase", "frisbee", "skis", "snowboard" ,
"sports ball", "kite", "baseball bat", "baseball glove" ,
"skateboard", "surfboard", "tennis racket", "bottle" ,
"wine glass", "cup", "fork", "knife" ,
"spoon", "bowl", "banana", "apple" ,
"sandwich", "orange", "broccoli", "carrot" ,
"hot dog", "pizza", "donut", "cake" ,
"chair", "couch", "potted plant", "bed" ,
"dining table", "toilet", "tv", "laptop" ,
"mouse", "remote", "keyboard", "cell phone" ,
"microwave", "oven", "toaster", "sink" ,
"refrigerator", "book", "clock", "vase" ,
"scissors", "teddy bear", "hair drier", "toothbrush" ,
};
#else
char* CLASSES[21] = { "__background__",
"aeroplane", "bicycle", "bird", "boat",
"bottle", "bus", "car", "cat", "chair",
"cow", "diningtable", "dog", "horse",
"motorbike", "person", "pottedplant",
"sheep", "sofa", "train", "tvmonitor" };
#endif
因此,需将该文件中的类修改为自己的类别后,重新编译即可。