https://github.com/ChenYingpeng/caffe-yolov3
原工程作者在TX2上实现将yolov3模型转换成caffemodel并调用。
1.修改为在Ubuntu16.04环境编译
CMakeLists.txt
主要修改交叉编译器为x86_64编译,修改自己的caffe路径(其中caffe.proto中增加upsample层),修改自己的opencv路径
cmake_minimum_required(VERSION 2.8)
project(sysDetectSpeed)
# setup tensorRT flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") # -std=gnu++11
set(BUILD_DEPS "YES" CACHE BOOL "If YES, will install dependencies into sandbox. Automatically reset to NO after dependencies are installed.")
# if this is the first time running cmake, perform pre-build dependency install script (or if the user manually triggers re-building the dependencies)
#if( ${BUILD_DEPS} )
# message("Launching pre-build dependency installer script...")
#
# execute_process(COMMAND sh ../CMakePreBuild.sh
# WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
# RESULT_VARIABLE PREBUILD_SCRIPT_RESULT)
# set(BUILD_DEPS "NO" CACHE BOOL "If YES, will install dependencies into sandbox. #Automatically reset to NO after dependencies are installed." FORCE)
# message("Finished installing dependencies")
#endif()
# Qt is used to load images (installed by ubuntu-desktop)
find_package(Qt4 REQUIRED)
include(${QT_USE_FILE})
add_definitions(${QT_DEFINITIONS})
# setup CUDA
find_package(CUDA)
set(
CUDA_NVCC_FLAGS
${CUDA_NVCC_FLAGS};
-O3
-gencode arch=compute_53,code=sm_53
-gencode arch=compute_62,code=sm_62
-gencode arch=compute_61,code=sm_61
)
# setup project output paths
set(PROJECT_OUTPUT_DIR ${PROJECT_BINARY_DIR}/${CMAKE_SYSTEM_PROCESSOR})
set(PROJECT_INCLUDE_DIR ${PROJECT_OUTPUT_DIR}/include)
file(MAKE_DIRECTORY ${PROJECT_INCLUDE_DIR})
file(MAKE_DIRECTORY ${PROJECT_OUTPUT_DIR}/bin)
message("-- system arch: ${CMAKE_SYSTEM_PROCESSOR}")
message("-- output path: ${PROJECT_OUTPUT_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_OUTPUT_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_OUTPUT_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_OUTPUT_DIR}/lib)
# build C/C++ interface
include_directories(${PROJECT_INCLUDE_DIR} ${GIE_PATH}/include)
include_directories(/usr/include/gstreamer-1.0 /usr/lib/x86_64-linux-gnu/gstreamer-1.0/include /usr/include/glib-2.0 /usr/include/libxml2 /usr/lib/x86_64-linux-gnu/glib-2.0/include/ /usr/local/cuda-8.0/extras/CUPTI/include)
include_directories(${PROJECT_INCLUDE_DIR}
/home/caffe/include
/home/caffe/build/include
/usr/local/include
/usr/local/cuda/include
/usr/include
)
file(GLOB inferenceSources *.cpp *.cu )
file(GLOB inferenceIncludes *.h )
cuda_add_library(sysDetectSpeed SHARED ${inferenceSources})
target_link_libraries(sysDetectSpeed nvcaffe_parser nvinfer Qt4::QtGui GL gstreamer-1.0 gstapp-1.0) #GLEW # gstreamer-0.10 gstbase-0.10 gstapp-0.10
target_link_libraries(sysDetectSpeed
/home/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
)
# transfer all headers to the include directory
foreach(include ${inferenceIncludes})
message("-- Copying ${include}")
configure_file(${include} ${PROJECT_INCLUDE_DIR} COPYONLY)
endforeach()
# create symbolic link for network data
execute_process( COMMAND "${CMAKE_COMMAND}" "-E" "create_symlink" "${PROJECT_SOURCE_DIR}/data/networks" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/networks" )
# copy image data
file(GLOB imageData ${PROJECT_SOURCE_DIR}/data/images/*)
foreach(image ${imageData})
message("-- Copying ${image}")
file(COPY ${image} DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
#configure_file(${include} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} COPYONLY)
endforeach()
add_subdirectory(detectnet)
#setup opencv
FIND_PACKAGE(OpenCV REQUIRED)
#TARGET_LINK_LIBRARIES(sysDetectSpeed ${OpenCV_LIBS})
target_link_libraries(sysDetectSpeed -I/usr/local/include/opencv -I/usr/local/include -L/usr/local/lib
-lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_imgcodecs -lopencv_video -lopencv_videoio)
# install
foreach(include ${inferenceIncludes})
install(FILES "${include}" DESTINATION include/sysDetectSpeed)
endforeach()
# install the shared library
install(TARGETS sysDetectSpeed DESTINATION lib/sysDetectSpeed EXPORT sysDetectSpeedConfig)
# install the cmake project, for importing
install(EXPORT sysDetectSpeedConfig DESTINATION share/sysDetectSpeed/cmake)
2.编译upsample层 caffe
增加include/caffe/layers/upsample_layer.hpp
#ifndef CAFFE_UPSAMPLE_LAYER_HPP_
#define CAFFE_UPSAMPLE_LAYER_HPP_
#include <vector>
#include "caffe/blob.hpp"
#include "caffe/layer.hpp"
#include "caffe/proto/caffe.pb.h"
namespace caffe {
template <typename Dtype>
class UpsampleLayer : public Layer<Dtype> {
public:
explicit UpsampleLayer(const LayerParameter& param)
: Layer<Dtype>(param) {}
virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top);
virtual void Reshape(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top);
virtual inline const char* type() const { return "Upsample"; }
virtual inline int MinBottomBlobs() const { return 1; }
virtual inline int MaxBottomBlobs() const { return 1; }
virtual inline int ExactNumTopBlobs() const { return 1; }
virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top);
virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top);
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);
private:
int scale_;
};
} // namespace caffe
#endif // CAFFE_UPSAMPLE_LAYER_HPP_
增加src/caffe/layers/upsample_layer.cpp
#include <vector>
#include "caffe/layers/upsample_layer.hpp"
namespace caffe {
template <typename Dtype>
void UpsampleLayer<Dtype>::LayerSetUp(
const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
UpsampleParameter upsample_param = this->layer_param_.upsample_param();
scale_ = upsample_param.scale();
}
template <typename Dtype>
void UpsampleLayer<Dtype>::Reshape(
const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
vector<int> out_shape;
for (int i = 0; i < bottom[0]->num_axes(); i++) {
out_shape.push_back(bottom[0]->shape(i));
}
out_shape[bottom[0]->num_axes() - 1] *= scale_;
out_shape[bottom[0]->num_axes() - 2] *= scale_;
top[0]->Reshape(out_shape);
}
template <typename Dtype>
void UpsampleLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
int N = top[0]->shape(0);
int C = top[0]->shape(1);
int H = top[0]->shape(2);
int W = top[0]->shape(3);
const Dtype *input = bottom[0]->cpu_data();
Dtype *output = top[0]->mutable_cpu_data();
for (int n = 0; n < N; n++) {
for (int c = 0; c < C; c++) {
for (int h = 0; h < H; h++) {
for (int w = 0; w < W; w++) {
int nw = w/scale_;
int nh = h/scale_;
int out_idx = (((n * C + c) * H) + h) * W + w;
int in_idx = (((n * C + c) * (H / scale_)) + nh) * (W / scale_) + nw;
output[out_idx] = input[in_idx];
}
}
}
}
}
template <typename Dtype>
void UpsampleLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
int N = bottom[0]->shape(0);
int C = bottom[0]->shape(1);
int H = bottom[0]->shape(2);
int W = bottom[0]->shape(3);
const Dtype *output_grad = top[0]->cpu_diff();
Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();
caffe_set(bottom[0]->count(), Dtype(0), bottom_diff);
for (int n = 0; n < N; n++) {
for (int c = 0; c < C; c++) {
for (int h = 0; h < H; h++) {
for (int w = 0; w < W; w++) {
for (int i = 0; i < scale_; i++) {
for (int j = 0; j < scale_; j++) {
int nw = w * scale_ + i;
int nh = h * scale_ + j;
int out_idx = (((n * C + c) * H) + h) * W + w;
int in_idx = (((n * C + c) * (H * scale_))
+ nh) * (W * scale_) + nw;
bottom_diff[out_idx] += output_grad[in_idx];
}
}
}
}
}
}
}
#ifdef CPU_ONLY
STUB_GPU(UpsampleLayer);
#endif
INSTANTIATE_CLASS(UpsampleLayer);
REGISTER_LAYER_CLASS(Upsample);
} // namespace caffe
增加src/caffe/layers/upsample_layer.cu
#include <vector>
#include "caffe/filler.hpp"
#include "caffe/layers/upsample_layer.hpp"
#include "caffe/util/math_functions.hpp"
namespace caffe {
__device__ int translate_idx(int ii, int d1, int d2, int d3, int scale_factor) {
int x, y, z, w;
w = ii % d3;
ii = ii/d3;
z = ii % d2;
ii = ii/d2;
y = ii % d1;
ii = ii/d1;
x = ii;
w = w/scale_factor;
z = z/scale_factor;
d2 /= scale_factor;
d3 /= scale_factor;
return (((x*d1+y)*d2)+z)*d3+w;
}
__device__ int translate_idx_inv(
int ii, int d1, int d2, int d3, int scale_factor, int off_x, int off_y) {
int x, y, z, w;
w = ii % d3;
ii = ii/d3;
z = ii % d2;
ii = ii/d2;
y = ii % d1;
ii = ii/d1;
x = ii;
w = w*scale_factor+off_x;
z = z*scale_factor+off_y;
d2 *= scale_factor;
d3 *= scale_factor;
return (((x*d1+y)*d2)+z)*d3+w;
}
template <typename Dtype>
__global__ void upscale(const Dtype *input, Dtype *output,
int no_elements, int scale_factor, int d1, int d2, int d3) {
int ii = threadIdx.x + blockDim.x * blockIdx.x;
if (ii >= no_elements) return;
int ipidx = translate_idx(ii, d1, d2, d3, scale_factor);
output[ii]=input[ipidx];
}
template <typename Dtype>
__global__ void downscale(Dtype *gradInput_data, const Dtype *gradOutput_data,
int no_elements, int scale_factor, int d1, int d2,
int d3) {
int ii = threadIdx.x + blockDim.x * blockIdx.x;
if (ii >= no_elements) return;
for (int i = 0; i < scale_factor; i++) {
for (int j = 0; j < scale_factor; j++) {
int ipidx = translate_idx_inv(ii, d1, d2, d3, scale_factor, i, j);
gradInput_data[ii] += gradOutput_data[ipidx];
}
}
}
template <typename Dtype>
void UpsampleLayer<Dtype>::Forward_gpu(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
int d1, d2, d3;
d1 = top[0]->shape(1);
d2 = top[0]->shape(2);
d3 = top[0]->shape(3);
int no_elements = top[0]->count();
upscale<Dtype> // NOLINT_NEXT_LINE(whitespace/operators)
<<<CAFFE_GET_BLOCKS(no_elements), CAFFE_CUDA_NUM_THREADS>>>(
bottom[0]->gpu_data(),
top[0]->mutable_gpu_data(), no_elements, scale_, d1, d2, d3);
}
template <typename Dtype>
void UpsampleLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
int d1, d2, d3;
Dtype* bottom_diff = bottom[0]->mutable_gpu_diff();
d1 = bottom[0]->shape(1);
d2 = bottom[0]->shape(2);
d3 = bottom[0]->shape(3);
int no_elements = bottom[0]->count();
caffe_gpu_set(bottom[0]->count(), Dtype(0), bottom_diff);
downscale<Dtype> // NOLINT_NEXT_LINE(whitespace/operators)
<<<CAFFE_GET_BLOCKS(no_elements), CAFFE_CUDA_NUM_THREADS>>>(
bottom_diff, top[0]->gpu_diff(), no_elements, scale_, d1, d2, d3);
}
INSTANTIATE_LAYER_GPU_FUNCS(UpsampleLayer);
} // namespace caffe
增加src/caffe/test/test_upsample_layer.cpp
#include <cmath>
#include <vector>
#include "boost/scoped_ptr.hpp"
#include "gtest/gtest.h"
#include "caffe/blob.hpp"
#include "caffe/filler.hpp"
#include "caffe/layers/upsample_layer.hpp"
#include "caffe/util/io.hpp"
#include "caffe/test/test_caffe_main.hpp"
#include "caffe/test/test_gradient_check_util.hpp"
using boost::scoped_ptr;
namespace caffe {
template <typename TypeParam>
class UpsampleLayerTest : public MultiDeviceTest<TypeParam> {
typedef typename TypeParam::Dtype Dtype;
protected:
UpsampleLayerTest()
: blob_bottom_data_(new Blob<Dtype>(2, 5, 2, 2)),
blob_top_data_(new Blob<Dtype>()) {
// fill the values
FillerParameter filler_param;
filler_param.set_std(10);
GaussianFiller<Dtype> filler(filler_param);
filler.Fill(this->blob_bottom_data_);
blob_bottom_vec_.push_back(blob_bottom_data_);
blob_top_vec_.push_back(blob_top_data_);
}
virtual ~UpsampleLayerTest() {
delete blob_bottom_data_;
delete blob_top_data_;
}
Blob<Dtype>* const blob_bottom_data_;
Blob<Dtype>* const blob_top_data_;
vector<Blob<Dtype>*> blob_bottom_vec_;
vector<Blob<Dtype>*> blob_top_vec_;
};
TYPED_TEST_CASE(UpsampleLayerTest, TestDtypesAndDevices);
TYPED_TEST(UpsampleLayerTest, TestGradient) {
typedef typename TypeParam::Dtype Dtype;
LayerParameter layer_param;
UpsampleParameter* upsample_param =
layer_param.mutable_upsample_param();
upsample_param->set_scale(2);
UpsampleLayer<Dtype> layer(layer_param);
GradientChecker<Dtype> checker(1e-2, 1e-2, 1701);
checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_,
this->blob_top_vec_, 0);
}
} // namespace caffe
最后在src/caffe/proto/caffe.proto中增加
message LayerParameter {
……
optional UpsampleParameter upsample_param = 148;
}
message UpsampleParameter {
optional int32 scale = 1 [default = 1];
}
重新编译caffe,后续转换需添加编译好的caffe路径
3.yolov3转caffemodel
https://github.com/marvis/pytorch-caffe-darknet-convert
原工程支持yolov2
修改darknet2caffe.py
import sys
sys.path.append('/home/caffe/python')
import caffe
import numpy as np
from collections import OrderedDict
from cfg import *
from prototxt import *
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
blocks = parse_cfg(cfgfile)
#Open the weights file
fp = open(weightfile, "rb")
#The first 4 values are header information
# 1. Major version number
# 2. Minor Version Number
# 3. Subversion number
# 4. IMages seen
header = np.fromfile(fp, dtype = np.int32, count = 5)
#fp = open(weightfile, 'rb')
#header = np.fromfile(fp, count=5, dtype=np.int32)
#header = np.ndarray(shape=(5,),dtype='int32',buffer=fp.read(20))
#print(header)
buf = np.fromfile(fp, dtype = np.float32)
#print(buf)
fp.close()
layers = []
layer_id = 1
start = 0
for block in blocks:
if start >= buf.size:
break
if block['type'] == 'net':
continue
elif block['type'] == 'convolutional':
batch_normalize = int(block['batch_normalize'])
if block.has_key('name'):
conv_layer_name = block['name']
bn_layer_name = '%s-bn' % block['name']
scale_layer_name = '%s-scale' % block['name']
else:
conv_layer_name = 'layer%d-conv' % layer_id
bn_layer_name = 'layer%d-bn' % layer_id
scale_layer_name = 'layer%d-scale' % layer_id
if batch_normalize:
start = load_conv_bn2caffe(buf, start, params[conv_layer_name], params[bn_layer_name], params[scale_layer_name])
else:
start = load_conv2caffe(buf, start, params[conv_layer_name])
layer_id = layer_id+1
elif block['type'] == 'connected':
if block.has_key('name'):
fc_layer_name = block['name']
else:
fc_layer_name = 'layer%d-fc' % layer_id
start = load_fc2caffe(buf, start, params[fc_layer_name])
layer_id = layer_id+1
elif block['type'] == 'maxpool':
layer_id = layer_id+1
elif block['type'] == 'avgpool':
layer_id = layer_id+1
elif block['type'] == 'region':
layer_id = layer_id + 1
elif block['type'] == 'route':
layer_id = layer_id + 1
elif block['type'] == 'shortcut':
layer_id = layer_id + 1
elif block['type'] == 'softmax':
layer_id = layer_id + 1
elif block['type'] == 'cost':
layer_id = layer_id + 1
elif block['type'] == 'upsample':
layer_id = layer_id + 1
else:
print('unknow layer type %s ' % block['type'])
layer_id = layer_id + 1
print('save prototxt to %s' % protofile)
save_prototxt(net_info , protofile, region=True)
print('save caffemodel to %s' % caffemodel)
net.save(caffemodel)
def load_conv2caffe(buf, start, conv_param):
weight = conv_param[0].data
bias = conv_param[1].data
conv_param[1].data[...] = np.reshape(buf[start:start+bias.size], bias.shape); start = start + bias.size
conv_param[0].data[...] = np.reshape(buf[start:start+weight.size], weight.shape); start = start + weight.size
return start
def load_fc2caffe(buf, start, fc_param):
weight = fc_param[0].data
bias = fc_param[1].data
fc_param[1].data[...] = np.reshape(buf[start:start+bias.size], bias.shape); start = start + bias.size
fc_param[0].data[...] = np.reshape(buf[start:start+weight.size], weight.shape); start = start + weight.size
return start
def load_conv_bn2caffe(buf, start, conv_param, bn_param, scale_param):
conv_weight = conv_param[0].data
running_mean = bn_param[0].data
running_var = bn_param[1].data
scale_weight = scale_param[0].data
scale_bias = scale_param[1].data
scale_param[1].data[...] = np.reshape(buf[start:start+scale_bias.size], scale_bias.shape); start = start + scale_bias.size
#print scale_bias.size
#print scale_bias
scale_param[0].data[...] = np.reshape(buf[start:start+scale_weight.size], scale_weight.shape); start = start + scale_weight.size
#print scale_weight.size
bn_param[0].data[...] = np.reshape(buf[start:start+running_mean.size], running_mean.shape); start = start + running_mean.size
#print running_mean.size
bn_param[1].data[...] = np.reshape(buf[start:start+running_var.size], running_var.shape); start = start + running_var.size
#print running_var.size
bn_param[2].data[...] = np.array([1.0])
conv_param[0].data[...] = np.reshape(buf[start:start+conv_weight.size], conv_weight.shape); start = start + conv_weight.size
#print conv_weight.size
return start
def cfg2prototxt(cfgfile):
blocks = parse_cfg(cfgfile)
layers = []
props = OrderedDict()
bottom = 'data'
layer_id = 1
topnames = dict()
for block in blocks:
if block['type'] == 'net':
props['name'] = 'Darkent2Caffe'
props['input'] = 'data'
props['input_dim'] = ['1']
props['input_dim'].append(block['channels'])
props['input_dim'].append(block['height'])
props['input_dim'].append(block['width'])
continue
elif block['type'] == 'convolutional':
conv_layer = OrderedDict()
conv_layer['bottom'] = bottom
if block.has_key('name'):
conv_layer['top'] = block['name']
conv_layer['name'] = block['name']
else:
conv_layer['top'] = 'layer%d-conv' % layer_id
conv_layer['name'] = 'layer%d-conv' % layer_id
conv_layer['type'] = 'Convolution'
convolution_param = OrderedDict()
convolution_param['num_output'] = block['filters']
convolution_param['kernel_size'] = block['size']
if block['pad'] == '1':
convolution_param['pad'] = str(int(convolution_param['kernel_size'])/2)
convolution_param['stride'] = block['stride']
if block['batch_normalize'] == '1':
convolution_param['bias_term'] = 'false'
else:
convolution_param['bias_term'] = 'true'
conv_layer['convolution_param'] = convolution_param
layers.append(conv_layer)
bottom = conv_layer['top']
if block['batch_normalize'] == '1':
bn_layer = OrderedDict()
bn_layer['bottom'] = bottom
bn_layer['top'] = bottom
if block.has_key('name'):
bn_layer['name'] = '%s-bn' % block['name']
else:
bn_layer['name'] = 'layer%d-bn' % layer_id
bn_layer['type'] = 'BatchNorm'
batch_norm_param = OrderedDict()
batch_norm_param['use_global_stats'] = 'true'
bn_layer['batch_norm_param'] = batch_norm_param
layers.append(bn_layer)
scale_layer = OrderedDict()
scale_layer['bottom'] = bottom
scale_layer['top'] = bottom
if block.has_key('name'):
scale_layer['name'] = '%s-scale' % block['name']
else:
scale_layer['name'] = 'layer%d-scale' % layer_id
scale_layer['type'] = 'Scale'
scale_param = OrderedDict()
scale_param['bias_term'] = 'true'
scale_layer['scale_param'] = scale_param
layers.append(scale_layer)
if block['activation'] != 'linear':
relu_layer = OrderedDict()
relu_layer['bottom'] = bottom
relu_layer['top'] = bottom
if block.has_key('name'):
relu_layer['name'] = '%s-act' % block['name']
else:
relu_layer['name'] = 'layer%d-act' % layer_id
relu_layer['type'] = 'ReLU'
if block['activation'] == 'leaky':
relu_param = OrderedDict()
relu_param['negative_slope'] = '0.1'
relu_layer['relu_param'] = relu_param
layers.append(relu_layer)
topnames[layer_id] = bottom
layer_id = layer_id+1
elif block['type'] == 'maxpool':
max_layer = OrderedDict()
max_layer['bottom'] = bottom
if block.has_key('name'):
max_layer['top'] = block['name']
max_layer['name'] = block['name']
else:
max_layer['top'] = 'layer%d-maxpool' % layer_id
max_layer['name'] = 'layer%d-maxpool' % layer_id
max_layer['type'] = 'Pooling'
pooling_param = OrderedDict()
pooling_param['kernel_size'] = block['size']
pooling_param['stride'] = block['stride']
pooling_param['pool'] = 'MAX'
if block.has_key('pad') and int(block['pad']) == 1:
pooling_param['pad'] = str((int(block['size'])-1)/2)
max_layer['pooling_param'] = pooling_param
layers.append(max_layer)
bottom = max_layer['top']
topnames[layer_id] = bottom
layer_id = layer_id+1
elif block['type'] == 'avgpool':
avg_layer = OrderedDict()
avg_layer['bottom'] = bottom
if block.has_key('name'):
avg_layer['top'] = block['name']
avg_layer['name'] = block['name']
else:
avg_layer['top'] = 'layer%d-avgpool' % layer_id
avg_layer['name'] = 'layer%d-avgpool' % layer_id
avg_layer['type'] = 'Pooling'
pooling_param = OrderedDict()
pooling_param['kernel_size'] = 7
pooling_param['stride'] = 1
pooling_param['pool'] = 'AVE'
avg_layer['pooling_param'] = pooling_param
layers.append(avg_layer)
bottom = avg_layer['top']
topnames[layer_id] = bottom
layer_id = layer_id+1
elif block['type'] == 'region':
if True:
region_layer = OrderedDict()
region_layer['bottom'] = bottom
if block.has_key('name'):
region_layer['top'] = block['name']
region_layer['name'] = block['name']
else:
region_layer['top'] = 'layer%d-region' % layer_id
region_layer['name'] = 'layer%d-region' % layer_id
region_layer['type'] = 'Region'
region_param = OrderedDict()
region_param['anchors'] = block['anchors'].strip()
region_param['classes'] = block['classes']
region_param['num'] = block['num']
region_layer['region_param'] = region_param
layers.append(region_layer)
bottom = region_layer['top']
topnames[layer_id] = bottom
layer_id = layer_id + 1
elif block['type'] == 'route':
route_layer = OrderedDict()
layer_name = str(block['layers']).split(',')
#print(layer_name[0])
bottom_layer_size = len(str(block['layers']).split(','))
#print(bottom_layer_size)
if(1 == bottom_layer_size):
prev_layer_id = layer_id + int(block['layers'])
bottom = topnames[prev_layer_id]
#topnames[layer_id] = bottom
route_layer['bottom'] = bottom
if(2 == bottom_layer_size):
prev_layer_id1 = layer_id + int(layer_name[0])
#print(prev_layer_id1)
prev_layer_id2 = int(layer_name[1]) + 1
print(topnames)
bottom1 = topnames[prev_layer_id1]
bottom2 = topnames[prev_layer_id2]
route_layer['bottom'] = [bottom1, bottom2]
if block.has_key('name'):
route_layer['top'] = block['name']
route_layer['name'] = block['name']
else:
route_layer['top'] = 'layer%d-route' % layer_id
route_layer['name'] = 'layer%d-route' % layer_id
route_layer['type'] = 'Concat'
print(route_layer)
layers.append(route_layer)
bottom = route_layer['top']
print(layer_id)
topnames[layer_id] = bottom
layer_id = layer_id + 1
elif block['type'] == 'upsample':
upsample_layer = OrderedDict()
print(block['stride'])
upsample_layer['bottom'] = bottom
if block.has_key('name'):
upsample_layer['top'] = block['name']
upsample_layer['name'] = block['name']
else:
upsample_layer['top'] = 'layer%d-upsample' % layer_id
upsample_layer['name'] = 'layer%d-upsample' % layer_id
upsample_layer['type'] = 'Upsample'
upsample_param = OrderedDict()
upsample_param['scale'] = block['stride']
upsample_layer['upsample_param'] = upsample_param
print(upsample_layer)
layers.append(upsample_layer)
bottom = upsample_layer['top']
print('upsample:',layer_id)
topnames[layer_id] = bottom
layer_id = layer_id + 1
elif block['type'] == 'shortcut':
prev_layer_id1 = layer_id + int(block['from'])
prev_layer_id2 = layer_id - 1
bottom1 = topnames[prev_layer_id1]
bottom2= topnames[prev_layer_id2]
shortcut_layer = OrderedDict()
shortcut_layer['bottom'] = [bottom1, bottom2]
if block.has_key('name'):
shortcut_layer['top'] = block['name']
shortcut_layer['name'] = block['name']
else:
shortcut_layer['top'] = 'layer%d-shortcut' % layer_id
shortcut_layer['name'] = 'layer%d-shortcut' % layer_id
shortcut_layer['type'] = 'Eltwise'
eltwise_param = OrderedDict()
eltwise_param['operation'] = 'SUM'
shortcut_layer['eltwise_param'] = eltwise_param
layers.append(shortcut_layer)
bottom = shortcut_layer['top']
if block['activation'] != 'linear':
relu_layer = OrderedDict()
relu_layer['bottom'] = bottom
relu_layer['top'] = bottom
if block.has_key('name'):
relu_layer['name'] = '%s-act' % block['name']
else:
relu_layer['name'] = 'layer%d-act' % layer_id
relu_layer['type'] = 'ReLU'
if block['activation'] == 'leaky':
relu_param = OrderedDict()
relu_param['negative_slope'] = '0.1'
relu_layer['relu_param'] = relu_param
layers.append(relu_layer)
topnames[layer_id] = bottom
layer_id = layer_id + 1
elif block['type'] == 'connected':
fc_layer = OrderedDict()
fc_layer['bottom'] = bottom
if block.has_key('name'):
fc_layer['top'] = block['name']
fc_layer['name'] = block['name']
else:
fc_layer['top'] = 'layer%d-fc' % layer_id
fc_layer['name'] = 'layer%d-fc' % layer_id
fc_layer['type'] = 'InnerProduct'
fc_param = OrderedDict()
fc_param['num_output'] = int(block['output'])
fc_layer['inner_product_param'] = fc_param
layers.append(fc_layer)
bottom = fc_layer['top']
if block['activation'] != 'linear':
relu_layer = OrderedDict()
relu_layer['bottom'] = bottom
relu_layer['top'] = bottom
if block.has_key('name'):
relu_layer['name'] = '%s-act' % block['name']
else:
relu_layer['name'] = 'layer%d-act' % layer_id
relu_layer['type'] = 'ReLU'
if block['activation'] == 'leaky':
relu_param = OrderedDict()
relu_param['negative_slope'] = '0.1'
relu_layer['relu_param'] = relu_param
layers.append(relu_layer)
topnames[layer_id] = bottom
layer_id = layer_id+1
else:
print('unknow layer type %s ' % block['type'])
topnames[layer_id] = bottom
layer_id = layer_id + 1
net_info = OrderedDict()
net_info['props'] = props
net_info['layers'] = layers
return net_info
if __name__ == '__main__':
import sys
if len(sys.argv) != 5:
print('try:')
print('python darknet2caffe.py tiny-yolo-voc.cfg tiny-yolo-voc.weights tiny-yolo-voc.prototxt tiny-yolo-voc.caffemodel')
print('')
print('please add name field for each block to avoid generated name')
exit()
cfgfile = sys.argv[1]
#net_info = cfg2prototxt(cfgfile)
#print_prototxt(net_info)
#save_prototxt(net_info, 'tmp.prototxt')
weightfile = sys.argv[2]
protofile = sys.argv[3]
caffemodel = sys.argv[4]
darknet2caffe(cfgfile, weightfile, protofile, caffemodel)
4.转换模型测试
caffe-yolov3/detectnet/detectnet.cpp
修改转换的caffemodel、prototxt路径,修改检测类别为一类。调用测试并无精度损失。