Skip to content

Commit

Permalink
Merge pull request xxradon#1 from xxradon/master
Browse files Browse the repository at this point in the history
update
  • Loading branch information
Guanmoyu authored Dec 11, 2019
2 parents 7b2e277 + abd764d commit 0b4f642
Show file tree
Hide file tree
Showing 11 changed files with 1,995 additions and 1,807 deletions.
2 changes: 1 addition & 1 deletion Caffe/ReadMe.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# The Caffe in nn_tools Provides some convenient API
# The Caffe in PytorchToCaffe 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`
Expand Down
Binary file removed Caffe/__pycache__/__init__.cpython-36.pyc
Binary file not shown.
Binary file removed Caffe/__pycache__/caffe_net.cpython-36.pyc
Binary file not shown.
Binary file removed Caffe/__pycache__/caffe_pb2.cpython-36.pyc
Binary file not shown.
Binary file removed Caffe/__pycache__/layer_param.cpython-36.pyc
Binary file not shown.
51 changes: 29 additions & 22 deletions Caffe/caffe.proto
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,7 @@ 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;
Expand Down Expand Up @@ -600,7 +601,7 @@ message LayerParameter {
optional CropParameter crop_param = 167;
optional DetectionEvaluateParameter detection_evaluate_param = 168;
optional DetectionOutputParameter detection_output_param = 169;
//optional NormalizeParameter normalize_param = 170;
optional NormalizeParameter norm_param = 170;
optional MultiBoxLossParameter multibox_loss_param = 171;
optional PermuteParameter permute_param = 172;
optional VideoDataParameter video_data_param = 173;
Expand Down Expand Up @@ -632,7 +633,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******************
Expand All @@ -658,13 +659,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];
//}



Expand Down Expand Up @@ -1592,19 +1593,15 @@ 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];
// //**************************************************
// optional string normalize_type = 1 [default = "L2"];
// optional bool fix_gradient = 2 [default = false];
// optional bool bp_norm = 3 [default = false];
//}
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 PermuteParameter {
// The new orders of the axes of data. Notice it should be with
Expand Down Expand Up @@ -1792,6 +1789,16 @@ 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).
Expand Down
18 changes: 17 additions & 1 deletion Caffe/caffe_net.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
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.
Expand Down Expand Up @@ -39,6 +40,18 @@ def remove_layer_by_name(self,layer_name):
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)
self.needChange[layer.top[0]]=layer.bottom[0]
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:
Expand All @@ -52,7 +65,10 @@ def save_prototxt(self,path):
for layer in prototxt.layer:
del layer.blobs[:]
with open(path,'w') as f:
f.write(text_format.MessageToString(prototxt))
string = text_format.MessageToString(prototxt)
for origin_name in self.needChange.keys():
string = string.replace(origin_name,self.needChange[origin_name])
f.write(string)

def layer(self,layer_name):
return self.get_layer_by_name(layer_name)
Expand Down
3,477 changes: 1,715 additions & 1,762 deletions Caffe/caffe_pb2.py

Large diffs are not rendered by default.

46 changes: 44 additions & 2 deletions Caffe/layer_param.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,57 @@ def conv_param(self, num_output, kernel_size, stride=(1), pad=(0,),
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 pool_param(self,type='MAX',kernel_size=2,stride=2,pad=None):
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):
pool_param=pb.PoolingParameter()
pool_param.pool=pool_param.PoolMethod.Value(type)
pool_param.kernel_size=pair_process(kernel_size)
pool_param.stride=pair_process(stride)
pool_param.ceil_mode=ceil_mode
if pad:
pool_param.pad=pad
if isinstance(pad,tuple):
pool_param.pad_h = pad[0]
pool_param.pad_w = pad[1]
else:
pool_param.pad=pad
self.param.pooling_param.CopyFrom(pool_param)

def batch_norm_param(self,use_global_stats=0,moving_average_fraction=None,eps=None):
Expand Down
33 changes: 26 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@

1. Converting a pytorch model to caffe model.
2. Some convenient tools of manipulate caffemodel and prototxt quickly(like get or set weights of layers).
3. Support pytorch version >= 0.2.(Have tested on 0.3,0.3.1, 0.4, 0.4.1 ,1.0)
3. Support pytorch version >= 0.2.(Have tested on 0.3,0.3.1, 0.4, 0.4.1 ,1.0, 1.2)
4. Analysing a model, get the operations number(ops) in every layers.

Noting: pytorch version 1.1 is not supported now

### requirements

- Python2.7 or Python3.x
Expand Down Expand Up @@ -53,7 +55,7 @@ For example `python pytorch_analyser.py example/resnet_pytorch_analysis_example.

## Pytorch to Caffe

The new version of pytorch_to_caffe supporting the newest version(from 0.2.0 to 0.4.1) of pytorch.
The new version of pytorch_to_caffe supporting the newest version(from 0.2.0 to 1.2.0) of pytorch.
NOTICE: The transfer output will be somewhat different with the original model, caused by implementation difference.

- Supporting layers types:
Expand All @@ -74,29 +76,46 @@ dropout -> Dropout,
batch_norm -> BatchNorm,Scale,
instance_norm -> BatchNorm,Scale,
_interpolate -> Upsample
_hardtanh -> ReLU6
_permute -> Permute
_l2Norm -> Normalize


- Supporting operations: torch.split, torch.max, torch.cat
- Supporting operations: torch.split, torch.max, torch.cat ,torch.sigmoid, torch.div
- Supporting tensor Variable operations: var.view, + (add), += (iadd), -(sub), -=(isub)
\* (mul) *= (imul)
\* (mul) *= (imul), torch.Tensor.contiguous(_contiguous), torch.Tensor.pow(_pow),
\* torch.Tensor.sum(_sum), torch.Tensor.sqrt(_sqrt), torch.Tensor.unsqueeze(_unsqueeze)
\* torch.Tensor.expand_as(_expand_as),

Need to be added for caffe in the future:
- Normalize,DepthwiseConv
- DepthwiseConv

The supported above can transfer many kinds of nets,
such as AlexNet(tested), VGG(tested), ResNet(fixed the bug in origin repo which mainly caused by ReLu layer function.), Inception_V3(tested).

The supported layers concluded the most popular layers and operations.
The other layer types will be added soon, you can ask me to add them in issues.

Example: please see file `example/alexnet_pytorch_to_caffe.py`. Just Run `python3 example/alexnet_pytorch_to_caffe.py`
Example: please see file `example/alexnet_pytorch_to_caffe.py`. Just Run `python3 example/alexnet_pytorch_to_caffe.py`.

# Deploy verify
Attention:
the main difference from convert model is the BN layer,you should pay more attention to the BN parameters like momentum=0.1, eps=1e-5.

# Deploy verify(Very Important)
After Converter,we should use verify_deploy.py to verify the output of pytorch model and the convertted caffe model.
If you want to verify the outputs of caffe and pytorch,you should make caffe and pytorch install in the same environment,anaconda is recommended.
using following script,we can install caffe-gpu(master branch).
```angular2html
conda install caffe-gpu pytorch cudatoolkit=9.0 -c pytorch
```
other way,we can use docker,and in https://github.com/ufoym/deepo,for cuda9
```
docker pull ufoym/deepo:all-py36-cu90
```
for cuda10
```
docker pull ufoym/deepo:all-py36-cu100
```

please see file `example/verify_deploy.py`,it can verify the output of pytorch model and the convertted caffe model in the same input.
Expand Down
Loading

0 comments on commit 0b4f642

Please sign in to comment.