diff --git a/fluid/adversarial/README.md b/fluid/adversarial/README.md index 39953ef491efb92e59e2ba9208fa92ad9df5b384..91661f7e1675d59c7d38c4c09bc67d5b9339573d 100644 --- a/fluid/adversarial/README.md +++ b/fluid/adversarial/README.md @@ -54,6 +54,7 @@ The structure of Advbox module are as follows: | ├── mnist_tutorial_fgsm.py | ├── mnist_tutorial_bim.py | ├── mnist_tutorial_ilcm.py + | ├── mnist_tutorial_mifgsm.py | ├── mnist_tutorial_jsma.py | └── mnist_tutorial_deepfool.py └── README.md @@ -77,6 +78,7 @@ The `./tutorials/` folder provides some tutorials to generate adversarial exampl * [FGSM](https://arxiv.org/abs/1412.6572) * [BIM](https://arxiv.org/abs/1607.02533) * [ILCM](https://arxiv.org/abs/1607.02533) +* [MI-FGSM](https://arxiv.org/pdf/1710.06081.pdf) * [JSMA](https://arxiv.org/pdf/1511.07528) * [DeepFool](https://arxiv.org/abs/1511.04599) @@ -91,6 +93,7 @@ Benchmarks on a vanilla CNN model. |FGSM| 57.8% | 26.55% | 0.3 | One shot| *** | |BIM| 97.4% | --- | 0.1 | 100 | **** | |ILCM| --- | 100.0% | 0.1 | 100 | **** | +|MI-FGSM| 94.4% | 100.0% | 0.1 | 100 | **** | |JSMA| 96.8% | 90.4%| 0.1 | 2000 | *** | |DeepFool| 97.7% | 51.3% | --- | 100 | **** | @@ -101,8 +104,9 @@ Benchmarks on a vanilla CNN model. * [Intriguing properties of neural networks](https://arxiv.org/abs/1312.6199), C. Szegedy et al., arxiv 2014 * [Explaining and Harnessing Adversarial Examples](https://arxiv.org/abs/1412.6572), I. Goodfellow et al., ICLR 2015 * [Adversarial Examples In The Physical World](https://arxiv.org/pdf/1607.02533v3.pdf), A. Kurakin et al., ICLR workshop 2017 +* [Boosting Adversarial Attacks with Momentum](https://arxiv.org/abs/1710.06081), Yinpeng Dong et al., arxiv 2018 * [The Limitations of Deep Learning in Adversarial Settings](https://arxiv.org/abs/1511.07528), N. Papernot et al., ESSP 2016 * [DeepFool: a simple and accurate method to fool deep neural networks](https://arxiv.org/abs/1511.04599), S. Moosavi-Dezfooli et al., CVPR 2016 -* [Foolbox: A Python toolbox to benchmark the robustness of machine learning models] (https://arxiv.org/abs/1707.04131), Jonas Rauber et al., arxiv 2018 +* [Foolbox: A Python toolbox to benchmark the robustness of machine learning models](https://arxiv.org/abs/1707.04131), Jonas Rauber et al., arxiv 2018 * [CleverHans: An adversarial example library for constructing attacks, building defenses, and benchmarking both](https://github.com/tensorflow/cleverhans#setting-up-cleverhans) * [Threat of Adversarial Attacks on Deep Learning in Computer Vision: A Survey](https://arxiv.org/abs/1801.00553), Naveed Akhtar, Ajmal Mian, arxiv 2018 diff --git a/fluid/adversarial/advbox/attacks/gradient_method.py b/fluid/adversarial/advbox/attacks/gradient_method.py index f4e1280972b4df887b02b54e272dde6484daf8a8..146b650c21464279f5527eb4a8bf44593e9dce29 100644 --- a/fluid/adversarial/advbox/attacks/gradient_method.py +++ b/fluid/adversarial/advbox/attacks/gradient_method.py @@ -14,7 +14,8 @@ __all__ = [ 'GradientMethodAttack', 'FastGradientSignMethodAttack', 'FGSM', 'FastGradientSignMethodTargetedAttack', 'FGSMT', 'BasicIterativeMethodAttack', 'BIM', - 'IterativeLeastLikelyClassMethodAttack', 'ILCM' + 'IterativeLeastLikelyClassMethodAttack', 'ILCM', 'MomentumIteratorAttack', + 'MIFGSM' ] @@ -76,9 +77,9 @@ class GradientMethodAttack(Attack): for epsilon in epsilons[:]: step = 1 adv_img = adversary.original + if epsilon == 0.0: + continue for i in range(steps): - if epsilon == 0.0: - continue if adversary.is_targeted_attack: gradient = -self.model.gradient(adv_img, adversary.target_label) @@ -175,7 +176,103 @@ class BasicIterativeMethodAttack(IterativeLeastLikelyClassMethodAttack): super(BasicIterativeMethodAttack, self).__init__(model, False) +class MomentumIteratorAttack(GradientMethodAttack): + """ + The Momentum Iterative Fast Gradient Sign Method (Dong et al. 2017). + This method won the first places in NIPS 2017 Non-targeted Adversarial + Attacks and Targeted Adversarial Attacks. The original paper used + hard labels for this attack; no label smoothing. inf norm. + Paper link: https://arxiv.org/pdf/1710.06081.pdf + """ + + def __init__(self, model, support_targeted=True): + """ + :param model(model): The model to be attacked. + :param support_targeted(bool): Does this attack method support targeted. + """ + super(MomentumIteratorAttack, self).__init__(model) + self.support_targeted = support_targeted + + def _apply(self, + adversary, + norm_ord=np.inf, + epsilons=0.1, + steps=100, + epsilon_steps=100, + decay_factor=1): + """ + Apply the momentum iterative gradient attack method. + :param adversary(Adversary): + The Adversary object. + :param norm_ord(int): + Order of the norm, such as np.inf, 1, 2, etc. It can't be 0. + :param epsilons(list|tuple|float): + Attack step size (input variation). + Largest step size if epsilons is not iterable. + :param epsilon_steps: + The number of Epsilons' iteration for each attack iteration. + :param steps: + The number of attack iteration. + :param decay_factor: + The decay factor for the momentum term. + :return: + adversary(Adversary): The Adversary object. + """ + if norm_ord == 0: + raise ValueError("L0 norm is not supported!") + + if not self.support_targeted: + if adversary.is_targeted_attack: + raise ValueError( + "This attack method doesn't support targeted attack!") + + assert self.model.channel_axis() == adversary.original.ndim + assert (self.model.channel_axis() == 1 or + self.model.channel_axis() == adversary.original.shape[0] or + self.model.channel_axis() == adversary.original.shape[-1]) + + if not isinstance(epsilons, Iterable): + epsilons = np.linspace(0, epsilons, num=epsilon_steps) + + min_, max_ = self.model.bounds() + pre_label = adversary.original_label + + for epsilon in epsilons[:]: + if epsilon == 0.0: + continue + step = 1 + adv_img = adversary.original + momentum = 0 + for i in range(steps): + if adversary.is_targeted_attack: + gradient = -self.model.gradient(adv_img, + adversary.target_label) + else: + gradient = self.model.gradient(adv_img, pre_label) + + # normalize gradient + velocity = gradient / self._norm(gradient, ord=1) + momentum = decay_factor * momentum + velocity + if norm_ord == np.inf: + normalized_grad = np.sign(momentum) + else: + normalized_grad = self._norm(momentum, ord=norm_ord) + perturbation = epsilon * normalized_grad + adv_img = adv_img + perturbation + adv_img = np.clip(adv_img, min_, max_) + adv_label = np.argmax(self.model.predict(adv_img)) + logging.info( + 'step={}, epsilon = {:.5f}, pre_label = {}, adv_label={}' + .format(step, epsilon, pre_label, adv_label)) + if adversary.try_accept_the_example(adv_img, adv_label): + return adversary + step += 1 + + return adversary + + FGSM = FastGradientSignMethodAttack FGSMT = FastGradientSignMethodTargetedAttack BIM = BasicIterativeMethodAttack ILCM = IterativeLeastLikelyClassMethodAttack +MIFGSM = MomentumIteratorAttack diff --git a/fluid/adversarial/tutorials/mnist_tutorial_mifgsm.py b/fluid/adversarial/tutorials/mnist_tutorial_mifgsm.py new file mode 100644 index 0000000000000000000000000000000000000000..ded7ef4b19cd4d99d2c3143f703e3d594058f705 --- /dev/null +++ b/fluid/adversarial/tutorials/mnist_tutorial_mifgsm.py @@ -0,0 +1,143 @@ +""" +MIFGSM tutorial on mnist using advbox tool. +MIFGSM is a broad class of momentum iterative gradient-based methods based on FSGM. +It supports non-targeted attack and targeted attack. +""" +import sys +sys.path.append("..") + +import matplotlib.pyplot as plt +import numpy as np +import paddle.fluid as fluid +import paddle.v2 as paddle + +from advbox.adversary import Adversary +from advbox.attacks.gradient_method import MIFGSM +from advbox.models.paddle import PaddleModel +from tutorials.mnist_model import mnist_cnn_model + + +def main(): + """ + Advbox demo which demonstrate how to use advbox. + """ + TOTAL_NUM = 500 + IMG_NAME = 'img' + LABEL_NAME = 'label' + + img = fluid.layers.data(name=IMG_NAME, shape=[1, 28, 28], dtype='float32') + # gradient should flow + img.stop_gradient = False + label = fluid.layers.data(name=LABEL_NAME, shape=[1], dtype='int64') + logits = mnist_cnn_model(img) + cost = fluid.layers.cross_entropy(input=logits, label=label) + avg_cost = fluid.layers.mean(x=cost) + + # use CPU + place = fluid.CPUPlace() + # use GPU + # place = fluid.CUDAPlace(0) + exe = fluid.Executor(place) + + BATCH_SIZE = 1 + train_reader = paddle.batch( + paddle.reader.shuffle( + paddle.dataset.mnist.train(), buf_size=128 * 10), + batch_size=BATCH_SIZE) + + test_reader = paddle.batch( + paddle.reader.shuffle( + paddle.dataset.mnist.test(), buf_size=128 * 10), + batch_size=BATCH_SIZE) + + fluid.io.load_params( + exe, "./mnist/", main_program=fluid.default_main_program()) + + # advbox demo + m = PaddleModel( + fluid.default_main_program(), + IMG_NAME, + LABEL_NAME, + logits.name, + avg_cost.name, (-1, 1), + channel_axis=1) + attack = MIFGSM(m) + attack_config = { + "norm_ord": np.inf, + "epsilons": 0.1, + "steps": 100, + "decay_factor": 1 + } + + # use train data to generate adversarial examples + total_count = 0 + fooling_count = 0 + for data in train_reader(): + total_count += 1 + adversary = Adversary(data[0][0], data[0][1]) + + # MIFGSM non-targeted attack + adversary = attack(adversary, **attack_config) + + # MIFGSM targeted attack + # tlabel = 0 + # adversary.set_target(is_targeted_attack=True, target_label=tlabel) + # adversary = attack(adversary, **attack_config) + + if adversary.is_successful(): + fooling_count += 1 + print( + 'attack success, original_label=%d, adversarial_label=%d, count=%d' + % (data[0][1], adversary.adversarial_label, total_count)) + # plt.imshow(adversary.target, cmap='Greys_r') + # plt.show() + # np.save('adv_img', adversary.target) + else: + print('attack failed, original_label=%d, count=%d' % + (data[0][1], total_count)) + + if total_count >= TOTAL_NUM: + print( + "[TRAIN_DATASET]: fooling_count=%d, total_count=%d, fooling_rate=%f" + % (fooling_count, total_count, + float(fooling_count) / total_count)) + break + + # use test data to generate adversarial examples + total_count = 0 + fooling_count = 0 + for data in test_reader(): + total_count += 1 + adversary = Adversary(data[0][0], data[0][1]) + + # MIFGSM non-targeted attack + adversary = attack(adversary, **attack_config) + + # MIFGSM targeted attack + # tlabel = 0 + # adversary.set_target(is_targeted_attack=True, target_label=tlabel) + # adversary = attack(adversary, **attack_config) + + if adversary.is_successful(): + fooling_count += 1 + print( + 'attack success, original_label=%d, adversarial_label=%d, count=%d' + % (data[0][1], adversary.adversarial_label, total_count)) + # plt.imshow(adversary.target, cmap='Greys_r') + # plt.show() + # np.save('adv_img', adversary.target) + else: + print('attack failed, original_label=%d, count=%d' % + (data[0][1], total_count)) + + if total_count >= TOTAL_NUM: + print( + "[TEST_DATASET]: fooling_count=%d, total_count=%d, fooling_rate=%f" + % (fooling_count, total_count, + float(fooling_count) / total_count)) + break + print("mifgsm attack done") + + +if __name__ == '__main__': + main() diff --git a/fluid/image_classification/caffe2fluid/README.md b/fluid/image_classification/caffe2fluid/README.md index 6aba34b9cafbd87b3474575fcbcee65819769c2f..64f6b9cf901337fced0ac4e7eb625012dfcf6d2c 100644 --- a/fluid/image_classification/caffe2fluid/README.md +++ b/fluid/image_classification/caffe2fluid/README.md @@ -2,20 +2,31 @@ This tool is used to convert a Caffe model to Fluid model ### 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 +
bash ./proto/compile.sh
- 1) generate it from caffe.proto using protoc
- bash ./proto/compile.sh
+- download one from github directly
+ cd proto/ && wget https://github.com/ethereon/caffe-tensorflow/blob/master/kaffe/caffe/caffepb.py
+
- 2) download one from github directly
- cd proto/ && wget https://github.com/ethereon/caffe-tensorflow/blob/master/kaffe/caffe/caffepb.py
+2. Convert the Caffe model to Fluid model
+- generate fluid code and weight file
+ python convert.py alexnet.prototxt \
+ --caffemodel alexnet.caffemodel \
+ --data-output-path alexnet.npy \
+ --code-output-path alexnet.py
+
-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
+ python alexnet.py alexnet.npy ./fluid_model
+
-3, Use the converted model to predict
-
- see more detail info in 'examples/xxx'
+3. Use the converted model to infer
+- see more details in '*examples/imagenet/run.sh*'
+4. compare the inference results with caffe
+- see more details in '*examples/imagenet/diff.sh*'
### Tested models
- Lenet
@@ -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)
### 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)
diff --git a/fluid/image_classification/caffe2fluid/examples/imagenet/README.md b/fluid/image_classification/caffe2fluid/examples/imagenet/README.md
index b82050859239be8804ddec8e2054edc38c4ac052..b9cf1941d29428c84c34df2a9ec00d7ae8e79014 100644
--- a/fluid/image_classification/caffe2fluid/examples/imagenet/README.md
+++ b/fluid/image_classification/caffe2fluid/examples/imagenet/README.md
@@ -1,10 +1,37 @@
-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
-1. prepare python environment
-2. download caffe model to "models.caffe/xxx" which contains "xxx.caffemodel" and "xxx.prototxt"
-3. run the tool
- eg: bash ./run.sh resnet50 ./models.caffe/resnet50 ./models/resnet50
+1. Prepare python environment
+
+2. Download caffe model to "models.caffe/xxx" which contains "xxx.caffemodel" and "xxx.prototxt"
+
+3. Convert the Caffe model to Fluid model
+ - generate fluid code and weight file
+ python convert.py alexnet.prototxt \
+ --caffemodel alexnet.caffemodel \
+ --data-output-path alexnet.npy \
+ --code-output-path alexnet.py
+
+
+ - save weights as fluid model file
+ python alexnet.py alexnet.npy ./fluid_model
+
+
+4. Do inference
+ python infer.py infer ./fluid_mode data/65.jpeg
+
+
+5. convert model and do inference together
+ bash ./run.sh alexnet ./models.caffe/alexnet ./models/alexnet
+
+ 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)
+ bash ./diff.sh resnet
+
+Make sure your caffemodel stored in './models.caffe/resnet'.
+The results will be stored in './results/resnet.paddle|caffe'
diff --git a/fluid/image_classification/caffe2fluid/examples/imagenet/diff.sh b/fluid/image_classification/caffe2fluid/examples/imagenet/diff.sh
old mode 100644
new mode 100755
diff --git a/fluid/image_classification/caffe2fluid/examples/imagenet/infer.py b/fluid/image_classification/caffe2fluid/examples/imagenet/infer.py
index bb75caa9e7364465042c5c88f471e8f6f5137237..099c0abb2e7773ca7ba5ccd8b90726d11613cc60 100644
--- a/fluid/image_classification/caffe2fluid/examples/imagenet/infer.py
+++ b/fluid/image_classification/caffe2fluid/examples/imagenet/infer.py
@@ -59,12 +59,12 @@ def build_model(net_file, net_name):
inputs_dict = MyNet.input_shapes()
input_name = inputs_dict.keys()[0]
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')
net = MyNet({input_name: images})
- input_shape = MyNet.input_shapes()[input_name]
- return net, input_shape
+ return net, inputs_dict
def dump_results(results, names, root):
@@ -78,26 +78,27 @@ def dump_results(results, names, root):
np.save(filename + '.npy', res)
-def infer(net_file, net_name, model_file, imgfile, debug=True):
- """ do inference using a model which consist 'xxx.py' and 'xxx.npy'
+def load_model(exe, place, net_file, net_name, net_weight, debug):
+ """ load model using xxxnet.py and xxxnet.npy
"""
-
fluid = import_fluid()
#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()
#2, load weights for this model
- place = fluid.CPUPlace()
- exe = fluid.Executor(place)
startup_program = fluid.default_startup_program()
exe.run(startup_program)
- if model_file.find('.npy') > 0:
- net.load(data_path=model_file, exe=exe, place=place)
+ #place = fluid.CPUPlace()
+ if net_weight.find('.npy') > 0:
+ net.load(data_path=net_weight, exe=exe, place=place)
else:
- net.load(data_path=model_file, exe=exe)
+ raise ValueError('not found weight file')
#3, test this model
test_program = fluid.default_main_program().clone()
@@ -111,10 +112,75 @@ def infer(net_file, net_name, model_file, imgfile, debug=True):
fetch_list_var.append(v)
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)
- results = exe.run(program=test_program,
- feed={'image': np_images},
- fetch_list=fetch_list_var)
+ results = exe.run(program=program,
+ feed={input_name: np_images},
+ fetch_list=fetch_targets)
if debug is True:
dump_path = 'results.paddle'
@@ -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))
else:
result = results[0]
- print('predicted class:', np.argmax(result))
+ print('succeed infer with results[class:%d]' % (np.argmax(result)))
return 0
@@ -167,9 +233,12 @@ if __name__ == "__main__":
weight_file = 'models/resnet50/resnet50.npy'
datafile = 'data/65.jpeg'
net_name = 'ResNet50'
+ model_file = 'models/resnet50/fluid'
- argc = len(sys.argv)
- if sys.argv[1] == 'caffe':
+ ret = None
+ if len(sys.argv) <= 2:
+ pass
+ elif sys.argv[1] == 'caffe':
if len(sys.argv) != 5:
print('usage:')
print('\tpython %s caffe [prototxt] [caffemodel] [datafile]' %
@@ -178,18 +247,34 @@ if __name__ == "__main__":
prototxt = sys.argv[2]
caffemodel = sys.argv[3]
datafile = sys.argv[4]
- sys.exit(caffe_infer(prototxt, caffemodel, datafile))
- elif argc == 5:
- net_file = sys.argv[1]
- weight_file = sys.argv[2]
+ ret = caffe_infer(prototxt, caffemodel, datafile)
+ elif sys.argv[1] == 'infer':
+ if len(sys.argv) != 4:
+ print('usage:')
+ print('\tpython %s infer [fluid_model] [datafile]' % (sys.argv[0]))
+ sys.exit(1)
+ model_path = sys.argv[2]
datafile = sys.argv[3]
- net_name = sys.argv[4]
- elif argc > 1:
+ ret = infer(model_path, datafile)
+ 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('\tpython %s [net_file] [weight_file] [datafile] [net_name]' %
- (sys.argv[0]))
- print('\teg:python %s %s %s %s %s' % (sys.argv[0], net_file,
- weight_file, datafile, net_name))
+ print(' python %s [infer] [fluid_model] [imgfile]' % (sys.argv[0]))
+ print(' eg:python %s infer %s %s' % (sys.argv[0], model_file, datafile))
sys.exit(1)
- infer(net_file, net_name, weight_file, datafile)
+ sys.exit(ret)
diff --git a/fluid/image_classification/caffe2fluid/examples/imagenet/run.sh b/fluid/image_classification/caffe2fluid/examples/imagenet/run.sh
old mode 100644
new mode 100755
index ff3cc4ac44a8ccaeb0b33f1bcdbc46886fb7d7e9..2f0a0ba01d6161c031cbc6b452b826cbbb6002b3
--- a/fluid/image_classification/caffe2fluid/examples/imagenet/run.sh
+++ b/fluid/image_classification/caffe2fluid/examples/imagenet/run.sh
@@ -71,7 +71,7 @@ if [[ -z $only_convert ]];then
if [[ -z $net_name ]];then
net_name="MyNet"
fi
- $PYTHON ./infer.py $net_file $weight_file $imgfile $net_name
+ $PYTHON ./infer.py dump $net_file $weight_file $imgfile $net_name
ret=$?
fi
exit $ret
diff --git a/fluid/image_classification/caffe2fluid/examples/mnist/run.sh b/fluid/image_classification/caffe2fluid/examples/mnist/run.sh
old mode 100644
new mode 100755
diff --git a/fluid/image_classification/caffe2fluid/kaffe/paddle/transformer.py b/fluid/image_classification/caffe2fluid/kaffe/paddle/transformer.py
index 3697529971fa6ca01d1703375243d16f0a0c1edd..20155e992f1bb804b823880a20600d31675f029a 100644
--- a/fluid/image_classification/caffe2fluid/kaffe/paddle/transformer.py
+++ b/fluid/image_classification/caffe2fluid/kaffe/paddle/transformer.py
@@ -216,7 +216,10 @@ class TensorFlowEmitter(object):
def emit_convert_def(self, input_nodes):
codes = []
inputs = {}
+ #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:
name = n.name
layer_var = name + '_layer'
@@ -235,8 +238,14 @@ class TensorFlowEmitter(object):
codes.append("exe = fluid.Executor(place)")
codes.append("exe.run(fluid.default_startup_program())")
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(
- "fluid.io.save_persistables(executor=exe, dirname=fluid_path)")
+ "print('save fluid model as [model] and [params] in directory [%s]' % (fluid_path))"
+ )
self.outdent()
func_def = self.statement('@classmethod')
@@ -254,8 +263,17 @@ class TensorFlowEmitter(object):
self.prefix = ''
main_def = self.statement('if __name__ == "__main__":')
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("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("fluid_model = sys.argv[2]")
main_def += self.statement("%s.convert(npy_weight, fluid_model)" %
diff --git a/fluid/image_classification/caffe2fluid/proto/compile.sh b/fluid/image_classification/caffe2fluid/proto/compile.sh
old mode 100644
new mode 100755
diff --git a/fluid/object_detection/README.md b/fluid/object_detection/README.md
index 4aa2c32865932bb949e20e32b63fc5cec2669dd0..67eccaed7303ad9bd6d5386729ae676eee52663f 100644
--- a/fluid/object_detection/README.md
+++ b/fluid/object_detection/README.md
@@ -2,7 +2,99 @@ The minimum PaddlePaddle version needed for the code sample in this directory is
---
-# MobileNet-SSD
+## SSD Object Detection
-This model built with paddle fluid is still under active development and is not
-the final version. We welcome feedbacks.
+### Introduction
+
+[Single Shot MultiBox Detector (SSD)](https://arxiv.org/abs/1512.02325) framework for object detection is based on a feed-forward convolutional network. The early network is a standard convolutional architecture for image classification, such as VGG, ResNet, or MobileNet, which is als called base network. In this tutorial we used [MobileNet](https://arxiv.org/abs/1704.04861).
+
+### Data Preparation
+
+You can use [PASCAL VOC dataset](http://host.robots.ox.ac.uk/pascal/VOC/) or [MS-COCO dataset](http://cocodataset.org/#download).
+
+#### PASCAL VOC Dataset
+
+If you want to train model on PASCAL VOC dataset, please download datset at first, skip this step if you already have one.
+
+```bash
+cd data/pascalvoc
+./download.sh
+```
+
+The command `download.sh` also will create training and testing file lists.
+
+#### MS-COCO Dataset
+
+If you want to train model on MS-COCO dataset, please download datset at first, skip this step if you already have one.
+
+```
+cd data/coco
+./download.sh
+```
+
+### Train
+
+#### Download the Pre-trained Model.
+
+We provide two pre-trained models. The one is MobileNet-v1 SSD trained on COCO dataset, but removed the convolutional predictors for COCO dataset. This model can be used to initialize the models when training other dataset, like PASCAL VOC. Then other pre-trained model is MobileNet v1 trained on ImageNet 2012 dataset, but removed the last weights and bias in Fully-Connected layer.
+
+Declaration: the MobileNet-v1 SSD model is converted by [TensorFlow model](https://github.com/tensorflow/models/blob/f87a58cd96d45de73c9a8330a06b2ab56749a7fa/research/object_detection/g3doc/detection_model_zoo.md). The MobileNet v1 model is converted [Caffe](https://github.com/shicai/MobileNet-Caffe).
+
+ - Download MobileNet-v1 SSD:
+ ```
+ ./pretrained/download_coco.sh
+ ```
+ - Download MobileNet-v1:
+ ```
+ ./pretrained/download_imagenet.sh
+ ```
+
+#### Train on PASCAL VOC
+ - Train on one device (/GPU).
+ ```python
+ env CUDA_VISIABLE_DEVICES=0 python -u train.py --parallel=False --data='pascalvoc' --pretrained_model='pretrained/ssd_mobilenet_v1_coco/'
+ ```
+ - Train on multi devices (/GPUs).
+
+ ```python
+ env CUDA_VISIABLE_DEVICES=0,1 python -u train.py --batch_size=64 --data='pascalvoc' --pretrained_model='pretrained/ssd_mobilenet_v1_coco/'
+ ```
+
+#### Train on MS-COCO
+ - Train on one device (/GPU).
+ ```python
+ env CUDA_VISIABLE_DEVICES=0 python -u train.py --parallel=False --data='coco' --pretrained_model='pretrained/mobilenet_imagenet/'
+ ```
+ - Train on multi devices (/GPUs).
+ ```python
+ env CUDA_VISIABLE_DEVICES=0,1 python -u train.py --batch_size=64 --data='coco' --pretrained_model='pretrained/mobilenet_imagenet/'
+ ```
+
+TBD
+
+### Evaluate
+
+```python
+env CUDA_VISIABLE_DEVICES=0 python eval.py --model='model/90' --test_list=''
+```
+
+TBD
+
+### Infer and Visualize
+
+```python
+env CUDA_VISIABLE_DEVICES=0 python infer.py --batch_size=2 --model='model/90' --test_list=''
+```
+
+TBD
+
+### Released Model
+
+
+| Model | Pre-trained Model | Training data | Test data | mAP |
+|:------------------------:|:------------------:|:----------------:|:------------:|:----:|
+|MobileNet-v1-SSD 300x300 | COCO MobileNet SSD | VOC07+12 trainval| VOC07 test | xx% |
+|MobileNet-v1-SSD 300x300 | ImageNet MobileNet | VOC07+12 trainval| VOC07 test | xx% |
+|MobileNet-v1-SSD 300x300 | ImageNet MobileNet | MS-COCO trainval | MS-COCO test | xx% |
+
+TBD
diff --git a/fluid/object_detection/data/pascalvoc/download.sh b/fluid/object_detection/data/pascalvoc/download.sh
old mode 100644
new mode 100755
diff --git a/fluid/object_detection/pretrained/download_coco.sh b/fluid/object_detection/pretrained/download_coco.sh
old mode 100644
new mode 100755
diff --git a/fluid/object_detection/pretrained/download_imagenet.sh b/fluid/object_detection/pretrained/download_imagenet.sh
old mode 100644
new mode 100755
diff --git a/fluid/ocr_recognition/README.md b/fluid/ocr_recognition/README.md
index e71386a8e9a5c94633d31ce9bf40e26dd483fa87..7d35846fb1b67ce4fec7f364a22dce9cb853bb24 100644
--- a/fluid/ocr_recognition/README.md
+++ b/fluid/ocr_recognition/README.md
@@ -1,4 +1,179 @@
-# OCR Model
+
+[toc]
-This model built with paddle fluid is still under active development and is not
-the final version. We welcome feedbacks.
+运行本目录下的程序示例需要使用PaddlePaddle develop最新版本。如果您的PaddlePaddle安装版本低于此要求,请按照安装文档中的说明更新PaddlePaddle安装版本。
+
+# Optical Character Recognition
+
+这里将介绍如何在PaddlePaddle fluid下使用CRNN-CTC 和 CRNN-Attention模型对图片中的文字内容进行识别。
+
+## 1. CRNN-CTC
+
+本章的任务是识别含有单行汉语字符图片,首先采用卷积将图片转为`features map`, 然后使用`im2sequence op`将`features map`转为`sequence`,经过`双向GRU RNN`得到每个step的汉语字符的概率分布。训练过程选用的损失函数为CTC loss,最终的评估指标为`instance error rate`。
+
+本路径下各个文件的作用如下:
+
+- **ctc_reader.py :** 下载、读取、处理数据。提供方法`train()` 和 `test()` 分别产生训练集和测试集的数据迭代器。
+- **crnn_ctc_model.py :** 在该脚本中定义了训练网络、预测网络和evaluate网络。
+- **ctc_train.py :** 用于模型的训练,可通过命令`python train.py --help` 获得使用方法。
+- **inference.py :** 加载训练好的模型文件,对新数据进行预测。可通过命令`python inference.py --help` 获得使用方法。
+- **eval.py :** 评估模型在指定数据集上的效果。可通过命令`python inference.py --help` 获得使用方法。
+- **utility.py :** 实现的一些通用方法,包括参数配置、tensor的构造等。
+
+
+### 1.1 数据
+
+数据的下载和简单预处理都在`ctc_reader.py`中实现。
+
+#### 1.1.1 数据格式
+
+我们使用的训练和测试数据如`图1`所示,每张图片包含单行不定长的中文字符串,这些图片都是经过检测算法进行预框选处理的。
+
+
+
+图 1
+
+
+图 2
+