yolo系列理论学习
pytorch版本yolov4-tiny实操
实操视频讲解
学完以上内容应该能掌握yolov4-tiny模型结构和数据处理方式
1、下载基于darknet框架的yolov4-tiny模型和权重
找到yolov4-tiny.cfg和yolov4-tiny.weight并下载
2、下载darknet转换caffe的代码
3、下载跑caffe推理的代码
4、打开模型可视化,把yolov4-tiny.cfg放进去,可以看到整个模型结构。
5、新建文本文档命名为 yolov4-tiny.prototxt,根据可视化模型来一步步构建caffe版本,也就38层,不多。
name: "yolov4-tiny"
input: "data"
input_dim: 1
input_dim: 3
input_dim: 416
input_dim: 416
layer {
bottom: "data"
top: "layer1-conv"
name: "layer1-conv"
type: "Convolution"
convolution_param {
num_output: 32
kernel_size: 3
pad: 1
stride: 2
bias_term: false
}
}
layer {
bottom: "layer1-conv"
top: "layer1-conv"
name: "layer1-bn"
type: "BatchNorm"
batch_norm_param {
use_global_stats: true
}
}
layer {
bottom: "layer1-conv"
top: "layer1-conv"
name: "layer1-scale"
type: "Scale"
scale_param {
bias_term: true
}
}
layer {
bottom: "layer1-conv"
top: "layer1-conv"
name: "layer1-act"
type: "ReLU"
relu_param {
negative_slope: 0.1
}
}
layer {
bottom: "layer36-conv"
top: "layer37-conv"
name: "layer37-conv"
type: "Convolution"
convolution_param {
num_output: 255
kernel_size: 1
pad: 0
stride: 1
bias_term: true
}
}
layer {
bottom: "layer3-conv"
top: "layer4-unuse"
top: "layer4-route"
name: "layer4-route"
type: "Slice"
slice_param {
slice_point: 32
}
}
layer {
bottom: "layer6-conv"
bottom: "layer5-conv"
top: "layer7-route"
name: "layer7-route"
type: "Concat"
}
layer {
bottom: "layer9-route"
top: "layer10-maxpool"
name: "layer10-maxpool"
type: "Pooling"
pooling_param {
pool: MAX
kernel_size: 2
stride: 2
}
}
layer {
bottom: "layer33-conv"
top: "layer34-upsample"
name: "layer34-upsample"
type: "Upsample"
upsample_param {
scale: 2
}
}
就这样一层层照着可视化模型往下写caffe模型,layer31和layer38为yolo输出层,这里不定义,后面再做数据处理。
docker pull bvlc/caffe:cpu
sh docker_caffe.sh
docker_caffe.sh内容如下,修改darknet2caffe的路径,(推荐https://github.com/lwplw/darknet2caffe下的转换代码,不依赖pytorch,不用在容器里装额外环境)
#/bin/bash
export MY_CONTAINER="caffe_1.0.0"
num=`docker ps -a|grep "$MY_CONTAINER"|wc -l`
echo $num
echo $MY_CONTAINER
if [ 0 -eq $num ];then
xhost +
docker run --net=host --pid=host -it --privileged --name $MY_CONTAINER -v darknet2caffe的路径:/映射到docker里的路径 \
bvlc/caffe:cpu /bin/bash
else
docker start $MY_CONTAINER
#sudo docker attach $MY_CONTAINER
docker exec -ti $MY_CONTAINER /bin/bash
fi
容器里的caffe路径在/opt/caffe里
1、复制 caffe_layers/upsample_layer/upsample_layer.hpp 到 include/caffe/layers/
2、复制 caffe_layers/upsample_layer/upsample_layer.cpp和upsample_layer.cu 到 src/caffe/layers/
3、在src/caffe/proto/caffe.proto添加如下语句
message LayerParameter {
(略)
optional UpsampleParameter upsample_param = 149; //added for Yolo, make sure this id 149 not the same as before.
}
// added for Yolo
message UpsampleParameter{
optional int32 scale = 1 [default = 1];
}
//如果是Docker容器里
cd /opt/caffe/build
cmake ..
make all -j12
//也可以按需修改CMakeList文件,比如只用cpu
caffe_root='/opt/caffe/'
def darknet2caffe(cfgfile, weightfile, protofile, caffemodel):
#net_info = cfg2prototxt(cfgfile)
#save_prototxt(net_info , protofile, region=False)
net = caffe.Net(protofile, caffe.TEST)
params = net.params
python darknet2caffe.py cfg/yolov4-tiny.cfg weights/yolov4-tiny.weights prototxt/yolov4-tiny.prototxt caffemodel/yolov4-tiny.caffemodel
# build C/C++ interface
include_directories(${PROJECT_INCLUDE_DIR} ${GIE_PATH}/include)
include_directories(${PROJECT_INCLUDE_DIR}
/home/chen/caffe/include
/home/chen/caffe/build/include
#改成自己caffe路径,编译有问题的话还能加上自己的anaconda/include路径
)
cuda_add_library(yolov3-plugin SHARED ${inferenceSources})
target_link_libraries(yolov3-plugin
/home/chen/caffe/build/lib/libcaffe.so
/usr/lib/x86_64-linux-gnu/libglog.so
/usr/lib/x86_64-linux-gnu/libgflags.so.2
/usr/lib/x86_64-linux-gnu/libboost_system.so
/usr/lib/x86_64-linux-gnu/libGLEW.so.1.13
#改成自己电脑里能找到的路径,有的.so.数字不一样,有的没安装就安装
)
// forward
m_net->Forward();
for(int i =2;i<m_net->(num_outputs()-1);++i){
m_blobs.push_back(m_net->output_blobs()[i]);
//LOG(INFO) << "w" << m_net->output_blobs()[i]->width();
//LOG(INFO) << "h" << m_net->output_blobs()[i]->height();
//LOG(INFO) << "c" << m_net->output_blobs()[i]->channel();
}
cd caffe-yolov3
mkdir build
cd build
cmake ..
make -j6
./x86_64/bin/demo ../prototxt/yolov4-tiny.prototxt ../caffemodel/yolov4-tiny.caffemodel ../images/dog.jpg
参考Caffe中BN层与CONV层的融合(merge_bn)
对代码做了点小改动,因为最后一层conv没有bn
import caffe
import os
import numpy as np
import google.protobuf as pb
import google.protobuf.text_format
# choose your source model and destination model
WEIGHT = './yolov4-tiny.caffemodel'
MODEL = './yolov4-tiny.prototxt'
DEPLOY_MODEL = './yolov4-tiny.prototxt'
# set network using caffe api
caffe.set_mode_cpu()
net = caffe.Net(MODEL, WEIGHT, caffe.TRAIN)
dst_net = caffe.Net(DEPLOY_MODEL, caffe.TEST)
with open(MODEL) as f:
model = caffe.proto.caffe_pb2.NetParameter()
pb.text_format.Parse(f.read(), model)
# go through source model
for i, layer in enumerate(model.layer):
if layer.type == 'Convolution':
# extract weight and bias in Convolution layer
name = layer.name
if 'fc' in name:
dst_net.params[name][0].data[...] = net.params[name][0].data
dst_net.params[name][1].data[...] = net.params[name][1].data
break
w = net.params[name][0].data
batch_size = w.shape[0]
try:
b = net.params[name][1].data
except:
b = np.zeros(batch_size)
try:
# extract mean and var in BN layer
bn = name[:-4]+'bn'
mean = net.params[bn][0].data
var = net.params[bn][1].data
scalef = net.params[bn][2].data
if scalef != 0:
scalef = 1. / scalef
mean = mean * scalef
var = var * scalef
# extract gamma and beta in Scale layer
scale = name[:-4]+'scale'
gamma = net.params[scale][0].data
beta = net.params[scale][1].data
# merge bn
tmp = gamma/np.sqrt(var+1e-5)
w = np.reshape(tmp, (batch_size, 1, 1, 1))*w
b = tmp*(b-mean)+beta
except:
print("nothing")
# store weight and bias in destination net
dst_net.params[name][0].data[...] = w
try:
dst_net.params[name][1].data[...] = b
except:
try:
net.params[scale][1].data[...] = b
dst_net.params[name].extend([net.params[scale][1]])
except:
print("nothing")
dst_net.save('yolov4-tiny-mergeBN.caffemodel')
对prototxt就手动修改一下,删除 BatchNorm 和 Scale,在 Convolution 中将 bias_term 设为 true
layer {
bottom: "data"
top: "layer1-conv"
name: "layer1-conv"
type: "Convolution"
convolution_param {
num_output: 32
kernel_size: 3
pad: 1
stride: 2
bias_term: true
}
}
layer {
bottom: "layer1-conv"
top: "layer1-conv"
name: "layer1-act"
type: "ReLU"
relu_param {
negative_slope: 0.1
}
}