caffe-yolov3
caffe-yolov3 copied to clipboard
how to transform yolov3 model to caffemodel
This link includes yolov2 weights to caffemodel.If you want to convert yolov3 weights to caffemodel,you need change some code.The code is below. `
import sys
sys.path.append('/home/ss/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)
`
thx a lot and I will try.
I have modify the Cross-compiler to x86_64 and compiled,tested your model and got some errors. Error parsing text-format caffe.NetParameter: 2622:20: Message type "caffe.LayerParameter" has no field named "upsample_param". i guess have to define yolov3 layers in caffe,is there any caffe project including yolov3 layers?
@Gotta-C You should add upsample layer into caffe.Check this link.
I have tried your model and worked ! But still some errors in darknet2caffe(cfgfile, weightfile, protofile, caffemodel)
Traceback (most recent call last):
File "darknet2caffe.py", line 429, in
except darknet2caffe.py ,do other files need to be modified ?
It worked on yolov3.cfg,yolov3.weight now. My dataset only one class,still have the problem.
@Gotta-C You need change the classes value in my projects,which is 80.
I used grep checked,only detect.py has classes 80,not that problem.In training,i have modify all the filters to 18,because 1 class,and the weights is only 505k,compared to yolov3.weights is 248M,I have no idea whether its a problem.
where the error happens,weights convert to caffemodel or others?
weight to caffemodel .May I have your Q number or wechat?
I have tried your python code which could transform yolov3 model to caffemodel. But there are some errors: ''' unknow layer type yolo [libprotobuf ERROR google/protobuf/text_format.cc:274] Error parsing text-format caffe.NetParameter: 2622:20: Message type "caffe.LayerParameter" has no field named "upsample_param". WARNING: Logging before InitGoogleLogging() is written to STDERR F0626 10:08:24.390600 9704 upgrade_proto.cpp:90] Check failed: ReadProtoFromTextFile(param_file, param) Failed to parse NetParameter file: yolov3.prototxt ''' could help me solve this problem? thanks a lot
How did you slove the yolo layer [yolo] in yolov3.cfg? thanks
@vvmex For unsample layer ,you should add it into caffe and i post the link in the previous content.For yolo layer,I have rewrite it in my projetcs.
Hi,Chen! It`s really exciting to find your project after spending so much time searching for something useful about yolov3-caffe and I really appreciate that you have implemented this and release your work to pubilc!
However,after trying out your code ,I have some errors which are the same with the other two guys when converting my darknet model and cfg file to caffemodel and prototxt : \ unknow layer type yolo [libprotobuf ERROR google/protobuf/text_format.cc:245] Error parsing text-format caffe.NetParameter: 2622:20: Message type "caffe.LayerParameter" has no field named "upsample_param". \ I have read the link you post and add unsample layer into caffe and change caffe.proto as the author pointed ,after compiling caffe I still have this error.I can see my cfg file has been converted to prototxt and compare to your prototxt provided,they are the same except "output" and "numclasses",so cfg file is ok,which means the problem is on converting model.
@zbw4034 Can you post the detail of error?
my error is this:
[libprotobuf ERROR google/protobuf/text_format.cc:245] Error parsing text-format caffe.NetParameter: 2622:20: Message type "caffe.LayerParameter" has no field named "upsample_param". WARNING: Logging before InitGoogleLogging() is written to STDERR F0627 20:21:10.194875 18559 upgrade_proto.cpp:79] Check failed: ReadProtoFromTextFile(param_file, param) Failed to parse NetParameter file: cfg/yolov3.prototxt *** Check failure stack trace: *** Aborted (core dumped)
and i have followed your link which add upsample layer to caffe,and modified caffe.proto,then recompile caffe,but it still said can`t parse upsample_param
and in darknet2caffe.py,i just modified the python path of caffe. the order i type in in the terminal is just "python darknet2caffe.py cfg/yolov3-voc.cfg cfg/yolov3-voc_final.weights cfg/yolov3.prototxt cfg/yolov3.caffemodel" @ChenYingpeng
From error you said, i guess you didn't add upsample layer into caffe successfully,Go Baidu or Google it! Give you the link.Good luck!
FINALLY I SUCCEED ! After a whole day searching and trying,I succeed to finish converting.The main reason I failed is that I have install 3 versions of caffe(ssd,R-fcn,standard caffe-master),which makes the environment complicated.And at last I change to another gpu and make it out.
Thank you all !!!
@zbw4034 is there a reason why one should convert weights on their own instead of using the weights provided in the README?
https://github.com/ChenYingpeng/caffe-yolov3#download-model
@aaronduino because we want to test our own caffemodel,which is different from the one provided.
@Gotta-C Hello, did you successfully convert the weights to caffemodel? My dataset also has 1 class, but I failed in converting weight.
The repo is excellent, I have run yolov3 model succefully and get right result with caffe-yolo. In other words, I suggest @ChenYingpeng add darknet2caffe.py in this repo, and revise the scripts format.
@ChenYingpeng hello , i hope that you are doing well , i followed your repository that regards conversion between pytorch,darknet and caffe. but i got this error :"[libprotobuf ERROR google/protobuf/text_format.cc:274] Error parsing text-format caffe.NetParameter: 2622:20: Message type "caffe.LayerParameter" has no field named "upsample_param". WARNING: Logging before InitGoogleLogging() is written to STDERR F0224 23:43:05.536036 7907 upgrade_proto.cpp:90] Check failed: ReadProtoFromTextFile(param_file, param) Failed to parse NetParameter file: yolov3.prototxt *** Check failure stack trace: *** Aborted (core dumped) " even i created the upsample layer (by creating three files and editing caffe.proto ) . i am wondering why this error occurs since i created upsampling layer . any suggestion will be helpful. i would like that you help me to solve this problem . thanks to all.
@adouwitti Hi,please make sure that you have added upsample layer into caffe and remember make it.Look for link from above.Good luck for you!
thanks for response @ChenYingpeng . i have added the upsample layer . when i tried to compile it again by running "make all" and " make ". another error has occurred :"PROTOC src/caffe/proto/caffe.proto caffe.proto:425:47: Field number 148 has already been used in "caffe.LayerParameter" by field "clip_param". Makefile:648: recipe for target '.build_release/src/caffe/proto/caffe.pb.cc' failed make: *** [.build_release/src/caffe/proto/caffe.pb.cc] Error 1 " . i got this error when i tried to compile it . thanks in advance.
Please look this “Field number 148 has already been used in "caffe.LayerParameter" by field "clip_param"”.You should change this number 148,such as 149,150 etc and make it.Good luck!
yeah i change the id numbers 149 ,150 and it works nice. thanks @ChenYingpeng
@ChenYingpeng hi, I failed to use script transformation model.My datasets only one class
@ycdhqzhiai Hi, please post your cfg file and running details.