Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions fluid/image_classification/caffe2fluid/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
### Caffe2Fluid
This tool is used to convert a Caffe model to a Fluid model

### Key Features
1. Convert caffe model to fluid model with codes of defining a network(useful for re-training)

2. Pycaffe is not necessary when just want convert model without do caffe-inference

3. Caffe's customized layers convertion also be supported by extending this tool

4. A bunch of tools in '*examples/imagenet/tools*' are provided to compare the difference

### HowTo
1. Prepare caffepb.py in ./proto if your python has no 'pycaffe' module, two options provided here:
- Generate pycaffe from caffe.proto
Expand Down Expand Up @@ -29,10 +38,10 @@ This tool is used to convert a Caffe model to a Fluid model
```

3. Use the converted model to infer
- See more details in '*examples/imagenet/run.sh*'
- See more details in '*examples/imagenet/tools/run.sh*'

4. Compare the inference results with caffe
- See more details in '*examples/imagenet/diff.sh*'
- See more details in '*examples/imagenet/tools/diff.sh*'

### How to convert custom layer
1. Implement your custom layer in a file under '*kaffe/custom_layers*', eg: mylayer.py
Expand Down
34 changes: 19 additions & 15 deletions fluid/image_classification/caffe2fluid/examples/imagenet/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
A demo to show converting caffe models on 'imagenet' using caffe2fluid
A demo to show converting caffe models trained on 'imagenet' using caffe2fluid

---

Expand All @@ -10,28 +10,32 @@ A demo to show converting caffe models on 'imagenet' using caffe2fluid

3. Convert the Caffe model to Fluid model
- generate fluid code and weight file
<pre><code>python convert.py alexnet.prototxt \
```python convert.py alexnet.prototxt \
--caffemodel alexnet.caffemodel \
--data-output-path alexnet.npy \
--code-output-path alexnet.py
</code></pre>
```

- save weights as fluid model file
<pre><code>python alexnet.py alexnet.npy ./fluid_model
</code></pre>
```
python alexnet.py alexnet.npy ./fluid
```

4. Do inference
<pre><code>python infer.py infer ./fluid_mode data/65.jpeg
</code></pre>
```
python infer.py infer ./fluid data/65.jpeg
```

5. convert model and do inference together
<pre><code>bash ./run.sh alexnet ./models.caffe/alexnet ./models/alexnet
</code></pre>
The Caffe model is stored in './models.caffe/alexnet/alexnet.prototxt|caffemodel'
and the Fluid model will be save in './models/alexnet/alexnet.py|npy'
```
bash ./tools/run.sh alexnet ./models.caffe/alexnet ./models/alexnet
```
* Assume the Caffe model is stored in '*./models.caffe/alexnet/alexnet.prototxt|caffemodel*'
* converted model will be stored as '*./models/alexnet/alexnet.py|npy*'

6. test the difference with caffe's results(need pycaffe installed)
<pre><code>bash ./diff.sh resnet
</code></pre>
Make sure your caffemodel stored in './models.caffe/resnet'.
The results will be stored in './results/resnet.paddle|caffe'
```
bash ./tools/diff.sh resnet
```
* Make sure your caffemodel stored in '*./models.caffe/resnet*'
* The results will be stored in '*./results/resnet.paddle|caffe*'
42 changes: 30 additions & 12 deletions fluid/image_classification/caffe2fluid/examples/imagenet/compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,21 @@ def walk_dir(rootdir):
def calc_diff(f1, f2):
import numpy as np

d1 = np.load(f1).flatten()
d2 = np.load(f2).flatten()
d1 = np.load(f1)
d2 = np.load(f2)

print d1.shape
print d2.shape
#print d1[0, 0, 0:10, 0:10]
#print d2[0, 0, 0:10, 0:10]
#d1 = d1[:, :, 1:-2, 1:-2]
#d2 = d2[:, :, 1:-2, 1:-2]

d1 = d1.flatten()
d2 = d2.flatten()

#print d1[:10]
#print d2[:10]

d1_num = reduce(lambda x, y: x * y, d1.shape)
d2_num = reduce(lambda x, y: x * y, d2.shape)
Expand All @@ -36,15 +49,16 @@ def calc_diff(f1, f2):
return -1.0, -1.0


def compare(path1, path2):
def compare(path1, path2, no_exception):
def diff(f1, f2):
max_df, sq_df = calc_diff(f1, f2)
print('compare %s <=> %s with result[max_df:%.4e, sq_df:%.4e]' %
(f1, f2, max_df, sq_df))
assert (max_df < 1e-5), \
'max_df is too large with value[%.6e]' % (max_df)
assert (sq_df < 1e-10), \
'sq_df is too large with value[%.6e]' % (sq_df)
print('[max_df:%.4e, sq_df:%.4e] when compare %s <=> %s' %
(max_df, sq_df, os.path.basename(f1), os.path.basename(f2)))
if no_exception is False:
assert (max_df < 1e-5), \
'max_df is too large with value[%.6e]' % (max_df)
assert (sq_df < 1e-10), \
'sq_df is too large with value[%.6e]' % (sq_df)

if os.path.exists(path1) is False:
print('not found %s' % (path1))
Expand Down Expand Up @@ -73,13 +87,17 @@ def diff(f1, f2):
if len(sys.argv) == 1:
path1 = 'lenet.tf/results'
path2 = 'lenet.paddle/results'
elif len(sys.argv) == 3:
elif len(sys.argv) >= 3:
path1 = sys.argv[1]
path2 = sys.argv[2]
if len(sys.argv) == 4:
no_exception = True
else:
no_exception = False
else:
print('usage:')
print(' %s [path1] [path2]' % (sys.argv[0]))
exit(1)

print('compare inner result in %s %s' % (path1, path2))
exit(compare(path1, path2))
#print('compare inner result in %s %s' % (path1, path2))
exit(compare(path1, path2, no_exception))
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,6 @@ def caffe_infer(prototxt, caffemodel, datafile):
results = []
names = []
for k, v in net.blobs.items():
k = k.rstrip('_output')
k = k.replace('/', '_')
names.append(k)
results.append(v.data.copy())
Expand Down Expand Up @@ -259,7 +258,7 @@ def caffe_infer(prototxt, caffemodel, datafile):
print('usage:')
print('\tpython %s dump [net_file] [weight_file] [datafile] [net_name]' \
% (sys.argv[0]))
print('\teg:python dump %s %s %s %s %s' % (sys.argv[0],\
print('\teg:python %s dump %s %s %s %s' % (sys.argv[0],\
net_file, weight_file, datafile, net_name))
sys.exit(1)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/bash

#
#function:
# a tool used to compare the results produced by paddle and caffe
#

if [[ $# -lt 2 ]];then
echo "usage:"
echo " bash $0 [model_name] [param_name] [caffe_name]"
exit 1
fi

model_name=$1
param_name=$2
paddle_file="./results/${model_name}.paddle/${param_name}.npy"
if [[ $# -eq 3 ]];then
caffe_file="./results/${model_name}.caffe/${3}.npy"
else
caffe_file="./results/${model_name}.caffe/${2}.npy"
fi
python ./compare.py $paddle_file $caffe_file
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/bin/bash

#function:
# a tool used to compare all layers' results
#

if [[ $# -ne 1 ]];then
echo "usage:"
echo " bash $0 [model_name]"
echo " eg:bash $0 alexnet"
exit 1
fi

model_name=$1
prototxt="models.caffe/$model_name/${model_name}.prototxt"
layers=$(cat $prototxt | perl -ne 'if(/^\s+name\s*:\s*\"([^\"]+)/){print $1."\n";}')

for i in $layers;do
cf_npy="results/${model_name}.caffe/${i}.npy"
pd_npy="results/${model_name}.paddle/${i}.npy"

if [[ ! -e $cf_npy ]];then
echo "caffe's result not exist[$cf_npy]"
continue
fi

if [[ ! -e $pd_npy ]];then
echo "paddle's result not exist[$pd_npy]"
continue
fi

python compare.py $cf_npy $pd_npy no_exception
if [[ $? -eq 0 ]];then
echo "succeed to compare layer[$i]"
else
echo "failed to compare layer[$i]"
fi

done
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ model_caffemodel="models.caffe/${model_name}/${model_name}.caffemodel"
paddle_results="$results_root/${model_name}.paddle"
rm -rf $paddle_results
rm -rf "results.paddle"
bash run.sh $model_name ./models.caffe/$model_name ./models/$model_name
bash ./tools/run.sh $model_name ./models.caffe/$model_name ./models/$model_name
if [[ $? -ne 0 ]] || [[ ! -e "results.paddle" ]];then
echo "not found paddle's results, maybe failed to convert"
exit 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# 2, do inference(only in fluid) using this model
#
#usage:
# bash run.sh resnet50 ./models.caffe/resnet50 ./models/resnet50
# cd caffe2fluid/examples/imagenet && bash run.sh resnet50 ./models.caffe/resnet50 ./models/resnet50
#

#set -x
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
import axpy
import flatten
import argmax
import reshape

#custom layer import ends

custom_layers = get_registered_layers()


def set_args(f, params):
def set_args(f, params, node=None):
""" set args for function 'f' using the parameters in node.layer.parameters

Args:
Expand All @@ -24,19 +25,15 @@ def set_args(f, params):
arg_names (list): a list of argument names
kwargs (dict): a dict contains needed arguments
"""
from ..protobuf_to_dict import protobuf_to_dict

argc = f.__code__.co_argcount
arg_list = f.__code__.co_varnames[0:argc]

kwargs = {}
for arg_name in arg_list:
try:
v = getattr(params, arg_name, None)
except Exception as e:
#maybe failed to extract caffe's parameters
v = None

if v is not None:
kwargs[arg_name] = v
if arg_name in params:
kwargs[arg_name] = params[arg_name]

return arg_list, kwargs

Expand All @@ -54,7 +51,7 @@ def compute_output_shape(kind, node):

parents = node.parents
inputs = [list(p.output_shape) for p in parents]
arg_names, kwargs = set_args(shape_func, node.layer.parameters)
arg_names, kwargs = set_args(shape_func, node.params)

if len(inputs) == 1:
inputs = inputs[0]
Expand All @@ -80,7 +77,7 @@ def make_node(template, kind, node):
layer_func = custom_layers[kind]['layer']

#construct arguments needed by custom layer function from node's parameters
arg_names, kwargs = set_args(layer_func, node.layer.parameters)
arg_names, kwargs = set_args(layer_func, node.params, node)

return template('custom_layer', kind, **kwargs)

Expand Down
Loading