提交 d300e5e4 编写于 作者: W walloollaw 提交者: qingqing01

Update readme for caffe2fluid (#839)

* fix code style problems

* fix bug when loading fluid model

* fix code style problem in brain.py

* update readme.md for caffe2fluid

* fix code style and add save_inference_model in caffe2fluid
上级 609dc345
...@@ -2,20 +2,31 @@ ...@@ -2,20 +2,31 @@
This tool is used to convert a Caffe model to Fluid model This tool is used to convert a Caffe model to Fluid model
### Howto ### Howto
1, Prepare caffepb.py in ./proto if your python has no 'pycaffe' module, two options provided here: 1. Prepare caffepb.py in ./proto if your python has no 'pycaffe' module, two options provided here:
- Generate pycaffe from caffe.proto
<pre><code>bash ./proto/compile.sh</code></pre>
1) generate it from caffe.proto using protoc - download one from github directly
bash ./proto/compile.sh <pre><code>cd proto/ && wget https://github.com/ethereon/caffe-tensorflow/blob/master/kaffe/caffe/caffepb.py
</code></pre>
2) download one from github directly 2. Convert the Caffe model to Fluid model
cd proto/ && wget https://github.com/ethereon/caffe-tensorflow/blob/master/kaffe/caffe/caffepb.py - generate fluid code and weight file
<pre><code>python convert.py alexnet.prototxt \
--caffemodel alexnet.caffemodel \
--data-output-path alexnet.npy \
--code-output-path alexnet.py
</code></pre>
2, Convert the caffe model using 'convert.py' which will generate a python script and a weight(in .npy) file - save weights as fluid model file
<pre><code>python alexnet.py alexnet.npy ./fluid_model
</code></pre>
3, Use the converted model to predict 3. Use the converted model to infer
- see more details in '*examples/imagenet/run.sh*'
see more detail info in 'examples/xxx'
4. compare the inference results with caffe
- see more details in '*examples/imagenet/diff.sh*'
### Tested models ### Tested models
- Lenet - Lenet
...@@ -33,4 +44,4 @@ This tool is used to convert a Caffe model to Fluid model ...@@ -33,4 +44,4 @@ This tool is used to convert a Caffe model to Fluid model
[model addr](https://github.com/BVLC/caffe/tree/master/models/bvlc_alexnet) [model addr](https://github.com/BVLC/caffe/tree/master/models/bvlc_alexnet)
### Notes ### Notes
Some of this code come from here: https://github.com/ethereon/caffe-tensorflow Some of this code come from here: [caffe-tensorflow](https://github.com/ethereon/caffe-tensorflow)
a demo to show converting caffe models on 'imagenet' using caffe2fluid A demo to show converting caffe models on 'imagenet' using caffe2fluid
--- ---
# How to use # How to use
1. prepare python environment 1. Prepare python environment
2. download caffe model to "models.caffe/xxx" which contains "xxx.caffemodel" and "xxx.prototxt"
3. run the tool 2. Download caffe model to "models.caffe/xxx" which contains "xxx.caffemodel" and "xxx.prototxt"
eg: bash ./run.sh resnet50 ./models.caffe/resnet50 ./models/resnet50
3. Convert the Caffe model to Fluid model
- generate fluid code and weight file
<pre><code>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>
4. Do inference
<pre><code>python infer.py infer ./fluid_mode data/65.jpeg
</code></pre>
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'
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'
...@@ -59,12 +59,12 @@ def build_model(net_file, net_name): ...@@ -59,12 +59,12 @@ def build_model(net_file, net_name):
inputs_dict = MyNet.input_shapes() inputs_dict = MyNet.input_shapes()
input_name = inputs_dict.keys()[0] input_name = inputs_dict.keys()[0]
input_shape = inputs_dict[input_name] input_shape = inputs_dict[input_name]
images = fluid.layers.data(name='image', shape=input_shape, dtype='float32') images = fluid.layers.data(
name=input_name, shape=input_shape, dtype='float32')
#label = fluid.layers.data(name='label', shape=[1], dtype='int64') #label = fluid.layers.data(name='label', shape=[1], dtype='int64')
net = MyNet({input_name: images}) net = MyNet({input_name: images})
input_shape = MyNet.input_shapes()[input_name] return net, inputs_dict
return net, input_shape
def dump_results(results, names, root): def dump_results(results, names, root):
...@@ -78,26 +78,27 @@ def dump_results(results, names, root): ...@@ -78,26 +78,27 @@ def dump_results(results, names, root):
np.save(filename + '.npy', res) np.save(filename + '.npy', res)
def infer(net_file, net_name, model_file, imgfile, debug=True): def load_model(exe, place, net_file, net_name, net_weight, debug):
""" do inference using a model which consist 'xxx.py' and 'xxx.npy' """ load model using xxxnet.py and xxxnet.npy
""" """
fluid = import_fluid() fluid = import_fluid()
#1, build model #1, build model
net, input_shape = build_model(net_file, net_name) net, input_map = build_model(net_file, net_name)
feed_names = input_map.keys()
feed_shapes = [v for k, v in input_map.items()]
prediction = net.get_output() prediction = net.get_output()
#2, load weights for this model #2, load weights for this model
place = fluid.CPUPlace()
exe = fluid.Executor(place)
startup_program = fluid.default_startup_program() startup_program = fluid.default_startup_program()
exe.run(startup_program) exe.run(startup_program)
if model_file.find('.npy') > 0: #place = fluid.CPUPlace()
net.load(data_path=model_file, exe=exe, place=place) if net_weight.find('.npy') > 0:
net.load(data_path=net_weight, exe=exe, place=place)
else: else:
net.load(data_path=model_file, exe=exe) raise ValueError('not found weight file')
#3, test this model #3, test this model
test_program = fluid.default_main_program().clone() test_program = fluid.default_main_program().clone()
...@@ -111,10 +112,75 @@ def infer(net_file, net_name, model_file, imgfile, debug=True): ...@@ -111,10 +112,75 @@ def infer(net_file, net_name, model_file, imgfile, debug=True):
fetch_list_var.append(v) fetch_list_var.append(v)
fetch_list_name.append(k) fetch_list_name.append(k)
return {
'program': test_program,
'feed_names': feed_names,
'fetch_vars': fetch_list_var,
'fetch_names': fetch_list_name,
'feed_shapes': feed_shapes
}
def get_shape(fluid, program, name):
for var in program.list_vars():
if var.name == 'data':
return list(var.shape[1:])
raise ValueError('not found shape for input layer[%s], '
'you can specify by yourself' % (name))
def load_inference_model(dirname, exe):
""" load fluid's inference model
"""
fluid = import_fluid()
model_fn = 'model'
params_fn = 'params'
if os.path.exists(os.path.join(dirname, model_fn)) \
and os.path.exists(os.path.join(dirname, params_fn)):
program, feed_names, fetch_targets = fluid.io.load_inference_model(\
dirname, exe, model_fn, params_fn)
else:
raise ValueError('not found model files in direcotry[%s]' % (dirname))
#print fluid.global_scope().find_var(feed_names[0])
input_shape = get_shape(fluid, program, feed_names[0])
feed_shapes = [input_shape]
return program, feed_names, fetch_targets, feed_shapes
def infer(model_path, imgfile, net_file=None, net_name=None, debug=True):
""" do inference using a model which consist 'xxx.py' and 'xxx.npy'
"""
fluid = import_fluid()
place = fluid.CPUPlace()
exe = fluid.Executor(place)
try:
ret = load_inference_model(model_path, exe)
program, feed_names, fetch_targets, feed_shapes = ret
debug = False
print('found a inference model for fluid')
except ValueError as e:
pass
print('try to load model using net file and weight file')
net_weight = model_path
ret = load_model(exe, place, net_file, net_name, net_weight, debug)
program = ret['program']
feed_names = ret['feed_names']
fetch_targets = ret['fetch_vars']
fetch_list_name = ret['fetch_names']
feed_shapes = ret['feed_shapes']
input_name = feed_names[0]
input_shape = feed_shapes[0]
np_images = load_data(imgfile, input_shape) np_images = load_data(imgfile, input_shape)
results = exe.run(program=test_program, results = exe.run(program=program,
feed={'image': np_images}, feed={input_name: np_images},
fetch_list=fetch_list_var) fetch_list=fetch_targets)
if debug is True: if debug is True:
dump_path = 'results.paddle' dump_path = 'results.paddle'
...@@ -122,7 +188,7 @@ def infer(net_file, net_name, model_file, imgfile, debug=True): ...@@ -122,7 +188,7 @@ def infer(net_file, net_name, model_file, imgfile, debug=True):
print('all result of layers dumped to [%s]' % (dump_path)) print('all result of layers dumped to [%s]' % (dump_path))
else: else:
result = results[0] result = results[0]
print('predicted class:', np.argmax(result)) print('succeed infer with results[class:%d]' % (np.argmax(result)))
return 0 return 0
...@@ -167,9 +233,12 @@ if __name__ == "__main__": ...@@ -167,9 +233,12 @@ if __name__ == "__main__":
weight_file = 'models/resnet50/resnet50.npy' weight_file = 'models/resnet50/resnet50.npy'
datafile = 'data/65.jpeg' datafile = 'data/65.jpeg'
net_name = 'ResNet50' net_name = 'ResNet50'
model_file = 'models/resnet50/fluid'
argc = len(sys.argv) ret = None
if sys.argv[1] == 'caffe': if len(sys.argv) <= 2:
pass
elif sys.argv[1] == 'caffe':
if len(sys.argv) != 5: if len(sys.argv) != 5:
print('usage:') print('usage:')
print('\tpython %s caffe [prototxt] [caffemodel] [datafile]' % print('\tpython %s caffe [prototxt] [caffemodel] [datafile]' %
...@@ -178,18 +247,34 @@ if __name__ == "__main__": ...@@ -178,18 +247,34 @@ if __name__ == "__main__":
prototxt = sys.argv[2] prototxt = sys.argv[2]
caffemodel = sys.argv[3] caffemodel = sys.argv[3]
datafile = sys.argv[4] datafile = sys.argv[4]
sys.exit(caffe_infer(prototxt, caffemodel, datafile)) ret = caffe_infer(prototxt, caffemodel, datafile)
elif argc == 5: elif sys.argv[1] == 'infer':
net_file = sys.argv[1] if len(sys.argv) != 4:
weight_file = sys.argv[2] print('usage:')
print('\tpython %s infer [fluid_model] [datafile]' % (sys.argv[0]))
sys.exit(1)
model_path = sys.argv[2]
datafile = sys.argv[3] datafile = sys.argv[3]
net_name = sys.argv[4] ret = infer(model_path, datafile)
elif argc > 1: elif sys.argv[1] == 'dump':
if len(sys.argv) != 6:
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],\
net_file, weight_file, datafile, net_name))
sys.exit(1)
net_file = sys.argv[2]
weight_file = sys.argv[3]
datafile = sys.argv[4]
net_name = sys.argv[5]
ret = infer(weight_file, datafile, net_file, net_name)
if ret is None:
print('usage:') print('usage:')
print('\tpython %s [net_file] [weight_file] [datafile] [net_name]' % print(' python %s [infer] [fluid_model] [imgfile]' % (sys.argv[0]))
(sys.argv[0])) print(' eg:python %s infer %s %s' % (sys.argv[0], model_file, datafile))
print('\teg:python %s %s %s %s %s' % (sys.argv[0], net_file,
weight_file, datafile, net_name))
sys.exit(1) sys.exit(1)
infer(net_file, net_name, weight_file, datafile) sys.exit(ret)
...@@ -71,7 +71,7 @@ if [[ -z $only_convert ]];then ...@@ -71,7 +71,7 @@ if [[ -z $only_convert ]];then
if [[ -z $net_name ]];then if [[ -z $net_name ]];then
net_name="MyNet" net_name="MyNet"
fi fi
$PYTHON ./infer.py $net_file $weight_file $imgfile $net_name $PYTHON ./infer.py dump $net_file $weight_file $imgfile $net_name
ret=$? ret=$?
fi fi
exit $ret exit $ret
文件模式从 100644 更改为 100755
...@@ -216,7 +216,10 @@ class TensorFlowEmitter(object): ...@@ -216,7 +216,10 @@ class TensorFlowEmitter(object):
def emit_convert_def(self, input_nodes): def emit_convert_def(self, input_nodes):
codes = [] codes = []
inputs = {} inputs = {}
#codes.append('shapes = cls.input_shapes()')
codes.append('shapes = cls.input_shapes()') codes.append('shapes = cls.input_shapes()')
codes.append('input_name = shapes.keys()[0]')
codes.append('input_shape = shapes[input_name]')
for n in input_nodes: for n in input_nodes:
name = n.name name = n.name
layer_var = name + '_layer' layer_var = name + '_layer'
...@@ -235,8 +238,14 @@ class TensorFlowEmitter(object): ...@@ -235,8 +238,14 @@ class TensorFlowEmitter(object):
codes.append("exe = fluid.Executor(place)") codes.append("exe = fluid.Executor(place)")
codes.append("exe.run(fluid.default_startup_program())") codes.append("exe.run(fluid.default_startup_program())")
codes.append("net.load(data_path=npy_model, exe=exe, place=place)") codes.append("net.load(data_path=npy_model, exe=exe, place=place)")
codes.append("output_vars = [net.get_output()]")
codes.append("fluid.io.save_inference_model(" \
"fluid_path, [input_name],output_vars," \
"exe, main_program=None, model_filename='model'," \
"params_filename='params')")
codes.append( codes.append(
"fluid.io.save_persistables(executor=exe, dirname=fluid_path)") "print('save fluid model as [model] and [params] in directory [%s]' % (fluid_path))"
)
self.outdent() self.outdent()
func_def = self.statement('@classmethod') func_def = self.statement('@classmethod')
...@@ -254,8 +263,17 @@ class TensorFlowEmitter(object): ...@@ -254,8 +263,17 @@ class TensorFlowEmitter(object):
self.prefix = '' self.prefix = ''
main_def = self.statement('if __name__ == "__main__":') main_def = self.statement('if __name__ == "__main__":')
self.indent() self.indent()
main_def += self.statement("#usage: python xxxnet.py xxx.npy ./model\n") main_def += self.statement(
"#usage: save as an inference model for online service\n")
main_def += self.statement("import sys") main_def += self.statement("import sys")
main_def += self.statement("if len(sys.argv) != 3:")
self.indent()
main_def += self.statement("print('usage:')")
main_def += self.statement(
"print('\tpython %s [xxxnet.npy] [save_dir]' % (sys.argv[0]))")
main_def += self.statement("exit(1)")
self.outdent()
main_def += self.statement("npy_weight = sys.argv[1]") main_def += self.statement("npy_weight = sys.argv[1]")
main_def += self.statement("fluid_model = sys.argv[2]") main_def += self.statement("fluid_model = sys.argv[2]")
main_def += self.statement("%s.convert(npy_weight, fluid_model)" % main_def += self.statement("%s.convert(npy_weight, fluid_model)" %
......
文件模式从 100644 更改为 100755
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册