From 2d09862db9697701d0573cc0945b4756e750f9af Mon Sep 17 00:00:00 2001 From: yancanxiang Date: Thu, 31 May 2018 17:52:34 +0800 Subject: [PATCH 01/47] small fix. --- fluid/image_classification/se_resnext.py | 1 - 1 file changed, 1 deletion(-) diff --git a/fluid/image_classification/se_resnext.py b/fluid/image_classification/se_resnext.py index ad533c756f..a6daa23577 100644 --- a/fluid/image_classification/se_resnext.py +++ b/fluid/image_classification/se_resnext.py @@ -4,7 +4,6 @@ import sys import paddle import paddle.fluid as fluid -import reader import paddle.fluid.layers.control_flow as control_flow import paddle.fluid.layers.nn as nn import paddle.fluid.layers.tensor as tensor From a6a3896e6f25ccd56b56016b0685080ccb6eef8a Mon Sep 17 00:00:00 2001 From: BigFishMaster Date: Thu, 31 May 2018 18:46:42 +0800 Subject: [PATCH 02/47] small fix. --- image_classification/train.py | 1 - 1 file changed, 1 deletion(-) diff --git a/image_classification/train.py b/image_classification/train.py index d824e10d7e..2bcb1e0918 100644 --- a/image_classification/train.py +++ b/image_classification/train.py @@ -16,7 +16,6 @@ CLASS_DIM = 102 BATCH_SIZE = 128 - def main(): # parse the argument parser = argparse.ArgumentParser() From 6385127723ea4e485f8dd6b4431bc67d73ac7216 Mon Sep 17 00:00:00 2001 From: BigFishMaster Date: Thu, 31 May 2018 23:50:57 +0800 Subject: [PATCH 03/47] add models folder --- fluid/image_classification/__init__.py | 0 fluid/image_classification/eval.py | 133 +++-- fluid/image_classification/inception_v4.py | 467 ------------------ fluid/image_classification/infer.py | 99 ++-- fluid/image_classification/mobilenet.py | 155 ------ fluid/image_classification/models/__init__.py | 7 + fluid/image_classification/models/alexnet.py | 147 ++++++ .../image_classification/models/googlenet.py | 141 ++++++ .../models/inception_v4.py | 204 ++++++++ .../models/learning_rate.py | 19 + .../image_classification/models/mobilenet.py | 164 ++++++ fluid/image_classification/models/resnet.py | 120 +++++ .../image_classification/models/se_resnext.py | 195 ++++++++ fluid/image_classification/models/vgg.py | 107 ++++ fluid/image_classification/reader.py | 20 +- fluid/image_classification/se_resnext.py | 137 ----- fluid/image_classification/train.py | 373 ++++---------- 17 files changed, 1365 insertions(+), 1123 deletions(-) create mode 100644 fluid/image_classification/__init__.py delete mode 100644 fluid/image_classification/inception_v4.py delete mode 100644 fluid/image_classification/mobilenet.py create mode 100644 fluid/image_classification/models/__init__.py create mode 100644 fluid/image_classification/models/alexnet.py create mode 100644 fluid/image_classification/models/googlenet.py create mode 100644 fluid/image_classification/models/inception_v4.py create mode 100644 fluid/image_classification/models/learning_rate.py create mode 100644 fluid/image_classification/models/mobilenet.py create mode 100644 fluid/image_classification/models/resnet.py create mode 100644 fluid/image_classification/models/se_resnext.py create mode 100644 fluid/image_classification/models/vgg.py delete mode 100644 fluid/image_classification/se_resnext.py diff --git a/fluid/image_classification/__init__.py b/fluid/image_classification/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/fluid/image_classification/eval.py b/fluid/image_classification/eval.py index dd1c2cc1d0..4f02c2cc86 100644 --- a/fluid/image_classification/eval.py +++ b/fluid/image_classification/eval.py @@ -1,83 +1,124 @@ import os -import sys import numpy as np -import argparse -import functools - +import time +import sys import paddle import paddle.fluid as fluid -from utility import add_arguments, print_arguments -from se_resnext import SE_ResNeXt +import models import reader +import argparse +import functools +from models.learning_rate import cosine_decay +from utility import add_arguments, print_arguments +import math parser = argparse.ArgumentParser(description=__doc__) add_arg = functools.partial(add_arguments, argparser=parser) -# yapf: disable -add_arg('batch_size', int, 32, "Minibatch size.") -add_arg('use_gpu', bool, True, "Whether to use GPU or not.") -add_arg('test_list', str, '', "The testing data lists.") -add_arg('num_layers', int, 50, "How many layers for SE-ResNeXt model.") -add_arg('model_dir', str, '', "The model path.") -# yapf: enable +add_arg('batch_size', int, 256, "Minibatch size.") +add_arg('class_dim', int, 1000, "Class number.") +add_arg('image_shape', str, "3,224,224", "input image size") +add_arg('with_mem_opt', bool, True, + "Whether to use memory optimization or not.") +add_arg('pretrained_model', str, None, "Whether to use pretrained model.") +add_arg('model', str, "SE_ResNeXt50_32x4d", "Set the network to use.") + +model_list = [m for m in dir(models) if "__" not in m] def eval(args): - class_dim = 1000 - image_shape = [3, 224, 224] + # parameters from arguments + class_dim = args.class_dim + model_name = args.model + pretrained_model = args.pretrained_model + with_memory_optimization = args.with_mem_opt + image_shape = [int(m) for m in args.image_shape.split(",")] + + assert model_name in model_list, "{} is not in lists: {}".format(args.model, + model_list) + image = fluid.layers.data(name='image', shape=image_shape, dtype='float32') label = fluid.layers.data(name='label', shape=[1], dtype='int64') - out = SE_ResNeXt(input=image, class_dim=class_dim, layers=args.num_layers) - cost = fluid.layers.cross_entropy(input=out, label=label) - acc_top1 = fluid.layers.accuracy(input=out, label=label, k=1) - acc_top5 = fluid.layers.accuracy(input=out, label=label, k=5) - avg_cost = fluid.layers.mean(x=cost) - inference_program = fluid.default_main_program().clone(for_test=True) + # model definition + model = models.__dict__[model_name]() + + if model_name in ["GoogleNet"]: + out0, out1, out2 = model.net(input=image, class_dim=class_dim) + cost0 = fluid.layers.cross_entropy(input=out0, label=label) + cost1 = fluid.layers.cross_entropy(input=out1, label=label) + cost2 = fluid.layers.cross_entropy(input=out2, label=label) + avg_cost0 = fluid.layers.mean(x=cost0) + avg_cost1 = fluid.layers.mean(x=cost1) + avg_cost2 = fluid.layers.mean(x=cost2) + + avg_cost = avg_cost0 + 0.3 * avg_cost1 + 0.3 * avg_cost2 + acc_top1 = fluid.layers.accuracy(input=out0, label=label, k=1) + acc_top5 = fluid.layers.accuracy(input=out0, label=label, k=5) + else: + out = model.net(input=image, class_dim=class_dim) + cost = fluid.layers.cross_entropy(input=out, label=label) + + avg_cost = fluid.layers.mean(x=cost) + acc_top1 = fluid.layers.accuracy(input=out, label=label, k=1) + acc_top5 = fluid.layers.accuracy(input=out, label=label, k=5) + + test_program = fluid.default_main_program().clone(for_test=True) - place = fluid.CUDAPlace(0) if args.use_gpu else fluid.CPUPlace() + if with_memory_optimization: + fluid.memory_optimize(fluid.default_main_program()) + + place = fluid.CUDAPlace(0) exe = fluid.Executor(place) + exe.run(fluid.default_startup_program()) - if not os.path.exists(args.model_dir): - raise ValueError("The model path [%s] does not exist." % - (args.model_dir)) - if not os.path.exists(args.test_list): - raise ValueError("The test lists [%s] does not exist." % - (args.test_list)) + if pretrained_model: - def if_exist(var): - return os.path.exists(os.path.join(args.model_dir, var.name)) + def if_exist(var): + return os.path.exists(os.path.join(pretrained_model, var.name)) - fluid.io.load_vars(exe, args.model_dir, predicate=if_exist) + fluid.io.load_vars(exe, pretrained_model, predicate=if_exist) - test_reader = paddle.batch( - reader.test(args.test_list), batch_size=args.batch_size) + test_batch_size = 128 + val_reader = paddle.batch(reader.val(), batch_size=test_batch_size) feeder = fluid.DataFeeder(place=place, feed_list=[image, label]) - fetch_list = [avg_cost, acc_top1, acc_top5] + fetch_list = [avg_cost.name, acc_top1.name, acc_top5.name] test_info = [[], [], []] - for batch_id, data in enumerate(test_reader()): - loss, acc1, acc5 = exe.run(inference_program, - feed=feeder.feed(data), - fetch_list=fetch_list) - test_info[0].append(loss[0]) - test_info[1].append(acc1[0]) - test_info[2].append(acc5[0]) + for batch_id, data in enumerate(val_reader()): + t1 = time.time() + loss, acc1, acc5 = exe.run(test_program, + fetch_list=fetch_list, + feed=feeder.feed(data)) + t2 = time.time() + period = t2 - t1 + loss = np.mean(np.array(loss)) + acc1 = np.mean(np.array(acc1)) + acc5 = np.mean(np.array(acc5)) + test_info[0].append(loss) + test_info[1].append(acc1) + test_info[2].append(acc5) if batch_id % 1 == 0: - print("Test {0}, loss {1}, acc1 {2}, acc5 {3}" - .format(batch_id, loss[0], acc1[0], acc5[0])) + print("Testbatch {0},loss {1}, " + "acc1 {2},acc5 {3},time {4}".format(batch_id, \ + loss, acc1, acc5, \ + "%2.2f sec" % period)) sys.stdout.flush() test_loss = np.array(test_info[0]).mean() test_acc1 = np.array(test_info[1]).mean() test_acc5 = np.array(test_info[2]).mean() - print("Test loss {0}, acc1 {1}, acc5 {2}".format(test_loss, test_acc1, - test_acc5)) + print("Test_loss {0}, test_acc1 {1}, test_acc5 {2}".format( + test_loss, test_acc1, test_acc5)) sys.stdout.flush() -if __name__ == '__main__': +def main(): args = parser.parse_args() print_arguments(args) eval(args) + + +if __name__ == '__main__': + main() diff --git a/fluid/image_classification/inception_v4.py b/fluid/image_classification/inception_v4.py deleted file mode 100644 index 3410bd6d2f..0000000000 --- a/fluid/image_classification/inception_v4.py +++ /dev/null @@ -1,467 +0,0 @@ -import os -import paddle.fluid as fluid - - -def inception_v4(img, class_dim): - - tmp = stem(input=img) - for i in range(1): - tmp = inception_A(input=tmp, depth=i) - tmp = reduction_A(input=tmp) - - for i in range(7): - tmp = inception_B(input=tmp, depth=i) - reduction_B(input=tmp) - - for i in range(3): - tmp = inception_C(input=tmp, depth=i) - - pool = fluid.layers.pool2d( - pool_type='avg', input=tmp, pool_size=7, pool_stride=1) - dropout = fluid.layers.dropout(x=pool, dropout_prob=0.2) - fc = fluid.layers.fc(input=dropout, size=class_dim, act='softmax') - out = fluid.layers.softmax(input=fc) - return out - - -def conv_bn_layer(name, - input, - num_filters, - filter_size, - padding=0, - stride=1, - groups=1, - act=None): - conv = fluid.layers.conv2d( - name=name, - input=input, - num_filters=num_filters, - filter_size=filter_size, - stride=stride, - padding=padding, - groups=groups, - act=None, - bias_attr=False) - return fluid.layers.batch_norm(name=name + '_norm', input=conv, act=act) - - -def stem(input): - conv0 = conv_bn_layer( - name='stem_conv_0', - input=input, - num_filters=32, - filter_size=3, - padding=1, - stride=2) - conv1 = conv_bn_layer( - name='stem_conv_1', - input=conv0, - num_filters=32, - filter_size=3, - padding=1) - conv2 = conv_bn_layer( - name='stem_conv_2', - input=conv1, - num_filters=64, - filter_size=3, - padding=1) - - def block0(input): - pool0 = fluid.layers.pool2d( - input=input, - pool_size=3, - pool_stride=2, - pool_type='max', - pool_padding=1) - conv0 = conv_bn_layer( - name='stem_block0_conv', - input=input, - num_filters=96, - filter_size=3, - stride=2, - padding=1) - return fluid.layers.concat(input=[pool0, conv0], axis=1) - - def block1(input): - l_conv0 = conv_bn_layer( - name='stem_block1_l_conv0', - input=input, - num_filters=64, - filter_size=1, - stride=1, - padding=0) - l_conv1 = conv_bn_layer( - name='stem_block1_l_conv1', - input=l_conv0, - num_filters=96, - filter_size=3, - stride=1, - padding=1) - r_conv0 = conv_bn_layer( - name='stem_block1_r_conv0', - input=input, - num_filters=64, - filter_size=1, - stride=1, - padding=0) - r_conv1 = conv_bn_layer( - name='stem_block1_r_conv1', - input=r_conv0, - num_filters=64, - filter_size=(7, 1), - stride=1, - padding=(3, 0)) - r_conv2 = conv_bn_layer( - name='stem_block1_r_conv2', - input=r_conv1, - num_filters=64, - filter_size=(1, 7), - stride=1, - padding=(0, 3)) - r_conv3 = conv_bn_layer( - name='stem_block1_r_conv3', - input=r_conv2, - num_filters=96, - filter_size=3, - stride=1, - padding=1) - return fluid.layers.concat(input=[l_conv1, r_conv3], axis=1) - - def block2(input): - conv0 = conv_bn_layer( - name='stem_block2_conv', - input=input, - num_filters=192, - filter_size=3, - stride=2, - padding=1) - pool0 = fluid.layers.pool2d( - input=input, - pool_size=3, - pool_stride=2, - pool_padding=1, - pool_type='max') - return fluid.layers.concat(input=[conv0, pool0], axis=1) - - conv3 = block0(conv2) - conv4 = block1(conv3) - conv5 = block2(conv4) - return conv5 - - -def inception_A(input, depth): - b0_pool0 = fluid.layers.pool2d( - name='inceptA{0}_branch0_pool0'.format(depth), - input=input, - pool_size=3, - pool_stride=1, - pool_padding=1, - pool_type='avg') - b0_conv0 = conv_bn_layer( - name='inceptA{0}_branch0_conv0'.format(depth), - input=b0_pool0, - num_filters=96, - filter_size=1, - stride=1, - padding=0) - b1_conv0 = conv_bn_layer( - name='inceptA{0}_branch1_conv0'.format(depth), - input=input, - num_filters=96, - filter_size=1, - stride=1, - padding=0) - b2_conv0 = conv_bn_layer( - name='inceptA{0}_branch2_conv0'.format(depth), - input=input, - num_filters=64, - filter_size=1, - stride=1, - padding=0) - b2_conv1 = conv_bn_layer( - name='inceptA{0}_branch2_conv1'.format(depth), - input=b2_conv0, - num_filters=96, - filter_size=3, - stride=1, - padding=1) - b3_conv0 = conv_bn_layer( - name='inceptA{0}_branch3_conv0'.format(depth), - input=input, - num_filters=64, - filter_size=1, - stride=1, - padding=0) - b3_conv1 = conv_bn_layer( - name='inceptA{0}_branch3_conv1'.format(depth), - input=b3_conv0, - num_filters=96, - filter_size=3, - stride=1, - padding=1) - b3_conv2 = conv_bn_layer( - name='inceptA{0}_branch3_conv2'.format(depth), - input=b3_conv1, - num_filters=96, - filter_size=3, - stride=1, - padding=1) - return fluid.layers.concat( - input=[b0_conv0, b1_conv0, b2_conv1, b3_conv2], axis=1) - - -def reduction_A(input): - b0_pool0 = fluid.layers.pool2d( - name='ReductA_branch0_pool0', - input=input, - pool_size=3, - pool_stride=2, - pool_padding=1, - pool_type='max') - b1_conv0 = conv_bn_layer( - name='ReductA_branch1_conv0', - input=input, - num_filters=384, - filter_size=3, - stride=2, - padding=1) - b2_conv0 = conv_bn_layer( - name='ReductA_branch2_conv0', - input=input, - num_filters=192, - filter_size=1, - stride=1, - padding=0) - b2_conv1 = conv_bn_layer( - name='ReductA_branch2_conv1', - input=b2_conv0, - num_filters=224, - filter_size=3, - stride=1, - padding=1) - b2_conv2 = conv_bn_layer( - name='ReductA_branch2_conv2', - input=b2_conv1, - num_filters=256, - filter_size=3, - stride=2, - padding=1) - return fluid.layers.concat(input=[b0_pool0, b1_conv0, b2_conv2], axis=1) - - -def inception_B(input, depth): - b0_pool0 = fluid.layers.pool2d( - name='inceptB{0}_branch0_pool0'.format(depth), - input=input, - pool_size=3, - pool_stride=1, - pool_padding=1, - pool_type='avg') - b0_conv0 = conv_bn_layer( - name='inceptB{0}_branch0_conv0'.format(depth), - input=b0_pool0, - num_filters=128, - filter_size=1, - stride=1, - padding=0) - b1_conv0 = conv_bn_layer( - name='inceptB{0}_branch1_conv0'.format(depth), - input=input, - num_filters=384, - filter_size=1, - stride=1, - padding=0) - b2_conv0 = conv_bn_layer( - name='inceptB{0}_branch2_conv0'.format(depth), - input=input, - num_filters=192, - filter_size=1, - stride=1, - padding=0) - b2_conv1 = conv_bn_layer( - name='inceptB{0}_branch2_conv1'.format(depth), - input=b2_conv0, - num_filters=224, - filter_size=(1, 7), - stride=1, - padding=(0, 3)) - b2_conv2 = conv_bn_layer( - name='inceptB{0}_branch2_conv2'.format(depth), - input=b2_conv1, - num_filters=256, - filter_size=(7, 1), - stride=1, - padding=(3, 0)) - b3_conv0 = conv_bn_layer( - name='inceptB{0}_branch3_conv0'.format(depth), - input=input, - num_filters=192, - filter_size=1, - stride=1, - padding=0) - b3_conv1 = conv_bn_layer( - name='inceptB{0}_branch3_conv1'.format(depth), - input=b3_conv0, - num_filters=192, - filter_size=(1, 7), - stride=1, - padding=(0, 3)) - b3_conv2 = conv_bn_layer( - name='inceptB{0}_branch3_conv2'.format(depth), - input=b3_conv1, - num_filters=224, - filter_size=(7, 1), - stride=1, - padding=(3, 0)) - b3_conv3 = conv_bn_layer( - name='inceptB{0}_branch3_conv3'.format(depth), - input=b3_conv2, - num_filters=224, - filter_size=(1, 7), - stride=1, - padding=(0, 3)) - b3_conv4 = conv_bn_layer( - name='inceptB{0}_branch3_conv4'.format(depth), - input=b3_conv3, - num_filters=256, - filter_size=(7, 1), - stride=1, - padding=(3, 0)) - return fluid.layers.concat( - input=[b0_conv0, b1_conv0, b2_conv2, b3_conv4], axis=1) - - -def reduction_B(input): - b0_pool0 = fluid.layers.pool2d( - name='ReductB_branch0_pool0', - input=input, - pool_size=3, - pool_stride=2, - pool_padding=1, - pool_type='max') - b1_conv0 = conv_bn_layer( - name='ReductB_branch1_conv0', - input=input, - num_filters=192, - filter_size=1, - stride=1, - padding=0) - b1_conv1 = conv_bn_layer( - name='ReductB_branch1_conv1', - input=b1_conv0, - num_filters=192, - filter_size=3, - stride=2, - padding=1) - b2_conv0 = conv_bn_layer( - name='ReductB_branch2_conv0', - input=input, - num_filters=256, - filter_size=1, - stride=1, - padding=0) - b2_conv1 = conv_bn_layer( - name='ReductB_branch2_conv1', - input=b2_conv0, - num_filters=256, - filter_size=(1, 7), - stride=1, - padding=(0, 3)) - b2_conv2 = conv_bn_layer( - name='ReductB_branch2_conv2', - input=b2_conv1, - num_filters=320, - filter_size=(7, 1), - stride=1, - padding=(3, 0)) - b2_conv3 = conv_bn_layer( - name='ReductB_branch2_conv3', - input=b2_conv2, - num_filters=320, - filter_size=3, - stride=2, - padding=1) - return fluid.layers.concat(input=[b0_pool0, b1_conv1, b2_conv3], axis=1) - - -def inception_C(input, depth): - b0_pool0 = fluid.layers.pool2d( - name='inceptC{0}_branch0_pool0'.format(depth), - input=input, - pool_size=3, - pool_stride=1, - pool_padding=1, - pool_type='avg') - b0_conv0 = conv_bn_layer( - name='inceptC{0}_branch0_conv0'.format(depth), - input=b0_pool0, - num_filters=256, - filter_size=1, - stride=1, - padding=0) - b1_conv0 = conv_bn_layer( - name='inceptC{0}_branch1_conv0'.format(depth), - input=input, - num_filters=256, - filter_size=1, - stride=1, - padding=0) - b2_conv0 = conv_bn_layer( - name='inceptC{0}_branch2_conv0'.format(depth), - input=input, - num_filters=384, - filter_size=1, - stride=1, - padding=0) - b2_conv1 = conv_bn_layer( - name='inceptC{0}_branch2_conv1'.format(depth), - input=b2_conv0, - num_filters=256, - filter_size=(1, 3), - stride=1, - padding=(0, 1)) - b2_conv2 = conv_bn_layer( - name='inceptC{0}_branch2_conv2'.format(depth), - input=b2_conv0, - num_filters=256, - filter_size=(3, 1), - stride=1, - padding=(1, 0)) - b3_conv0 = conv_bn_layer( - name='inceptC{0}_branch3_conv0'.format(depth), - input=input, - num_filters=384, - filter_size=1, - stride=1, - padding=0) - b3_conv1 = conv_bn_layer( - name='inceptC{0}_branch3_conv1'.format(depth), - input=b3_conv0, - num_filters=448, - filter_size=(1, 3), - stride=1, - padding=(0, 1)) - b3_conv2 = conv_bn_layer( - name='inceptC{0}_branch3_conv2'.format(depth), - input=b3_conv1, - num_filters=512, - filter_size=(3, 1), - stride=1, - padding=(1, 0)) - b3_conv3 = conv_bn_layer( - name='inceptC{0}_branch3_conv3'.format(depth), - input=b3_conv2, - num_filters=256, - filter_size=(3, 1), - stride=1, - padding=(1, 0)) - b3_conv4 = conv_bn_layer( - name='inceptC{0}_branch3_conv4'.format(depth), - input=b3_conv2, - num_filters=256, - filter_size=(1, 3), - stride=1, - padding=(0, 1)) - return fluid.layers.concat( - input=[b0_conv0, b1_conv0, b2_conv1, b2_conv2, b3_conv3, b3_conv4], - axis=1) diff --git a/fluid/image_classification/infer.py b/fluid/image_classification/infer.py index f2a6ca3c70..adb99d4524 100644 --- a/fluid/image_classification/infer.py +++ b/fluid/image_classification/infer.py @@ -1,69 +1,90 @@ import os -import sys import numpy as np -import argparse -import functools - +import time +import sys import paddle import paddle.fluid as fluid -from utility import add_arguments, print_arguments -from se_resnext import SE_ResNeXt +import models import reader +import argparse +import functools +from models.learning_rate import cosine_decay +from utility import add_arguments, print_arguments +import math parser = argparse.ArgumentParser(description=__doc__) add_arg = functools.partial(add_arguments, argparser=parser) -# yapf: disable -add_arg('batch_size', int, 1, "Minibatch size.") -add_arg('use_gpu', bool, True, "Whether to use GPU or not.") -add_arg('test_list', str, '', "The testing data lists.") -add_arg('num_layers', int, 50, "How many layers for SE-ResNeXt model.") -add_arg('model_dir', str, '', "The model path.") -# yapf: enable +add_arg('batch_size', int, 256, "Minibatch size.") +add_arg('class_dim', int, 1000, "Class number.") +add_arg('image_shape', str, "3,224,224", "input image size") +add_arg('with_mem_opt', bool, True, + "Whether to use memory optimization or not.") +add_arg('pretrained_model', str, None, "Whether to use pretrained model.") +add_arg('model', str, "SE_ResNeXt50_32x4d", "Set the network to use.") + +model_list = [m for m in dir(models) if "__" not in m] def infer(args): - class_dim = 1000 - image_shape = [3, 224, 224] + # parameters from arguments + class_dim = args.class_dim + model_name = args.model + pretrained_model = args.pretrained_model + with_memory_optimization = args.with_mem_opt + image_shape = [int(m) for m in args.image_shape.split(",")] + + assert model_name in model_list, "{} is not in lists: {}".format(args.model, + model_list) + image = fluid.layers.data(name='image', shape=image_shape, dtype='float32') - out = SE_ResNeXt(input=image, class_dim=class_dim, layers=args.num_layers) - out = fluid.layers.softmax(input=out) - inference_program = fluid.default_main_program().clone(for_test=True) + # model definition + model = models.__dict__[model_name]() + + if model_name in ["GoogleNet"]: + out, _, _ = model.net(input=image, class_dim=class_dim) + else: + out = model.net(input=image, class_dim=class_dim) + + test_program = fluid.default_main_program().clone(for_test=True) + + if with_memory_optimization: + fluid.memory_optimize(fluid.default_main_program()) - place = fluid.CUDAPlace(0) if args.use_gpu else fluid.CPUPlace() + place = fluid.CUDAPlace(0) exe = fluid.Executor(place) + exe.run(fluid.default_startup_program()) - if not os.path.exists(args.model_dir): - raise ValueError("The model path [%s] does not exist." % - (args.model_dir)) - if not os.path.exists(args.test_list): - raise ValueError("The test lists [%s] does not exist." % - (args.test_list)) + if pretrained_model: - def if_exist(var): - return os.path.exists(os.path.join(args.model_dir, var.name)) + def if_exist(var): + return os.path.exists(os.path.join(pretrained_model, var.name)) - fluid.io.load_vars(exe, args.model_dir, predicate=if_exist) + fluid.io.load_vars(exe, pretrained_model, predicate=if_exist) - test_reader = paddle.batch( - reader.infer(args.test_list), batch_size=args.batch_size) + test_batch_size = 1 + test_reader = paddle.batch(reader.test(), batch_size=test_batch_size) feeder = fluid.DataFeeder(place=place, feed_list=[image]) - fetch_list = [out] + fetch_list = [out.name] TOPK = 1 for batch_id, data in enumerate(test_reader()): - result = exe.run(inference_program, - feed=feeder.feed(data), - fetch_list=fetch_list) - result = result[0] - pred_label = np.argsort(result)[::-1][0][0] - print("Test {0}-score {1}, class {2}: " - .format(batch_id, result[0][pred_label], pred_label)) + result = exe.run(test_program, + fetch_list=fetch_list, + feed=feeder.feed(data)) + result = result[0][0] + pred_label = np.argsort(result)[::-1][:TOPK] + print("Test-{0}-score: {1}, class {2}" + .format(batch_id, result[pred_label], pred_label)) sys.stdout.flush() -if __name__ == '__main__': +def main(): args = parser.parse_args() print_arguments(args) infer(args) + + +if __name__ == '__main__': + main() diff --git a/fluid/image_classification/mobilenet.py b/fluid/image_classification/mobilenet.py deleted file mode 100644 index edee1bf075..0000000000 --- a/fluid/image_classification/mobilenet.py +++ /dev/null @@ -1,155 +0,0 @@ -import os - -import paddle.v2 as paddle -import paddle.fluid as fluid -from paddle.fluid.initializer import MSRA -from paddle.fluid.param_attr import ParamAttr - -parameter_attr = ParamAttr(initializer=MSRA()) - - -def conv_bn_layer(input, - filter_size, - num_filters, - stride, - padding, - channels=None, - num_groups=1, - act='relu', - use_cudnn=True): - conv = fluid.layers.conv2d( - input=input, - num_filters=num_filters, - filter_size=filter_size, - stride=stride, - padding=padding, - groups=num_groups, - act=None, - use_cudnn=use_cudnn, - param_attr=parameter_attr, - bias_attr=False) - return fluid.layers.batch_norm(input=conv, act=act) - - -def depthwise_separable(input, num_filters1, num_filters2, num_groups, stride, - scale): - """ - """ - depthwise_conv = conv_bn_layer( - input=input, - filter_size=3, - num_filters=int(num_filters1 * scale), - stride=stride, - padding=1, - num_groups=int(num_groups * scale), - use_cudnn=False) - - pointwise_conv = conv_bn_layer( - input=depthwise_conv, - filter_size=1, - num_filters=int(num_filters2 * scale), - stride=1, - padding=0) - return pointwise_conv - - -def mobile_net(img, class_dim, scale=1.0): - - # conv1: 112x112 - tmp = conv_bn_layer( - img, - filter_size=3, - channels=3, - num_filters=int(32 * scale), - stride=2, - padding=1) - - # 56x56 - tmp = depthwise_separable( - tmp, - num_filters1=32, - num_filters2=64, - num_groups=32, - stride=1, - scale=scale) - - tmp = depthwise_separable( - tmp, - num_filters1=64, - num_filters2=128, - num_groups=64, - stride=2, - scale=scale) - - # 28x28 - tmp = depthwise_separable( - tmp, - num_filters1=128, - num_filters2=128, - num_groups=128, - stride=1, - scale=scale) - - tmp = depthwise_separable( - tmp, - num_filters1=128, - num_filters2=256, - num_groups=128, - stride=2, - scale=scale) - - # 14x14 - tmp = depthwise_separable( - tmp, - num_filters1=256, - num_filters2=256, - num_groups=256, - stride=1, - scale=scale) - - tmp = depthwise_separable( - tmp, - num_filters1=256, - num_filters2=512, - num_groups=256, - stride=2, - scale=scale) - - # 14x14 - for i in range(5): - tmp = depthwise_separable( - tmp, - num_filters1=512, - num_filters2=512, - num_groups=512, - stride=1, - scale=scale) - # 7x7 - tmp = depthwise_separable( - tmp, - num_filters1=512, - num_filters2=1024, - num_groups=512, - stride=2, - scale=scale) - - tmp = depthwise_separable( - tmp, - num_filters1=1024, - num_filters2=1024, - num_groups=1024, - stride=1, - scale=scale) - - tmp = fluid.layers.pool2d( - input=tmp, - pool_size=0, - pool_stride=1, - pool_type='avg', - global_pooling=True) - - tmp = fluid.layers.fc(input=tmp, - size=class_dim, - act='softmax', - param_attr=parameter_attr) - return tmp diff --git a/fluid/image_classification/models/__init__.py b/fluid/image_classification/models/__init__.py new file mode 100644 index 0000000000..a9418fdd2b --- /dev/null +++ b/fluid/image_classification/models/__init__.py @@ -0,0 +1,7 @@ +from .alexnet import AlexNet +from .mobilenet import MobileNet +from .googlenet import GoogleNet +from .vgg import VGG11, VGG13, VGG16, VGG19 +from .resnet import ResNet50, ResNet101, ResNet152 +from .inception_v4 import InceptionV4 +from .se_resnext import SE_ResNeXt50_32x4d, SE_ResNeXt101_32x4d, SE_ResNeXt152_32x4d diff --git a/fluid/image_classification/models/alexnet.py b/fluid/image_classification/models/alexnet.py new file mode 100644 index 0000000000..d21b798a5d --- /dev/null +++ b/fluid/image_classification/models/alexnet.py @@ -0,0 +1,147 @@ +import paddle +import paddle.fluid as fluid +import math + +__all__ = ['AlexNet'] + +train_parameters = { + "input_size": [3, 224, 224], + "input_mean": [0.485, 0.456, 0.406], + "input_std": [0.229, 0.224, 0.225], + "learning_strategy": { + "name": "piecewise_decay", + "batch_size": 256, + "epochs": [40, 70, 100], + "steps": [0.01, 0.001, 0.0001, 0.00001] + } +} + + +class AlexNet(): + def __init__(self): + self.params = train_parameters + + def net(self, input, class_dim): + stdv = 1.0 / math.sqrt(input.shape[1] * 11 * 11) + conv1 = fluid.layers.conv2d( + input=input, + num_filters=64, + filter_size=11, + stride=4, + padding=2, + groups=1, + act='relu', + bias_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv)), + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv))) + pool1 = fluid.layers.pool2d( + input=conv1, + pool_size=3, + pool_stride=2, + pool_padding=0, + pool_type='max') + + stdv = 1.0 / math.sqrt(pool1.shape[1] * 5 * 5) + conv2 = fluid.layers.conv2d( + input=pool1, + num_filters=192, + filter_size=5, + stride=1, + padding=2, + groups=1, + act='relu', + bias_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv)), + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv))) + pool2 = fluid.layers.pool2d( + input=conv2, + pool_size=3, + pool_stride=2, + pool_padding=0, + pool_type='max') + + stdv = 1.0 / math.sqrt(pool2.shape[1] * 3 * 3) + conv3 = fluid.layers.conv2d( + input=pool2, + num_filters=384, + filter_size=3, + stride=1, + padding=1, + groups=1, + act='relu', + bias_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv)), + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv))) + + stdv = 1.0 / math.sqrt(conv3.shape[1] * 3 * 3) + conv4 = fluid.layers.conv2d( + input=conv3, + num_filters=256, + filter_size=3, + stride=1, + padding=1, + groups=1, + act='relu', + bias_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv)), + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv))) + + stdv = 1.0 / math.sqrt(conv4.shape[1] * 3 * 3) + conv5 = fluid.layers.conv2d( + input=conv4, + num_filters=256, + filter_size=3, + stride=1, + padding=1, + groups=1, + act='relu', + bias_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv)), + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv))) + pool5 = fluid.layers.pool2d( + input=conv5, + pool_size=3, + pool_stride=2, + pool_padding=0, + pool_type='max') + + drop6 = fluid.layers.dropout(x=pool5, dropout_prob=0.5) + + stdv = 1.0 / math.sqrt(drop6.shape[1] * drop6.shape[2] * + drop6.shape[3] * 1.0) + fc6 = fluid.layers.fc( + input=drop6, + size=4096, + act='relu', + bias_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv)), + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv))) + + drop7 = fluid.layers.dropout(x=fc6, dropout_prob=0.5) + + stdv = 1.0 / math.sqrt(drop7.shape[1] * 1.0) + fc7 = fluid.layers.fc( + input=drop7, + size=4096, + act='relu', + bias_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv)), + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv))) + + stdv = 1.0 / math.sqrt(fc7.shape[1] * 1.0) + out = fluid.layers.fc( + input=fc7, + size=class_dim, + act='softmax', + bias_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv)), + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv))) + return out diff --git a/fluid/image_classification/models/googlenet.py b/fluid/image_classification/models/googlenet.py new file mode 100644 index 0000000000..c7d5ce7f9a --- /dev/null +++ b/fluid/image_classification/models/googlenet.py @@ -0,0 +1,141 @@ +import paddle +import paddle.fluid as fluid + +__all__ = ['GoogleNet'] + +train_parameters = { + "input_size": [3, 224, 224], + "input_mean": [0.485, 0.456, 0.406], + "input_std": [0.229, 0.224, 0.225], + "learning_strategy": { + "name": "piecewise_decay", + "batch_size": 256, + "epochs": [30, 60, 90], + "steps": [0.1, 0.01, 0.001, 0.0001] + } +} + + +class GoogleNet(): + def __init__(self): + self.params = train_parameters + + def conv_layer(self, + input, + num_filters, + filter_size, + stride=1, + groups=1, + act=None): + channels = input.shape[1] + stdv = (3.0 / (filter_size**2 * channels))**0.5 + param_attr = fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv)) + conv = fluid.layers.conv2d( + input=input, + num_filters=num_filters, + filter_size=filter_size, + stride=stride, + padding=(filter_size - 1) / 2, + groups=groups, + act=act, + param_attr=param_attr, + bias_attr=False) + return conv + + def inception(self, name, input, channels, filter1, filter3R, filter3, + filter5R, filter5, proj): + conv1 = self.conv_layer( + input=input, num_filters=filter1, filter_size=1, stride=1, act=None) + conv3r = self.conv_layer( + input=input, + num_filters=filter3R, + filter_size=1, + stride=1, + act=None) + conv3 = self.conv_layer( + input=conv3r, + num_filters=filter3, + filter_size=3, + stride=1, + act=None) + conv5r = self.conv_layer( + input=input, + num_filters=filter5R, + filter_size=1, + stride=1, + act=None) + conv5 = self.conv_layer( + input=conv5r, + num_filters=filter5, + filter_size=5, + stride=1, + act=None) + pool = fluid.layers.pool2d( + input=input, + pool_size=3, + pool_stride=1, + pool_padding=1, + pool_type='max') + convprj = fluid.layers.conv2d( + input=pool, filter_size=1, num_filters=proj, stride=1, padding=0) + cat = fluid.layers.concat(input=[conv1, conv3, conv5, convprj], axis=1) + return cat + + def net(self, input, class_dim): + conv = self.conv_layer( + input=input, num_filters=64, filter_size=7, stride=2, act=None) + pool = fluid.layers.pool2d( + input=conv, pool_size=3, pool_type='max', pool_stride=2) + + conv = self.conv_layer( + input=pool, num_filters=64, filter_size=1, stride=1, act=None) + conv = self.conv_layer( + input=conv, num_filters=192, filter_size=3, stride=1, act=None) + pool = fluid.layers.pool2d( + input=conv, pool_size=3, pool_type='max', pool_stride=2) + + ince3a = self.inception("ince3a", pool, 192, 64, 96, 128, 16, 32, 32) + ince3b = self.inception("ince3b", ince3a, 256, 128, 128, 192, 32, 96, + 64) + pool3 = fluid.layers.pool2d( + input=ince3b, pool_size=3, pool_type='max', pool_stride=2) + + ince4a = self.inception("ince4a", pool3, 480, 192, 96, 208, 16, 48, 64) + ince4b = self.inception("ince4b", ince4a, 512, 160, 112, 224, 24, 64, + 64) + ince4c = self.inception("ince4c", ince4b, 512, 128, 128, 256, 24, 64, + 64) + ince4d = self.inception("ince4d", ince4c, 512, 112, 144, 288, 32, 64, + 64) + ince4e = self.inception("ince4e", ince4d, 528, 256, 160, 320, 32, 128, + 128) + pool4 = fluid.layers.pool2d( + input=ince4e, pool_size=3, pool_type='max', pool_stride=2) + + ince5a = self.inception("ince5a", pool4, 832, 256, 160, 320, 32, 128, + 128) + ince5b = self.inception("ince5b", ince5a, 832, 384, 192, 384, 48, 128, + 128) + pool5 = fluid.layers.pool2d( + input=ince5b, pool_size=7, pool_type='avg', pool_stride=7) + dropout = fluid.layers.dropout(x=pool5, dropout_prob=0.4) + out = fluid.layers.fc(input=dropout, size=class_dim, act='softmax') + + pool_o1 = fluid.layers.pool2d( + input=ince4a, pool_size=5, pool_type='avg', pool_stride=3) + conv_o1 = self.conv_layer( + input=pool_o1, num_filters=128, filter_size=1, stride=1, act=None) + fc_o1 = fluid.layers.fc(input=conv_o1, size=1024, act='relu') + dropout_o1 = fluid.layers.dropout(x=fc_o1, dropout_prob=0.7) + out1 = fluid.layers.fc(input=dropout_o1, size=class_dim, act='softmax') + + pool_o2 = fluid.layers.pool2d( + input=ince4d, pool_size=5, pool_type='avg', pool_stride=3) + conv_o2 = self.conv_layer( + input=pool_o2, num_filters=128, filter_size=1, stride=1, act=None) + fc_o2 = fluid.layers.fc(input=conv_o2, size=1024, act='relu') + dropout_o2 = fluid.layers.dropout(x=fc_o2, dropout_prob=0.7) + out2 = fluid.layers.fc(input=dropout_o2, size=class_dim, act='softmax') + + return out, out1, out2 diff --git a/fluid/image_classification/models/inception_v4.py b/fluid/image_classification/models/inception_v4.py new file mode 100644 index 0000000000..7da00d87be --- /dev/null +++ b/fluid/image_classification/models/inception_v4.py @@ -0,0 +1,204 @@ +import paddle +import paddle.fluid as fluid +import math + +__all__ = ['InceptionV4'] + +train_parameters = { + "input_size": [3, 224, 224], + "input_mean": [0.485, 0.456, 0.406], + "input_std": [0.229, 0.224, 0.225], + "learning_strategy": { + "name": "piecewise_decay", + "batch_size": 256, + "epochs": [30, 60, 90], + "steps": [0.1, 0.01, 0.001, 0.0001] + } +} + + +class InceptionV4(): + def __init__(self): + self.params = train_parameters + + def net(self, input, class_dim): + x = self.inception_stem(input) + + for i in range(4): + x = self.inceptionA(x) + x = self.reductionA(x) + + for i in range(7): + x = self.inceptionB(x) + x = self.reductionB(x) + + for i in range(3): + x = self.inceptionC(x) + + pool = fluid.layers.pool2d( + input=x, pool_size=8, pool_type='avg', global_pooling=True) + + drop = fluid.layers.dropout(x=pool, dropout_prob=0.2) + + stdv = 1.0 / math.sqrt(drop.shape[1] * 1.0) + out = fluid.layers.fc( + input=drop, + size=class_dim, + act='softmax', + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv))) + return out + + def conv_bn_layer(self, + data, + num_filters, + filter_size, + stride=1, + padding=0, + groups=1, + act='relu'): + conv = fluid.layers.conv2d( + input=data, + num_filters=num_filters, + filter_size=filter_size, + stride=stride, + padding=padding, + groups=groups, + act=None, + bias_attr=False) + return fluid.layers.batch_norm(input=conv, act=act) + + def inception_stem(self, data): + conv = self.conv_bn_layer(data, 32, 3, stride=2, act='relu') + conv = self.conv_bn_layer(conv, 32, 3, act='relu') + conv = self.conv_bn_layer(conv, 64, 3, padding=1, act='relu') + + pool1 = fluid.layers.pool2d( + input=conv, pool_size=3, pool_stride=2, pool_type='max') + conv2 = self.conv_bn_layer(conv, 96, 3, stride=2, act='relu') + concat = fluid.layers.concat([pool1, conv2], axis=1) + + conv1 = self.conv_bn_layer(concat, 64, 1, act='relu') + conv1 = self.conv_bn_layer(conv1, 96, 3, act='relu') + + conv2 = self.conv_bn_layer(concat, 64, 1, act='relu') + conv2 = self.conv_bn_layer( + conv2, 64, (7, 1), padding=(3, 0), act='relu') + conv2 = self.conv_bn_layer( + conv2, 64, (1, 7), padding=(0, 3), act='relu') + conv2 = self.conv_bn_layer(conv2, 96, 3, act='relu') + + concat = fluid.layers.concat([conv1, conv2], axis=1) + + conv1 = self.conv_bn_layer(concat, 192, 3, stride=2, act='relu') + pool1 = fluid.layers.pool2d( + input=concat, pool_size=3, pool_stride=2, pool_type='max') + + concat = fluid.layers.concat([conv1, pool1], axis=1) + + return concat + + def inceptionA(self, data): + pool1 = fluid.layers.pool2d( + input=data, pool_size=3, pool_padding=1, pool_type='avg') + conv1 = self.conv_bn_layer(pool1, 96, 1, act='relu') + + conv2 = self.conv_bn_layer(data, 96, 1, act='relu') + + conv3 = self.conv_bn_layer(data, 64, 1, act='relu') + conv3 = self.conv_bn_layer(conv3, 96, 3, padding=1, act='relu') + + conv4 = self.conv_bn_layer(data, 64, 1, act='relu') + conv4 = self.conv_bn_layer(conv4, 96, 3, padding=1, act='relu') + conv4 = self.conv_bn_layer(conv4, 96, 3, padding=1, act='relu') + + concat = fluid.layers.concat([conv1, conv2, conv3, conv4], axis=1) + + return concat + + def reductionA(self, data): + pool1 = fluid.layers.pool2d( + input=data, pool_size=3, pool_stride=2, pool_type='max') + + conv2 = self.conv_bn_layer(data, 384, 3, stride=2, act='relu') + + conv3 = self.conv_bn_layer(data, 192, 1, act='relu') + conv3 = self.conv_bn_layer(conv3, 224, 3, padding=1, act='relu') + conv3 = self.conv_bn_layer(conv3, 256, 3, stride=2, act='relu') + + concat = fluid.layers.concat([pool1, conv2, conv3], axis=1) + + return concat + + def inceptionB(self, data): + pool1 = fluid.layers.pool2d( + input=data, pool_size=3, pool_padding=1, pool_type='avg') + conv1 = self.conv_bn_layer(pool1, 128, 1, act='relu') + + conv2 = self.conv_bn_layer(data, 384, 1, act='relu') + + conv3 = self.conv_bn_layer(data, 192, 1, act='relu') + conv3 = self.conv_bn_layer( + conv3, 224, (1, 7), padding=(0, 3), act='relu') + conv3 = self.conv_bn_layer( + conv3, 256, (7, 1), padding=(3, 0), act='relu') + + conv4 = self.conv_bn_layer(data, 192, 1, act='relu') + conv4 = self.conv_bn_layer( + conv4, 192, (1, 7), padding=(0, 3), act='relu') + conv4 = self.conv_bn_layer( + conv4, 224, (7, 1), padding=(3, 0), act='relu') + conv4 = self.conv_bn_layer( + conv4, 224, (1, 7), padding=(0, 3), act='relu') + conv4 = self.conv_bn_layer( + conv4, 256, (7, 1), padding=(3, 0), act='relu') + + concat = fluid.layers.concat([conv1, conv2, conv3, conv4], axis=1) + + return concat + + def reductionB(self, data): + pool1 = fluid.layers.pool2d( + input=data, pool_size=3, pool_stride=2, pool_type='max') + + conv2 = self.conv_bn_layer(data, 192, 1, act='relu') + conv2 = self.conv_bn_layer(conv2, 192, 3, stride=2, act='relu') + + conv3 = self.conv_bn_layer(data, 256, 1, act='relu') + conv3 = self.conv_bn_layer( + conv3, 256, (1, 7), padding=(0, 3), act='relu') + conv3 = self.conv_bn_layer( + conv3, 320, (7, 1), padding=(3, 0), act='relu') + conv3 = self.conv_bn_layer(conv3, 320, 3, stride=2, act='relu') + + concat = fluid.layers.concat([pool1, conv2, conv3], axis=1) + + return concat + + def inceptionC(self, data): + pool1 = fluid.layers.pool2d( + input=data, pool_size=3, pool_padding=1, pool_type='avg') + conv1 = self.conv_bn_layer(pool1, 256, 1, act='relu') + + conv2 = self.conv_bn_layer(data, 256, 1, act='relu') + + conv3 = self.conv_bn_layer(data, 384, 1, act='relu') + conv3_1 = self.conv_bn_layer( + conv3, 256, (1, 3), padding=(0, 1), act='relu') + conv3_2 = self.conv_bn_layer( + conv3, 256, (3, 1), padding=(1, 0), act='relu') + + conv4 = self.conv_bn_layer(data, 384, 1, act='relu') + conv4 = self.conv_bn_layer( + conv4, 448, (1, 3), padding=(0, 1), act='relu') + conv4 = self.conv_bn_layer( + conv4, 512, (3, 1), padding=(1, 0), act='relu') + conv4_1 = self.conv_bn_layer( + conv4, 256, (1, 3), padding=(0, 1), act='relu') + conv4_2 = self.conv_bn_layer( + conv4, 256, (3, 1), padding=(1, 0), act='relu') + + concat = fluid.layers.concat( + [conv1, conv2, conv3_1, conv3_2, conv4_1, conv4_2], axis=1) + + return concat diff --git a/fluid/image_classification/models/learning_rate.py b/fluid/image_classification/models/learning_rate.py new file mode 100644 index 0000000000..d8c137e6db --- /dev/null +++ b/fluid/image_classification/models/learning_rate.py @@ -0,0 +1,19 @@ +import paddle +import paddle.fluid as fluid +import paddle.fluid.layers.ops as ops +from paddle.fluid.initializer import init_on_cpu +from paddle.fluid.layers.learning_rate_scheduler import _decay_step_counter +import math + + +def cosine_decay(learning_rate, step_each_epoch, epochs=120): + """Applies cosine decay to the learning rate. + lr = 0.05 * (math.cos(epoch * (math.pi / 120)) + 1) + """ + global_step = _decay_step_counter() + + with init_on_cpu(): + epoch = ops.floor(global_step / step_each_epoch) + decayed_lr = learning_rate * \ + (ops.cos(epoch * (math.pi / epochs)) + 1)/2 + return decayed_lr diff --git a/fluid/image_classification/models/mobilenet.py b/fluid/image_classification/models/mobilenet.py new file mode 100644 index 0000000000..70b9c95d05 --- /dev/null +++ b/fluid/image_classification/models/mobilenet.py @@ -0,0 +1,164 @@ +import paddle.fluid as fluid +from paddle.fluid.initializer import MSRA +from paddle.fluid.param_attr import ParamAttr + +__all__ = ['MobileNet'] + +train_parameters = { + "input_size": [3, 224, 224], + "input_mean": [0.485, 0.456, 0.406], + "input_std": [0.229, 0.224, 0.225], + "learning_strategy": { + "name": "piecewise_decay", + "batch_size": 256, + "epochs": [30, 60, 90], + "steps": [0.1, 0.01, 0.001, 0.0001] + } +} + + +class MobileNet(): + def __init__(self): + self.params = train_parameters + + def net(self, input, class_dim, scale=1.0): + # conv1: 112x112 + input = self.conv_bn_layer( + input, + filter_size=3, + channels=3, + num_filters=int(32 * scale), + stride=2, + padding=1) + + # 56x56 + input = self.depthwise_separable( + input, + num_filters1=32, + num_filters2=64, + num_groups=32, + stride=1, + scale=scale) + + input = self.depthwise_separable( + input, + num_filters1=64, + num_filters2=128, + num_groups=64, + stride=2, + scale=scale) + + # 28x28 + input = self.depthwise_separable( + input, + num_filters1=128, + num_filters2=128, + num_groups=128, + stride=1, + scale=scale) + + input = self.depthwise_separable( + input, + num_filters1=128, + num_filters2=256, + num_groups=128, + stride=2, + scale=scale) + + # 14x14 + input = self.depthwise_separable( + input, + num_filters1=256, + num_filters2=256, + num_groups=256, + stride=1, + scale=scale) + + input = self.depthwise_separable( + input, + num_filters1=256, + num_filters2=512, + num_groups=256, + stride=2, + scale=scale) + + # 14x14 + for i in range(5): + input = self.depthwise_separable( + input, + num_filters1=512, + num_filters2=512, + num_groups=512, + stride=1, + scale=scale) + # 7x7 + input = self.depthwise_separable( + input, + num_filters1=512, + num_filters2=1024, + num_groups=512, + stride=2, + scale=scale) + + input = self.depthwise_separable( + input, + num_filters1=1024, + num_filters2=1024, + num_groups=1024, + stride=1, + scale=scale) + + input = fluid.layers.pool2d( + input=input, + pool_size=0, + pool_stride=1, + pool_type='avg', + global_pooling=True) + + output = fluid.layers.fc(input=input, + size=class_dim, + act='softmax', + param_attr=ParamAttr(initializer=MSRA())) + return output + + def conv_bn_layer(self, + input, + filter_size, + num_filters, + stride, + padding, + channels=None, + num_groups=1, + act='relu', + use_cudnn=True): + conv = fluid.layers.conv2d( + input=input, + num_filters=num_filters, + filter_size=filter_size, + stride=stride, + padding=padding, + groups=num_groups, + act=None, + use_cudnn=use_cudnn, + param_attr=ParamAttr(initializer=MSRA()), + bias_attr=False) + return fluid.layers.batch_norm(input=conv, act=act) + + def depthwise_separable(self, input, num_filters1, num_filters2, num_groups, + stride, scale): + depthwise_conv = self.conv_bn_layer( + input=input, + filter_size=3, + num_filters=int(num_filters1 * scale), + stride=stride, + padding=1, + num_groups=int(num_groups * scale), + use_cudnn=False) + + pointwise_conv = self.conv_bn_layer( + input=depthwise_conv, + filter_size=1, + num_filters=int(num_filters2 * scale), + stride=1, + padding=0) + return pointwise_conv diff --git a/fluid/image_classification/models/resnet.py b/fluid/image_classification/models/resnet.py new file mode 100644 index 0000000000..fa88609f46 --- /dev/null +++ b/fluid/image_classification/models/resnet.py @@ -0,0 +1,120 @@ +import paddle +import paddle.fluid as fluid +import math + +__all__ = ["ResNet", "ResNet50", "ResNet101", "ResNet152"] + +train_parameters = { + "input_size": [3, 224, 224], + "input_mean": [0.485, 0.456, 0.406], + "input_std": [0.229, 0.224, 0.225], + "learning_strategy": { + "name": "piecewise_decay", + "batch_size": 256, + "epochs": [30, 60, 90], + "steps": [0.1, 0.01, 0.001, 0.0001] + } +} + + +class ResNet(): + def __init__(self, layers=50): + self.params = train_parameters + self.layers = layers + + def net(self, input, class_dim): + layers = self.layers + supported_layers = [50, 101, 152] + assert layers in supported_layers, \ + "supported layers are {} but input layer is {}".format(supported_layers, layers) + + if layers == 50: + depth = [3, 4, 6, 3] + elif layers == 101: + depth = [3, 4, 23, 3] + elif layers == 152: + depth = [3, 8, 36, 3] + num_filters = [64, 128, 256, 512] + + conv = self.conv_bn_layer( + input=input, num_filters=64, filter_size=7, stride=2, act='relu') + conv = fluid.layers.pool2d( + input=conv, + pool_size=3, + pool_stride=2, + pool_padding=1, + pool_type='max') + + for block in range(len(depth)): + for i in range(depth[block]): + conv = self.bottleneck_block( + input=conv, + num_filters=num_filters[block], + stride=2 if i == 0 and block != 0 else 1) + + pool = fluid.layers.pool2d( + input=conv, pool_size=7, pool_type='avg', global_pooling=True) + stdv = 1.0 / math.sqrt(pool.shape[1] * 1.0) + out = fluid.layers.fc(input=pool, + size=class_dim, + act='softmax', + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, + stdv))) + return out + + def conv_bn_layer(self, + input, + num_filters, + filter_size, + stride=1, + groups=1, + act=None): + conv = fluid.layers.conv2d( + input=input, + num_filters=num_filters, + filter_size=filter_size, + stride=stride, + padding=(filter_size - 1) / 2, + groups=groups, + act=None, + bias_attr=False) + return fluid.layers.batch_norm(input=conv, act=act) + + def shortcut(self, input, ch_out, stride): + ch_in = input.shape[1] + if ch_in != ch_out or stride != 1: + return self.conv_bn_layer(input, ch_out, 1, stride) + else: + return input + + def bottleneck_block(self, input, num_filters, stride): + conv0 = self.conv_bn_layer( + input=input, num_filters=num_filters, filter_size=1, act='relu') + conv1 = self.conv_bn_layer( + input=conv0, + num_filters=num_filters, + filter_size=3, + stride=stride, + act='relu') + conv2 = self.conv_bn_layer( + input=conv1, num_filters=num_filters * 4, filter_size=1, act=None) + + short = self.shortcut(input, num_filters * 4, stride) + + return fluid.layers.elementwise_add(x=short, y=conv2, act='relu') + + +def ResNet50(): + model = ResNet(layers=50) + return model + + +def ResNet101(): + model = ResNet(layers=101) + return model + + +def ResNet152(): + model = ResNet(layers=152) + return model diff --git a/fluid/image_classification/models/se_resnext.py b/fluid/image_classification/models/se_resnext.py new file mode 100644 index 0000000000..ec28170cc7 --- /dev/null +++ b/fluid/image_classification/models/se_resnext.py @@ -0,0 +1,195 @@ +import paddle +import paddle.fluid as fluid +import math + +__all__ = [ + "SE_ResNeXt", "SE_ResNeXt50_32x4d", "SE_ResNeXt101_32x4d", + "SE_ResNeXt152_32x4d" +] + +train_parameters = { + "input_size": [3, 224, 224], + "input_mean": [0.485, 0.456, 0.406], + "input_std": [0.229, 0.224, 0.225], + "learning_strategy": { + "name": "piecewise_decay", + "batch_size": 256, + "epochs": [30, 60, 90], + "steps": [0.1, 0.01, 0.001, 0.0001] + } +} + + +class SE_ResNeXt(): + def __init__(self, layers=50): + self.params = train_parameters + self.layers = layers + + def net(self, input, class_dim): + layers = self.layers + supported_layers = [50, 101, 152] + assert layers in supported_layers, \ + "supported layers are {} but input layer is {}".format(supported_layers, layers) + if layers == 50: + cardinality = 32 + reduction_ratio = 16 + depth = [3, 4, 6, 3] + num_filters = [128, 256, 512, 1024] + + conv = self.conv_bn_layer( + input=input, + num_filters=64, + filter_size=7, + stride=2, + act='relu') + conv = fluid.layers.pool2d( + input=conv, + pool_size=3, + pool_stride=2, + pool_padding=1, + pool_type='max') + elif layers == 101: + cardinality = 32 + reduction_ratio = 16 + depth = [3, 4, 23, 3] + num_filters = [128, 256, 512, 1024] + + conv = self.conv_bn_layer( + input=input, + num_filters=64, + filter_size=7, + stride=2, + act='relu') + conv = fluid.layers.pool2d( + input=conv, + pool_size=3, + pool_stride=2, + pool_padding=1, + pool_type='max') + elif layers == 152: + cardinality = 64 + reduction_ratio = 16 + depth = [3, 8, 36, 3] + num_filters = [128, 256, 512, 1024] + + conv = self.conv_bn_layer( + input=input, + num_filters=64, + filter_size=3, + stride=2, + act='relu') + conv = self.conv_bn_layer( + input=conv, num_filters=64, filter_size=3, stride=1, act='relu') + conv = self.conv_bn_layer( + input=conv, + num_filters=128, + filter_size=3, + stride=1, + act='relu') + conv = fluid.layers.pool2d( + input=conv, pool_size=3, pool_stride=2, pool_padding=1, \ + pool_type='max') + + for block in range(len(depth)): + for i in range(depth[block]): + conv = self.bottleneck_block( + input=conv, + num_filters=num_filters[block], + stride=2 if i == 0 and block != 0 else 1, + cardinality=cardinality, + reduction_ratio=reduction_ratio) + + pool = fluid.layers.pool2d( + input=conv, pool_size=7, pool_type='avg', global_pooling=True) + drop = fluid.layers.dropout(x=pool, dropout_prob=0.5) + stdv = 1.0 / math.sqrt(drop.shape[1] * 1.0) + out = fluid.layers.fc(input=drop, + size=class_dim, + act='softmax', + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, + stdv))) + return out + + def shortcut(self, input, ch_out, stride): + ch_in = input.shape[1] + if ch_in != ch_out or stride != 1: + filter_size = 1 + return self.conv_bn_layer(input, ch_out, filter_size, stride) + else: + return input + + def bottleneck_block(self, input, num_filters, stride, cardinality, + reduction_ratio): + conv0 = self.conv_bn_layer( + input=input, num_filters=num_filters, filter_size=1, act='relu') + conv1 = self.conv_bn_layer( + input=conv0, + num_filters=num_filters, + filter_size=3, + stride=stride, + groups=cardinality, + act='relu') + conv2 = self.conv_bn_layer( + input=conv1, num_filters=num_filters * 2, filter_size=1, act=None) + scale = self.squeeze_excitation( + input=conv2, + num_channels=num_filters * 2, + reduction_ratio=reduction_ratio) + + short = self.shortcut(input, num_filters * 2, stride) + + return fluid.layers.elementwise_add(x=short, y=scale, act='relu') + + def conv_bn_layer(self, + input, + num_filters, + filter_size, + stride=1, + groups=1, + act=None): + conv = fluid.layers.conv2d( + input=input, + num_filters=num_filters, + filter_size=filter_size, + stride=stride, + padding=(filter_size - 1) / 2, + groups=groups, + act=None, + bias_attr=False) + return fluid.layers.batch_norm(input=conv, act=act) + + def squeeze_excitation(self, input, num_channels, reduction_ratio): + pool = fluid.layers.pool2d( + input=input, pool_size=0, pool_type='avg', global_pooling=True) + stdv = 1.0 / math.sqrt(pool.shape[1] * 1.0) + squeeze = fluid.layers.fc(input=pool, + size=num_channels / reduction_ratio, + act='relu', + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform( + -stdv, stdv))) + stdv = 1.0 / math.sqrt(squeeze.shape[1] * 1.0) + excitation = fluid.layers.fc(input=squeeze, + size=num_channels, + act='sigmoid', + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform( + -stdv, stdv))) + scale = fluid.layers.elementwise_mul(x=input, y=excitation, axis=0) + return scale + + +def SE_ResNeXt50_32x4d(): + model = SE_ResNeXt(layers=50) + return model + + +def SE_ResNeXt101_32x4d(): + model = SE_ResNeXt(layers=101) + return model + + +def SE_ResNeXt152_32x4d(): + model = SE_ResNeXt(layers=152) + return model diff --git a/fluid/image_classification/models/vgg.py b/fluid/image_classification/models/vgg.py new file mode 100644 index 0000000000..6cd63b1482 --- /dev/null +++ b/fluid/image_classification/models/vgg.py @@ -0,0 +1,107 @@ +import paddle +import paddle.fluid as fluid + +__all__ = ["VGGNet", "VGG11", "VGG13", "VGG16", "VGG19"] + +train_parameters = { + "input_size": [3, 224, 224], + "input_mean": [0.485, 0.456, 0.406], + "input_std": [0.229, 0.224, 0.225], + "learning_strategy": { + "name": "piecewise_decay", + "batch_size": 256, + "epochs": [30, 60, 90], + "steps": [0.1, 0.01, 0.001, 0.0001] + } +} + + +class VGGNet(): + def __init__(self, layers=16): + self.params = train_parameters + self.layers = layers + + def net(self, input, class_dim): + layers = self.layers + vgg_spec = { + 11: ([1, 1, 2, 2, 2]), + 13: ([2, 2, 2, 2, 2]), + 16: ([2, 2, 3, 3, 3]), + 19: ([2, 2, 4, 4, 4]) + } + assert layers in vgg_spec.keys(), \ + "supported layers are {} but input layer is {}".format(vgg_spec.keys(), layers) + + nums = vgg_spec[layers] + conv1 = self.conv_block(input, 64, nums[0]) + conv2 = self.conv_block(conv1, 128, nums[1]) + conv3 = self.conv_block(conv2, 256, nums[2]) + conv4 = self.conv_block(conv3, 512, nums[3]) + conv5 = self.conv_block(conv4, 512, nums[4]) + + fc_dim = 4096 + fc1 = fluid.layers.fc( + input=conv5, + size=fc_dim, + act='relu', + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Normal(scale=0.005)), + bias_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Constant(value=0.1))) + fc1 = fluid.layers.dropout(x=fc1, dropout_prob=0.5) + fc2 = fluid.layers.fc( + input=fc1, + size=fc_dim, + act='relu', + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Normal(scale=0.005)), + bias_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Constant(value=0.1))) + fc2 = fluid.layers.dropout(x=fc2, dropout_prob=0.5) + out = fluid.layers.fc( + input=fc2, + size=class_dim, + act='softmax', + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Normal(scale=0.005)), + bias_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Constant(value=0.1))) + + return out + + def conv_block(self, input, num_filter, groups): + conv = input + for i in range(groups): + conv = fluid.layers.conv2d( + input=conv, + num_filters=num_filter, + filter_size=3, + stride=1, + padding=1, + act='relu', + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Normal(scale=0.01)), + bias_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Constant(value=0.0))) + return fluid.layers.pool2d( + input=conv, pool_size=2, pool_type='max', pool_stride=2) + + +def VGG11(): + model = VGGNet(layers=11) + return model + + +def VGG13(): + model = VGGNet(layers=13) + return model + + +def VGG16(): + model = VGGNet(layers=16) + return model + + +def VGG19(): + model = VGGNet(layers=19) + return model diff --git a/fluid/image_classification/reader.py b/fluid/image_classification/reader.py index a5a8f45dc7..b503b67ce0 100644 --- a/fluid/image_classification/reader.py +++ b/fluid/image_classification/reader.py @@ -11,7 +11,7 @@ DATA_DIM = 224 THREAD = 8 -BUF_SIZE = 1024 +BUF_SIZE = 102400 DATA_DIR = 'data/ILSVRC2012' TRAIN_LIST = 'data/ILSVRC2012/train_list.txt' @@ -105,7 +105,7 @@ def process_image(sample, mode, color_jitter, rotate): if rotate: img = rotate_image(img) img = random_crop(img, DATA_DIM) else: - img = resize_short(img, DATA_DIM) + img = resize_short(img, target_size=256) img = crop_image(img, target_size=DATA_DIM, center=True) if mode == 'train': if color_jitter: @@ -120,9 +120,9 @@ def process_image(sample, mode, color_jitter, rotate): img -= img_mean img /= img_std - if mode == 'train' or mode == 'test': + if mode == 'train' or mode == 'val': return img, sample[1] - elif mode == 'infer': + elif mode == 'test': return [img] @@ -137,11 +137,11 @@ def reader(): if shuffle: random.shuffle(lines) for line in lines: - if mode == 'train' or mode == 'test': + if mode == 'train' or mode == 'val': img_path, label = line.split() img_path = os.path.join(DATA_DIR, img_path) yield img_path, int(label) - elif mode == 'infer': + elif mode == 'test': img_path = os.path.join(DATA_DIR, line) yield [img_path] @@ -156,9 +156,9 @@ def train(file_list=TRAIN_LIST): file_list, 'train', shuffle=True, color_jitter=False, rotate=False) -def test(file_list=TEST_LIST): - return _reader_creator(file_list, 'test', shuffle=False) +def val(file_list=TEST_LIST): + return _reader_creator(file_list, 'val', shuffle=False) -def infer(file_list): - return _reader_creator(file_list, 'infer', shuffle=False) +def test(file_list): + return _reader_creator(file_list, 'test', shuffle=False) diff --git a/fluid/image_classification/se_resnext.py b/fluid/image_classification/se_resnext.py deleted file mode 100644 index a6daa23577..0000000000 --- a/fluid/image_classification/se_resnext.py +++ /dev/null @@ -1,137 +0,0 @@ -import os -import numpy as np -import time -import sys -import paddle -import paddle.fluid as fluid -import paddle.fluid.layers.control_flow as control_flow -import paddle.fluid.layers.nn as nn -import paddle.fluid.layers.tensor as tensor -import math - - -def conv_bn_layer(input, num_filters, filter_size, stride=1, groups=1, - act=None): - conv = fluid.layers.conv2d( - input=input, - num_filters=num_filters, - filter_size=filter_size, - stride=stride, - padding=(filter_size - 1) / 2, - groups=groups, - act=None, - bias_attr=False) - return fluid.layers.batch_norm(input=conv, act=act) - - -def squeeze_excitation(input, num_channels, reduction_ratio): - pool = fluid.layers.pool2d( - input=input, pool_size=0, pool_type='avg', global_pooling=True) - stdv = 1.0 / math.sqrt(pool.shape[1] * 1.0) - squeeze = fluid.layers.fc(input=pool, - size=num_channels / reduction_ratio, - act='relu', - param_attr=fluid.param_attr.ParamAttr( - initializer=fluid.initializer.Uniform(-stdv, - stdv))) - stdv = 1.0 / math.sqrt(squeeze.shape[1] * 1.0) - excitation = fluid.layers.fc(input=squeeze, - size=num_channels, - act='sigmoid', - param_attr=fluid.param_attr.ParamAttr( - initializer=fluid.initializer.Uniform( - -stdv, stdv))) - scale = fluid.layers.elementwise_mul(x=input, y=excitation, axis=0) - return scale - - -def shortcut(input, ch_out, stride): - ch_in = input.shape[1] - if ch_in != ch_out or stride != 1: - filter_size = 1 - return conv_bn_layer(input, ch_out, filter_size, stride) - else: - return input - - -def bottleneck_block(input, num_filters, stride, cardinality, reduction_ratio): - conv0 = conv_bn_layer( - input=input, num_filters=num_filters, filter_size=1, act='relu') - conv1 = conv_bn_layer( - input=conv0, - num_filters=num_filters, - filter_size=3, - stride=stride, - groups=cardinality, - act='relu') - conv2 = conv_bn_layer( - input=conv1, num_filters=num_filters * 2, filter_size=1, act=None) - scale = squeeze_excitation( - input=conv2, - num_channels=num_filters * 2, - reduction_ratio=reduction_ratio) - - short = shortcut(input, num_filters * 2, stride) - - return fluid.layers.elementwise_add(x=short, y=scale, act='relu') - - -def SE_ResNeXt(input, class_dim, infer=False, layers=50): - supported_layers = [50, 152] - if layers not in supported_layers: - print("supported layers are", supported_layers, \ - "but input layer is ", layers) - exit() - if layers == 50: - cardinality = 32 - reduction_ratio = 16 - depth = [3, 4, 6, 3] - num_filters = [128, 256, 512, 1024] - - conv = conv_bn_layer( - input=input, num_filters=64, filter_size=7, stride=2, act='relu') - conv = fluid.layers.pool2d( - input=conv, - pool_size=3, - pool_stride=2, - pool_padding=1, - pool_type='max') - elif layers == 152: - cardinality = 64 - reduction_ratio = 16 - depth = [3, 8, 36, 3] - num_filters = [128, 256, 512, 1024] - - conv = conv_bn_layer( - input=input, num_filters=64, filter_size=3, stride=2, act='relu') - conv = conv_bn_layer( - input=conv, num_filters=64, filter_size=3, stride=1, act='relu') - conv = conv_bn_layer( - input=conv, num_filters=128, filter_size=3, stride=1, act='relu') - conv = fluid.layers.pool2d( - input=conv, pool_size=3, pool_stride=2, pool_padding=1, \ - pool_type='max') - - for block in range(len(depth)): - for i in range(depth[block]): - conv = bottleneck_block( - input=conv, - num_filters=num_filters[block], - stride=2 if i == 0 and block != 0 else 1, - cardinality=cardinality, - reduction_ratio=reduction_ratio) - - pool = fluid.layers.pool2d( - input=conv, pool_size=7, pool_type='avg', global_pooling=True) - if not infer: - drop = fluid.layers.dropout(x=pool, dropout_prob=0.5) - else: - drop = pool - stdv = 1.0 / math.sqrt(drop.shape[1] * 1.0) - out = fluid.layers.fc(input=drop, - size=class_dim, - act='softmax', - param_attr=fluid.param_attr.ParamAttr( - initializer=fluid.initializer.Uniform(-stdv, - stdv))) - return out diff --git a/fluid/image_classification/train.py b/fluid/image_classification/train.py index 84e05ecd77..0551bf16ee 100644 --- a/fluid/image_classification/train.py +++ b/fluid/image_classification/train.py @@ -4,278 +4,144 @@ import sys import paddle import paddle.fluid as fluid -from se_resnext import SE_ResNeXt -from mobilenet import mobile_net -from inception_v4 import inception_v4 +import models import reader import argparse import functools -import paddle.fluid.layers.ops as ops +from models.learning_rate import cosine_decay from utility import add_arguments, print_arguments -from paddle.fluid.initializer import init_on_cpu -from paddle.fluid.layers.learning_rate_scheduler import _decay_step_counter import math parser = argparse.ArgumentParser(description=__doc__) add_arg = functools.partial(add_arguments, argparser=parser) add_arg('batch_size', int, 256, "Minibatch size.") -add_arg('num_layers', int, 50, "How many layers for SE-ResNeXt model.") +add_arg('total_images', int, 1281167, "Training image number.") +add_arg('num_epochs', int, 120, "number of epochs.") +add_arg('class_dim', int, 1000, "Class number.") +add_arg('image_shape', str, "3,224,224", "input image size") +add_arg('model_save_dir', str, "output", "model save directory") add_arg('with_mem_opt', bool, True, "Whether to use memory optimization or not.") -add_arg('parallel_exe', bool, True, - "Whether to use ParallelExecutor to train or not.") -add_arg('init_model', str, None, "Whether to use initialized model.") add_arg('pretrained_model', str, None, "Whether to use pretrained model.") -add_arg('lr_strategy', str, "cosine_decay", +add_arg('checkpoint', str, None, "Whether to resume checkpoint.") +add_arg('lr', float, 0.1, "set learning rate.") +add_arg('lr_strategy', str, "piecewise_decay", "Set the learning rate decay strategy.") -add_arg('model', str, "se_resnext", "Set the network to use.") - - -def cosine_decay(learning_rate, step_each_epoch, epochs=120): - """Applies cosine decay to the learning rate. - lr = 0.05 * (math.cos(epoch * (math.pi / 120)) + 1) - """ - global_step = _decay_step_counter() - - with init_on_cpu(): - epoch = ops.floor(global_step / step_each_epoch) - decayed_lr = learning_rate * \ - (ops.cos(epoch * (math.pi / epochs)) + 1)/2 - return decayed_lr - - -def train_parallel_do(args, - learning_rate, - batch_size, - num_passes, - init_model=None, - pretrained_model=None, - model_save_dir='model', - parallel=True, - use_nccl=True, - lr_strategy=None, - layers=50): - class_dim = 1000 - image_shape = [3, 224, 224] +add_arg('model', str, "SE_ResNeXt50_32x4d", "Set the network to use.") - image = fluid.layers.data(name='image', shape=image_shape, dtype='float32') - label = fluid.layers.data(name='label', shape=[1], dtype='int64') +model_list = [m for m in dir(models) if "__" not in m] - if parallel: - places = fluid.layers.get_places() - pd = fluid.layers.ParallelDo(places, use_nccl=use_nccl) - - with pd.do(): - image_ = pd.read_input(image) - label_ = pd.read_input(label) - if args.model is 'se_resnext': - out = SE_ResNeXt( - input=image_, class_dim=class_dim, layers=layers) - elif args.model is 'mobile_net': - out = mobile_net(img=image_, class_dim=class_dim) - else: - out = inception_v4(img=image_, class_dim=class_dim) - - cost = fluid.layers.cross_entropy(input=out, label=label_) - avg_cost = fluid.layers.mean(x=cost) - acc_top1 = fluid.layers.accuracy(input=out, label=label_, k=1) - acc_top5 = fluid.layers.accuracy(input=out, label=label_, k=5) - pd.write_output(avg_cost) - pd.write_output(acc_top1) - pd.write_output(acc_top5) - - avg_cost, acc_top1, acc_top5 = pd() - avg_cost = fluid.layers.mean(x=avg_cost) - acc_top1 = fluid.layers.mean(x=acc_top1) - acc_top5 = fluid.layers.mean(x=acc_top5) - else: - if args.model is 'se_resnext': - out = SE_ResNeXt(input=image, class_dim=class_dim, layers=layers) - elif args.model is 'mobile_net': - out = mobile_net(img=image, class_dim=class_dim) - else: - out = inception_v4(img=image, class_dim=class_dim) - cost = fluid.layers.cross_entropy(input=out, label=label) - avg_cost = fluid.layers.mean(x=cost) - acc_top1 = fluid.layers.accuracy(input=out, label=label, k=1) - acc_top5 = fluid.layers.accuracy(input=out, label=label, k=5) +def optimizer_setting(params): + ls = params["learning_strategy"] + + if ls["name"] == "piecewise_decay": + if "total_images" not in params: + total_images = 1281167 + else: + total_images = params["total_images"] - inference_program = fluid.default_main_program().clone(for_test=True) + batch_size = ls["batch_size"] + step = int(total_images / batch_size + 1) - if "piecewise_decay" in lr_strategy: - bd = lr_strategy["piecewise_decay"]["bd"] - lr = lr_strategy["piecewise_decay"]["lr"] + bd = [step * e for e in ls["epochs"]] + base_lr = params["lr"] + lr = [] + lr = [base_lr * (0.1**i) for i in range(len(bd) + 1)] optimizer = fluid.optimizer.Momentum( learning_rate=fluid.layers.piecewise_decay( boundaries=bd, values=lr), momentum=0.9, regularization=fluid.regularizer.L2Decay(1e-4)) - elif "cosine_decay" in lr_strategy: - step_each_epoch = lr_strategy["cosine_decay"]["step_each_epoch"] - epochs = lr_strategy["cosine_decay"]["epochs"] + elif ls["name"] == "cosine_decay": + if "total_images" not in params: + total_images = 1281167 + else: + total_images = params["total_images"] + + batch_size = ls["batch_size"] + step = int(total_images / batch_size + 1) + + lr = params["lr"] + num_epochs = params["num_epochs"] + optimizer = fluid.optimizer.Momentum( learning_rate=cosine_decay( - learning_rate=learning_rate, - step_each_epoch=step_each_epoch, - epochs=epochs), + learning_rate=lr, step_each_epoch=step, epochs=num_epochs), momentum=0.9, regularization=fluid.regularizer.L2Decay(1e-4)) else: + lr = params["lr"] optimizer = fluid.optimizer.Momentum( - learning_rate=learning_rate, + learning_rate=lr, momentum=0.9, regularization=fluid.regularizer.L2Decay(1e-4)) - opts = optimizer.minimize(avg_cost) - if args.with_mem_opt: - fluid.memory_optimize(fluid.default_main_program()) - - place = fluid.CUDAPlace(0) - exe = fluid.Executor(place) - exe.run(fluid.default_startup_program()) - - if init_model is not None: - fluid.io.load_persistables(exe, init_model) - - if pretrained_model: - - def if_exist(var): - return os.path.exists(os.path.join(pretrained_model, var.name)) - - fluid.io.load_vars(exe, pretrained_model, predicate=if_exist) - - train_reader = paddle.batch(reader.train(), batch_size=batch_size) - test_reader = paddle.batch(reader.test(), batch_size=batch_size) - feeder = fluid.DataFeeder(place=place, feed_list=[image, label]) - - for pass_id in range(num_passes): - train_info = [[], [], []] - test_info = [[], [], []] - for batch_id, data in enumerate(train_reader()): - t1 = time.time() - loss, acc1, acc5 = exe.run( - fluid.default_main_program(), - feed=feeder.feed(data), - fetch_list=[avg_cost, acc_top1, acc_top5]) - t2 = time.time() - period = t2 - t1 - train_info[0].append(loss[0]) - train_info[1].append(acc1[0]) - train_info[2].append(acc5[0]) - if batch_id % 10 == 0: - print("Pass {0}, trainbatch {1}, loss {2}, \ - acc1 {3}, acc5 {4} time {5}" - .format(pass_id, \ - batch_id, loss[0], acc1[0], acc5[0], \ - "%2.2f sec" % period)) - sys.stdout.flush() - - train_loss = np.array(train_info[0]).mean() - train_acc1 = np.array(train_info[1]).mean() - train_acc5 = np.array(train_info[2]).mean() - for data in test_reader(): - t1 = time.time() - loss, acc1, acc5 = exe.run( - inference_program, - feed=feeder.feed(data), - fetch_list=[avg_cost, acc_top1, acc_top5]) - t2 = time.time() - period = t2 - t1 - test_info[0].append(loss[0]) - test_info[1].append(acc1[0]) - test_info[2].append(acc5[0]) - if batch_id % 10 == 0: - print("Pass {0},testbatch {1},loss {2}, \ - acc1 {3},acc5 {4},time {5}" - .format(pass_id, \ - batch_id, loss[0], acc1[0], acc5[0], \ - "%2.2f sec" % period)) - sys.stdout.flush() - - test_loss = np.array(test_info[0]).mean() - test_acc1 = np.array(test_info[1]).mean() - test_acc5 = np.array(test_info[2]).mean() + return optimizer - print("End pass {0}, train_loss {1}, train_acc1 {2}, train_acc5 {3}, \ - test_loss {4}, test_acc1 {5}, test_acc5 {6}" - .format(pass_id, \ - train_loss, train_acc1, train_acc5, test_loss, test_acc1, \ - test_acc5)) - sys.stdout.flush() - - model_path = os.path.join(model_save_dir + '/' + args.model, - str(pass_id)) - if not os.path.isdir(model_path): - os.makedirs(model_path) - fluid.io.save_persistables(exe, model_path) +def train(args): + # parameters from arguments + class_dim = args.class_dim + model_name = args.model + checkpoint = args.checkpoint + pretrained_model = args.pretrained_model + with_memory_optimization = args.with_mem_opt + model_save_dir = args.model_save_dir + image_shape = [int(m) for m in args.image_shape.split(",")] -def train_parallel_exe(args, - learning_rate, - batch_size, - num_passes, - init_model=None, - pretrained_model=None, - model_save_dir='model', - parallel=True, - use_nccl=True, - lr_strategy=None, - layers=50): - class_dim = 1000 - image_shape = [3, 224, 224] + assert model_name in model_list, "{} is not in lists: {}".format(args.model, + model_list) image = fluid.layers.data(name='image', shape=image_shape, dtype='float32') label = fluid.layers.data(name='label', shape=[1], dtype='int64') - if args.model is 'se_resnext': - out = SE_ResNeXt(input=image, class_dim=class_dim, layers=layers) - elif args.model is 'mobile_net': - out = mobile_net(img=image, class_dim=class_dim) + + # model definition + model = models.__dict__[model_name]() + + if model_name in ["GoogleNet"]: + out0, out1, out2 = model.net(input=image, class_dim=class_dim) + cost0 = fluid.layers.cross_entropy(input=out0, label=label) + cost1 = fluid.layers.cross_entropy(input=out1, label=label) + cost2 = fluid.layers.cross_entropy(input=out2, label=label) + avg_cost0 = fluid.layers.mean(x=cost0) + avg_cost1 = fluid.layers.mean(x=cost1) + avg_cost2 = fluid.layers.mean(x=cost2) + + avg_cost = avg_cost0 + 0.3 * avg_cost1 + 0.3 * avg_cost2 + acc_top1 = fluid.layers.accuracy(input=out0, label=label, k=1) + acc_top5 = fluid.layers.accuracy(input=out0, label=label, k=5) else: - out = inception_v4(img=image, class_dim=class_dim) + out = model.net(input=image, class_dim=class_dim) + cost = fluid.layers.cross_entropy(input=out, label=label) - cost = fluid.layers.cross_entropy(input=out, label=label) - acc_top1 = fluid.layers.accuracy(input=out, label=label, k=1) - acc_top5 = fluid.layers.accuracy(input=out, label=label, k=5) - avg_cost = fluid.layers.mean(x=cost) + avg_cost = fluid.layers.mean(x=cost) + acc_top1 = fluid.layers.accuracy(input=out, label=label, k=1) + acc_top5 = fluid.layers.accuracy(input=out, label=label, k=5) test_program = fluid.default_main_program().clone(for_test=True) - if "piecewise_decay" in lr_strategy: - bd = lr_strategy["piecewise_decay"]["bd"] - lr = lr_strategy["piecewise_decay"]["lr"] - optimizer = fluid.optimizer.Momentum( - learning_rate=fluid.layers.piecewise_decay( - boundaries=bd, values=lr), - momentum=0.9, - regularization=fluid.regularizer.L2Decay(1e-4)) - elif "cosine_decay" in lr_strategy: - step_each_epoch = lr_strategy["cosine_decay"]["step_each_epoch"] - epochs = lr_strategy["cosine_decay"]["epochs"] - optimizer = fluid.optimizer.Momentum( - learning_rate=cosine_decay( - learning_rate=learning_rate, - step_each_epoch=step_each_epoch, - epochs=epochs), - momentum=0.9, - regularization=fluid.regularizer.L2Decay(1e-4)) - else: - optimizer = fluid.optimizer.Momentum( - learning_rate=learning_rate, - momentum=0.9, - regularization=fluid.regularizer.L2Decay(1e-4)) + # parameters from model and arguments + params = model.params + params["total_images"] = args.total_images + params["lr"] = args.lr + params["num_epochs"] = args.num_epochs + params["learning_strategy"]["batch_size"] = args.batch_size + params["learning_strategy"]["name"] = args.lr_strategy + # initialize optimizer + optimizer = optimizer_setting(params) opts = optimizer.minimize(avg_cost) - if args.with_mem_opt: + if with_memory_optimization: fluid.memory_optimize(fluid.default_main_program()) place = fluid.CUDAPlace(0) exe = fluid.Executor(place) exe.run(fluid.default_startup_program()) - if init_model is not None: - fluid.io.load_persistables(exe, init_model) + if checkpoint is not None: + fluid.io.load_persistables(exe, checkpoint) if pretrained_model: @@ -284,18 +150,17 @@ def if_exist(var): fluid.io.load_vars(exe, pretrained_model, predicate=if_exist) - train_reader = paddle.batch(reader.train(), batch_size=batch_size) - test_reader = paddle.batch(reader.test(), batch_size=batch_size) - + train_batch_size = args.batch_size + test_batch_size = 16 + train_reader = paddle.batch(reader.train(), batch_size=train_batch_size) + test_reader = paddle.batch(reader.val(), batch_size=test_batch_size) feeder = fluid.DataFeeder(place=place, feed_list=[image, label]) train_exe = fluid.ParallelExecutor(use_cuda=True, loss_name=avg_cost.name) - test_exe = fluid.ParallelExecutor( - use_cuda=True, main_program=test_program, share_vars_from=train_exe) fetch_list = [avg_cost.name, acc_top1.name, acc_top5.name] - for pass_id in range(num_passes): + for pass_id in range(params["num_epochs"]): train_info = [[], [], []] test_info = [[], [], []] for batch_id, data in enumerate(train_reader()): @@ -316,13 +181,16 @@ def if_exist(var): batch_id, loss, acc1, acc5, \ "%2.2f sec" % period)) sys.stdout.flush() + break train_loss = np.array(train_info[0]).mean() train_acc1 = np.array(train_info[1]).mean() train_acc5 = np.array(train_info[2]).mean() for data in test_reader(): t1 = time.time() - loss, acc1, acc5 = test_exe.run(fetch_list, feed=feeder.feed(data)) + loss, acc1, acc5 = exe.run(test_program, + fetch_list=fetch_list, + feed=feeder.feed(data)) t2 = time.time() period = t2 - t1 loss = np.mean(np.array(loss)) @@ -338,63 +206,30 @@ def if_exist(var): batch_id, loss, acc1, acc5, \ "%2.2f sec" % period)) sys.stdout.flush() + break test_loss = np.array(test_info[0]).mean() test_acc1 = np.array(test_info[1]).mean() test_acc5 = np.array(test_info[2]).mean() - print("End pass {0}, train_loss {1}, train_acc1 {2}, train_acc5 {3}, \ - test_loss {4}, test_acc1 {5}, test_acc5 {6}" - .format(pass_id, \ + print("End pass {0}, train_loss {1}, train_acc1 {2}, train_acc5 {3}, " + "test_loss {4}, test_acc1 {5}, test_acc5 {6}".format(pass_id, \ train_loss, train_acc1, train_acc5, test_loss, test_acc1, \ test_acc5)) sys.stdout.flush() - model_path = os.path.join(model_save_dir + '/' + args.model, + model_path = os.path.join(model_save_dir + '/' + model_name, str(pass_id)) if not os.path.isdir(model_path): os.makedirs(model_path) fluid.io.save_persistables(exe, model_path) -if __name__ == '__main__': +def main(): args = parser.parse_args() print_arguments(args) + train(args) - total_images = 1281167 - batch_size = args.batch_size - step = int(total_images / batch_size + 1) - num_epochs = 120 - - learning_rate_mode = args.lr_strategy - lr_strategy = {} - if learning_rate_mode == "piecewise_decay": - epoch_points = [30, 60, 90] - bd = [e * step for e in epoch_points] - lr = [0.1, 0.01, 0.001, 0.0001] - lr_strategy[learning_rate_mode] = {"bd": bd, "lr": lr} - elif learning_rate_mode == "cosine_decay": - lr_strategy[learning_rate_mode] = { - "step_each_epoch": step, - "epochs": num_epochs - } - else: - lr_strategy = None - - use_nccl = True - # layers: 50, 152 - layers = args.num_layers - method = train_parallel_exe if args.parallel_exe else train_parallel_do - init_model = args.init_model if args.init_model else None - pretrained_model = args.pretrained_model if args.pretrained_model else None - method( - args, - learning_rate=0.1, - batch_size=batch_size, - num_passes=num_epochs, - init_model=init_model, - pretrained_model=pretrained_model, - parallel=True, - use_nccl=True, - lr_strategy=lr_strategy, - layers=layers) + +if __name__ == '__main__': + main() From f3bcc1144f423a1f8a69293b3b5cfbaecd3b9fbb Mon Sep 17 00:00:00 2001 From: BigFishMaster Date: Fri, 1 Jun 2018 00:08:32 +0800 Subject: [PATCH 04/47] update readme --- fluid/image_classification/README.md | 52 +++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index 1000717c87..5c2ecc4f8b 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -5,7 +5,8 @@ The minimum PaddlePaddle version needed for the code sample in this directory is # SE-ResNeXt for image classification This model built with paddle fluid is still under active development and is not -the final version. We welcome feedbacks. +ang +he final version. We welcome feedbacks. ## Introduction @@ -57,18 +58,54 @@ val/ILSVRC2012_val_00000005.jpeg 516 To start a training task, one can use command line as: ``` -python train.py --num_layers=50 --batch_size=8 --with_mem_opt=True --parallel_exe=False +python train.py \ + --model=SE_ResNeXt101_32x4d \ + --batch_size=32 \ + --total_images=1281167 \ + --class_dim=1000 + --image_shape=3,224,224 \ + --model_save_dir=output/ \ + --with_mem_opt=False \ + --lr_strategy=piecewise_decay \ + --lr=0.1 ``` -## Finetune a model + +## Finetuning ``` -python train.py --num_layers=50 --batch_size=8 --with_mem_opt=True --parallel_exe=False --pretrained_model="pretrain/96/" +python train.py + --model=SE_ResNeXt101_32x4d \ + --pretrained_model=${path_to_pretrain_model} \ + --batch_size=32 \ + --total_images=1281167 \ + --class_dim=1000 \ + --image_shape=3,224,224 \ + --model_save_dir=output/ \ + --with_mem_opt=False \ + --lr_strategy=piecewise_decay \ + --lr=0.1 ``` -TBD + +## Evaluation +``` +python eval.py \ + --model=SE_ResNeXt50_32x4d \ + --batch_size=32 \ + --class_dim=1000 \ + --image_shape=3,224,224 \ + --with_mem_opt=False \ + --pretrained_model=${path_to_pretrain_model} +``` + ## Inference ``` -python infer.py --num_layers=50 --batch_size=8 --model='model/90' --test_list='' +python infer.py \ + --model=SE_ResNeXt50_32x4d \ + --batch_size=32 \ + --class_dim=1000 \ + --image_shape=3,224,224 \ + --with_mem_opt=False \ + --pretrained_model=${path_to_pretrain_model} ``` -TBD ## Results @@ -79,7 +116,6 @@ The SE-ResNeXt-50 model is trained by starting with learning rate ```0.1``` and |SE-ResNeXt-50 | 77.6%/- | 77.71%/93.63% | 77.42%/93.50% - ## Released models |model | Baidu Cloud |- | -: From a394d72fbaf39e4a1e16a5d07eea899919f37f27 Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Fri, 1 Jun 2018 00:53:51 +0800 Subject: [PATCH 05/47] Update README.md --- fluid/image_classification/README.md | 89 +++++++++++++++++----------- 1 file changed, 55 insertions(+), 34 deletions(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index 5c2ecc4f8b..1906830b5f 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -1,39 +1,30 @@ -The minimum PaddlePaddle version needed for the code sample in this directory is the lastest develop branch. If you are on a version of PaddlePaddle earlier than this, [please update your installation](http://www.paddlepaddle.org/docs/develop/documentation/en/build_and_install/pip_install_en.html). +# Image Classification and Paddle Model Zoo +This page introduces how to do image classification with Paddle fluid. To run the examples below, please [install](http://www.paddlepaddle.org/docs/develop/documentation/en/build_and_install/pip_install_en.html) the newest Paddle first. --- -# SE-ResNeXt for image classification +To train a model using ImageNet dataset, please follow the steps below. -This model built with paddle fluid is still under active development and is not -ang -he final version. We welcome feedbacks. - -## Introduction - -The current code support the training of [SE-ResNeXt](https://arxiv.org/abs/1709.01507) (50/152 layers). ## Data Preparation -1. Download ImageNet-2012 dataset +1. Download ImageNet-2012 dataset from website ``` cd data/ mkdir -p ILSVRC2012/ cd ILSVRC2012/ -# get training set -wget http://www.image-net.org/challenges/LSVRC/2012/nnoupb/ILSVRC2012_img_train.tar -# get validation set -wget http://www.image-net.org/challenges/LSVRC/2012/nnoupb/ILSVRC2012_img_val.tar -# prepare directory -tar xf ILSVRC2012_img_train.tar -tar xf ILSVRC2012_img_val.tar - -# unzip all classes data using unzip.sh -sh unzip.sh +wget paddl_imagenet2012_dataset_url/ImageNet2012_dataset.tar +tar xf ImageNet2012_dataset.tar ``` -2. Download training and validation label files from [ImageNet2012 url](https://pan.baidu.com/s/1Y6BCo0nmxsm_FsEqmx2hKQ)(password:```wx99```). Untar it into workspace ```ILSVRC2012/```. The files include +2. Download training and validation label files +``` +wget paddl_imagenet2012_label_url/ImageNet2012_label.tar +tar xf ImageNet2012_label.tar +``` +there are two label files which train and validation image labels respectively: -**train_list.txt**: training list of imagenet 2012 classification task, with each line seperated by SPACE. +**train_list.txt**: label file imagenet-2012 training set, with each line seperated by SPACE, like: ``` train/n02483708/n02483708_2436.jpeg 369 train/n03998194/n03998194_7015.jpeg 741 @@ -42,7 +33,7 @@ train/n04596742/n04596742_3032.jpeg 909 train/n03208938/n03208938_7065.jpeg 535 ... ``` -**val_list.txt**: validation list of imagenet 2012 classification task, with each line seperated by SPACE. +**val_list.txt**: label file of imagenet-2012 validation set, with each line seperated by SPACE, like. ``` val/ILSVRC2012_val_00000001.jpeg 65 val/ILSVRC2012_val_00000002.jpeg 970 @@ -51,11 +42,10 @@ val/ILSVRC2012_val_00000004.jpeg 809 val/ILSVRC2012_val_00000005.jpeg 516 ... ``` -**synset_words.txt**: the semantic label of each class. -## Training a model +## Training a model with flexible parameters -To start a training task, one can use command line as: +After data preparation, one can start the training by: ``` python train.py \ @@ -69,6 +59,19 @@ python train.py \ --lr_strategy=piecewise_decay \ --lr=0.1 ``` +**parameter introduction:** +* **model**: name model to use. Default: "SE_ResNeXt50_32x4d". +* **num_epochs**: the number of epochs. Default: 120. +* **batch_size**: the size of each mini-batch. Default: 256. +* **total_images**: total number of images in the training set. Default: 1281167. +* **class_dim**: the class number of the classification task. Default: 1000. +* **image_shape**: input size of the network. Default: "3,224,224". +* **model_save_dir**: the directory to save trained model. Default: "output". +* **with_mem_opt**: whether to use memory optimization or not. Default: False. +* **lr_strategy**: learning rate changing strategy. Default: "piecewise_decay". +* **lr**: initialized learning rate. Default: 0.1. +* **pretrained_model**: model path for pretraining. Default: None. +* **checkpoint**: the checkpoint path to resume. Default: None. ## Finetuning ``` @@ -107,17 +110,35 @@ python infer.py \ --pretrained_model=${path_to_pretrain_model} ``` -## Results +## Supported models and performances The SE-ResNeXt-50 model is trained by starting with learning rate ```0.1``` and decaying it by ```0.1``` after each ```10``` epoches. Top-1/Top-5 Validation Accuracy on ImageNet 2012 is listed in table. -|model | [original paper(Fig.5)](https://arxiv.org/abs/1709.01507) | Pytorch | Paddle fluid -|- | :-: |:-: | -: -|SE-ResNeXt-50 | 77.6%/- | 77.71%/93.63% | 77.42%/93.50% - - -## Released models -|model | Baidu Cloud +|model | top1/top5 accuracy +|- | -: +|AlexNet | - +|VGG11 | - +|VGG13 | - +|VGG16 | - +|VGG19 | - +|GoogleNet | - +|InceptionV4 | - +|MobileNet | - +|ResNet50 | - +|ResNet101 | - +|ResNet152 | - +|SE_ResNeXt50_32x4d | 77.42%/93.50% +|SE_ResNeXt101_32x4d | - +|SE_ResNeXt152_32x4d | - +|DPN68 | - +|DPN92 | - +|DPN98 | - +|DPN107 | - +|DPN131 | - + + +## Download models +|model | url |- | -: |SE-ResNeXt-50 | [url]() TBD From 4693b4dc2d8ff015b77500d3d6f56d57fff4a135 Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Fri, 1 Jun 2018 00:58:48 +0800 Subject: [PATCH 06/47] Update README.md --- fluid/image_classification/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index 1906830b5f..465d9e2481 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -112,9 +112,9 @@ python infer.py \ ## Supported models and performances -The SE-ResNeXt-50 model is trained by starting with learning rate ```0.1``` and decaying it by ```0.1``` after each ```10``` epoches. Top-1/Top-5 Validation Accuracy on ImageNet 2012 is listed in table. +Models are trained by starting with learning rate ```0.1``` and decaying it by ```0.1``` after each ```10``` epoches, if not special introduced. Available top-1/top-5 validation accuracy on ImageNet 2012 is listed in table. -|model | top1/top5 accuracy +|model | top-1/top-5 accuracy |- | -: |AlexNet | - |VGG11 | - From eb89a6e3df343464def647b873b7fb9cca24d716 Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Fri, 1 Jun 2018 01:00:22 +0800 Subject: [PATCH 07/47] Update README.md --- fluid/image_classification/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index 465d9e2481..8151bce73a 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -22,7 +22,7 @@ tar xf ImageNet2012_dataset.tar wget paddl_imagenet2012_label_url/ImageNet2012_label.tar tar xf ImageNet2012_label.tar ``` -there are two label files which train and validation image labels respectively: +there are two label files which contain train and validation image labels respectively: **train_list.txt**: label file imagenet-2012 training set, with each line seperated by SPACE, like: ``` From 82bea3ebc055e71a29bcf71ab7c981e4d66ab3ae Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Fri, 1 Jun 2018 01:01:19 +0800 Subject: [PATCH 08/47] Update README.md --- fluid/image_classification/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index 8151bce73a..b9477ca3a5 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -112,7 +112,7 @@ python infer.py \ ## Supported models and performances -Models are trained by starting with learning rate ```0.1``` and decaying it by ```0.1``` after each ```10``` epoches, if not special introduced. Available top-1/top-5 validation accuracy on ImageNet 2012 is listed in table. +Models are trained by starting with learning rate ```0.1``` and decaying it by ```0.1``` after each ```30``` epoches, if not special introduced. Available top-1/top-5 validation accuracy on ImageNet 2012 is listed in table. |model | top-1/top-5 accuracy |- | -: From 2dc67ba9720d3c3acca91b73681fd91f83e6a6ae Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Fri, 1 Jun 2018 11:32:57 +0800 Subject: [PATCH 09/47] Update README.md --- fluid/image_classification/README.md | 47 ++++++++++++---------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index b9477ca3a5..ce5cb70d30 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -112,33 +112,26 @@ python infer.py \ ## Supported models and performances -Models are trained by starting with learning rate ```0.1``` and decaying it by ```0.1``` after each ```30``` epoches, if not special introduced. Available top-1/top-5 validation accuracy on ImageNet 2012 is listed in table. +Models are trained by starting with learning rate ```0.1``` and decaying it by ```0.1``` after each ```30``` epoches, if not special introduced. Available top-1/top-5 validation accuracy on ImageNet 2012 is listed in table. Pretrained models can be downloaded by clicking related model names. |model | top-1/top-5 accuracy |- | -: -|AlexNet | - -|VGG11 | - -|VGG13 | - -|VGG16 | - -|VGG19 | - -|GoogleNet | - -|InceptionV4 | - -|MobileNet | - -|ResNet50 | - -|ResNet101 | - -|ResNet152 | - -|SE_ResNeXt50_32x4d | 77.42%/93.50% -|SE_ResNeXt101_32x4d | - -|SE_ResNeXt152_32x4d | - -|DPN68 | - -|DPN92 | - -|DPN98 | - -|DPN107 | - -|DPN131 | - - - -## Download models -|model | url -|- | -: -|SE-ResNeXt-50 | [url]() -TBD +|[AlexNet]() | - +|[VGG11]() | - +|[VGG13]() | - +|[VGG16]() | - +|[VGG19]() | - +|[GoogleNet]() | - +|[InceptionV4]() | - +|[MobileNet]() | - +|[ResNet50]() | - +|[ResNet101]() | - +|[ResNet152]() | - +|[SE_ResNeXt50_32x4d]() | 77.42%/93.50% +|[SE_ResNeXt101_32x4d]() | - +|[SE_ResNeXt152_32x4d]() | - +|[DPN68]() | - +|[DPN92]() | - +|[DPN98]() | - +|[DPN107]() | - +|[DPN131]() | - From 7f61a6934657a34abf7e12373c05a679cefc3278 Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Fri, 1 Jun 2018 12:07:00 +0800 Subject: [PATCH 10/47] Update README.md --- fluid/image_classification/README.md | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index ce5cb70d30..db74f4f77d 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -1,14 +1,25 @@ -# Image Classification and Paddle Model Zoo -This page introduces how to do image classification with Paddle fluid. To run the examples below, please [install](http://www.paddlepaddle.org/docs/develop/documentation/en/build_and_install/pip_install_en.html) the newest Paddle first. +# Image Classification and Model Zoo +Image classification, which is an important field of computer vision, is to classify an image into pre-defined labels. Recently, many researchers developed different kinds of neural networks and highly improve the classification performance. This page introduces how to do image classification with PaddlePaddle, including [data preparation](#data-preparation), [training](#training-a-model), [finetuning](#finetuning), [evaluation](#evaluation) and [inference](#inference). --- +## Table of Contents +- [Installation](#installation) +- [Data Preparation](#data-preparation) +- [Training a Model with flexible parameters](#training-a-model) +- [Finetuning](#finetuning) +- [Evaluation](#evaluation) +- [Inference](#inference) +- [Supported models and performances](#supported-models) -To train a model using ImageNet dataset, please follow the steps below. +## Installation +Running sample code in this directory requires PaddelPaddle v0.10.0 and later. If the PaddlePaddle on your device is lower than this version, please follow the instructions in [installation document](http://www.paddlepaddle.org/docs/develop/documentation/zh/build_and_install/pip_install_cn.html) and make an update. -## Data Preparation +## Data preparation -1. Download ImageNet-2012 dataset from website +An example for ImageNet classification is as follows. First of all, preparation of imagenet data can be done with two steps: + +##step-1:## Download ImageNet-2012 dataset from website ``` cd data/ mkdir -p ILSVRC2012/ @@ -17,14 +28,14 @@ wget paddl_imagenet2012_dataset_url/ImageNet2012_dataset.tar tar xf ImageNet2012_dataset.tar ``` -2. Download training and validation label files +##step-2:## Download training and validation label files ``` wget paddl_imagenet2012_label_url/ImageNet2012_label.tar tar xf ImageNet2012_label.tar ``` there are two label files which contain train and validation image labels respectively: -**train_list.txt**: label file imagenet-2012 training set, with each line seperated by SPACE, like: +* *train_list.txt*: label file imagenet-2012 training set, with each line seperated by SPACE, like: ``` train/n02483708/n02483708_2436.jpeg 369 train/n03998194/n03998194_7015.jpeg 741 @@ -33,7 +44,7 @@ train/n04596742/n04596742_3032.jpeg 909 train/n03208938/n03208938_7065.jpeg 535 ... ``` -**val_list.txt**: label file of imagenet-2012 validation set, with each line seperated by SPACE, like. +* *val_list.txt*: label file of imagenet-2012 validation set, with each line seperated by SPACE, like. ``` val/ILSVRC2012_val_00000001.jpeg 65 val/ILSVRC2012_val_00000002.jpeg 970 From 0f534bff5af71d5f80fe44125802c2c16289b279 Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Fri, 1 Jun 2018 12:08:32 +0800 Subject: [PATCH 11/47] Update README.md --- fluid/image_classification/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index db74f4f77d..bc282a8e04 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -19,7 +19,7 @@ Running sample code in this directory requires PaddelPaddle v0.10.0 and later. I An example for ImageNet classification is as follows. First of all, preparation of imagenet data can be done with two steps: -##step-1:## Download ImageNet-2012 dataset from website +**step-1:** Download ImageNet-2012 dataset from website ``` cd data/ mkdir -p ILSVRC2012/ @@ -28,7 +28,7 @@ wget paddl_imagenet2012_dataset_url/ImageNet2012_dataset.tar tar xf ImageNet2012_dataset.tar ``` -##step-2:## Download training and validation label files +**step-2:** Download training and validation label files ``` wget paddl_imagenet2012_label_url/ImageNet2012_label.tar tar xf ImageNet2012_label.tar From 9dfcd6003e981d13893fb1f29ff6d9ec9cc65153 Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Fri, 1 Jun 2018 12:20:04 +0800 Subject: [PATCH 12/47] Update README.md --- fluid/image_classification/README.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index bc282a8e04..ea80851aba 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -4,8 +4,8 @@ Image classification, which is an important field of computer vision, is to clas --- ## Table of Contents - [Installation](#installation) -- [Data Preparation](#data-preparation) -- [Training a Model with flexible parameters](#training-a-model) +- [Data preparation](#data-preparation) +- [Training a model with flexible parameters](#training-a-model) - [Finetuning](#finetuning) - [Evaluation](#evaluation) - [Inference](#inference) @@ -84,6 +84,19 @@ python train.py \ * **pretrained_model**: model path for pretraining. Default: None. * **checkpoint**: the checkpoint path to resume. Default: None. +**data reader introduction:** +Data reader is defined in ```reader.py```. Supported data augmentation includes: +* rotation +* color jitter +* random crop +* center crop +* resize +* flipping + +The default data augmentation used in training and evaluation/inference are +* training: random crop, and flipping. +* evaluation/inference: center crop + ## Finetuning ``` python train.py From 1b301e161b78161df2a10b16ed04d5c57457c956 Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Fri, 1 Jun 2018 12:24:43 +0800 Subject: [PATCH 13/47] Update README.md --- fluid/image_classification/README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index ea80851aba..31507aa7d6 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -85,7 +85,8 @@ python train.py \ * **checkpoint**: the checkpoint path to resume. Default: None. **data reader introduction:** -Data reader is defined in ```reader.py```. Supported data augmentation includes: + +Data reader is defined in ```reader.py```. In [trainiing stage](#training-a-model), random crop and flipping are used, while center crop is used in [evaluation](#inference) and [inference](#inference) stages. Supported data augmentation includes: * rotation * color jitter * random crop @@ -93,9 +94,9 @@ Data reader is defined in ```reader.py```. Supported data augmentation includes: * resize * flipping -The default data augmentation used in training and evaluation/inference are -* training: random crop, and flipping. -* evaluation/inference: center crop +The default data augmentation are used: +* **training:** random crop, and flipping. +* **evaluation/inference:** center crop ## Finetuning ``` From 4814877602f300c256adb54ecaaecfa9064da1a3 Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Fri, 1 Jun 2018 12:26:33 +0800 Subject: [PATCH 14/47] Update README.md --- fluid/image_classification/README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index 31507aa7d6..4bc14d31a9 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -94,10 +94,6 @@ Data reader is defined in ```reader.py```. In [trainiing stage](#training-a-mode * resize * flipping -The default data augmentation are used: -* **training:** random crop, and flipping. -* **evaluation/inference:** center crop - ## Finetuning ``` python train.py From b1c78e333a47fd1402a1ef88913a695fa1aa65fa Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Fri, 1 Jun 2018 12:27:39 +0800 Subject: [PATCH 15/47] Update README.md --- fluid/image_classification/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index 4bc14d31a9..7fe80e0cdc 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -86,7 +86,7 @@ python train.py \ **data reader introduction:** -Data reader is defined in ```reader.py```. In [trainiing stage](#training-a-model), random crop and flipping are used, while center crop is used in [evaluation](#inference) and [inference](#inference) stages. Supported data augmentation includes: +Data reader is defined in ```reader.py```. In [training stage](#training-a-model), random crop and flipping are used, while center crop is used in [evaluation](#inference) and [inference](#inference) stages. Supported data augmentation includes: * rotation * color jitter * random crop From 604b72c7e0558c3253ee95785d6ce4a0769b7140 Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Fri, 1 Jun 2018 16:40:15 +0800 Subject: [PATCH 16/47] Update README.md --- fluid/image_classification/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index 7fe80e0cdc..33c149467e 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -60,7 +60,7 @@ After data preparation, one can start the training by: ``` python train.py \ - --model=SE_ResNeXt101_32x4d \ + --model=SE_ResNeXt50_32x4d \ --batch_size=32 \ --total_images=1281167 \ --class_dim=1000 @@ -97,7 +97,7 @@ Data reader is defined in ```reader.py```. In [training stage](#training-a-model ## Finetuning ``` python train.py - --model=SE_ResNeXt101_32x4d \ + --model=SE_ResNeXt50_32x4d \ --pretrained_model=${path_to_pretrain_model} \ --batch_size=32 \ --total_images=1281167 \ From f8131a907f8623bfbf45b3e61d1358ff47cbcd9e Mon Sep 17 00:00:00 2001 From: BigFishMaster Date: Mon, 11 Jun 2018 19:21:36 +0800 Subject: [PATCH 17/47] add dpn --- fluid/image_classification/models/__init__.py | 1 + fluid/image_classification/models/alexnet.py | 2 +- fluid/image_classification/models/dpn.py | 281 ++++++++++++++++++ .../image_classification/models/googlenet.py | 2 +- .../models/inception_v4.py | 2 +- .../image_classification/models/mobilenet.py | 2 +- fluid/image_classification/models/resnet.py | 2 +- .../image_classification/models/se_resnext.py | 2 +- fluid/image_classification/models/vgg.py | 2 +- 9 files changed, 289 insertions(+), 7 deletions(-) create mode 100644 fluid/image_classification/models/dpn.py diff --git a/fluid/image_classification/models/__init__.py b/fluid/image_classification/models/__init__.py index a9418fdd2b..34134fd01e 100644 --- a/fluid/image_classification/models/__init__.py +++ b/fluid/image_classification/models/__init__.py @@ -5,3 +5,4 @@ from .resnet import ResNet50, ResNet101, ResNet152 from .inception_v4 import InceptionV4 from .se_resnext import SE_ResNeXt50_32x4d, SE_ResNeXt101_32x4d, SE_ResNeXt152_32x4d +from .dpn import DPN68, DPN92, DPN98, DPN107, DPN131 diff --git a/fluid/image_classification/models/alexnet.py b/fluid/image_classification/models/alexnet.py index d21b798a5d..b090f6bddb 100644 --- a/fluid/image_classification/models/alexnet.py +++ b/fluid/image_classification/models/alexnet.py @@ -21,7 +21,7 @@ class AlexNet(): def __init__(self): self.params = train_parameters - def net(self, input, class_dim): + def net(self, input, class_dim=1000): stdv = 1.0 / math.sqrt(input.shape[1] * 11 * 11) conv1 = fluid.layers.conv2d( input=input, diff --git a/fluid/image_classification/models/dpn.py b/fluid/image_classification/models/dpn.py new file mode 100644 index 0000000000..f62f6d0553 --- /dev/null +++ b/fluid/image_classification/models/dpn.py @@ -0,0 +1,281 @@ +import os +import numpy as np +import time +import sys +import paddle +import paddle.fluid as fluid +import paddle.fluid.layers.control_flow as control_flow +import paddle.fluid.layers.nn as nn +import paddle.fluid.layers.tensor as tensor +import math + +__all__ = ["DPN", "DPN68", "DPN92", "DPN98", "DPN107", "DPN131"] + +train_parameters = { + "input_size": [3, 224, 224], + "input_mean": [0.485, 0.456, 0.406], + "input_std": [0.229, 0.224, 0.225], + "learning_strategy": { + "name": "piecewise_decay", + "batch_size": 256, + "epochs": [30, 60, 90], + "steps": [0.1, 0.01, 0.001, 0.0001] + } +} + + +class DPN(object): + def __init__(self, layers=68): + self.params = train_parameters + self.layers = layers + + def net(self, input, class_dim=1000): + # get network args + args = self.get_net_args(self.layers) + bws = args['bw'] + inc_sec = args['inc_sec'] + rs = args['bw'] + k_R = args['k_R'] + k_sec = args['k_sec'] + G = args['G'] + init_num_filter = args['init_num_filter'] + init_filter_size = args['init_filter_size'] + init_padding = args['init_padding'] + + ## define Dual Path Network + + # conv1 + conv1_x_1 = fluid.layers.conv2d( + input=input, + num_filters=init_num_filter, + filter_size=init_filter_size, + stride=2, + padding=init_padding, + groups=1, + act=None, + bias_attr=False) + conv1_x_1 = fluid.layers.batch_norm( + input=conv1_x_1, act='relu', is_test=False) + convX_x_x = fluid.layers.pool2d( + input=conv1_x_1, + pool_size=3, + pool_stride=2, + pool_padding=1, + pool_type='max') + + #conv2 - conv5 + for gc in range(4): + bw = bws[gc] + inc = inc_sec[gc] + R = (k_R * bw) / rs[gc] + if gc == 0: + _type1 = 'proj' + _type2 = 'normal' + else: + _type1 = 'down' + _type2 = 'normal' + convX_x_x = self.DualPathFactory(convX_x_x, R, R, bw, inc, G, + _type1) + for i_ly in range(2, k_sec[gc] + 1): + convX_x_x = self.DualPathFactory(convX_x_x, R, R, bw, inc, G, + _type2) + + conv5_x_x = fluid.layers.concat(convX_x_x, axis=1) + conv5_x_x = fluid.layers.batch_norm( + input=conv5_x_x, act='relu', is_test=False) + pool5 = fluid.layers.pool2d( + input=conv5_x_x, + pool_size=7, + pool_stride=1, + pool_padding=0, + pool_type='avg') + + #stdv = 1.0 / math.sqrt(pool5.shape[1] * 1.0) + stdv = 0.01 + param_attr = fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv)) + fc6 = fluid.layers.fc(input=pool5, + size=class_dim, + act='softmax', + param_attr=param_attr) + + return fc6 + + def get_net_args(self, layers): + if layers == 68: + k_R = 128 + G = 32 + k_sec = [3, 4, 12, 3] + inc_sec = [16, 32, 32, 64] + bw = [64, 128, 256, 512] + r = [64, 64, 64, 64] + init_num_filter = 10 + init_filter_size = 3 + init_padding = 1 + elif layers == 92: + k_R = 96 + G = 32 + k_sec = [3, 4, 20, 3] + inc_sec = [16, 32, 24, 128] + bw = [256, 512, 1024, 2048] + r = [256, 256, 256, 256] + init_num_filter = 64 + init_filter_size = 7 + init_padding = 3 + elif layers == 98: + k_R = 160 + G = 40 + k_sec = [3, 6, 20, 3] + inc_sec = [16, 32, 32, 128] + bw = [256, 512, 1024, 2048] + r = [256, 256, 256, 256] + init_num_filter = 96 + init_filter_size = 7 + init_padding = 3 + elif layers == 107: + k_R = 200 + G = 50 + k_sec = [4, 8, 20, 3] + inc_sec = [20, 64, 64, 128] + bw = [256, 512, 1024, 2048] + r = [256, 256, 256, 256] + init_num_filter = 128 + init_filter_size = 7 + init_padding = 3 + elif layers == 131: + k_R = 160 + G = 40 + k_sec = [4, 8, 28, 3] + inc_sec = [16, 32, 32, 128] + bw = [256, 512, 1024, 2048] + r = [256, 256, 256, 256] + init_num_filter = 128 + init_filter_size = 7 + init_padding = 3 + else: + raise NotImplementedError + netArg = { + 'k_R': k_R, + 'G': G, + 'k_sec': k_sec, + 'inc_sec': inc_sec, + 'bw': bw, + 'r': r + } + netArg['init_num_filter'] = init_num_filter + netArg['init_filter_size'] = init_filter_size + netArg['init_padding'] = init_padding + + return netArg + + def DualPathFactory(self, + data, + num_1x1_a, + num_3x3_b, + num_1x1_c, + inc, + G, + _type='normal'): + kw = 3 + kh = 3 + pw = (kw - 1) / 2 + ph = (kh - 1) / 2 + + # type + if _type is 'proj': + key_stride = 1 + has_proj = True + if _type is 'down': + key_stride = 2 + has_proj = True + if _type is 'normal': + key_stride = 1 + has_proj = False + + # PROJ + if type(data) is list: + data_in = fluid.layers.concat([data[0], data[1]], axis=1) + else: + data_in = data + + if has_proj: + c1x1_w = self.BN_AC_Conv( + data=data_in, + num_filter=(num_1x1_c + 2 * inc), + kernel=(1, 1), + pad=(0, 0), + stride=(key_stride, key_stride)) + data_o1, data_o2 = fluid.layers.split( + c1x1_w, num_or_sections=[num_1x1_c, 2 * inc], dim=1) + else: + data_o1 = data[0] + data_o2 = data[1] + + # MAIN + c1x1_a = self.BN_AC_Conv( + data=data_in, num_filter=num_1x1_a, kernel=(1, 1), pad=(0, 0)) + c3x3_b = self.BN_AC_Conv( + data=c1x1_a, + num_filter=num_3x3_b, + kernel=(kw, kh), + pad=(pw, ph), + stride=(key_stride, key_stride), + num_group=G) + c1x1_c = self.BN_AC_Conv( + data=c3x3_b, + num_filter=(num_1x1_c + inc), + kernel=(1, 1), + pad=(0, 0)) + + c1x1_c1, c1x1_c2 = fluid.layers.split( + c1x1_c, num_or_sections=[num_1x1_c, inc], dim=1) + + # OUTPUTS + summ = fluid.layers.elementwise_add(x=data_o1, y=c1x1_c1) + dense = fluid.layers.concat([data_o2, c1x1_c2], axis=1) + + return [summ, dense] + + def BN_AC_Conv(self, + data, + num_filter, + kernel, + pad, + stride=(1, 1), + num_group=1): + bn_ac = fluid.layers.batch_norm(input=data, act='relu', is_test=False) + bn_ac_conv = fluid.layers.conv2d( + input=bn_ac, + num_filters=num_filter, + filter_size=kernel, + stride=stride, + padding=pad, + groups=num_group, + act=None, + bias_attr=False) + return bn_ac_conv + + +def DPN68(): + model = DPN(layers=68) + return model + + +def DPN92(): + model = DPN(layers=92) + return model + + +def DPN98(): + model = DPN(layers=98) + return model + + +def DPN107(): + model = DPN(layers=107) + return model + + +def DPN131(): + model = DPN(layers=131) + return model diff --git a/fluid/image_classification/models/googlenet.py b/fluid/image_classification/models/googlenet.py index c7d5ce7f9a..ed4b1e052f 100644 --- a/fluid/image_classification/models/googlenet.py +++ b/fluid/image_classification/models/googlenet.py @@ -82,7 +82,7 @@ def inception(self, name, input, channels, filter1, filter3R, filter3, cat = fluid.layers.concat(input=[conv1, conv3, conv5, convprj], axis=1) return cat - def net(self, input, class_dim): + def net(self, input, class_dim=1000): conv = self.conv_layer( input=input, num_filters=64, filter_size=7, stride=2, act=None) pool = fluid.layers.pool2d( diff --git a/fluid/image_classification/models/inception_v4.py b/fluid/image_classification/models/inception_v4.py index 7da00d87be..51c7266f69 100644 --- a/fluid/image_classification/models/inception_v4.py +++ b/fluid/image_classification/models/inception_v4.py @@ -21,7 +21,7 @@ class InceptionV4(): def __init__(self): self.params = train_parameters - def net(self, input, class_dim): + def net(self, input, class_dim=1000): x = self.inception_stem(input) for i in range(4): diff --git a/fluid/image_classification/models/mobilenet.py b/fluid/image_classification/models/mobilenet.py index 70b9c95d05..bae564fc31 100644 --- a/fluid/image_classification/models/mobilenet.py +++ b/fluid/image_classification/models/mobilenet.py @@ -21,7 +21,7 @@ class MobileNet(): def __init__(self): self.params = train_parameters - def net(self, input, class_dim, scale=1.0): + def net(self, input, class_dim=1000, scale=1.0): # conv1: 112x112 input = self.conv_bn_layer( input, diff --git a/fluid/image_classification/models/resnet.py b/fluid/image_classification/models/resnet.py index fa88609f46..b3a6956222 100644 --- a/fluid/image_classification/models/resnet.py +++ b/fluid/image_classification/models/resnet.py @@ -22,7 +22,7 @@ def __init__(self, layers=50): self.params = train_parameters self.layers = layers - def net(self, input, class_dim): + def net(self, input, class_dim=1000): layers = self.layers supported_layers = [50, 101, 152] assert layers in supported_layers, \ diff --git a/fluid/image_classification/models/se_resnext.py b/fluid/image_classification/models/se_resnext.py index ec28170cc7..2cef2ef6bd 100644 --- a/fluid/image_classification/models/se_resnext.py +++ b/fluid/image_classification/models/se_resnext.py @@ -25,7 +25,7 @@ def __init__(self, layers=50): self.params = train_parameters self.layers = layers - def net(self, input, class_dim): + def net(self, input, class_dim=1000): layers = self.layers supported_layers = [50, 101, 152] assert layers in supported_layers, \ diff --git a/fluid/image_classification/models/vgg.py b/fluid/image_classification/models/vgg.py index 6cd63b1482..6b6f8bd171 100644 --- a/fluid/image_classification/models/vgg.py +++ b/fluid/image_classification/models/vgg.py @@ -21,7 +21,7 @@ def __init__(self, layers=16): self.params = train_parameters self.layers = layers - def net(self, input, class_dim): + def net(self, input, class_dim=1000): layers = self.layers vgg_spec = { 11: ([1, 1, 2, 2, 2]), From 7a6ad78954d39094393ab1438f17cdb3c804e13e Mon Sep 17 00:00:00 2001 From: BigFishMaster Date: Mon, 11 Jun 2018 20:25:56 +0800 Subject: [PATCH 18/47] update train.py --- image_classification/train.py | 1 + 1 file changed, 1 insertion(+) diff --git a/image_classification/train.py b/image_classification/train.py index 2bcb1e0918..d824e10d7e 100644 --- a/image_classification/train.py +++ b/image_classification/train.py @@ -16,6 +16,7 @@ CLASS_DIM = 102 BATCH_SIZE = 128 + def main(): # parse the argument parser = argparse.ArgumentParser() From 177919f50ee05653a3d5e5b7cef7ee4e0a9666ce Mon Sep 17 00:00:00 2001 From: BigFishMaster Date: Tue, 12 Jun 2018 14:32:38 +0800 Subject: [PATCH 19/47] update train.py --- fluid/image_classification/train.py | 1 - 1 file changed, 1 deletion(-) diff --git a/fluid/image_classification/train.py b/fluid/image_classification/train.py index 0551bf16ee..df6f3b592f 100644 --- a/fluid/image_classification/train.py +++ b/fluid/image_classification/train.py @@ -181,7 +181,6 @@ def if_exist(var): batch_id, loss, acc1, acc5, \ "%2.2f sec" % period)) sys.stdout.flush() - break train_loss = np.array(train_info[0]).mean() train_acc1 = np.array(train_info[1]).mean() From 49af8fd4343b762f841d0966c646cbc27bab98d4 Mon Sep 17 00:00:00 2001 From: BigFishMaster Date: Tue, 12 Jun 2018 14:53:05 +0800 Subject: [PATCH 20/47] update train and eval --- fluid/image_classification/eval.py | 23 +++++++++++++---------- fluid/image_classification/train.py | 27 ++++++++++++++------------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/fluid/image_classification/eval.py b/fluid/image_classification/eval.py index 4f02c2cc86..fa5aad140d 100644 --- a/fluid/image_classification/eval.py +++ b/fluid/image_classification/eval.py @@ -85,6 +85,7 @@ def if_exist(var): fetch_list = [avg_cost.name, acc_top1.name, acc_top5.name] test_info = [[], [], []] + cnt = 0 for batch_id, data in enumerate(val_reader()): t1 = time.time() loss, acc1, acc5 = exe.run(test_program, @@ -92,22 +93,24 @@ def if_exist(var): feed=feeder.feed(data)) t2 = time.time() period = t2 - t1 - loss = np.mean(np.array(loss)) - acc1 = np.mean(np.array(acc1)) - acc5 = np.mean(np.array(acc5)) - test_info[0].append(loss) - test_info[1].append(acc1) - test_info[2].append(acc5) - if batch_id % 1 == 0: + loss = np.mean(loss) + acc1 = np.mean(acc1) + acc5 = np.mean(acc5) + test_info[0].append(loss * len(data)) + test_info[1].append(acc1 * len(data)) + test_info[2].append(acc5 * len(data)) + cnt += len(data) + print("total_number:", cnt) + if batch_id % 10 == 0: print("Testbatch {0},loss {1}, " "acc1 {2},acc5 {3},time {4}".format(batch_id, \ loss, acc1, acc5, \ "%2.2f sec" % period)) sys.stdout.flush() - test_loss = np.array(test_info[0]).mean() - test_acc1 = np.array(test_info[1]).mean() - test_acc5 = np.array(test_info[2]).mean() + test_loss = np.sum(test_info[0]) / cnt + test_acc1 = np.sum(test_info[1]) / cnt + test_acc5 = np.sum(test_info[2]) / cnt print("Test_loss {0}, test_acc1 {1}, test_acc5 {2}".format( test_loss, test_acc1, test_acc5)) diff --git a/fluid/image_classification/train.py b/fluid/image_classification/train.py index df6f3b592f..bd75e7e6fa 100644 --- a/fluid/image_classification/train.py +++ b/fluid/image_classification/train.py @@ -185,31 +185,32 @@ def if_exist(var): train_loss = np.array(train_info[0]).mean() train_acc1 = np.array(train_info[1]).mean() train_acc5 = np.array(train_info[2]).mean() - for data in test_reader(): + cnt = 0 + for test_batch_id, data in enumerate(test_reader()): t1 = time.time() loss, acc1, acc5 = exe.run(test_program, fetch_list=fetch_list, feed=feeder.feed(data)) t2 = time.time() period = t2 - t1 - loss = np.mean(np.array(loss)) - acc1 = np.mean(np.array(acc1)) - acc5 = np.mean(np.array(acc5)) - test_info[0].append(loss) - test_info[1].append(acc1) - test_info[2].append(acc5) - if batch_id % 10 == 0: + loss = np.mean(loss) + acc1 = np.mean(acc1) + acc5 = np.mean(acc5) + test_info[0].append(loss * len(data)) + test_info[1].append(acc1 * len(data)) + test_info[2].append(acc5 * len(data)) + cnt += len(data) + if test_batch_id % 10 == 0: print("Pass {0},testbatch {1},loss {2}, \ acc1 {3},acc5 {4},time {5}" .format(pass_id, \ - batch_id, loss, acc1, acc5, \ + test_batch_id, loss, acc1, acc5, \ "%2.2f sec" % period)) sys.stdout.flush() - break - test_loss = np.array(test_info[0]).mean() - test_acc1 = np.array(test_info[1]).mean() - test_acc5 = np.array(test_info[2]).mean() + test_loss = np.sum(test_info[0]) / cnt + test_acc1 = np.sum(test_info[1]) / cnt + test_acc5 = np.sum(test_info[2]) / cnt print("End pass {0}, train_loss {1}, train_acc1 {2}, train_acc5 {3}, " "test_loss {4}, test_acc1 {5}, test_acc5 {6}".format(pass_id, \ From dfcf8411f9e643cee6611dd6508726089397db6f Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Tue, 12 Jun 2018 17:56:10 +0800 Subject: [PATCH 21/47] Update README.md --- fluid/image_classification/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index 33c149467e..b845780ed0 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -137,7 +137,7 @@ Models are trained by starting with learning rate ```0.1``` and decaying it by ` |model | top-1/top-5 accuracy |- | -: -|[AlexNet]() | - +|[AlexNet]() | 56.65%/79.20% |[VGG11]() | - |[VGG13]() | - |[VGG16]() | - @@ -145,7 +145,7 @@ Models are trained by starting with learning rate ```0.1``` and decaying it by ` |[GoogleNet]() | - |[InceptionV4]() | - |[MobileNet]() | - -|[ResNet50]() | - +|[ResNet50]() | 76.44%/93.21% |[ResNet101]() | - |[ResNet152]() | - |[SE_ResNeXt50_32x4d]() | 77.42%/93.50% From 90712cb2eae2bbdc8a444211535cedf940563181 Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Tue, 12 Jun 2018 18:07:29 +0800 Subject: [PATCH 22/47] Update README.md --- fluid/image_classification/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index b845780ed0..918438dd75 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -148,7 +148,7 @@ Models are trained by starting with learning rate ```0.1``` and decaying it by ` |[ResNet50]() | 76.44%/93.21% |[ResNet101]() | - |[ResNet152]() | - -|[SE_ResNeXt50_32x4d]() | 77.42%/93.50% +|[SE_ResNeXt50_32x4d]() | 78.25%/93.97% |[SE_ResNeXt101_32x4d]() | - |[SE_ResNeXt152_32x4d]() | - |[DPN68]() | - From 4f82ea4afb019853cd1e03908d1d75687af373ec Mon Sep 17 00:00:00 2001 From: BigFishMaster Date: Wed, 13 Jun 2018 11:22:16 +0800 Subject: [PATCH 23/47] format --- fluid/image_classification/eval.py | 3 +-- fluid/image_classification/models/googlenet.py | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fluid/image_classification/eval.py b/fluid/image_classification/eval.py index fa5aad140d..dd0ec58f40 100644 --- a/fluid/image_classification/eval.py +++ b/fluid/image_classification/eval.py @@ -78,8 +78,7 @@ def if_exist(var): fluid.io.load_vars(exe, pretrained_model, predicate=if_exist) - test_batch_size = 128 - val_reader = paddle.batch(reader.val(), batch_size=test_batch_size) + val_reader = paddle.batch(reader.val(), batch_size=args.batch_size) feeder = fluid.DataFeeder(place=place, feed_list=[image, label]) fetch_list = [avg_cost.name, acc_top1.name, acc_top5.name] diff --git a/fluid/image_classification/models/googlenet.py b/fluid/image_classification/models/googlenet.py index ed4b1e052f..c2e76efd01 100644 --- a/fluid/image_classification/models/googlenet.py +++ b/fluid/image_classification/models/googlenet.py @@ -138,4 +138,5 @@ def net(self, input, class_dim=1000): dropout_o2 = fluid.layers.dropout(x=fc_o2, dropout_prob=0.7) out2 = fluid.layers.fc(input=dropout_o2, size=class_dim, act='softmax') + # last fc layer is "out" return out, out1, out2 From b5feaeb007f6b5d4f5d20e77e04a6ae63e1ed6da Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Wed, 13 Jun 2018 17:02:16 +0800 Subject: [PATCH 24/47] Update README.md --- fluid/image_classification/README.md | 38 ++++++++++++++-------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index 918438dd75..9a05c36776 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -137,22 +137,22 @@ Models are trained by starting with learning rate ```0.1``` and decaying it by ` |model | top-1/top-5 accuracy |- | -: -|[AlexNet]() | 56.65%/79.20% -|[VGG11]() | - -|[VGG13]() | - -|[VGG16]() | - -|[VGG19]() | - -|[GoogleNet]() | - -|[InceptionV4]() | - -|[MobileNet]() | - -|[ResNet50]() | 76.44%/93.21% -|[ResNet101]() | - -|[ResNet152]() | - -|[SE_ResNeXt50_32x4d]() | 78.25%/93.97% -|[SE_ResNeXt101_32x4d]() | - -|[SE_ResNeXt152_32x4d]() | - -|[DPN68]() | - -|[DPN92]() | - -|[DPN98]() | - -|[DPN107]() | - -|[DPN131]() | - +|[AlexNet](http://paddle-imagenet-models.bj.bcebos.com/alexnet_model.tar) | 56.65%/79.20% +|VGG11 | - +|VGG13 | - +|VGG16 | - +|VGG19 | - +|GoogleNet | - +|InceptionV4 | - +|MobileNet | - +|[ResNet50](http://paddle-imagenet-models.bj.bcebos.com/resnet_50_model.tar) | 76.44%/93.21% +|ResNet101 | - +|ResNet152 | - +|[SE_ResNeXt50_32x4d](http://paddle-imagenet-models.bj.bcebos.com/se_resnext_50_model.tar) | 78.25%/93.97% +|SE_ResNeXt101_32x4d | - +|SE_ResNeXt152_32x4d | - +|DPN68 | - +|DPN92 | - +|DPN98 | - +|DPN107 | - +|DPN131 | - From fc71934f2fff85bdf3306ae8ffc1a46f722c2b34 Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Wed, 13 Jun 2018 17:04:00 +0800 Subject: [PATCH 25/47] Update README.md --- fluid/image_classification/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index 9a05c36776..ec29631d71 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -137,7 +137,7 @@ Models are trained by starting with learning rate ```0.1``` and decaying it by ` |model | top-1/top-5 accuracy |- | -: -|[AlexNet](http://paddle-imagenet-models.bj.bcebos.com/alexnet_model.tar) | 56.65%/79.20% +|[AlexNet](http://paddle-imagenet-models.bj.bcebos.com/alexnet_model.tar) | 57.21%/79.72% |VGG11 | - |VGG13 | - |VGG16 | - @@ -145,10 +145,10 @@ Models are trained by starting with learning rate ```0.1``` and decaying it by ` |GoogleNet | - |InceptionV4 | - |MobileNet | - -|[ResNet50](http://paddle-imagenet-models.bj.bcebos.com/resnet_50_model.tar) | 76.44%/93.21% +|[ResNet50](http://paddle-imagenet-models.bj.bcebos.com/resnet_50_model.tar) | 76.63%/93.10% |ResNet101 | - |ResNet152 | - -|[SE_ResNeXt50_32x4d](http://paddle-imagenet-models.bj.bcebos.com/se_resnext_50_model.tar) | 78.25%/93.97% +|[SE_ResNeXt50_32x4d](http://paddle-imagenet-models.bj.bcebos.com/se_resnext_50_model.tar) | 78.33%/93.96% |SE_ResNeXt101_32x4d | - |SE_ResNeXt152_32x4d | - |DPN68 | - From 339af6fae481a49500f2fb849977e37258692fd7 Mon Sep 17 00:00:00 2001 From: BigFishMaster Date: Wed, 13 Jun 2018 17:23:18 +0800 Subject: [PATCH 26/47] update --- .../data/ILSVRC2012/download_imagenet2012.sh | 39 +++++++++++ .../data/ILSVRC2012/unzip.sh | 9 --- fluid/image_classification/eval.py | 6 +- fluid/image_classification/infer.py | 5 +- fluid/image_classification/models/dpn.py | 64 +++++++++---------- fluid/image_classification/train.py | 5 +- 6 files changed, 80 insertions(+), 48 deletions(-) create mode 100644 fluid/image_classification/data/ILSVRC2012/download_imagenet2012.sh delete mode 100644 fluid/image_classification/data/ILSVRC2012/unzip.sh diff --git a/fluid/image_classification/data/ILSVRC2012/download_imagenet2012.sh b/fluid/image_classification/data/ILSVRC2012/download_imagenet2012.sh new file mode 100644 index 0000000000..a74b3c9f8d --- /dev/null +++ b/fluid/image_classification/data/ILSVRC2012/download_imagenet2012.sh @@ -0,0 +1,39 @@ +set -e +if [ "x${IMAGENET_USERNAME}" == x -o "x${IMAGENET_ACCESS_KEY}" == x ];then + echo "Please create an account on image-net.org." + echo "It will provide you a pair of username and accesskey to download imagenet data." + read -p "Username: " IMAGENET_USERNAME + read -p "Accesskey: " IMAGENET_ACCESS_KEY +fi + +root_url=http://www.image-net.org/challenges/LSVRC/2012/nnoupb +valid_tar=ILSVRC2012_img_val.tar +train_tar=ILSVRC2012_img_train.tar +train_folder=train/ +valid_folder=val/ + +echo "Download imagenet training data..." +mkdir -p ${train_folder} +wget -nd -c ${root_url}/${train_tar} +tar xf ${train_tar} -C ${train_folder} + +cd ${train_folder} +for x in `ls *.tar` +do + filename=`basename $x .tar` + mkdir -p $filename + tar -xf $x -C $filename +done +cd - + +echo "Download imagenet validation data..." +mkdir -p ${valid_folder} +wget -nd -c ${root_url}/${valid_tar} +tar xf ${valid_tar} -C ${valid_folder} + +echo "Download imagenet label file: val_list.txt & train_list.txt" +label_file=ImageNet_label.tgz +label_url=http://imagenet-data.bj.bcebos.com/${label_file} +wget -nd -c ${label_url} +tar zxf ${label_file} + diff --git a/fluid/image_classification/data/ILSVRC2012/unzip.sh b/fluid/image_classification/data/ILSVRC2012/unzip.sh deleted file mode 100644 index 704a0e5577..0000000000 --- a/fluid/image_classification/data/ILSVRC2012/unzip.sh +++ /dev/null @@ -1,9 +0,0 @@ -cd train - -dir=./ -for x in `ls *.tar` -do -filename=`basename $x .tar` -mkdir $filename -tar -xvf $x -C ./$filename -done diff --git a/fluid/image_classification/eval.py b/fluid/image_classification/eval.py index dd0ec58f40..0d66c85e2d 100644 --- a/fluid/image_classification/eval.py +++ b/fluid/image_classification/eval.py @@ -15,6 +15,7 @@ parser = argparse.ArgumentParser(description=__doc__) add_arg = functools.partial(add_arguments, argparser=parser) add_arg('batch_size', int, 256, "Minibatch size.") +add_arg('use_gpu', bool, True, "Whether to use GPU or not.") add_arg('class_dim', int, 1000, "Class number.") add_arg('image_shape', str, "3,224,224", "input image size") add_arg('with_mem_opt', bool, True, @@ -42,7 +43,7 @@ def eval(args): # model definition model = models.__dict__[model_name]() - if model_name in ["GoogleNet"]: + if model_name is "GoogleNet": out0, out1, out2 = model.net(input=image, class_dim=class_dim) cost0 = fluid.layers.cross_entropy(input=out0, label=label) cost1 = fluid.layers.cross_entropy(input=out1, label=label) @@ -67,7 +68,7 @@ def eval(args): if with_memory_optimization: fluid.memory_optimize(fluid.default_main_program()) - place = fluid.CUDAPlace(0) + place = fluid.CUDAPlace(0) if args.use_gpu else fluid.CPUPlace() exe = fluid.Executor(place) exe.run(fluid.default_startup_program()) @@ -99,7 +100,6 @@ def if_exist(var): test_info[1].append(acc1 * len(data)) test_info[2].append(acc5 * len(data)) cnt += len(data) - print("total_number:", cnt) if batch_id % 10 == 0: print("Testbatch {0},loss {1}, " "acc1 {2},acc5 {3},time {4}".format(batch_id, \ diff --git a/fluid/image_classification/infer.py b/fluid/image_classification/infer.py index adb99d4524..5880999d73 100644 --- a/fluid/image_classification/infer.py +++ b/fluid/image_classification/infer.py @@ -15,6 +15,7 @@ parser = argparse.ArgumentParser(description=__doc__) add_arg = functools.partial(add_arguments, argparser=parser) add_arg('batch_size', int, 256, "Minibatch size.") +add_arg('use_gpu', bool, True, "Whether to use GPU or not.") add_arg('class_dim', int, 1000, "Class number.") add_arg('image_shape', str, "3,224,224", "input image size") add_arg('with_mem_opt', bool, True, @@ -41,7 +42,7 @@ def infer(args): # model definition model = models.__dict__[model_name]() - if model_name in ["GoogleNet"]: + if model_name is "GoogleNet": out, _, _ = model.net(input=image, class_dim=class_dim) else: out = model.net(input=image, class_dim=class_dim) @@ -51,7 +52,7 @@ def infer(args): if with_memory_optimization: fluid.memory_optimize(fluid.default_main_program()) - place = fluid.CUDAPlace(0) + place = fluid.CUDAPlace(0) if args.use_gpu else fluid.CPUPlace() exe = fluid.Executor(place) exe.run(fluid.default_startup_program()) diff --git a/fluid/image_classification/models/dpn.py b/fluid/image_classification/models/dpn.py index f62f6d0553..8f0680aad0 100644 --- a/fluid/image_classification/models/dpn.py +++ b/fluid/image_classification/models/dpn.py @@ -35,7 +35,7 @@ def net(self, input, class_dim=1000): bws = args['bw'] inc_sec = args['inc_sec'] rs = args['bw'] - k_R = args['k_R'] + k_r = args['k_r'] k_sec = args['k_sec'] G = args['G'] init_num_filter = args['init_num_filter'] @@ -67,18 +67,18 @@ def net(self, input, class_dim=1000): for gc in range(4): bw = bws[gc] inc = inc_sec[gc] - R = (k_R * bw) / rs[gc] + R = (k_r * bw) / rs[gc] if gc == 0: _type1 = 'proj' _type2 = 'normal' else: _type1 = 'down' _type2 = 'normal' - convX_x_x = self.DualPathFactory(convX_x_x, R, R, bw, inc, G, - _type1) + convX_x_x = self.dual_path_factory(convX_x_x, R, R, bw, inc, G, + _type1) for i_ly in range(2, k_sec[gc] + 1): - convX_x_x = self.DualPathFactory(convX_x_x, R, R, bw, inc, G, - _type2) + convX_x_x = self.dual_path_factory(convX_x_x, R, R, bw, inc, G, + _type2) conv5_x_x = fluid.layers.concat(convX_x_x, axis=1) conv5_x_x = fluid.layers.batch_norm( @@ -103,7 +103,7 @@ def net(self, input, class_dim=1000): def get_net_args(self, layers): if layers == 68: - k_R = 128 + k_r = 128 G = 32 k_sec = [3, 4, 12, 3] inc_sec = [16, 32, 32, 64] @@ -113,7 +113,7 @@ def get_net_args(self, layers): init_filter_size = 3 init_padding = 1 elif layers == 92: - k_R = 96 + k_r = 96 G = 32 k_sec = [3, 4, 20, 3] inc_sec = [16, 32, 24, 128] @@ -123,7 +123,7 @@ def get_net_args(self, layers): init_filter_size = 7 init_padding = 3 elif layers == 98: - k_R = 160 + k_r = 160 G = 40 k_sec = [3, 6, 20, 3] inc_sec = [16, 32, 32, 128] @@ -133,7 +133,7 @@ def get_net_args(self, layers): init_filter_size = 7 init_padding = 3 elif layers == 107: - k_R = 200 + k_r = 200 G = 50 k_sec = [4, 8, 20, 3] inc_sec = [20, 64, 64, 128] @@ -143,7 +143,7 @@ def get_net_args(self, layers): init_filter_size = 7 init_padding = 3 elif layers == 131: - k_R = 160 + k_r = 160 G = 40 k_sec = [4, 8, 28, 3] inc_sec = [16, 32, 32, 128] @@ -154,28 +154,28 @@ def get_net_args(self, layers): init_padding = 3 else: raise NotImplementedError - netArg = { - 'k_R': k_R, + net_arg = { + 'k_r': k_r, 'G': G, 'k_sec': k_sec, 'inc_sec': inc_sec, 'bw': bw, 'r': r } - netArg['init_num_filter'] = init_num_filter - netArg['init_filter_size'] = init_filter_size - netArg['init_padding'] = init_padding - - return netArg - - def DualPathFactory(self, - data, - num_1x1_a, - num_3x3_b, - num_1x1_c, - inc, - G, - _type='normal'): + net_arg['init_num_filter'] = init_num_filter + net_arg['init_filter_size'] = init_filter_size + net_arg['init_padding'] = init_padding + + return net_arg + + def dual_path_factory(self, + data, + num_1x1_a, + num_3x3_b, + num_1x1_c, + inc, + G, + _type='normal'): kw = 3 kh = 3 pw = (kw - 1) / 2 @@ -199,7 +199,7 @@ def DualPathFactory(self, data_in = data if has_proj: - c1x1_w = self.BN_AC_Conv( + c1x1_w = self.bn_ac_conv( data=data_in, num_filter=(num_1x1_c + 2 * inc), kernel=(1, 1), @@ -212,16 +212,16 @@ def DualPathFactory(self, data_o2 = data[1] # MAIN - c1x1_a = self.BN_AC_Conv( + c1x1_a = self.bn_ac_conv( data=data_in, num_filter=num_1x1_a, kernel=(1, 1), pad=(0, 0)) - c3x3_b = self.BN_AC_Conv( + c3x3_b = self.bn_ac_conv( data=c1x1_a, num_filter=num_3x3_b, kernel=(kw, kh), pad=(pw, ph), stride=(key_stride, key_stride), num_group=G) - c1x1_c = self.BN_AC_Conv( + c1x1_c = self.bn_ac_conv( data=c3x3_b, num_filter=(num_1x1_c + inc), kernel=(1, 1), @@ -236,7 +236,7 @@ def DualPathFactory(self, return [summ, dense] - def BN_AC_Conv(self, + def bn_ac_conv(self, data, num_filter, kernel, diff --git a/fluid/image_classification/train.py b/fluid/image_classification/train.py index bd75e7e6fa..2978fda743 100644 --- a/fluid/image_classification/train.py +++ b/fluid/image_classification/train.py @@ -15,6 +15,7 @@ parser = argparse.ArgumentParser(description=__doc__) add_arg = functools.partial(add_arguments, argparser=parser) add_arg('batch_size', int, 256, "Minibatch size.") +add_arg('use_gpu', bool, True, "Whether to use GPU or not.") add_arg('total_images', int, 1281167, "Training image number.") add_arg('num_epochs', int, 120, "number of epochs.") add_arg('class_dim', int, 1000, "Class number.") @@ -99,7 +100,7 @@ def train(args): # model definition model = models.__dict__[model_name]() - if model_name in ["GoogleNet"]: + if model_name is "GoogleNet": out0, out1, out2 = model.net(input=image, class_dim=class_dim) cost0 = fluid.layers.cross_entropy(input=out0, label=label) cost1 = fluid.layers.cross_entropy(input=out1, label=label) @@ -136,7 +137,7 @@ def train(args): if with_memory_optimization: fluid.memory_optimize(fluid.default_main_program()) - place = fluid.CUDAPlace(0) + place = fluid.CUDAPlace(0) if args.use_gpu else fluid.CPUPlace() exe = fluid.Executor(place) exe.run(fluid.default_startup_program()) From 69089035c9a603fe5ce50316e707ec6a2214ce77 Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Wed, 13 Jun 2018 17:34:20 +0800 Subject: [PATCH 27/47] Update README.md --- fluid/image_classification/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index ec29631d71..ccc43af279 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -74,6 +74,7 @@ python train.py \ * **model**: name model to use. Default: "SE_ResNeXt50_32x4d". * **num_epochs**: the number of epochs. Default: 120. * **batch_size**: the size of each mini-batch. Default: 256. +* **use_gpu**: whether to use GPU or not. Default: True. * **total_images**: total number of images in the training set. Default: 1281167. * **class_dim**: the class number of the classification task. Default: 1000. * **image_shape**: input size of the network. Default: "3,224,224". From 1835b1f767a65c75a6255e68036f289fad12eee4 Mon Sep 17 00:00:00 2001 From: BigFishMaster Date: Wed, 13 Jun 2018 17:39:16 +0800 Subject: [PATCH 28/47] update shell --- .../data/ILSVRC2012/download_imagenet2012.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fluid/image_classification/data/ILSVRC2012/download_imagenet2012.sh b/fluid/image_classification/data/ILSVRC2012/download_imagenet2012.sh index a74b3c9f8d..0b68c14ff0 100644 --- a/fluid/image_classification/data/ILSVRC2012/download_imagenet2012.sh +++ b/fluid/image_classification/data/ILSVRC2012/download_imagenet2012.sh @@ -14,7 +14,7 @@ valid_folder=val/ echo "Download imagenet training data..." mkdir -p ${train_folder} -wget -nd -c ${root_url}/${train_tar} +#wget -nd -c ${root_url}/${train_tar} tar xf ${train_tar} -C ${train_folder} cd ${train_folder} @@ -23,17 +23,18 @@ do filename=`basename $x .tar` mkdir -p $filename tar -xf $x -C $filename + rm -rf $x done cd - echo "Download imagenet validation data..." mkdir -p ${valid_folder} -wget -nd -c ${root_url}/${valid_tar} +#wget -nd -c ${root_url}/${valid_tar} tar xf ${valid_tar} -C ${valid_folder} echo "Download imagenet label file: val_list.txt & train_list.txt" label_file=ImageNet_label.tgz label_url=http://imagenet-data.bj.bcebos.com/${label_file} -wget -nd -c ${label_url} +#wget -nd -c ${label_url} tar zxf ${label_file} From 609b87f279e9bccda735cf7d7adceaa432a0a7d3 Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Wed, 13 Jun 2018 18:00:49 +0800 Subject: [PATCH 29/47] Update README.md --- fluid/image_classification/README.md | 38 +++++++++++++--------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index ccc43af279..fe6c9d0cc0 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -17,25 +17,19 @@ Running sample code in this directory requires PaddelPaddle v0.10.0 and later. I ## Data preparation -An example for ImageNet classification is as follows. First of all, preparation of imagenet data can be done with two steps: - -**step-1:** Download ImageNet-2012 dataset from website +An example for ImageNet classification is as follows. First of all, preparation of imagenet data can be done as: ``` -cd data/ -mkdir -p ILSVRC2012/ -cd ILSVRC2012/ -wget paddl_imagenet2012_dataset_url/ImageNet2012_dataset.tar -tar xf ImageNet2012_dataset.tar +cd data/ILSVRC2012/ +sh download_imagenet2012.sh ``` -**step-2:** Download training and validation label files -``` -wget paddl_imagenet2012_label_url/ImageNet2012_label.tar -tar xf ImageNet2012_label.tar -``` -there are two label files which contain train and validation image labels respectively: +In the shell script ```download_imagenet2012.sh```, there are two steps to prepare data: + +**step-1:** Download ImageNet-2012 dataset from website. The training and validation data will be downloaded into folder "train" and "val" respectively. + +**step-2:** Download training and validation label files. There are two label files which contain train and validation image labels respectively: -* *train_list.txt*: label file imagenet-2012 training set, with each line seperated by SPACE, like: +* *train_list.txt*: label file of imagenet-2012 training set, with each line seperated by ```SPACE```, like: ``` train/n02483708/n02483708_2436.jpeg 369 train/n03998194/n03998194_7015.jpeg 741 @@ -44,7 +38,7 @@ train/n04596742/n04596742_3032.jpeg 909 train/n03208938/n03208938_7065.jpeg 535 ... ``` -* *val_list.txt*: label file of imagenet-2012 validation set, with each line seperated by SPACE, like. +* *val_list.txt*: label file of imagenet-2012 validation set, with each line seperated by ```SPACE```, like. ``` val/ILSVRC2012_val_00000001.jpeg 65 val/ILSVRC2012_val_00000002.jpeg 970 @@ -56,7 +50,7 @@ val/ILSVRC2012_val_00000005.jpeg 516 ## Training a model with flexible parameters -After data preparation, one can start the training by: +After data preparation, one can start the training step by: ``` python train.py \ @@ -96,6 +90,8 @@ Data reader is defined in ```reader.py```. In [training stage](#training-a-model * flipping ## Finetuning + +Finetuning is to finetune model weights in a specific task by loading pretrained weights. After initializing ```path_to_pretrain_model``` , one can finetune a model as: ``` python train.py --model=SE_ResNeXt50_32x4d \ @@ -105,30 +101,32 @@ python train.py --class_dim=1000 \ --image_shape=3,224,224 \ --model_save_dir=output/ \ - --with_mem_opt=False \ + --with_mem_opt=True \ --lr_strategy=piecewise_decay \ --lr=0.1 ``` ## Evaluation +Evaluation is to evaluate the performance of a trained model. One can get top1/top5 accuracy by running the following command: ``` python eval.py \ --model=SE_ResNeXt50_32x4d \ --batch_size=32 \ --class_dim=1000 \ --image_shape=3,224,224 \ - --with_mem_opt=False \ + --with_mem_opt=True \ --pretrained_model=${path_to_pretrain_model} ``` ## Inference +Inference is used to get prediction score or image features based on trained models. ``` python infer.py \ --model=SE_ResNeXt50_32x4d \ --batch_size=32 \ --class_dim=1000 \ --image_shape=3,224,224 \ - --with_mem_opt=False \ + --with_mem_opt=True \ --pretrained_model=${path_to_pretrain_model} ``` From 96661c574d3dee92ce2d67994542205a2f31a250 Mon Sep 17 00:00:00 2001 From: BigFishMaster Date: Wed, 13 Jun 2018 18:11:56 +0800 Subject: [PATCH 30/47] add yapf disable to args --- fluid/image_classification/eval.py | 17 ++++++++-------- fluid/image_classification/infer.py | 17 ++++++++-------- fluid/image_classification/train.py | 30 ++++++++++++++--------------- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/fluid/image_classification/eval.py b/fluid/image_classification/eval.py index 0d66c85e2d..e0c96d0f13 100644 --- a/fluid/image_classification/eval.py +++ b/fluid/image_classification/eval.py @@ -14,14 +14,15 @@ parser = argparse.ArgumentParser(description=__doc__) add_arg = functools.partial(add_arguments, argparser=parser) -add_arg('batch_size', int, 256, "Minibatch size.") -add_arg('use_gpu', bool, True, "Whether to use GPU or not.") -add_arg('class_dim', int, 1000, "Class number.") -add_arg('image_shape', str, "3,224,224", "input image size") -add_arg('with_mem_opt', bool, True, - "Whether to use memory optimization or not.") -add_arg('pretrained_model', str, None, "Whether to use pretrained model.") -add_arg('model', str, "SE_ResNeXt50_32x4d", "Set the network to use.") +# yapf: disable +add_arg('batch_size', int, 256, "Minibatch size.") +add_arg('use_gpu', bool, True, "Whether to use GPU or not.") +add_arg('class_dim', int, 1000, "Class number.") +add_arg('image_shape', str, "3,224,224", "Input image size") +add_arg('with_mem_opt', bool, True, "Whether to use memory optimization or not.") +add_arg('pretrained_model', str, None, "Whether to use pretrained model.") +add_arg('model', str, "SE_ResNeXt50_32x4d", "Set the network to use.") +# yapf: enable model_list = [m for m in dir(models) if "__" not in m] diff --git a/fluid/image_classification/infer.py b/fluid/image_classification/infer.py index 5880999d73..a835926da2 100644 --- a/fluid/image_classification/infer.py +++ b/fluid/image_classification/infer.py @@ -13,15 +13,16 @@ import math parser = argparse.ArgumentParser(description=__doc__) +# yapf: disable add_arg = functools.partial(add_arguments, argparser=parser) -add_arg('batch_size', int, 256, "Minibatch size.") -add_arg('use_gpu', bool, True, "Whether to use GPU or not.") -add_arg('class_dim', int, 1000, "Class number.") -add_arg('image_shape', str, "3,224,224", "input image size") -add_arg('with_mem_opt', bool, True, - "Whether to use memory optimization or not.") -add_arg('pretrained_model', str, None, "Whether to use pretrained model.") -add_arg('model', str, "SE_ResNeXt50_32x4d", "Set the network to use.") +add_arg('batch_size', int, 256, "Minibatch size.") +add_arg('use_gpu', bool, True, "Whether to use GPU or not.") +add_arg('class_dim', int, 1000, "Class number.") +add_arg('image_shape', str, "3,224,224", "Input image size") +add_arg('with_mem_opt', bool, True, "Whether to use memory optimization or not.") +add_arg('pretrained_model', str, None, "Whether to use pretrained model.") +add_arg('model', str, "SE_ResNeXt50_32x4d", "Set the network to use.") +# yapf: enable model_list = [m for m in dir(models) if "__" not in m] diff --git a/fluid/image_classification/train.py b/fluid/image_classification/train.py index 2978fda743..74588e21c9 100644 --- a/fluid/image_classification/train.py +++ b/fluid/image_classification/train.py @@ -14,21 +14,21 @@ parser = argparse.ArgumentParser(description=__doc__) add_arg = functools.partial(add_arguments, argparser=parser) -add_arg('batch_size', int, 256, "Minibatch size.") -add_arg('use_gpu', bool, True, "Whether to use GPU or not.") -add_arg('total_images', int, 1281167, "Training image number.") -add_arg('num_epochs', int, 120, "number of epochs.") -add_arg('class_dim', int, 1000, "Class number.") -add_arg('image_shape', str, "3,224,224", "input image size") -add_arg('model_save_dir', str, "output", "model save directory") -add_arg('with_mem_opt', bool, True, - "Whether to use memory optimization or not.") -add_arg('pretrained_model', str, None, "Whether to use pretrained model.") -add_arg('checkpoint', str, None, "Whether to resume checkpoint.") -add_arg('lr', float, 0.1, "set learning rate.") -add_arg('lr_strategy', str, "piecewise_decay", - "Set the learning rate decay strategy.") -add_arg('model', str, "SE_ResNeXt50_32x4d", "Set the network to use.") +# yapf: disable +add_arg('batch_size', int, 256, "Minibatch size.") +add_arg('use_gpu', bool, True, "Whether to use GPU or not.") +add_arg('total_images', int, 1281167, "Training image number.") +add_arg('num_epochs', int, 120, "number of epochs.") +add_arg('class_dim', int, 1000, "Class number.") +add_arg('image_shape', str, "3,224,224", "input image size") +add_arg('model_save_dir', str, "output", "model save directory") +add_arg('with_mem_opt', bool, True, "Whether to use memory optimization or not.") +add_arg('pretrained_model', str, None, "Whether to use pretrained model.") +add_arg('checkpoint', str, None, "Whether to resume checkpoint.") +add_arg('lr', float, 0.1, "set learning rate.") +add_arg('lr_strategy', str, "piecewise_decay", "Set the learning rate decay strategy.") +add_arg('model', str, "SE_ResNeXt50_32x4d", "Set the network to use.") +# yapf: enable model_list = [m for m in dir(models) if "__" not in m] From 020f94bf585272fc4f82d6c14a238eedf0036599 Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Wed, 13 Jun 2018 19:27:47 +0800 Subject: [PATCH 31/47] Create README_cn.md --- fluid/image_classification/README_cn.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 fluid/image_classification/README_cn.md diff --git a/fluid/image_classification/README_cn.md b/fluid/image_classification/README_cn.md new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/fluid/image_classification/README_cn.md @@ -0,0 +1 @@ + From 6bd987135f0dc251af40837559b5d0c9f5ef912f Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Wed, 13 Jun 2018 20:39:13 +0800 Subject: [PATCH 32/47] Update README_cn.md --- fluid/image_classification/README_cn.md | 155 ++++++++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/fluid/image_classification/README_cn.md b/fluid/image_classification/README_cn.md index 8b13789179..4940e8f895 100644 --- a/fluid/image_classification/README_cn.md +++ b/fluid/image_classification/README_cn.md @@ -1 +1,156 @@ +# 图像分类以及模型库 +图像分类是计算机视觉的重要领域,它的目标是将图像分类到预定义的标签。近期,需要研究者提出很多不同种类的神经网络,并且极大的提升了分类算法的性能。本页将介绍如何使用PaddlePaddle进行图像分类,包括[数据准备](#data-preparation)、 [训练](#training-a-model)、[参数微调](#finetuning)、[模型评估](#evaluation)以及[模型推断](#inference)。 + +--- +## 内容 +- [安装](#installation) +- [数据准备](#data-preparation) +- [模型训练](#training-a-model) +- [参数微调](#finetuning) +- [模型评估](#evaluation) +- [模型推断](#inference) +- [已有模型及其性能](#supported-models) + +## 安装 + +在当前目录下运行样例代码需要PadddlePaddle的v0.10.0或以上的版本。如果你的运行环境中的PaddlePaddle低于此版本,请根据[安装文档](http://www.paddlepaddle.org/docs/develop/documentation/zh/build_and_install/pip_install_cn.html)中的说明来更新PaddlePaddle。 + +## 数据准备 + +下面给出了ImageNet分类任务的样例,首先,通过如下的方式进行数据的准备: +``` +cd data/ILSVRC2012/ +sh download_imagenet2012.sh +``` +在```download_imagenet2012.sh```脚本中,通过下面两步来准备数据: + +**步骤一:** 从ImageNet官网下载ImageNet-2012的图像数据。训练以及验证数据集会分别被下载到"train" 和 "val" 目录中。 + +**步骤二:** 下载训练与验证集合对应的标签文件。下面两个文件分别包含了训练集合与验证集合中图像的标签: + +* *train_list.txt*: ImageNet-2012训练集合的标签文件,每一行采用"空格"分隔图像路径与标注,例如: +``` +train/n02483708/n02483708_2436.jpeg 369 +train/n03998194/n03998194_7015.jpeg 741 +train/n04523525/n04523525_38118.jpeg 884 +train/n04596742/n04596742_3032.jpeg 909 +train/n03208938/n03208938_7065.jpeg 535 +... +``` +* *val_list.txt*: ImageNet-2012验证集合的标签文件,每一行采用"空格"分隔图像路径与标注,例如: +``` +val/ILSVRC2012_val_00000001.jpeg 65 +val/ILSVRC2012_val_00000002.jpeg 970 +val/ILSVRC2012_val_00000003.jpeg 230 +val/ILSVRC2012_val_00000004.jpeg 809 +val/ILSVRC2012_val_00000005.jpeg 516 +... +``` + +## 模型训练 + +数据准备完毕后,可以通过如下的方式启动训练: +``` +python train.py \ + --model=SE_ResNeXt50_32x4d \ + --batch_size=32 \ + --total_images=1281167 \ + --class_dim=1000 + --image_shape=3,224,224 \ + --model_save_dir=output/ \ + --with_mem_opt=False \ + --lr_strategy=piecewise_decay \ + --lr=0.1 +``` +**参数说明:** +* **model**: name model to use. Default: "SE_ResNeXt50_32x4d". +* **num_epochs**: the number of epochs. Default: 120. +* **batch_size**: the size of each mini-batch. Default: 256. +* **use_gpu**: whether to use GPU or not. Default: True. +* **total_images**: total number of images in the training set. Default: 1281167. +* **class_dim**: the class number of the classification task. Default: 1000. +* **image_shape**: input size of the network. Default: "3,224,224". +* **model_save_dir**: the directory to save trained model. Default: "output". +* **with_mem_opt**: whether to use memory optimization or not. Default: False. +* **lr_strategy**: learning rate changing strategy. Default: "piecewise_decay". +* **lr**: initialized learning rate. Default: 0.1. +* **pretrained_model**: model path for pretraining. Default: None. +* **checkpoint**: the checkpoint path to resume. Default: None. + +**数据读取器说明:** + +数据读取器定义在```reader.py```中。在[训练阶段](#training-a-model), 默认采用的增广方式是随机裁剪与水平翻转, 而在[评估](#inference)与[推断](#inference)阶段用的默认方式是中心裁剪。当前支持的数据增广方式有: +* 旋转 +* 颜色抖动 +* 随机裁剪 +* 中心裁剪 +* 长宽调整 +* 水平翻转 + +## 参数微调 + +参数微调是指在特定任务上微调已训练模型的参数。通过初始化```path_to_pretrain_model```,微调一个模型可以采用如下的命令: +``` +python train.py + --model=SE_ResNeXt50_32x4d \ + --pretrained_model=${path_to_pretrain_model} \ + --batch_size=32 \ + --total_images=1281167 \ + --class_dim=1000 \ + --image_shape=3,224,224 \ + --model_save_dir=output/ \ + --with_mem_opt=True \ + --lr_strategy=piecewise_decay \ + --lr=0.1 +``` + +## 模型评估 +模型评估是指对训练完毕的模型评估各类性能指标。运行如下的命令,可以获得一个模型top-1/top-5精度: +``` +python eval.py \ + --model=SE_ResNeXt50_32x4d \ + --batch_size=32 \ + --class_dim=1000 \ + --image_shape=3,224,224 \ + --with_mem_opt=True \ + --pretrained_model=${path_to_pretrain_model} +``` + +## 模型推断 +模型推断可以获取一个模型的预测分数或者图像的特征: +``` +python infer.py \ + --model=SE_ResNeXt50_32x4d \ + --batch_size=32 \ + --class_dim=1000 \ + --image_shape=3,224,224 \ + --with_mem_opt=True \ + --pretrained_model=${path_to_pretrain_model} +``` + +## 已有模型及其性能 + +表格中列出了在"models"目录下支持的神经网络种类,并且给出了已完成训练的模型在ImageNet-2012验证集合上的top-1/top-5精度。预训练模型可以通过点击相应模型的名称进行下载。 + +|model | top-1/top-5 accuracy +|- | -: +|[AlexNet](http://paddle-imagenet-models.bj.bcebos.com/alexnet_model.tar) | 57.21%/79.72% +|VGG11 | - +|VGG13 | - +|VGG16 | - +|VGG19 | - +|GoogleNet | - +|InceptionV4 | - +|MobileNet | - +|[ResNet50](http://paddle-imagenet-models.bj.bcebos.com/resnet_50_model.tar) | 76.63%/93.10% +|ResNet101 | - +|ResNet152 | - +|[SE_ResNeXt50_32x4d](http://paddle-imagenet-models.bj.bcebos.com/se_resnext_50_model.tar) | 78.33%/93.96% +|SE_ResNeXt101_32x4d | - +|SE_ResNeXt152_32x4d | - +|DPN68 | - +|DPN92 | - +|DPN98 | - +|DPN107 | - +|DPN131 | - From a744622d5057f8531d95dac9449e7376d5a1ee30 Mon Sep 17 00:00:00 2001 From: BigFishMaster Date: Thu, 14 Jun 2018 14:27:10 +0800 Subject: [PATCH 33/47] update googlenet --- .../image_classification/models/googlenet.py | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/fluid/image_classification/models/googlenet.py b/fluid/image_classification/models/googlenet.py index c2e76efd01..5f8043a2b6 100644 --- a/fluid/image_classification/models/googlenet.py +++ b/fluid/image_classification/models/googlenet.py @@ -43,6 +43,12 @@ def conv_layer(self, bias_attr=False) return conv + def xavier(self, channels, filter_size): + stdv = (3.0 / (filter_size**2 * channels))**0.5 + param_attr = fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv)) + return param_attr + def inception(self, name, input, channels, filter1, filter3R, filter3, filter5R, filter5, proj): conv1 = self.conv_layer( @@ -80,6 +86,7 @@ def inception(self, name, input, channels, filter1, filter3R, filter3, convprj = fluid.layers.conv2d( input=pool, filter_size=1, num_filters=proj, stride=1, padding=0) cat = fluid.layers.concat(input=[conv1, conv3, conv5, convprj], axis=1) + cat = fluid.layers.relu(cat) return cat def net(self, input, class_dim=1000): @@ -120,23 +127,38 @@ def net(self, input, class_dim=1000): pool5 = fluid.layers.pool2d( input=ince5b, pool_size=7, pool_type='avg', pool_stride=7) dropout = fluid.layers.dropout(x=pool5, dropout_prob=0.4) - out = fluid.layers.fc(input=dropout, size=class_dim, act='softmax') + out = fluid.layers.fc(input=dropout, + size=class_dim, + act='softmax', + param_attr=self.xavier(1024, 1)) pool_o1 = fluid.layers.pool2d( input=ince4a, pool_size=5, pool_type='avg', pool_stride=3) conv_o1 = self.conv_layer( input=pool_o1, num_filters=128, filter_size=1, stride=1, act=None) - fc_o1 = fluid.layers.fc(input=conv_o1, size=1024, act='relu') + fc_o1 = fluid.layers.fc(input=conv_o1, + size=1024, + act='relu', + param_attr=self.xavier(2048, 1)) dropout_o1 = fluid.layers.dropout(x=fc_o1, dropout_prob=0.7) - out1 = fluid.layers.fc(input=dropout_o1, size=class_dim, act='softmax') + out1 = fluid.layers.fc(input=dropout_o1, + size=class_dim, + act='softmax', + param_attr=self.xavier(1024, 1)) pool_o2 = fluid.layers.pool2d( input=ince4d, pool_size=5, pool_type='avg', pool_stride=3) conv_o2 = self.conv_layer( input=pool_o2, num_filters=128, filter_size=1, stride=1, act=None) - fc_o2 = fluid.layers.fc(input=conv_o2, size=1024, act='relu') + fc_o2 = fluid.layers.fc(input=conv_o2, + size=1024, + act='relu', + param_attr=self.xavier(2048, 1)) dropout_o2 = fluid.layers.dropout(x=fc_o2, dropout_prob=0.7) - out2 = fluid.layers.fc(input=dropout_o2, size=class_dim, act='softmax') + out2 = fluid.layers.fc(input=dropout_o2, + size=class_dim, + act='softmax', + param_attr=self.xavier(1024, 1)) # last fc layer is "out" return out, out1, out2 From bb1106124370f696813e370aebb404b6e4da4b45 Mon Sep 17 00:00:00 2001 From: BigFishMaster Date: Thu, 14 Jun 2018 19:17:47 +0800 Subject: [PATCH 34/47] add images folder --- .../images/alexnet_curve.jpg | Bin 0 -> 49795 bytes .../images/resnet_50_curve.jpg | Bin 0 -> 50227 bytes .../images/se_resnext_50_curve.jpg | Bin 0 -> 52888 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 fluid/image_classification/images/alexnet_curve.jpg create mode 100644 fluid/image_classification/images/resnet_50_curve.jpg create mode 100644 fluid/image_classification/images/se_resnext_50_curve.jpg diff --git a/fluid/image_classification/images/alexnet_curve.jpg b/fluid/image_classification/images/alexnet_curve.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6cbe0b393250df71b28fb327957ddb23b37075bd GIT binary patch literal 49795 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¨#Hp= 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 literal 0 HcmV?d00001 diff --git a/fluid/image_classification/images/resnet_50_curve.jpg b/fluid/image_classification/images/resnet_50_curve.jpg new file mode 100644 index 0000000000000000000000000000000000000000..edc534e1bf559f2c6586a0868c160f0a61a0ae46 GIT binary patch literal 50227 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 z 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 Bp`-u+ literal 0 HcmV?d00001 diff --git a/fluid/image_classification/images/se_resnext_50_curve.jpg b/fluid/image_classification/images/se_resnext_50_curve.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3af4916a441d4f001e3ec77812f4b8d40f0aef4a GIT binary patch literal 52888 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

@mGcvu8mg1-gf@rsnoWeb%X=$vC>?hSKhGup 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

$Z@$}c@wP6I>vi-Xl9ood z2qKL*(NbBZez2&>{27w!o=p*~sA}(>76%{rFPChu%f=gR)RumEz4pN$R-uE+#?7at z-a1Z_13MN+$;*Mhjw33*&TzCwyL{vYx6iB}5G5Toi3buBLxWY8@g>+H8UlFpy`KEv zaNErry8d1b|L^br2*OzY(IWrep9!Slu)p%p%m2zhhal_r!mhVV{eb){q2&@5toa~H_@}_&8|`W(aweqO(NQ%YYcJ-+_Yu)FdN z%3O*5w#Ux23dYtitC!+7371Y#85qBv)e?V*oidc?j503Vft~mHaEY&Kf8ItXQPL;0aY8{H-}5qJDsbYHzB!k*lil0>We2Rhn{nt^*!fO@LDi*+xQnY< zS0nY)ufF%1!5ZU=pmJ~T6Je&tI49WT_w5_@5# zjtf}Ii(eg-?EdPY^j8#hT1zie6_}oVJ~J^Z@y~9kZybAiU)WtM;r3vRHmNIfaJ;Qq zuj=cZ1cSXDMz@jh8uVr*v62F5gms(Ol3_sC2OhsLW1r7KslVee! z8TV^M{5w!trOpCu9fSXwniJFqT%5TDPpUubG!yHs0(cCs?S7g&IKkLBBql3>+AXd9 zG>8d2SnH&sV7mc#C@21a%%2L%VAui;TP|fAu-m+2Jf~S+$t%HLbpF|Y;}r!tXZ*fI zzfY+F#G16*vHJ^mO0e_dg-%~p-AVXVVraT!l!yXdv72=}04M601>N)qq3SPqN|twq=0#(qI1Nw99mQ*`XfSQw#ua0LXOkC7>wgHVpwhg^SJ^F1 zo%9ukYOQZ2>U*u%=qh$h&-E7}?f(~viQ6DxF|8L89sB`_79_%0njjo5vJ85q%dUr7 zKn#5!7}4J?#s1`Z2JNRSz7R-Fv4Lu@KEl&Cy-2Wq$h*C%+g2=SwVtfJV<-;MPOZ#} z10X-u8@$(*7N4!$z9#yNIx9J}FE71a6VAvDymnAOUODd7KY;wSp_sj!f0pFCXwx42 zf;?c#Tq@giphSyF-gzkrFlFi>MTe3^~w^LY}Kf(0hUKL*Jw}K&-A`* z^Ia}dj|&av2E0E%+m`&60m<*%)Q7*wUayQ<%dl_b$I1^Ll~t!jg36d2Uhau{v7ly{ zFSHRv%Co3B9R)J-l$X{L2S)Vq^N|}G2Z9o7akob=afK#td7>Y@Y+&^7om>Do9PAA1 z!#m`LFI@SerCsxIZY>*A$PrTzi_|lHqA=~8VoqqR)OP`;HwKi}DS*eR2L`{k0X**c zT>o|*kNw;Z3^V8X#-9=HHz_~=Gfx&+CfaxhLOA(F?|1F8hwf|kFY`GP%A%26$DeF) zz8hvvz}4uFuV0(0J=NEbOZhVD+J=a5=-zhtQ(JlZ+D6+07-r0o@#lk~|Ah6xldp}x zD5F5VSs{^e(M%gFIofb(4=vEJ&h2Ati{5G1j~t5>s}-b2l3LLE*3aqkAC#%MQ}$HF1ypWFz{`(s z`M&m~?X>P@k1k@ib}j11eC8fRa${Z9?_tXfqy0!0_n?v(x$(?HP4jqy6J4*NqWY=! z^8F;C_hoT;^l3L)hV|Ju$QJE!b`^{r;yz9Y!x2HpyO1^z)Wqq<@-ZaY;vodK5So5W zA5{{R&G3ZHtLwF_>UWkRZ>-v`V&0XW+zv`FuxbA1OdUVX6D!e;{6U(rutL~Ae~b^$JIN$W9w0~j&mJBsb@ z3gyF&73#{fCGE!q`q|=G8xW0C!$Z~#qgFpK)xd+4jS0{_yzarA=+{}!C}xc-@ZC6p zr*s=Z(LJ2*>3;ip8{}`dLDt!M$N%d$KOpIN0T8I8D_cOR=>!P;2PEIC51dKbD()G^ z7uXYlDOr!}-XamAmdQ%IOUt)B5dO$ZyT9#Lrs;)cWBL0Smpn8G-~GDlM;HZNnRCCr&IV6$`51$Tl#2x|U`b*GUU)MnP z82tiBXSB-t?RwtpW8fzK&rMu0f>W#bc_#~-r`Qe(idGm3CsK^$7#C~LU4w6Q9(d`u z@mAm_jPfsCf&6^-^#R-b9Pkoq0KdrIjHc!jwbA3!>a@3XftSZzs5(t|B<(DKELRjK zx)Elt-8yx>Nlz#x@AFT}*X@tw6ixD^K^Q4NCHYT7$^IqaczTD|J$+*9*RzSA`lL_$sZT&j+A8Ad7YG!qr_Mi>(-BMQSOeCkRvE{)Ad%$==H7Lc zI&J(**_*w9db<3sp3`g%pwh7K9&4S@RsYZ2UEi!f0nhciwl_1iD?dQdOpV~;ACL|Y z@F|FD7V4G$fNagDaL@cytsjtOdn1`SQet7IFAh6s7jlG~Rs)VOP2GFbhz!N1ZCq_A zjkcTow_bkRRFO|a;U$3BiYeoy{yG6}Lh!m0YVjfhsoHZ#N^7EN$X=qv%|yDpeb1@+ zh(`74*Jj+&ZCk}RU1B^u96t-3%s~5o&Bfn(^!FqGe7H&^?go>iITt)Mc+L(FuAe{I z@Tcni`Uy7?=<>^ZFk*Qv1gsFCv%c#(_FoV4KW5?W`Yen?DR=@T_-|oD!+t6(Y<&Uz zx)@jnsUCkXfOSoO1T-Bik0Agbwm;zmEStYUz~Ihb3*$3)HGPA-^AQvSdFH3NwMa8f zQUT`HJH*RY%I4-`)7i~qOItmxaZbhM1g3~HNDy|gZ#v{ecA!8_qdG}mG2e8`P(YRo zryjZ0D)yAkD2?h{%7|K*yB&q^+An+fll9#@mA@3j0=AAd0A&Ey{8T1@H7{xb#)koj z-{{u#Q#vdpK*4x`f`6gQFHD13tSi$xZvDhT01oTZ^Gnv#>r3V5AO-3df&PKx;J?5Y zAo@>G`*ov#L`kp^{%L&xjGhx~#@Qc|f(}T8*jupBmupSZoHs$s8>e2`hu9g+a-Xy3 zdZb*B{RQJ-NHGB8n_2e3#hq-2@<~|5g>{jQq3b=Anhxczi_AJ|ndB9!saX~ZL`IJB zx#6hTef#V5D8h1=l~T3sDflL1aibRdJNJUx{*Pdm2*SsO6z=%7ieIbjcQkvN1QrhX z61Dzi{I4D2Hz9wY`?;WyU_Je@+@b5+hra*M<^FRwxKCMErcUPd$`3Ng*`e=QuqE=} zd)MFk^lKwppPc_ym_)cJu>Dl3lR`x&vsbaa|7@>_YxiIv;`03T}=;ME$n}0U| z)JaP7BMd!+BQ-9PDnx4jV6l;&-5?{8aDvzo(BLRq_8#-)sWzpr+gwtgJD}sSe3tw5 zej*ANt?J@Ll}^R6wo98dx^0KQV5{yG$*{3`v2?{gm#=zE;b_x~!$X#nJEW{YbhiZ| z%|Zop26sxR_J{v~fOQxmvyGyi8RYMYF3^`I<~tmajBKe({({%EMtE0+1kHffxOeGC z7+Or7YC4*VYr5rnXKMk)UaLK2sZ(J^sHOOb*OqPBZQh!X4!tDgvFmHK)J$x$~6s)^i@!UP-NZq&F^@cVPR5 ztM>$MveE#L)8H~Kf_@v{KTkv-F^qoZSP|`)gSRX@Air6f@v-V$Y+ z@Zh$r$2Fxc;zRLKH?UhVmka3jrzy>m^PgGK4Pw>)30G<{ zZ=PWAWyK`_UGVE#2*ta>+%BPd8k-W4(t+7&4=2QFH6wd(o;(={earB8n?|NMJiW z!mit;sD{FL9`^R;+e_6^dif_#h)xV)+~t$_1tU-OvarCTsvd%+obDW?ImN>y%6BBI zeRtJ#+T!LjyKOMm$-2r~n}%}B1X&_G4@ys`rRcthGI0*8qenMX1akl)L?Kcq-lYy( z#vN*?MF*2hOQe`Ipz&gC5z$&3ntsdi~4@ zrFFWJYL0#Q+sm6pmpbszWK8UL9aQs09PcDsp4tZ~ETl03kQ;$McPR|=K)Db30pmae_UlcrRZYo8{1%Yf}{zYK6gX-_G`zgUehZT+0H zR^O)os|ndW12lpl z5-bjw!|Z6UUys0}#?KcO_o?_ng=_{1X0<_9eWQ}DuQp%^dKTMDZw_Eh+3iqKwgm9z zQO;v`u)Cq9>d~tDmK25wIE%yWZKzpMr_%kO7gQAA4U~RrdB1{W@9uv+LC$OU=$rjp z8jZLIdwy#@BSH+`2O#uuaAPnhz1WZ9+~_1OL$K~HpYsr~!p7qcJ;fWQy&ev{A}RUa zPVahAS(US<(GktBtBD+tB9Vn;dL!cm9DS;y-_QWA$@Ir`A#8&f$5m;`3~_0N6VL`H zrL!eV>XiqiPjsKNxq@-KIUUuy(u8Osb=XUNYNk@Rh6dHy=LN zM@%5YJGdRW1?%d?AKW^sO}`)LG9E8F((LwZCYl&~(*169M9AF-Vd$Ne?lxClJ#ue7 zI$2<~>jSA6=IS-HNQ2VF#=q0G7)FRQrR6WXPICm(l@BI3hreD<+Mzn# z{Vkl*AE}zczUse8&sV>=K|$AHA^&Njqb(In3!{ruLON+A`ZcPrO~e_hKr_fZupjHo z+?qYyMg=58`r?;!2Jmji!mM{GOQR&wIQ`Wt#_}E}qeg}ktZabt@qk#)LQa6}OYXXQF$ zeM|m?ELB!UEp%p7qW8Ov1l(^fQ)a8xR%?@TgrETd8cIGB8_MBoXFaa3fzLa65rz%9nH4KSfuQ5k6ObIkix^B#Q%xaQ1w7*r+I z+}E?H#WWW4O)=yV?n$5LZ6r`zN!Ht7UFIJ86cV_WH0HijI&l_wp|N;!9k9?e=`gAV zO^>RDeF&%x7sooI<>>bd-K+`{+#=4u``nb7eKGTyiN8eCtfedck)Ws9-UV^SZ~M(( zv8Mm&SLNk^1}BOwDqbSB!9ob0OH`_V?e_!1O}8icO@}#Cw9_aWP3bAcZ}9`O5$5lE zWc$go9=o^&L>jt=4w!B}`dWd~(q24A*I{oy!MKC2)58u~lEgxTg^~67pAB_y$nf^- z!(Ps;Ma@;(oex${GK#kfAuix~aw20+(PH^l>%|?eN3@$JaD7vYqMMA1F@@b}H57E1 z;Q@BPBL^h_S4rPbQEm>X=6;Adm~ZE#6RE}UIAH4ByIA;kyvpAFh-4XwFQD>CyXw-H zV^fgYr0n3&KOhwmWJ$(xgc-$U{sUnPMh}!HI_@i{RFnsfzZW{&<0l|^!^NVc$1?@A z0QLWvi<8o!Q48LtDh?kU5Z-bx$n03~rH_om?0#fP>O-VwJl=P#FPgHpQU~1{tX26C zWBrnz(noW!a14j?!u=M=Hz&j4q#`&un?LDf>dq62JkBw4{i}jH4MZlU3i!nFRRb#RpK^S+U5mM=KR5{(iQ^-Dc#rc~vYCPET!GA@F2V&12Y7 zy=q9}p4uMG=$S9NFEeCJi>erVFTUJl+WYEW+my@V$=zI2ut+D$N%VcB5aKS$!}kn5 z2P9rnkZ}kLFOoWxsr1Ef$d#!>GC!%Vq%qvk*WnXl>BXD1TWx2QPg>B3ix3xkvH zVofI(GK1-t8Am`1X|FtZwfjMgUp8IRy2u>XkYv}8aLk~=I>mbHmeHf$M%{Lp?fTxb z*AfN$HoXqADJ( z4KMh1q#=5rM2de@G(DD0ZD#Y15Yc$ai#28RWX36`brnTB$M02VK66imO?Rqst+tcP q{-%b3jDc*IintT<;j^0lYNo3X(a-b#OKX<%H_P_F^IqV`;Qs=GnB}qn literal 0 HcmV?d00001 From 5d5a1df306cee58b95c61bebb81107a012a113b8 Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Thu, 14 Jun 2018 23:06:03 +0800 Subject: [PATCH 35/47] Update README.md --- fluid/image_classification/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index fe6c9d0cc0..f7b0fe9a9a 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -89,6 +89,14 @@ Data reader is defined in ```reader.py```. In [training stage](#training-a-model * resize * flipping +**training curve:" + +The training curve can be drawn based on training log. The error rate curves of AlexNet, ResNet50 and SE-ResNeXt-50 are below. Each Figure gives +

+
+"" +

+ ## Finetuning Finetuning is to finetune model weights in a specific task by loading pretrained weights. After initializing ```path_to_pretrain_model``` , one can finetune a model as: From df07ee47b0372387844a9beaa67650eba62b8c2e Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Thu, 14 Jun 2018 23:19:59 +0800 Subject: [PATCH 36/47] Update README.md --- fluid/image_classification/README.md | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index f7b0fe9a9a..1d3c95f694 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -91,10 +91,24 @@ Data reader is defined in ```reader.py```. In [training stage](#training-a-model **training curve:" -The training curve can be drawn based on training log. The error rate curves of AlexNet, ResNet50 and SE-ResNeXt-50 are below. Each Figure gives -

-
-"" +The training curve can be drawn based on training log. For example, the log of training AlexNet is like: +```shell +End pass 1, train_loss 6.23153877258, train_acc1 0.0150696625933, train_acc5 0.0552518665791, test_loss 5.41981744766, test_acc1 0.0519132651389, test_acc5 0.156150355935 +End pass 2, train_loss 5.15442800522, train_acc1 0.0784279331565, train_acc5 0.211050540209, test_loss 4.45795249939, test_acc1 0.140469551086, test_acc5 0.333163291216 +End pass 3, train_loss 4.51505613327, train_acc1 0.145300447941, train_acc5 0.331567406654, test_loss 3.86548018456, test_acc1 0.219443559647, test_acc5 0.446448504925 +End pass 4, train_loss 4.12735557556, train_acc1 0.19437250495, train_acc5 0.405713528395, test_loss 3.56990146637, test_acc1 0.264536827803, test_acc5 0.507190704346 +End pass 5, train_loss 3.87505435944, train_acc1 0.229518383741, train_acc5 0.453582793474, test_loss 3.35345435143, test_acc1 0.297349333763, test_acc5 0.54753267765 +End pass 6, train_loss 3.6929500103, train_acc1 0.255628824234, train_acc5 0.487188398838, test_loss 3.17112898827, test_acc1 0.326953113079, test_acc5 0.581780135632 +End pass 7, train_loss 3.55882954597, train_acc1 0.275381118059, train_acc5 0.511990904808, test_loss 3.03736782074, test_acc1 0.349035382271, test_acc5 0.606293857098 +End pass 8, train_loss 3.45595097542, train_acc1 0.291462600231, train_acc5 0.530815005302, test_loss 2.96034455299, test_acc1 0.362228929996, test_acc5 0.617390751839 +End pass 9, train_loss 3.3745200634, train_acc1 0.303871691227, train_acc5 0.545210540295, test_loss 2.93932366371, test_acc1 0.37129303813, test_acc5 0.623573005199 +``` + +The error rate curves of AlexNet, ResNet50 and SE-ResNeXt-50 are shown in figures below from left to right. +

+ + +

## Finetuning From 0e44ef4549b27ce6ad73d962c6c993c36358f815 Mon Sep 17 00:00:00 2001 From: BigFishMaster Date: Fri, 15 Jun 2018 00:49:48 +0800 Subject: [PATCH 37/47] add curve.jpg --- .../images/alexnet_curve.jpg | Bin 49795 -> 0 bytes fluid/image_classification/images/curve.jpg | Bin 0 -> 74187 bytes .../images/resnet_50_curve.jpg | Bin 50227 -> 0 bytes .../images/se_resnext_50_curve.jpg | Bin 52888 -> 0 bytes 4 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 fluid/image_classification/images/alexnet_curve.jpg create mode 100644 fluid/image_classification/images/curve.jpg delete mode 100644 fluid/image_classification/images/resnet_50_curve.jpg delete mode 100644 fluid/image_classification/images/se_resnext_50_curve.jpg diff --git a/fluid/image_classification/images/alexnet_curve.jpg b/fluid/image_classification/images/alexnet_curve.jpg deleted file mode 100644 index 6cbe0b393250df71b28fb327957ddb23b37075bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49795 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¨#Hp= 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 diff --git a/fluid/image_classification/images/curve.jpg b/fluid/image_classification/images/curve.jpg new file mode 100644 index 0000000000000000000000000000000000000000..15694c2962ae3a4a93cbb6f0f8b07c39e4db79ae GIT binary patch literal 74187 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
1yCYTX|zBt8D?3 z;p4TQM(?Ehzr7eOp?JHtdTa%zWw38drx6?Rxy$*>4Kd-~!cK}MUPs5kS`cYlk3yFb z_%8mMXm8U)I5Zb&Z(1aB3PO>ej|7?jFc$tw(3BQUBwDieRQ?9XN`C)na(|51KEInU z`mF>RHQorT;O?_L;MoMpu`rp1y~}1uU>JYGNT1TZP0Dul@!aQOZnk8iS~5lPE>LjN zz^i1?T@gL0INr_W6NwO%UhS~ed5en?d29wOADhAKjkE38&N97Mb2*9Jh4;|UI-iL7vrjWJI`j}|dnqtr1U$2ifHXd_u!Z>hG#xsYpSxWNNIDc?9?Z?-#fP~qe)=Nv! z%{BUj49{N{lnFGHFz)I#BX}&AhqMIfH4rsp-8V7WQbfYv+gGSj*feOn` zd0n+soLg@`>6+U^N$RrIuBaBBl`%)bWR_hZ40uR^FOmrCItw}??%TO3?!Otn4>`vzn^|y$F!2cT?YnslksLPYG4uAO}x^Ro>dL;`hm)lPY44oryX(nNYkMh|*Jo(f?PC%DT_-R(2o&x_ELwmXcdxq^-lgew?_;~Rdgc4di&)hm{+=I_c zxsTQl1!YpTP-X@(m|v!%n|ZoBG)7;q)YoMiMGdAmJfxsciw#~X8}L`n;H{4nMGeN5 z?&cF+twewnO3AKl^rL4z)U`If0NRILMb*C>Vn{}>11WFgJD`umc5NU z1gonqyk=d%kC}?j6jX%>$j&y^^lrJzGvSfI^H9s_EmJ%IJ%Q5M7+E)&8&Fa_`}RJl z?u8J+d#M8*^#g_Fnx^_jhK z{M1F>ZDk?lI{H>99u4Uz5Zw3piuca08BArWbP!w732iP^a%FqgSouzKfs<}u3)q<` ztnoz*Kr#n(UVg+oH`aI1XE*~8@8E1>|6(I!?NOa%4-o2=zzN+-yk@Obq=j{#%4JEm`Haha=%BCeJ#02+bgfKh5q%?kU0umf z{y{!D?olx6d8YVx!n==Lf%LSd{2pHOeZzG$hDQMD)pW8_LhwTE0J{8&LC<7ok^Gpw zGQ%L8xO?I=`LnGn)&}$bN=ovZDg9%3Z_EMW(c%WQ*jTx6ej~*tY*y#_e1UKNvz3@e zF3Z)(H5&^8f{dZQ2u65rPadkLA_4+*+X4z?f7}%LleQ`M{m|*Rv+OH4UN9aog^}c! zzdH*z!a{tky$ej>io*e`r~{rh~KP~4)#d=LG4 zcmiAri|~Y|6Tntf#3$|cy=_G4@YB>c%o>1%&lLB@peOOqoda*?I$Y@m^4^;?ts7T? z>dWYt0`{F8+lErR^t)@x*+4cme#UpVW##x{2=TX0PEt5n@6_OUES z4c4h=JNgVljq4 zf9_7N@1vwM^7;N658q5lqxZuhw{kN(SlCm$O!VjDVBya`Pu!biyKADs=XA^Vg=%JE zts}cTPo})@5D#DcTA3_t8&DO7m|xCder+UupKL|#dAInfMf8)H4F`B2F)!%tZL z_9BHGOJ0F}mUy(sJ0B#Iv$dTk9lk#(KH-)5%!~QZZB%vuI){ZVs2>_2w#oC>% z$Jy&w@qI~i*LwZB7qPMLrEH3Uj7unmM^Lkfj7H}_)TK!WB3Z_AGVGr4*EPh;9u25z zZ)j8=$F~i!(R0_m#d6yzz~y8XSPE0${CS5-B>6G7<7+R!+MmC(@S?Ay`VJ#;{a5-e zSl0UQ5|&?X%HYq93H58;F?{4uUhK`t2;BjKYsv3?>l|tcY|P)~;KNQJs{-FLd_x5r zuq0I0yR5sS&gI||{AhC#NWmM_-f_Cp!L&bRJbo4_057EVV6t4jGZ3bHdF?5rBdRA} z3U%(L7Y;NMq%jdrQ4jn4&&_5$mv{W1+IStCj~SeJy|9j^38Nd=63c+-h5F@sJN`h5 z4~mnxX28DGIEMmS_E+YH3Yv_Y{61E;(m;ne8ucSC)4ga9GopXRrQL*W17clPB!wYLBE_rIA4X#P8yhTt4`dFw6#P?+f< z20lpsK@dT{489OCH5{QnY6V6;5dAgk!Rl}QzJGMCi6rw(HVY1{jGH6$1$`d8%V$5e zc>G)4x2Yn&PWrVfD*IoO$OgxO2)O>FBil&3SzbWCOx-1v@{!2YJFD3mGW4`XCst2PN-xeZCw=R@?5j;kcpV5ieZ}wpb`8;oySGxYwfeA~T%9YpzEGmBlY> zmlAEv4xz_#EehCsz_9@UxM?6O!Let^<$Ktd%LBTgg+uU2)h~3D%+Da6lZV4!%4o%D znsPOAG{>7ne;mvhP)c>a$XhnaprQWEG3p`oK{f1rM%?4rzWVs}2_z8A=s6S!x{1HC z^asIg9hx=(E`C638m%s?Ejn@6;q30+mRFiw@~=FEq**r(cbVnOY_E~OhlXMgaN_XW z7x^+w3xwDcOsmR)*avSqt8vF8jw*70OyAcyq8`R zC@iH9XLLi8cpkQ>?dUMu5qGnl-3!zE_8uL7`D&6R$J?t7O9#{Thi*q>+9OB4XKFSn zs_He_>OQ6ULzY(UGlSIVMBCtQjUu=Fo#csn2R&@TAVtEaQku2T6PE&yR&V|+-xBI0 z+cq#6vdvgV`T+c_8oPZ!v=kExC;$0%%IP>tT&H$Yrj@^zPWLKlxB5rGF==|88q^I6 zhhX%Ei1F%^B7YD7EZWMUj!Y`-b91Z5;{tG-Q$ri(?2jYZ`9^QzZXq?Cs!;YWr&8AB z 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 Bp`-u+ diff --git a/fluid/image_classification/images/se_resnext_50_curve.jpg b/fluid/image_classification/images/se_resnext_50_curve.jpg deleted file mode 100644 index 3af4916a441d4f001e3ec77812f4b8d40f0aef4a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52888 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

@mGcvu8mg1-gf@rsnoWeb%X=$vC>?hSKhGup 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

$Z@$}c@wP6I>vi-Xl9ood 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 From 4b611d017a22f072dc76385033facbbbb5ddb73a Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Fri, 15 Jun 2018 01:41:30 +0800 Subject: [PATCH 38/47] Update README.md --- fluid/image_classification/README.md | 43 +++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index 1d3c95f694..74a4840fcd 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -92,7 +92,7 @@ Data reader is defined in ```reader.py```. In [training stage](#training-a-model **training curve:" The training curve can be drawn based on training log. For example, the log of training AlexNet is like: -```shell +``` End pass 1, train_loss 6.23153877258, train_acc1 0.0150696625933, train_acc5 0.0552518665791, test_loss 5.41981744766, test_acc1 0.0519132651389, test_acc5 0.156150355935 End pass 2, train_loss 5.15442800522, train_acc1 0.0784279331565, train_acc5 0.211050540209, test_loss 4.45795249939, test_acc1 0.140469551086, test_acc5 0.333163291216 End pass 3, train_loss 4.51505613327, train_acc1 0.145300447941, train_acc5 0.331567406654, test_loss 3.86548018456, test_acc1 0.219443559647, test_acc5 0.446448504925 @@ -104,11 +104,10 @@ End pass 8, train_loss 3.45595097542, train_acc1 0.291462600231, train_acc5 0.53 End pass 9, train_loss 3.3745200634, train_acc1 0.303871691227, train_acc5 0.545210540295, test_loss 2.93932366371, test_acc1 0.37129303813, test_acc5 0.623573005199 ``` -The error rate curves of AlexNet, ResNet50 and SE-ResNeXt-50 are shown in figures below from left to right. -

- - - +The error rate curves of AlexNet, ResNet50 and SE-ResNeXt-50 are shown in the figure below. +

+
+Training Curve

## Finetuning @@ -129,7 +128,7 @@ python train.py ``` ## Evaluation -Evaluation is to evaluate the performance of a trained model. One can get top1/top5 accuracy by running the following command: +Evaluation is to evaluate the performance of a trained model. One can download [pretrained models(#supported-models) and set its path to ```path_to_pretrain_model```. Then top1/top5 accuracy can be obtained by running the following command: ``` python eval.py \ --model=SE_ResNeXt50_32x4d \ @@ -140,6 +139,20 @@ python eval.py \ --pretrained_model=${path_to_pretrain_model} ``` +According to the congfiguration of evaluation, the output log is like: +``` +Testbatch 0,loss 2.1786134243, acc1 0.625,acc5 0.8125,time 0.48 sec +Testbatch 10,loss 0.898496925831, acc1 0.75,acc5 0.9375,time 0.51 sec +Testbatch 20,loss 1.32524681091, acc1 0.6875,acc5 0.9375,time 0.37 sec +Testbatch 30,loss 1.46830511093, acc1 0.5,acc5 0.9375,time 0.51 sec +Testbatch 40,loss 1.12802267075, acc1 0.625,acc5 0.9375,time 0.35 sec +Testbatch 50,loss 0.881597697735, acc1 0.8125,acc5 1.0,time 0.32 sec +Testbatch 60,loss 0.300163716078, acc1 0.875,acc5 1.0,time 0.48 sec +Testbatch 70,loss 0.692037761211, acc1 0.875,acc5 1.0,time 0.35 sec +Testbatch 80,loss 0.0969972759485, acc1 1.0,acc5 1.0,time 0.41 sec +... +``` + ## Inference Inference is used to get prediction score or image features based on trained models. ``` @@ -151,6 +164,22 @@ python infer.py \ --with_mem_opt=True \ --pretrained_model=${path_to_pretrain_model} ``` +The output contains predication results, including maximum score (before softmax) and corresponding predicted label. +``` +Test-0-score: [13.168352], class [491] +Test-1-score: [7.913302], class [975] +Test-2-score: [16.959702], class [21] +Test-3-score: [14.197695], class [383] +Test-4-score: [12.607652], class [878] +Test-5-score: [17.725458], class [15] +Test-6-score: [12.678599], class [118] +Test-7-score: [12.353498], class [505] +Test-8-score: [20.828007], class [747] +Test-9-score: [15.135801], class [315] +Test-10-score: [14.585114], class [920] +Test-11-score: [13.739927], class [679] +Test-12-score: [15.040644], class [386] +``` ## Supported models and performances From b9c62e2cf06f1e9f951d4b4fb8240db8f1752b7b Mon Sep 17 00:00:00 2001 From: BigFishMaster Date: Fri, 15 Jun 2018 01:50:06 +0800 Subject: [PATCH 39/47] update download_imagenet2012.sh --- .../data/ILSVRC2012/download_imagenet2012.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fluid/image_classification/data/ILSVRC2012/download_imagenet2012.sh b/fluid/image_classification/data/ILSVRC2012/download_imagenet2012.sh index 0b68c14ff0..947b8900bd 100644 --- a/fluid/image_classification/data/ILSVRC2012/download_imagenet2012.sh +++ b/fluid/image_classification/data/ILSVRC2012/download_imagenet2012.sh @@ -14,7 +14,7 @@ valid_folder=val/ echo "Download imagenet training data..." mkdir -p ${train_folder} -#wget -nd -c ${root_url}/${train_tar} +wget -nd -c ${root_url}/${train_tar} tar xf ${train_tar} -C ${train_folder} cd ${train_folder} @@ -29,12 +29,12 @@ cd - echo "Download imagenet validation data..." mkdir -p ${valid_folder} -#wget -nd -c ${root_url}/${valid_tar} +wget -nd -c ${root_url}/${valid_tar} tar xf ${valid_tar} -C ${valid_folder} echo "Download imagenet label file: val_list.txt & train_list.txt" label_file=ImageNet_label.tgz label_url=http://imagenet-data.bj.bcebos.com/${label_file} -#wget -nd -c ${label_url} +wget -nd -c ${label_url} tar zxf ${label_file} From 8db82cbbde6029de40d84b79b153741f869ac5fc Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Fri, 15 Jun 2018 01:50:51 +0800 Subject: [PATCH 40/47] Update README.md --- fluid/image_classification/README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index 74a4840fcd..a27536d3f1 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -13,7 +13,7 @@ Image classification, which is an important field of computer vision, is to clas ## Installation -Running sample code in this directory requires PaddelPaddle v0.10.0 and later. If the PaddlePaddle on your device is lower than this version, please follow the instructions in [installation document](http://www.paddlepaddle.org/docs/develop/documentation/zh/build_and_install/pip_install_cn.html) and make an update. +Running sample code in this directory requires PaddelPaddle Fluid v0.13.0 and later. If the PaddlePaddle on your device is lower than this version, please follow the instructions in [installation document](http://www.paddlepaddle.org/docs/develop/documentation/zh/build_and_install/pip_install_cn.html) and make an update. ## Data preparation @@ -23,11 +23,13 @@ cd data/ILSVRC2012/ sh download_imagenet2012.sh ``` -In the shell script ```download_imagenet2012.sh```, there are two steps to prepare data: +In the shell script ```download_imagenet2012.sh```, there are three steps to prepare data: -**step-1:** Download ImageNet-2012 dataset from website. The training and validation data will be downloaded into folder "train" and "val" respectively. +**step-1:** Register at ```image-net.org``` first in order to get a pair of ```Username``` and ```AccessKey```, which are used to download ImageNet data. -**step-2:** Download training and validation label files. There are two label files which contain train and validation image labels respectively: +**step-2:** Download ImageNet-2012 dataset from website. The training and validation data will be downloaded into folder "train" and "val" respectively. + +**step-3:** Download training and validation label files. There are two label files which contain train and validation image labels respectively: * *train_list.txt*: label file of imagenet-2012 training set, with each line seperated by ```SPACE```, like: ``` From a6e9f0f8b8313c6f7b29445b7e9f814e44e8bae3 Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Fri, 15 Jun 2018 01:59:23 +0800 Subject: [PATCH 41/47] Update README.md --- fluid/image_classification/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index a27536d3f1..3779b6ad6d 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -104,17 +104,18 @@ End pass 6, train_loss 3.6929500103, train_acc1 0.255628824234, train_acc5 0.487 End pass 7, train_loss 3.55882954597, train_acc1 0.275381118059, train_acc5 0.511990904808, test_loss 3.03736782074, test_acc1 0.349035382271, test_acc5 0.606293857098 End pass 8, train_loss 3.45595097542, train_acc1 0.291462600231, train_acc5 0.530815005302, test_loss 2.96034455299, test_acc1 0.362228929996, test_acc5 0.617390751839 End pass 9, train_loss 3.3745200634, train_acc1 0.303871691227, train_acc5 0.545210540295, test_loss 2.93932366371, test_acc1 0.37129303813, test_acc5 0.623573005199 +... ``` The error rate curves of AlexNet, ResNet50 and SE-ResNeXt-50 are shown in the figure below.


-Training Curve +Training and validation Curves

## Finetuning -Finetuning is to finetune model weights in a specific task by loading pretrained weights. After initializing ```path_to_pretrain_model``` , one can finetune a model as: +Finetuning is to finetune model weights in a specific task by loading pretrained weights. After initializing ```path_to_pretrain_model```, one can finetune a model as: ``` python train.py --model=SE_ResNeXt50_32x4d \ @@ -181,11 +182,12 @@ Test-9-score: [15.135801], class [315] Test-10-score: [14.585114], class [920] Test-11-score: [13.739927], class [679] Test-12-score: [15.040644], class [386] +... ``` ## Supported models and performances -Models are trained by starting with learning rate ```0.1``` and decaying it by ```0.1``` after each ```30``` epoches, if not special introduced. Available top-1/top-5 validation accuracy on ImageNet 2012 is listed in table. Pretrained models can be downloaded by clicking related model names. +Models are trained by starting with learning rate ```0.1``` and decaying it by ```0.1``` after each pre-defined epoches, if not special introduced. Available top-1/top-5 validation accuracy on ImageNet 2012 are listed in table. Pretrained models can be downloaded by clicking related model names. |model | top-1/top-5 accuracy |- | -: From 8113cbb919def4b8cec552a440ca6576bc8bc576 Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Fri, 15 Jun 2018 01:59:50 +0800 Subject: [PATCH 42/47] Update README.md --- fluid/image_classification/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index 3779b6ad6d..11b476e4fa 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -1,5 +1,5 @@ # Image Classification and Model Zoo -Image classification, which is an important field of computer vision, is to classify an image into pre-defined labels. Recently, many researchers developed different kinds of neural networks and highly improve the classification performance. This page introduces how to do image classification with PaddlePaddle, including [data preparation](#data-preparation), [training](#training-a-model), [finetuning](#finetuning), [evaluation](#evaluation) and [inference](#inference). +Image classification, which is an important field of computer vision, is to classify an image into pre-defined labels. Recently, many researchers developed different kinds of neural networks and highly improve the classification performance. This page introduces how to do image classification with PaddlePaddle Fluid, including [data preparation](#data-preparation), [training](#training-a-model), [finetuning](#finetuning), [evaluation](#evaluation) and [inference](#inference). --- ## Table of Contents From 94aaea6b359305d267eb5f0e89d83b0ba61c1d4a Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Fri, 15 Jun 2018 02:06:56 +0800 Subject: [PATCH 43/47] Update README.md --- fluid/image_classification/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index 11b476e4fa..a89f62e52f 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -91,9 +91,9 @@ Data reader is defined in ```reader.py```. In [training stage](#training-a-model * resize * flipping -**training curve:" +**training curve:** -The training curve can be drawn based on training log. For example, the log of training AlexNet is like: +The training curve can be drawn based on training log. For example, the log from training AlexNet is like: ``` End pass 1, train_loss 6.23153877258, train_acc1 0.0150696625933, train_acc5 0.0552518665791, test_loss 5.41981744766, test_acc1 0.0519132651389, test_acc5 0.156150355935 End pass 2, train_loss 5.15442800522, train_acc1 0.0784279331565, train_acc5 0.211050540209, test_loss 4.45795249939, test_acc1 0.140469551086, test_acc5 0.333163291216 @@ -131,7 +131,7 @@ python train.py ``` ## Evaluation -Evaluation is to evaluate the performance of a trained model. One can download [pretrained models(#supported-models) and set its path to ```path_to_pretrain_model```. Then top1/top5 accuracy can be obtained by running the following command: +Evaluation is to evaluate the performance of a trained model. One can download [pretrained models](#supported-models) and set its path to ```path_to_pretrain_model```. Then top1/top5 accuracy can be obtained by running the following command: ``` python eval.py \ --model=SE_ResNeXt50_32x4d \ From e8d2db66ae6ca8ee28a58d3bc6797c0f09ae0adc Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Fri, 15 Jun 2018 02:16:20 +0800 Subject: [PATCH 44/47] Update README.md --- fluid/image_classification/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index a89f62e52f..32642ebefc 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -27,7 +27,7 @@ In the shell script ```download_imagenet2012.sh```, there are three steps to pr **step-1:** Register at ```image-net.org``` first in order to get a pair of ```Username``` and ```AccessKey```, which are used to download ImageNet data. -**step-2:** Download ImageNet-2012 dataset from website. The training and validation data will be downloaded into folder "train" and "val" respectively. +**step-2:** Download ImageNet-2012 dataset from website. The training and validation data will be downloaded into folder "train" and "val" respectively. Please note that the size of data is more than 40 GB, it will take much time to download. Users who have downloaded the ImageNet data can organize it into ```data/ILSVRC2012``` directly. **step-3:** Download training and validation label files. There are two label files which contain train and validation image labels respectively: From 3803d34824cbb26afda095281baab72b018f17ce Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Fri, 15 Jun 2018 02:35:28 +0800 Subject: [PATCH 45/47] Update README_cn.md --- fluid/image_classification/README_cn.md | 68 ++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 6 deletions(-) diff --git a/fluid/image_classification/README_cn.md b/fluid/image_classification/README_cn.md index 4940e8f895..ace5c2d5d0 100644 --- a/fluid/image_classification/README_cn.md +++ b/fluid/image_classification/README_cn.md @@ -14,7 +14,7 @@ ## 安装 -在当前目录下运行样例代码需要PadddlePaddle的v0.10.0或以上的版本。如果你的运行环境中的PaddlePaddle低于此版本,请根据[安装文档](http://www.paddlepaddle.org/docs/develop/documentation/zh/build_and_install/pip_install_cn.html)中的说明来更新PaddlePaddle。 +在当前目录下运行样例代码需要PadddlePaddle Fluid的v0.13.0或以上的版本。如果你的运行环境中的PaddlePaddle低于此版本,请根据[安装文档](http://www.paddlepaddle.org/docs/develop/documentation/zh/build_and_install/pip_install_cn.html)中的说明来更新PaddlePaddle。 ## 数据准备 @@ -23,11 +23,13 @@ cd data/ILSVRC2012/ sh download_imagenet2012.sh ``` -在```download_imagenet2012.sh```脚本中,通过下面两步来准备数据: +在```download_imagenet2012.sh```脚本中,通过下面三步来准备数据: -**步骤一:** 从ImageNet官网下载ImageNet-2012的图像数据。训练以及验证数据集会分别被下载到"train" 和 "val" 目录中。 +**步骤一:** 首先在```image-net.org```网站上完成注册,用于获得一对```Username```和```AccessKey```。 -**步骤二:** 下载训练与验证集合对应的标签文件。下面两个文件分别包含了训练集合与验证集合中图像的标签: +**步骤二:** 从ImageNet官网下载ImageNet-2012的图像数据。训练以及验证数据集会分别被下载到"train" 和 "val" 目录中。请注意,ImaegNet数据的大小超过40GB,下载非常耗时;已经自行下载ImageNet的用户可以直接将数据组织到```data/ILSVRC2012```。 + +**步骤三:** 下载训练与验证集合对应的标签文件。下面两个文件分别包含了训练集合与验证集合中图像的标签: * *train_list.txt*: ImageNet-2012训练集合的标签文件,每一行采用"空格"分隔图像路径与标注,例如: ``` @@ -88,6 +90,28 @@ python train.py \ * 长宽调整 * 水平翻转 +**训练曲线:** +通过训练过程中的日志可以画出训练曲线。举个例子,训练AlexNet出来的日志如下所示: +``` +End pass 1, train_loss 6.23153877258, train_acc1 0.0150696625933, train_acc5 0.0552518665791, test_loss 5.41981744766, test_acc1 0.0519132651389, test_acc5 0.156150355935 +End pass 2, train_loss 5.15442800522, train_acc1 0.0784279331565, train_acc5 0.211050540209, test_loss 4.45795249939, test_acc1 0.140469551086, test_acc5 0.333163291216 +End pass 3, train_loss 4.51505613327, train_acc1 0.145300447941, train_acc5 0.331567406654, test_loss 3.86548018456, test_acc1 0.219443559647, test_acc5 0.446448504925 +End pass 4, train_loss 4.12735557556, train_acc1 0.19437250495, train_acc5 0.405713528395, test_loss 3.56990146637, test_acc1 0.264536827803, test_acc5 0.507190704346 +End pass 5, train_loss 3.87505435944, train_acc1 0.229518383741, train_acc5 0.453582793474, test_loss 3.35345435143, test_acc1 0.297349333763, test_acc5 0.54753267765 +End pass 6, train_loss 3.6929500103, train_acc1 0.255628824234, train_acc5 0.487188398838, test_loss 3.17112898827, test_acc1 0.326953113079, test_acc5 0.581780135632 +End pass 7, train_loss 3.55882954597, train_acc1 0.275381118059, train_acc5 0.511990904808, test_loss 3.03736782074, test_acc1 0.349035382271, test_acc5 0.606293857098 +End pass 8, train_loss 3.45595097542, train_acc1 0.291462600231, train_acc5 0.530815005302, test_loss 2.96034455299, test_acc1 0.362228929996, test_acc5 0.617390751839 +End pass 9, train_loss 3.3745200634, train_acc1 0.303871691227, train_acc5 0.545210540295, test_loss 2.93932366371, test_acc1 0.37129303813, test_acc5 0.623573005199 +... +``` + +下图给出了AlexNet、ResNet50以及SE-ResNeXt-50网络的错误率曲线: +

+
+训练集合与验证集合上的错误率曲线 +

+ + ## 参数微调 参数微调是指在特定任务上微调已训练模型的参数。通过初始化```path_to_pretrain_model```,微调一个模型可以采用如下的命令: @@ -106,7 +130,7 @@ python train.py ``` ## 模型评估 -模型评估是指对训练完毕的模型评估各类性能指标。运行如下的命令,可以获得一个模型top-1/top-5精度: +模型评估是指对训练完毕的模型评估各类性能指标。用户可以下载[预训练模型](#supported-models)并且设置```path_to_pretrain_model```为模型所在路径。运行如下的命令,可以获得一个模型top-1/top-5精度: ``` python eval.py \ --model=SE_ResNeXt50_32x4d \ @@ -117,6 +141,21 @@ python eval.py \ --pretrained_model=${path_to_pretrain_model} ``` +根据这个评估程序的配置,输出日志形式如下: +``` +Testbatch 0,loss 2.1786134243, acc1 0.625,acc5 0.8125,time 0.48 sec +Testbatch 10,loss 0.898496925831, acc1 0.75,acc5 0.9375,time 0.51 sec +Testbatch 20,loss 1.32524681091, acc1 0.6875,acc5 0.9375,time 0.37 sec +Testbatch 30,loss 1.46830511093, acc1 0.5,acc5 0.9375,time 0.51 sec +Testbatch 40,loss 1.12802267075, acc1 0.625,acc5 0.9375,time 0.35 sec +Testbatch 50,loss 0.881597697735, acc1 0.8125,acc5 1.0,time 0.32 sec +Testbatch 60,loss 0.300163716078, acc1 0.875,acc5 1.0,time 0.48 sec +Testbatch 70,loss 0.692037761211, acc1 0.875,acc5 1.0,time 0.35 sec +Testbatch 80,loss 0.0969972759485, acc1 1.0,acc5 1.0,time 0.41 sec +... +``` + + ## 模型推断 模型推断可以获取一个模型的预测分数或者图像的特征: ``` @@ -128,10 +167,27 @@ python infer.py \ --with_mem_opt=True \ --pretrained_model=${path_to_pretrain_model} ``` +输出的预测结果包括最终类别分数(未经过softmax处理)以及相应的预测标签。 +``` +Test-0-score: [13.168352], class [491] +Test-1-score: [7.913302], class [975] +Test-2-score: [16.959702], class [21] +Test-3-score: [14.197695], class [383] +Test-4-score: [12.607652], class [878] +Test-5-score: [17.725458], class [15] +Test-6-score: [12.678599], class [118] +Test-7-score: [12.353498], class [505] +Test-8-score: [20.828007], class [747] +Test-9-score: [15.135801], class [315] +Test-10-score: [14.585114], class [920] +Test-11-score: [13.739927], class [679] +Test-12-score: [15.040644], class [386] +... +``` ## 已有模型及其性能 -表格中列出了在"models"目录下支持的神经网络种类,并且给出了已完成训练的模型在ImageNet-2012验证集合上的top-1/top-5精度。预训练模型可以通过点击相应模型的名称进行下载。 +表格中列出了在"models"目录下支持的神经网络种类,并且给出了已完成训练的模型在ImageNet-2012验证集合上的top-1/top-5精度;如无特征说明,训练模型的初始学习率为0.1,每隔预定的epochs会下降0.1。预训练模型可以通过点击相应模型的名称进行下载。 |model | top-1/top-5 accuracy |- | -: From 2c59d9e9f29e1a62d136b532c609f1904686a89f Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Fri, 15 Jun 2018 02:37:14 +0800 Subject: [PATCH 46/47] Update README.md --- fluid/image_classification/README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/fluid/image_classification/README.md b/fluid/image_classification/README.md index 32642ebefc..b8cd82a68a 100644 --- a/fluid/image_classification/README.md +++ b/fluid/image_classification/README.md @@ -81,9 +81,7 @@ python train.py \ * **pretrained_model**: model path for pretraining. Default: None. * **checkpoint**: the checkpoint path to resume. Default: None. -**data reader introduction:** - -Data reader is defined in ```reader.py```. In [training stage](#training-a-model), random crop and flipping are used, while center crop is used in [evaluation](#inference) and [inference](#inference) stages. Supported data augmentation includes: +**data reader introduction:** Data reader is defined in ```reader.py```. In [training stage](#training-a-model), random crop and flipping are used, while center crop is used in [evaluation](#inference) and [inference](#inference) stages. Supported data augmentation includes: * rotation * color jitter * random crop @@ -91,9 +89,7 @@ Data reader is defined in ```reader.py```. In [training stage](#training-a-model * resize * flipping -**training curve:** - -The training curve can be drawn based on training log. For example, the log from training AlexNet is like: +**training curve:** The training curve can be drawn based on training log. For example, the log from training AlexNet is like: ``` End pass 1, train_loss 6.23153877258, train_acc1 0.0150696625933, train_acc5 0.0552518665791, test_loss 5.41981744766, test_acc1 0.0519132651389, test_acc5 0.156150355935 End pass 2, train_loss 5.15442800522, train_acc1 0.0784279331565, train_acc5 0.211050540209, test_loss 4.45795249939, test_acc1 0.140469551086, test_acc5 0.333163291216 From 20080a7761fc0cec2e336abf07000ee905638d42 Mon Sep 17 00:00:00 2001 From: Chris Yann Date: Fri, 15 Jun 2018 02:41:04 +0800 Subject: [PATCH 47/47] Update README_cn.md --- fluid/image_classification/README_cn.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/fluid/image_classification/README_cn.md b/fluid/image_classification/README_cn.md index ace5c2d5d0..937dd148c7 100644 --- a/fluid/image_classification/README_cn.md +++ b/fluid/image_classification/README_cn.md @@ -27,7 +27,7 @@ sh download_imagenet2012.sh **步骤一:** 首先在```image-net.org```网站上完成注册,用于获得一对```Username```和```AccessKey```。 -**步骤二:** 从ImageNet官网下载ImageNet-2012的图像数据。训练以及验证数据集会分别被下载到"train" 和 "val" 目录中。请注意,ImaegNet数据的大小超过40GB,下载非常耗时;已经自行下载ImageNet的用户可以直接将数据组织到```data/ILSVRC2012```。 +**步骤二:** 从ImageNet官网下载ImageNet-2012的图像数据。训练以及验证数据集会分别被下载到"train" 和 "val" 目录中。请注意,ImaegNet数据的大小超过40GB,下载非常耗时;已经自行下载ImageNet的用户可以直接将数据组织放置到```data/ILSVRC2012```。 **步骤三:** 下载训练与验证集合对应的标签文件。下面两个文件分别包含了训练集合与验证集合中图像的标签: @@ -80,9 +80,7 @@ python train.py \ * **pretrained_model**: model path for pretraining. Default: None. * **checkpoint**: the checkpoint path to resume. Default: None. -**数据读取器说明:** - -数据读取器定义在```reader.py```中。在[训练阶段](#training-a-model), 默认采用的增广方式是随机裁剪与水平翻转, 而在[评估](#inference)与[推断](#inference)阶段用的默认方式是中心裁剪。当前支持的数据增广方式有: +**数据读取器说明:** 数据读取器定义在```reader.py```中。在[训练阶段](#training-a-model), 默认采用的增广方式是随机裁剪与水平翻转, 而在[评估](#inference)与[推断](#inference)阶段用的默认方式是中心裁剪。当前支持的数据增广方式有: * 旋转 * 颜色抖动 * 随机裁剪 @@ -90,8 +88,7 @@ python train.py \ * 长宽调整 * 水平翻转 -**训练曲线:** -通过训练过程中的日志可以画出训练曲线。举个例子,训练AlexNet出来的日志如下所示: +**训练曲线:** 通过训练过程中的日志可以画出训练曲线。举个例子,训练AlexNet出来的日志如下所示: ``` End pass 1, train_loss 6.23153877258, train_acc1 0.0150696625933, train_acc5 0.0552518665791, test_loss 5.41981744766, test_acc1 0.0519132651389, test_acc5 0.156150355935 End pass 2, train_loss 5.15442800522, train_acc1 0.0784279331565, train_acc5 0.211050540209, test_loss 4.45795249939, test_acc1 0.140469551086, test_acc5 0.333163291216 @@ -167,7 +164,7 @@ python infer.py \ --with_mem_opt=True \ --pretrained_model=${path_to_pretrain_model} ``` -输出的预测结果包括最终类别分数(未经过softmax处理)以及相应的预测标签。 +输出的预测结果包括最高分数(未经过softmax处理)以及相应的预测标签。 ``` Test-0-score: [13.168352], class [491] Test-1-score: [7.913302], class [975] @@ -187,7 +184,7 @@ Test-12-score: [15.040644], class [386] ## 已有模型及其性能 -表格中列出了在"models"目录下支持的神经网络种类,并且给出了已完成训练的模型在ImageNet-2012验证集合上的top-1/top-5精度;如无特征说明,训练模型的初始学习率为0.1,每隔预定的epochs会下降0.1。预训练模型可以通过点击相应模型的名称进行下载。 +表格中列出了在"models"目录下支持的神经网络种类,并且给出了已完成训练的模型在ImageNet-2012验证集合上的top-1/top-5精度;如无特征说明,训练模型的初始学习率为```0.1```,每隔预定的epochs会下降```0.1```。预训练模型可以通过点击相应模型的名称进行下载。 |model | top-1/top-5 accuracy |- | -: