update pytorchtocaffe tool

Summary: update pytorch to caffe toolchain to support model layers and bash scripts
pull/150/head
liaoxingyu 2020-06-09 14:45:27 +08:00
parent 3732f94405
commit 27c48c8f02
8 changed files with 4799 additions and 4836 deletions

View File

@ -1,4 +1,4 @@
# The Caffe in PytorchToCaffe Provides some convenient API
# The Caffe in nn_tools Provides some convenient API
If there are some problem in parse your prototxt or caffemodel, Please replace
the caffe.proto with your own version and compile it with command
`protoc --python_out ./ caffe.proto`

View File

@ -565,7 +565,6 @@ message LayerParameter {
optional RecurrentParameter recurrent_param = 146;
optional ReductionParameter reduction_param = 136;
optional ReLUParameter relu_param = 123;
optional ReLU6Parameter relu6_param = 208;
optional ReshapeParameter reshape_param = 133;
optional ROIPoolingParameter roi_pooling_param = 8266711; //roi pooling
optional ScaleParameter scale_param = 142;
@ -601,7 +600,7 @@ message LayerParameter {
optional CropParameter crop_param = 167;
optional DetectionEvaluateParameter detection_evaluate_param = 168;
optional DetectionOutputParameter detection_output_param = 169;
optional NormalizeParameter norm_param = 170;
//optional NormalizeParameter normalize_param = 170;
optional MultiBoxLossParameter multibox_loss_param = 171;
optional PermuteParameter permute_param = 172;
optional VideoDataParameter video_data_param = 173;
@ -633,7 +632,7 @@ message LayerParameter {
optional UpsampleParameter upsample_param = 100003;
optional MatMulParameter matmul_param = 100005;
optional PassThroughParameter pass_through_param = 100004;
//optional NormalizeParameter norm_param = 100001;
optional NormalizeParameter norm_param = 100001;
}
//*********************add by wdd******************
@ -659,13 +658,13 @@ message PassThroughParameter {
optional uint32 block_width = 3 [default = 0];
}
//message NormalizeParameter{
//optional bool across_spatial = 1 [default = true];
//optional FillerParameter scale_filler = 2;
//optional bool channel_shared = 3 [default = true];
//optional float eps = 4 [default = 1e-10];
//optional float sqrt_a = 5 [default = 1];
//}
message NormalizeParameter{
optional bool across_spatial = 1 [default = true];
optional FillerParameter scale_filler = 2;
optional bool channel_shared = 3 [default = true];
optional float eps = 4 [default = 1e-10];
optional float sqrt_a = 5 [default = 1];
}
@ -1593,15 +1592,19 @@ message MultiBoxLossParameter {
}
// Message that stores parameters used by NormalizeLayer
message NormalizeParameter {
optional bool across_spatial = 1 [default = true];
// Initial value of scale. Default is 1.0 for all
optional FillerParameter scale_filler = 2;
// Whether or not scale parameters are shared across channels.
optional bool channel_shared = 3 [default = true];
// Epsilon for not dividing by zero while normalizing variance
optional float eps = 4 [default = 1e-10];
}
//message NormalizeParameter {
// //optional bool across_spatial = 1 [default = true];
// // Initial value of scale. Default is 1.0 for all
// //optional FillerParameter scale_filler = 2;
// // Whether or not scale parameters are shared across channels.
// //optional bool channel_shared = 3 [default = true];
// // Epsilon for not dividing by zero while normalizing variance
// //optional float eps = 4 [default = 1e-10];
// //**************************************************
// optional string normalize_type = 1 [default = "L2"];
// optional bool fix_gradient = 2 [default = false];
// optional bool bp_norm = 3 [default = false];
//}
message PermuteParameter {
// The new orders of the axes of data. Notice it should be with
@ -1789,16 +1792,6 @@ message ReLUParameter {
optional Engine engine = 2 [default = DEFAULT];
}
// Message that stores parameters used by ReLU6Layer
message ReLU6Parameter {
enum Engine {
DEFAULT = 0;
CAFFE = 1;
CUDNN = 2;
}
optional Engine engine = 2 [default = DEFAULT];
}
message ReshapeParameter {
// Specify the output dimensions. If some of the dimensions are set to 0,
// the corresponding dimension from the bottom layer is used (unchanged).

View File

@ -7,7 +7,6 @@ from .layer_param import Layer_param
class _Net(object):
def __init__(self):
self.net=pb.NetParameter()
self.needChange = {}
def layer_index(self,layer_name):
# find a layer's index by name. if the layer was found, return the layer position in the net, else return -1.
@ -40,20 +39,6 @@ class _Net(object):
return
raise(AttributeError, "cannot found layer %s" % str(layer_name))
def remove_layer_by_type(self,type_name):
for i,layer in enumerate(self.net.layer):
if layer.type == type_name:
# self.change_layer_bottom(layer.top,layer.bottom)
s1 = "\"" + layer.top[0] + "\""
s2 = "\"" + layer.bottom[0] + "\""
self.needChange[s1]=s2
del self.net.layer[i]
return
def get_layer_by_name(self, layer_name):
# get the layer by layer_name
for layer in self.net.layer:
@ -67,10 +52,7 @@ class _Net(object):
for layer in prototxt.layer:
del layer.blobs[:]
with open(path,'w') as f:
string = text_format.MessageToString(prototxt)
for origin_name in self.needChange.keys():
string = string.replace(origin_name,self.needChange[origin_name])
f.write(string)
f.write(text_format.MessageToString(prototxt))
def layer(self,layer_name):
return self.get_layer_by_name(layer_name)

File diff suppressed because one or more lines are too long

View File

@ -71,46 +71,9 @@ class Layer_param():
conv_param.dilation.extend(pair_reduce(dilation))
if groups:
conv_param.group=groups
if groups != 1:
conv_param.engine = 1
self.param.convolution_param.CopyFrom(conv_param)
def norm_param(self, eps):
"""
add a conv_param layer if you spec the layer type "Convolution"
Args:
num_output: a int
kernel_size: int list
stride: a int list
weight_filler_type: the weight filer type
bias_filler_type: the bias filler type
Returns:
"""
l2norm_param = pb.NormalizeParameter()
l2norm_param.across_spatial = False
l2norm_param.channel_shared = False
l2norm_param.eps = eps
self.param.norm_param.CopyFrom(l2norm_param)
def permute_param(self, order1, order2, order3, order4):
"""
add a conv_param layer if you spec the layer type "Convolution"
Args:
num_output: a int
kernel_size: int list
stride: a int list
weight_filler_type: the weight filer type
bias_filler_type: the bias filler type
Returns:
"""
permute_param = pb.PermuteParameter()
permute_param.order.extend([order1, order2, order3, order4])
self.param.permute_param.CopyFrom(permute_param)
def pool_param(self,type='MAX',kernel_size=2,stride=2,pad=None, ceil_mode = True):
def pool_param(self,type='MAX',kernel_size=2,stride=2,pad=None, ceil_mode = False):
pool_param=pb.PoolingParameter()
pool_param.pool=pool_param.PoolMethod.Value(type)
pool_param.kernel_size=pair_process(kernel_size)
@ -158,10 +121,22 @@ class Layer_param():
if isinstance(size,int):
upsample_param.upsample_h = size
else:
upsample_param.upsample_h = size[0] * scale_factor
upsample_param.\
upsample_w = size[1] * scale_factor
upsample_param.upsample_h = size[0]
upsample_param.upsample_w = size[1]
#upsample_param.upsample_h = size[0] * scale_factor
#upsample_param.upsample_w = size[1] * scale_factor
self.param.upsample_param.CopyFrom(upsample_param)
def interp_param(self,size=None, scale_factor=None):
interp_param=pb.InterpParameter()
if scale_factor:
if isinstance(scale_factor,int):
interp_param.zoom_factor = scale_factor
if size:
print('size:', size)
interp_param.height = size[0]
interp_param.width = size[1]
self.param.interp_param.CopyFrom(interp_param)
def add_data(self,*args):
"""Args are data numpy array

View File

@ -1 +1 @@
raise ImportError('the nn_tools.Caffe.net is no longer used, please use nn_tools.Caffe.caffe_net')
raise ImportError,'the nn_tools.Caffe.net is no longer used, please use nn_tools.Caffe.caffe_net'

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import torch
import torch.nn as nn
import traceback
@ -7,6 +10,8 @@ from torch.autograd import Variable
from Caffe import layer_param
from torch.nn.modules.utils import _pair
import numpy as np
import math
from torch.nn.modules.utils import _list_with_default
"""
How to support a new layer type:
@ -18,24 +23,28 @@ How to support a new layer type:
log.cnet.add_layer(layer)
Please MUTE the inplace operations to avoid not find in graph
注意只有torch.nn.functional中的函数才能转换为caffe中的层
"""
# TODO: support the inplace output of the layers
class Blob_LOG():
def __init__(self):
self.data = {}
def __setitem__(self, key, value):
self.data[key] = value
def __getitem__(self, key):
return self.data[key]
def __len__(self):
return len(self.data)
NET_INITTED = False
# 转换原理解析:通过记录
class TransLog(object):
def __init__(self):
@ -55,6 +64,7 @@ class TransLog(object):
:param inputs: is a list of input variables
"""
self.add_blobs(inputs)
def add_layer(self, name='layer'):
if name in self.layers:
return self.layers[name]
@ -81,24 +91,27 @@ class TransLog(object):
rst.append('{}'.format(name))
if self.debug:
print("{}:{} was added to blobs".format(blob_id, rst[-1]))
# print('Add blob {} : {}'.format(rst[-1].center(21),blob.size()))
print('Add blob {} : {}'.format(rst[-1].center(21), blob.size()))
self._blobs[blob_id] = rst[-1]
return rst
def blobs(self, var):
var = id(var)
# if self.debug:
# print("{}:{} getting".format(var, self._blobs[var]))
if self.debug:
print("{}:{} getting".format(var, self._blobs[var]))
try:
return self._blobs[var]
except:
print("WARNING: CANNOT FOUND blob {}".format(var))
return None
log = TransLog()
layer_names = {}
def _conv2d(raw, input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1):
print('conv: ',log.blobs(input))
x = raw(input, weight, bias, stride, padding, dilation, groups)
name = log.add_layer(name='conv')
log.add_blobs([x], name='conv_blob')
@ -108,12 +121,15 @@ def _conv2d(raw,input, weight, bias=None, stride=1, padding=0, dilation=1, group
pad=_pair(padding), dilation=_pair(dilation), bias_term=bias is not None, groups=groups)
if bias is not None:
layer.add_data(weight.cpu().data.numpy(), bias.cpu().data.numpy())
#print('conv2d weight, bias: ',weight.cpu().data.numpy(), bias.cpu().data.numpy())
else:
layer.param.convolution_param.bias_term = False
layer.add_data(weight.cpu().data.numpy())
log.cnet.add_layer(layer)
return x
def _conv_transpose2d(raw, input, weight, bias=None, stride=1, padding=0, output_padding=0, groups=1, dilation=1):
x = raw(input, weight, bias, stride, padding, output_padding, groups, dilation)
name = log.add_layer(name='conv_transpose')
@ -121,7 +137,7 @@ def _conv_transpose2d(raw,input, weight, bias=None, stride=1, padding=0, output_
layer = caffe_net.Layer_param(name=name, type='Deconvolution',
bottom=[log.blobs(input)], top=[log.blobs(x)])
layer.conv_param(x.size()[1], weight.size()[2:], stride=_pair(stride),
pad=_pair(padding),dilation=_pair(dilation),bias_term=bias is not None, groups = groups)
pad=_pair(padding), dilation=_pair(dilation), bias_term=bias is not None)
if bias is not None:
layer.add_data(weight.cpu().data.numpy(), bias.cpu().data.numpy())
else:
@ -130,6 +146,7 @@ def _conv_transpose2d(raw,input, weight, bias=None, stride=1, padding=0, output_
log.cnet.add_layer(layer)
return x
def _linear(raw, input, weight, bias=None):
x = raw(input, weight, bias)
layer_name = log.add_layer(name='fc')
@ -144,6 +161,7 @@ def _linear(raw,input, weight, bias=None):
log.cnet.add_layer(layer)
return x
def _split(raw, tensor, split_size, dim=0):
# split in pytorch is slice in caffe
x = raw(tensor, split_size, dim)
@ -162,23 +180,25 @@ def _pool(type,raw,input,x,kernel_size,stride,padding,ceil_mode):
# TODO dilation,ceil_mode,return indices
layer_name = log.add_layer(name='{}_pool'.format(type))
top_blobs = log.add_blobs([x], name='{}_pool_blob'.format(type))
layer = caffe_net.Layer_param(name=layer_name, type='Pooling',
bottom=[log.blobs(input)], top=top_blobs)
layer = caffe_net.Layer_param(name=layer_name, type='Pooling', bottom=[log.blobs(input)], top=top_blobs)
# TODO w,h different kernel, stride and padding
# processing ceil mode
layer.pool_param(kernel_size=kernel_size, stride=kernel_size if stride is None else stride,
pad=padding, type=type.upper() , ceil_mode = ceil_mode)
pad=padding, type=type.upper())
log.cnet.add_layer(layer)
if ceil_mode == False and stride is not None:
oheight = (input.size()[2] - _pair(kernel_size)[0] + 2 * _pair(padding)[0]) % (_pair(stride)[0])
owidth = (input.size()[3] - _pair(kernel_size)[1] + 2 * _pair(padding)[1]) % (_pair(stride)[1])
if oheight != 0 or owidth != 0:
caffe_out=raw(input, kernel_size, stride, padding, ceil_mode=True)
caffe_out = raw(input, kernel_size, stride, padding, ceil_mode=False)
print("WARNING: the output shape miss match at {}: "
"input {} output---Pytorch:{}---Caffe:{}\n"
"This is caused by the different implementation that ceil mode in caffe and the floor mode in pytorch.\n"
"You can add the clip layer in caffe prototxt manually if shape mismatch error is caused in caffe. ".format(layer_name,input.size(),x.size(),caffe_out.size()))
"You can add the clip layer in caffe prototxt manually if shape mismatch error is caused in caffe. ".format(
layer_name, input.size(), x.size(), caffe_out.size()))
def _max_pool2d(raw, input, kernel_size, stride=None, padding=0, dilation=1,
ceil_mode=False, return_indices=False):
@ -186,23 +206,12 @@ def _max_pool2d(raw,input, kernel_size, stride=None, padding=0, dilation=1,
_pool('max', raw, input, x, kernel_size, stride, padding, ceil_mode)
return x
def _avg_pool2d(raw, input, kernel_size, stride=None, padding=0, ceil_mode=False, count_include_pad=True):
x = raw(input, kernel_size, stride, padding, ceil_mode, count_include_pad)
_pool('ave', raw, input, x, kernel_size, stride, padding, ceil_mode)
return x
def _adaptive_avg_pool2d(raw, input, output_size):
_output_size = _list_with_default(output_size, input.size())
x = raw(input, _output_size)
if isinstance(_output_size, int):
out_dim = _output_size
else:
out_dim = _output_size[0]
tmp = max(input.shape[2], input.shape[3])
stride = tmp //out_dim
kernel_size = tmp - (out_dim - 1) * stride
_pool('ave', raw, input, x, kernel_size, stride, 0, False)
return x
def _max(raw, *args):
x = raw(*args)
@ -221,6 +230,7 @@ def _max(raw,*args):
log.cnet.add_layer(layer)
return x
def _cat(raw, inputs, dimension=0):
x = raw(inputs, dimension)
bottom_blobs = []
@ -234,6 +244,7 @@ def _cat(raw,inputs, dimension=0):
log.cnet.add_layer(layer)
return x
def _dropout(raw, input, p=0.5, training=False, inplace=False):
x = raw(input, p, training, inplace)
bottom_blobs = [log.blobs(input)]
@ -246,6 +257,7 @@ def _dropout(raw,input,p=0.5, training=False, inplace=False):
log.cnet.add_layer(layer)
return x
def _threshold(raw, input, threshold, value, inplace=False):
# for threshold or relu
if threshold == 0 and value == 0:
@ -269,6 +281,7 @@ def _threshold(raw,input, threshold, value, inplace=False):
log.cnet.add_layer(layer)
return x
def _relu(raw, input, inplace=False):
# for threshold or prelu
x = raw(input, False)
@ -278,6 +291,8 @@ def _relu(raw, input, inplace=False):
bottom=[log.blobs(input)], top=[log.blobs(x)])
log.cnet.add_layer(layer)
return x
def _prelu(raw, input, weight):
# for threshold or prelu
x = raw(input, weight)
@ -294,6 +309,7 @@ def _prelu(raw, input, weight):
log.cnet.add_layer(layer)
return x
def _leaky_relu(raw, input, negative_slope=0.01, inplace=False):
x = raw(input, negative_slope)
name = log.add_layer(name='leaky_relu')
@ -304,6 +320,7 @@ def _leaky_relu(raw, input, negative_slope=0.01, inplace=False):
log.cnet.add_layer(layer)
return x
def _tanh(raw, input):
# for tanh activation
x = raw(input)
@ -314,6 +331,7 @@ def _tanh(raw, input):
log.cnet.add_layer(layer)
return x
def _softmax(raw, input, dim=None, _stacklevel=3):
# for F.softmax
x = raw(input, dim=dim)
@ -328,6 +346,18 @@ def _softmax(raw, input, dim=None, _stacklevel=3):
log.cnet.add_layer(layer)
return x
def _sigmoid(raw, input):
# for tanh activation
x = raw(input)
name = log.add_layer(name='Sigmoid')
log.add_blobs([x], name='Sigmoid_blob')
layer = caffe_net.Layer_param(name=name, type='Sigmoid',
bottom=[log.blobs(input)], top=[log.blobs(x)])
log.cnet.add_layer(layer)
return x
def _batch_norm(raw, input, running_mean, running_var, weight=None, bias=None,
training=False, momentum=0.1, eps=1e-5):
# because the runing_mean and runing_var will be changed after the _batch_norm operation, we first save the parameters
@ -347,6 +377,8 @@ def _batch_norm(raw,input, running_mean, running_var, weight=None, bias=None,
running_mean_clone = running_mean.clone()
running_var_clone = running_var.clone()
layer1.add_data(running_mean_clone.cpu().numpy(), running_var_clone.cpu().numpy(), np.array([1.0]))
#print('running_mean: ',running_mean_clone.cpu().numpy())
#print('running_var: ',running_var_clone.cpu().numpy())
log.cnet.add_layer(layer1)
if weight is not None and bias is not None:
layer_name2 = log.add_layer(name='bn_scale')
@ -355,8 +387,11 @@ def _batch_norm(raw,input, running_mean, running_var, weight=None, bias=None,
layer2.param.scale_param.bias_term = True
layer2.add_data(weight.cpu().data.numpy(), bias.cpu().data.numpy())
log.cnet.add_layer(layer2)
#print('scale weight: ', weight.cpu().data.numpy())
#print('scale bias: ', bias.cpu().data.numpy())
return x
def _instance_norm(raw, input, running_mean=None, running_var=None, weight=None,
bias=None, use_input_stats=True, momentum=0.1, eps=1e-5):
# TODO: the batch size!=1 view operations
@ -400,88 +435,61 @@ def _interpolate(raw, input,size=None, scale_factor=None, mode='nearest', align_
# 有用,对输出进行额外 padding 在 h、w 方向上的数值;upsample_h、upsample_w,输
# 出图像尺寸的数值。在 Upsample 的相关代码中,推荐仅仅使用 upsample_h、
# upsample_w 准确定义 Upsample 层的输出尺寸,其他所有的参数都不推荐继续使用。
'''
if mode == 'bilinear':
x = raw(input, size, scale_factor, mode)
name = log.add_layer(name='conv_transpose')
log.add_blobs([x], name='conv_transpose_blob')
layer = caffe_net.Layer_param(name=name, type='Deconvolution',
bottom=[log.blobs(input)], top=[log.blobs(x)])
print('Deconv: ', name)
print(input.shape)
print(x.size())
print(size)
factor = float(size[0]) / input.shape[2]
C = x.size()[1]
print(factor,C)
kernel_size = int(2 * factor - factor % 2)
stride = int(factor)
num_output = C
group = C
pad = math.ceil((factor-1) / 2.)
print('kernel_size, stride, num_output, group, pad')
print(kernel_size, stride, num_output, group, pad)
layer.conv_param(num_output, kernel_size, stride=stride,
pad=pad, weight_filler_type='bilinear', bias_term=False, groups=group)
layer.param.convolution_param.bias_term = False
log.cnet.add_layer(layer)
return x
'''
# transfer bilinear align_corners=True to caffe-interp
if mode == "bilinear" and align_corners == True:
x = raw(input, size, scale_factor, mode)
name = log.add_layer(name='interp')
log.add_blobs([x], name='interp_blob')
layer = caffe_net.Layer_param(name=name, type='Interp',
bottom=[log.blobs(input)], top=[log.blobs(x)])
layer.interp_param(size=size, scale_factor=scale_factor)
log.cnet.add_layer(layer)
return x
# for nearest _interpolate
if mode != "nearest" or align_corners != None:
raise NotImplementedError("not implement F.interpolate totoaly")
x = raw(input, size, scale_factor, mode)
layer_name = log.add_layer(name='upsample')
top_blobs = log.add_blobs([x], name='upsample_blob'.format(type))
layer = caffe_net.Layer_param(name=layer_name, type='Upsample',
bottom=[log.blobs(input)], top=top_blobs)
#layer.upsample_param(size=(input.size(2), input.size(3)), scale_factor=scale_factor)
#layer.upsample_param(size=size, scale_factor=scale_factor)
layer.upsample_param(size=None, scale_factor=size[0])
layer.upsample_param(size =(input.size(2),input.size(3)), scale_factor= scale_factor)
log.cnet.add_layer(layer)
return x
#sigmid layer
def _sigmoid(raw, input):
# Applies the element-wise function:
#
# Sigmoid(x)= 1/(1+exp(x)
#
#
x = raw(input)
name = log.add_layer(name='sigmoid')
log.add_blobs([x], name='sigmoid_blob')
layer = caffe_net.Layer_param(name=name, type='Sigmoid',
bottom=[log.blobs(input)], top=[log.blobs(x)])
log.cnet.add_layer(layer)
#tanh layer
def _tanh(raw, input):
# Applies the element-wise function:
#
# torch.nn.Tanh
#
#
x = raw(input)
name = log.add_layer(name='tanh')
log.add_blobs([x], name='tanh_blob')
layer = caffe_net.Layer_param(name=name, type='TanH',
bottom=[log.blobs(input)], top=[log.blobs(x)])
log.cnet.add_layer(layer)
def _hardtanh(raw, input, min_val, max_val, inplace):
# Applies the element-wise function:
#
# torch.nn.ReLu6
#
#
print('relu6: ', log.blobs(input))
x = raw(input, min_val, max_val)
name = log.add_layer(name='relu6')
log.add_blobs([x], name='relu6_blob')
layer = caffe_net.Layer_param(name=name, type='ReLU6',
bottom=[log.blobs(input)], top=[log.blobs(x)])
log.cnet.add_layer(layer)
return x
#L2Norm layer
def _l2Norm(raw, input, weight, eps):
# Applies the element-wise function:
#
# L2Norm in vgg_ssd
#
#
x = raw(input, weight, eps)
name = log.add_layer(name='normalize')
log.add_blobs([x], name='normalize_blob')
layer = caffe_net.Layer_param(name=name, type='Normalize',
bottom=[log.blobs(input)], top=[log.blobs(x)])
layer.norm_param(eps)
layer.add_data(weight.cpu().data.numpy())
log.cnet.add_layer(layer)
return x
def _div(raw,inputs, inputs2):
x=raw(inputs, inputs2)
log.add_blobs([x],name='div_blob')
return x
# ----- for Variable operations --------
def _view(input, *args):
@ -490,8 +498,13 @@ def _view(input, *args):
return x
layer_name = log.add_layer(name='view')
top_blobs = log.add_blobs([x], name='view_blob')
layer=caffe_net.Layer_param(name=layer_name,type='Reshape',
bottom=[log.blobs(input)],top=top_blobs)
# print('*'*60)
# print('input={}'.format(input))
# print('layer_name={}'.format(layer_name))
# print('top_blobs={}'.format(top_blobs))
layer = caffe_net.Layer_param(name=layer_name, type='Reshape', bottom=[log.blobs(input)], top=top_blobs)
# TODO: reshpae added to nn_tools layer
dims = list(args)
dims[0] = 0 # the first dim should be batch_size
@ -499,6 +512,7 @@ def _view(input, *args):
log.cnet.add_layer(layer)
return x
def _mean(input, *args, **kwargs):
x = raw_mean(input, *args, **kwargs)
if not NET_INITTED:
@ -518,21 +532,37 @@ def _mean(input, *args,**kwargs):
log.cnet.add_layer(layer)
return x
def _add(input, *args):
# check if add a const value
if isinstance(args[0], int):
print('value: ',args[0])
x = raw__add__(input, *args)
#x = raw(input)
layer_name = log.add_layer(name='scale')
log.add_blobs([x], name='Scale_blob')
layer = caffe_net.Layer_param(name=layer_name, type='Scale',
bottom=[log.blobs(input)], top=[log.blobs(x)])
dim = x.shape[1]
layer.param.scale_param.bias_term = True
weight = np.ones(dim, dtype=np.float32)
bias = args[0] * np.ones(dim, dtype=np.float32)
layer.add_data(weight, bias)
log.cnet.add_layer(layer)
return x
# otherwise add a tensor
x = raw__add__(input, *args)
if not NET_INITTED:
return x
layer_name = log.add_layer(name='add')
top_blobs = log.add_blobs([x], name='add_blob')
if log.blobs(args[0]) == None:
log.add_blobs([args[0]], name='extra_blob')
else:
layer = caffe_net.Layer_param(name=layer_name, type='Eltwise',
bottom=[log.blobs(input), log.blobs(args[0])], top=top_blobs)
layer.param.eltwise_param.operation = 1 # sum is 1
log.cnet.add_layer(layer)
return x
def _iadd(input, *args):
x = raw__iadd__(input, *args)
if not NET_INITTED:
@ -546,6 +576,7 @@ def _iadd(input, *args):
log.cnet.add_layer(layer)
return x
def _sub(input, *args):
x = raw__sub__(input, *args)
if not NET_INITTED:
@ -559,6 +590,7 @@ def _sub(input, *args):
log.cnet.add_layer(layer)
return x
def _isub(input, *args):
x = raw__isub__(input, *args)
if not NET_INITTED:
@ -572,8 +604,9 @@ def _isub(input, *args):
log.cnet.add_layer(layer)
return x
def _mul(input, *args):
x = raw__mul__(input, *args)
x = raw__sub__(input, *args)
if not NET_INITTED:
return x
layer_name = log.add_layer(name='mul')
@ -584,8 +617,9 @@ def _mul(input, *args):
log.cnet.add_layer(layer)
return x
def _imul(input, *args):
x = raw__imul__(input, *args)
x = raw__isub__(input, *args)
if not NET_INITTED:
return x
x = x.clone()
@ -599,64 +633,12 @@ def _imul(input, *args):
return x
#Permute layer
def _permute(input, *args):
x = raw__permute__(input, *args)
name = log.add_layer(name='permute')
log.add_blobs([x], name='permute_blob')
layer = caffe_net.Layer_param(name=name, type='Permute',
bottom=[log.blobs(input)], top=[log.blobs(x)])
order1 = args[0]
order2 = args[1]
order3 = args[2]
order4 = args[3]
layer.permute_param(order1, order2, order3, order4)
log.cnet.add_layer(layer)
def _adaptive_avg_pool2d(raw, input, output_size):
_output_size = _list_with_default(output_size, input.size())
x = raw(input, _output_size)
_pool('ave', raw, input, x, input.shape[2], input.shape[2], 0, False)
return x
#contiguous
def _contiguous(input, *args):
x = raw__contiguous__(input, *args)
name = log.add_layer(name='contiguous')
log.add_blobs([x], name='contiguous_blob')
layer = caffe_net.Layer_param(name=name, type='NeedRemove',
bottom=[log.blobs(input)], top=[log.blobs(x)])
log.cnet.add_layer(layer)
return x
#pow
def _pow(input, *args):
x = raw__pow__(input, *args)
log.add_blobs([x], name='pow_blob')
return x
#sum
def _sum(input, *args):
x = raw__sum__(input, *args)
log.add_blobs([x], name='sum_blob')
return x
# sqrt
def _sqrt(input, *args):
x = raw__sqrt__(input, *args)
log.add_blobs([x], name='sqrt_blob')
return x
# unsqueeze
def _unsqueeze(input, *args):
x = raw__unsqueeze__(input, *args)
log.add_blobs([x], name='unsqueeze_blob')
return x
# sqrt
def _expand_as(input, *args):
x = raw__expand_as__(input, *args)
log.add_blobs([x], name='expand_as_blob')
return x
# 核心组件通过该类实现对torch的function中的operators的输入输出以及参数的读取
class Rp(object):
@ -681,11 +663,10 @@ class Rp(object):
return out
F.conv2d = Rp(F.conv2d, _conv2d)
F.linear = Rp(F.linear, _linear)
F.relu = Rp(F.relu, _relu)
F.leaky_relu = Rp(F.leaky_relu, _leaky_relu)
F.max_pool2d = Rp(F.max_pool2d, _max_pool2d)
F.avg_pool2d = Rp(F.avg_pool2d, _avg_pool2d)
@ -697,16 +678,12 @@ F.instance_norm=Rp(F.instance_norm,_instance_norm)
F.softmax = Rp(F.softmax, _softmax)
F.conv_transpose2d = Rp(F.conv_transpose2d, _conv_transpose2d)
F.interpolate = Rp(F.interpolate, _interpolate)
F.sigmoid = Rp(F.sigmoid,_sigmoid)
F.tanh = Rp(F.tanh,_tanh)
F.tanh = Rp(F.tanh,_tanh)
F.hardtanh = Rp(F.hardtanh,_hardtanh)
# F.l2norm = Rp(F.l2norm,_l2Norm)
F.adaptive_avg_pool2d = Rp(F.adaptive_avg_pool2d, _adaptive_avg_pool2d)
torch.split = Rp(torch.split, _split)
torch.max = Rp(torch.max, _max)
torch.cat = Rp(torch.cat, _cat)
torch.div=Rp(torch.div,_div)
torch.sigmoid = Rp(torch.sigmoid, _sigmoid)
# TODO: other types of the view function
try:
@ -745,20 +722,6 @@ except:
t.__mul__ = _mul
raw__imul__ = t.__imul__
t.__imul__ = _imul
raw__permute__ = t.permute
t.permute = _permute
raw__contiguous__ = t.contiguous
t.contiguous = _contiguous
raw__pow__ = t.pow
t.pow = _pow
raw__sum__ = t.sum
t.sum = _sum
raw__sqrt__ = t.sqrt
t.sqrt = _sqrt
raw__unsqueeze__ = t.unsqueeze
t.unsqueeze = _unsqueeze
raw__expand_as__ = t.expand_as
t.expand_as = _expand_as
def trans_net(net, input_var, name='TransferedPytorchModel'):
@ -775,9 +738,10 @@ def trans_net(net,input_var,name='TransferedPytorchModel'):
out = net.forward(input_var)
print('Transform Completed')
def save_prototxt(save_name):
log.cnet.remove_layer_by_type("NeedRemove")
log.cnet.save_prototxt(save_name)
def save_caffemodel(save_name):
log.cnet.save(save_name)

View File

@ -1,8 +1,10 @@
python caffe_inference.py --model-def "logs/caffe_R34/baseline_R34.prototxt" \
--model-weights "logs/caffe_R34/baseline_R34.caffemodel" \
--height 256 --width 128 \
--input \
'/export/home/DATA/Market-1501-v15.09.15/bounding_box_test/1182_c5s3_015240_04.jpg' \
'/export/home/DATA/Market-1501-v15.09.15/bounding_box_test/1182_c6s3_038217_01.jpg' \
'/export/home/DATA/Market-1501-v15.09.15/bounding_box_test/1183_c5s3_006943_05.jpg' \
'/export/home/DATA/DukeMTMC-reID/bounding_box_train/0728_c4_f0161265.jpg' \
--output "caffe_R34_output"