From 0a29c100516a876b408331c8bc3650d780a25214 Mon Sep 17 00:00:00 2001 From: ruri Date: Wed, 5 Dec 2018 17:08:56 +0800 Subject: [PATCH] Update image classification (#1492) * Update Image Classification Models. --- fluid/PaddleCV/image_classification/README.md | 38 +- .../images/alexnet_imagenet1k_acc1.png | Bin 0 -> 20621 bytes .../images/mobielenetv1_imagenet1k_acc1.png | Bin 0 -> 20997 bytes .../images/resnet101_imagenet1k_acc1.png | Bin 0 -> 21559 bytes .../images/resnet50_imagenet1k_acc1.png | Bin 0 -> 21940 bytes .../images/vgg11_imagenet1k_acc1.png | Bin 0 -> 21448 bytes .../image_classification/models/__init__.py | 3 +- .../image_classification/models/dpn.py | 3 +- .../image_classification/models/googlenet.py | 2 +- .../models/mobilenet_v2.py | 169 +++++++++ .../models/shufflenet_v2.py | 253 +++++++++++++ .../models_name/__init__.py | 10 + .../models_name/alexnet.py | 169 +++++++++ .../image_classification/models_name/dpn.py | 334 +++++++++++++++++ .../models_name/googlenet.py | 233 ++++++++++++ .../models_name/inception_v4.py | 341 ++++++++++++++++++ .../models_name/mobilenet.py | 196 ++++++++++ .../models_name/mobilenet_v2.py | 199 ++++++++++ .../models_name/resnet.py | 162 +++++++++ .../models_name/se_resnext.py | 247 +++++++++++++ .../models_name/shufflenet_v2.py | 289 +++++++++++++++ .../image_classification/models_name/vgg.py | 105 ++++++ fluid/PaddleCV/image_classification/reader.py | 9 +- fluid/PaddleCV/image_classification/run.sh | 80 ++++ fluid/PaddleCV/image_classification/train.py | 311 ++++++++++------ .../image_classification/utils/__init__.py | 1 + .../{models => utils}/learning_rate.py | 9 +- 27 files changed, 3029 insertions(+), 134 deletions(-) create mode 100644 fluid/PaddleCV/image_classification/images/alexnet_imagenet1k_acc1.png create mode 100644 fluid/PaddleCV/image_classification/images/mobielenetv1_imagenet1k_acc1.png create mode 100644 fluid/PaddleCV/image_classification/images/resnet101_imagenet1k_acc1.png create mode 100644 fluid/PaddleCV/image_classification/images/resnet50_imagenet1k_acc1.png create mode 100644 fluid/PaddleCV/image_classification/images/vgg11_imagenet1k_acc1.png create mode 100644 fluid/PaddleCV/image_classification/models/mobilenet_v2.py create mode 100644 fluid/PaddleCV/image_classification/models/shufflenet_v2.py create mode 100644 fluid/PaddleCV/image_classification/models_name/__init__.py create mode 100644 fluid/PaddleCV/image_classification/models_name/alexnet.py create mode 100644 fluid/PaddleCV/image_classification/models_name/dpn.py create mode 100644 fluid/PaddleCV/image_classification/models_name/googlenet.py create mode 100644 fluid/PaddleCV/image_classification/models_name/inception_v4.py create mode 100644 fluid/PaddleCV/image_classification/models_name/mobilenet.py create mode 100644 fluid/PaddleCV/image_classification/models_name/mobilenet_v2.py create mode 100644 fluid/PaddleCV/image_classification/models_name/resnet.py create mode 100644 fluid/PaddleCV/image_classification/models_name/se_resnext.py create mode 100644 fluid/PaddleCV/image_classification/models_name/shufflenet_v2.py create mode 100644 fluid/PaddleCV/image_classification/models_name/vgg.py create mode 100644 fluid/PaddleCV/image_classification/run.sh create mode 100644 fluid/PaddleCV/image_classification/utils/__init__.py rename fluid/PaddleCV/image_classification/{models => utils}/learning_rate.py (90%) diff --git a/fluid/PaddleCV/image_classification/README.md b/fluid/PaddleCV/image_classification/README.md index b8cd82a6..0f46acbb 100644 --- a/fluid/PaddleCV/image_classification/README.md +++ b/fluid/PaddleCV/image_classification/README.md @@ -59,7 +59,7 @@ python train.py \ --model=SE_ResNeXt50_32x4d \ --batch_size=32 \ --total_images=1281167 \ - --class_dim=1000 + --class_dim=1000 \ --image_shape=3,224,224 \ --model_save_dir=output/ \ --with_mem_opt=False \ @@ -80,6 +80,9 @@ python train.py \ * **lr**: initialized learning rate. Default: 0.1. * **pretrained_model**: model path for pretraining. Default: None. * **checkpoint**: the checkpoint path to resume. Default: None. +* **model_category**: the category of models, ("models"|"models_name"). Default: "models". + +Or can start the training step by running the ```run.sh```. **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 @@ -183,26 +186,23 @@ Test-12-score: [15.040644], class [386] ## Supported models and performances +Models consists of two categories: Models with specified parameters names in model definition and Models without specified parameters, Generate named model by indicating ```model_category = models_name```. + 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. +- Released models: specify parameter names + +|model | top-1/top-5 accuracy +|- | -: +|[AlexNet](http://paddle-imagenet-models-name.bj.bcebos.com/AlexNet_pretrained.zip) | 56.34%/79.02% +|[VGG11](http://paddle-imagenet-models-name.bj.bcebos.com/VGG11_pretained.zip) | 68.86%/88.64% +|[MobileNetV1](http://paddle-imagenet-models-name.bj.bcebos.com/MobileNetV1_pretrained.zip) | 70.7%/89.41% +|[ResNet50](http://paddle-imagenet-models-name.bj.bcebos.com/ResNet50_pretrained.zip) | 76.46%/93.04% +|[ResNet101](http://paddle-imagenet-models-name.bj.bcebos.com/ResNet101_pretrained.zip) | 77.65%/93.71% + +- Released models: not specify parameter names + |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 | - +|[ResNet152](http://paddle-imagenet-models.bj.bcebos.com/ResNet152_pretrained.zip) | 78.29%/94.11% |[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 | - diff --git a/fluid/PaddleCV/image_classification/images/alexnet_imagenet1k_acc1.png b/fluid/PaddleCV/image_classification/images/alexnet_imagenet1k_acc1.png new file mode 100644 index 0000000000000000000000000000000000000000..d9dde696f7eb15b9eda6352b488749fba76d9f5a GIT binary patch literal 20621 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

2K**hg%IT~GE^lT)rTgMF6wW8+b7X;;sycE=tc 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 literal 0 HcmV?d00001 diff --git a/fluid/PaddleCV/image_classification/images/mobielenetv1_imagenet1k_acc1.png b/fluid/PaddleCV/image_classification/images/mobielenetv1_imagenet1k_acc1.png new file mode 100644 index 0000000000000000000000000000000000000000..7b41b61244810ec3da67ebd76cb85c244cd61300 GIT binary patch literal 20997 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 literal 0 HcmV?d00001 diff --git a/fluid/PaddleCV/image_classification/images/resnet101_imagenet1k_acc1.png b/fluid/PaddleCV/image_classification/images/resnet101_imagenet1k_acc1.png new file mode 100644 index 0000000000000000000000000000000000000000..f6436324bc67f81d5eec5309afba9edefadfc483 GIT binary patch literal 21559 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 I?S!QGU&Q=y9RL6T literal 0 HcmV?d00001 diff --git a/fluid/PaddleCV/image_classification/images/resnet50_imagenet1k_acc1.png b/fluid/PaddleCV/image_classification/images/resnet50_imagenet1k_acc1.png new file mode 100644 index 0000000000000000000000000000000000000000..c23f2f34af0aca4b41d7537314c60f6105a88bc0 GIT binary patch literal 21940 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 literal 0 HcmV?d00001 diff --git a/fluid/PaddleCV/image_classification/images/vgg11_imagenet1k_acc1.png b/fluid/PaddleCV/image_classification/images/vgg11_imagenet1k_acc1.png new file mode 100644 index 0000000000000000000000000000000000000000..691071c7acc5f5aa7f807f4d51748fc2b91df356 GIT binary patch literal 21448 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 literal 0 HcmV?d00001 diff --git a/fluid/PaddleCV/image_classification/models/__init__.py b/fluid/PaddleCV/image_classification/models/__init__.py index f43275b6..f05195f2 100644 --- a/fluid/PaddleCV/image_classification/models/__init__.py +++ b/fluid/PaddleCV/image_classification/models/__init__.py @@ -1,5 +1,6 @@ from .alexnet import AlexNet from .mobilenet import MobileNet +from .mobilenet_v2 import MobileNetV2 from .googlenet import GoogleNet from .vgg import VGG11, VGG13, VGG16, VGG19 from .resnet import ResNet50, ResNet101, ResNet152 @@ -7,4 +8,4 @@ from .resnet_dist import DistResNet 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 -import learning_rate +from .shufflenet_v2 import ShuffleNetV2_x0_5, ShuffleNetV2_x1_0, ShuffleNetV2_x1_5, ShuffleNetV2_x2_0 diff --git a/fluid/PaddleCV/image_classification/models/dpn.py b/fluid/PaddleCV/image_classification/models/dpn.py index d9144eeb..ca49898f 100644 --- a/fluid/PaddleCV/image_classification/models/dpn.py +++ b/fluid/PaddleCV/image_classification/models/dpn.py @@ -5,8 +5,8 @@ import os import numpy as np import time import sys -import math import paddle.fluid as fluid +import math __all__ = ["DPN", "DPN68", "DPN92", "DPN98", "DPN107", "DPN131"] @@ -62,7 +62,6 @@ class DPN(object): pool_padding=1, pool_type='max') - #conv2 - conv5 for gc in range(4): bw = bws[gc] inc = inc_sec[gc] diff --git a/fluid/PaddleCV/image_classification/models/googlenet.py b/fluid/PaddleCV/image_classification/models/googlenet.py index ebc8566e..be52ed96 100644 --- a/fluid/PaddleCV/image_classification/models/googlenet.py +++ b/fluid/PaddleCV/image_classification/models/googlenet.py @@ -13,7 +13,7 @@ train_parameters = { "learning_strategy": { "name": "piecewise_decay", "batch_size": 256, - "epochs": [30, 60, 90], + "epochs": [30, 70, 100], "steps": [0.1, 0.01, 0.001, 0.0001] } } diff --git a/fluid/PaddleCV/image_classification/models/mobilenet_v2.py b/fluid/PaddleCV/image_classification/models/mobilenet_v2.py new file mode 100644 index 00000000..9ec118f2 --- /dev/null +++ b/fluid/PaddleCV/image_classification/models/mobilenet_v2.py @@ -0,0 +1,169 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +import paddle.fluid as fluid +from paddle.fluid.initializer import MSRA +from paddle.fluid.param_attr import ParamAttr + +__all__ = ['MobileNetV2'] + +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 MobileNetV2(): + def __init__(self): + self.params = train_parameters + + def net(self, input, class_dim=1000, scale=1.0): + + bottleneck_params_list = [ + (1, 16, 1, 1), + (6, 24, 2, 2), + (6, 32, 3, 2), + (6, 64, 4, 2), + (6, 96, 3, 1), + (6, 160, 3, 2), + (6, 320, 1, 1), + ] + + input = self.conv_bn_layer( + input, + num_filters=int(32 * scale), + filter_size=3, + stride=2, + padding=1, + if_act=True) + + in_c = int(32 * scale) + for layer_setting in bottleneck_params_list: + t, c, n, s = layer_setting + input = self.invresi_blocks( + input=input, + in_c=in_c, + t=t, + c=int(c * scale), + n=n, + s=s, ) + in_c = int(c * scale) + + input = self.conv_bn_layer( + input=input, + num_filters=int(1280 * scale) if scale > 1.0 else 1280, + filter_size=1, + stride=1, + padding=0, + if_act=True) + + input = fluid.layers.pool2d( + input=input, + pool_size=7, + 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, + use_cudnn=True, + if_act=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) + bn = fluid.layers.batch_norm(input=conv) + if if_act: + return fluid.layers.relu6(bn) + else: + return bn + + def shortcut(self, input, data_residual): + return fluid.layers.elementwise_add(input, data_residual) + + def inverted_residual_unit(self, input, num_in_filter, num_filters, + ifshortcut, stride, filter_size, padding, + expansion_factor): + num_expfilter = int(round(num_in_filter * expansion_factor)) + channel_expand = self.conv_bn_layer( + input=input, + num_filters=num_expfilter, + filter_size=1, + stride=1, + padding=0, + num_groups=1, + if_act=True) + bottleneck_conv = self.conv_bn_layer( + input=channel_expand, + num_filters=num_expfilter, + filter_size=filter_size, + stride=stride, + padding=padding, + num_groups=num_expfilter, + if_act=True, + use_cudnn=False) + linear_out = self.conv_bn_layer( + input=bottleneck_conv, + num_filters=num_filters, + filter_size=1, + stride=1, + padding=0, + num_groups=1, + if_act=False) + if ifshortcut: + out = self.shortcut(input=input, data_residual=linear_out) + return out + else: + return linear_out + + def invresi_blocks(self, input, in_c, t, c, n, s): + first_block = self.inverted_residual_unit( + input=input, + num_in_filter=in_c, + num_filters=c, + ifshortcut=False, + stride=s, + filter_size=3, + padding=1, + expansion_factor=t) + + last_residual_block = first_block + last_c = c + + for i in range(1, n): + last_residual_block = self.inverted_residual_unit( + input=last_residual_block, + num_in_filter=last_c, + num_filters=c, + ifshortcut=True, + stride=1, + filter_size=3, + padding=1, + expansion_factor=t) + return last_residual_block diff --git a/fluid/PaddleCV/image_classification/models/shufflenet_v2.py b/fluid/PaddleCV/image_classification/models/shufflenet_v2.py new file mode 100644 index 00000000..bc61508e --- /dev/null +++ b/fluid/PaddleCV/image_classification/models/shufflenet_v2.py @@ -0,0 +1,253 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +import paddle.fluid as fluid +from paddle.fluid.initializer import MSRA +from paddle.fluid.param_attr import ParamAttr + +__all__ = [ + 'ShuffleNetV2', 'ShuffleNetV2_x0_5', 'ShuffleNetV2_x1_0', + 'ShuffleNetV2_x1_5', 'ShuffleNetV2_x2_0' +] + +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 ShuffleNetV2(): + def __init__(self, scale=1.0): + self.params = train_parameters + self.scale = scale + + def net(self, input, class_dim=1000): + scale = self.scale + stage_repeats = [4, 8, 4] + + if scale == 0.5: + stage_out_channels = [-1, 24, 48, 96, 192, 1024] + elif scale == 1.0: + stage_out_channels = [-1, 24, 116, 232, 464, 1024] + elif scale == 1.5: + stage_out_channels = [-1, 24, 176, 352, 704, 1024] + elif scale == 2.0: + stage_out_channels = [-1, 24, 224, 488, 976, 2048] + else: + raise ValueError("""{} groups is not supported for + 1x1 Grouped Convolutions""".format(num_groups)) + + #conv1 + + input_channel = stage_out_channels[1] + conv1 = self.conv_bn_layer( + input=input, + filter_size=3, + num_filters=input_channel, + padding=1, + stride=2) + pool1 = fluid.layers.pool2d( + input=conv1, + pool_size=3, + pool_stride=2, + pool_padding=1, + pool_type='max') + conv = pool1 + # bottleneck sequences + for idxstage in range(len(stage_repeats)): + numrepeat = stage_repeats[idxstage] + output_channel = stage_out_channels[idxstage + 2] + for i in range(numrepeat): + if i == 0: + conv = self.inverted_residual_unit( + input=conv, + num_filters=output_channel, + stride=2, + benchmodel=2) + else: + conv = self.inverted_residual_unit( + input=conv, + num_filters=output_channel, + stride=1, + benchmodel=1) + + conv_last = self.conv_bn_layer( + input=conv, + filter_size=1, + num_filters=stage_out_channels[-1], + padding=0, + stride=1) + pool_last = fluid.layers.pool2d( + input=conv_last, + pool_size=7, + pool_stride=7, + pool_padding=0, + pool_type='avg') + + output = fluid.layers.fc(input=pool_last, + size=class_dim, + act='softmax', + param_attr=ParamAttr(initializer=MSRA())) + return output + + def conv_bn_layer(self, + input, + filter_size, + num_filters, + stride, + padding, + num_groups=1, + use_cudnn=True, + if_act=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) + if if_act: + return fluid.layers.batch_norm(input=conv, act='relu') + else: + return fluid.layers.batch_norm(input=conv) + + def channel_shuffle(self, x, groups): + batchsize, num_channels, height, width = x.shape[0], x.shape[ + 1], x.shape[2], x.shape[3] + channels_per_group = num_channels // groups + + # reshape + x = fluid.layers.reshape( + x=x, shape=[batchsize, groups, channels_per_group, height, width]) + + x = fluid.layers.transpose(x=x, perm=[0, 2, 1, 3, 4]) + + # flatten + x = fluid.layers.reshape( + x=x, shape=[batchsize, num_channels, height, width]) + + return x + + def inverted_residual_unit(self, input, num_filters, stride, benchmodel): + assert stride in [1, 2], \ + "supported stride are {} but your stride is {}".format([1,2], stride) + + oup_inc = num_filters // 2 + inp = input.shape[1] + + if benchmodel == 1: + x1, x2 = fluid.layers.split( + input, + num_or_sections=[input.shape[1] // 2, input.shape[1] // 2], + dim=1) + + conv_pw = self.conv_bn_layer( + input=x2, + num_filters=oup_inc, + filter_size=1, + stride=1, + padding=0, + num_groups=1, + if_act=True) + + conv_dw = self.conv_bn_layer( + input=conv_pw, + num_filters=oup_inc, + filter_size=3, + stride=stride, + padding=1, + num_groups=oup_inc, + if_act=False) + + conv_linear = self.conv_bn_layer( + input=conv_dw, + num_filters=oup_inc, + filter_size=1, + stride=1, + padding=0, + num_groups=1, + if_act=True) + + out = fluid.layers.concat([x1, conv_linear], axis=1) + + else: + #branch1 + conv_dw = self.conv_bn_layer( + input=input, + num_filters=inp, + filter_size=3, + stride=stride, + padding=1, + num_groups=inp, + if_act=False) + + conv_linear_1 = self.conv_bn_layer( + input=conv_dw, + num_filters=oup_inc, + filter_size=1, + stride=1, + padding=0, + num_groups=1, + if_act=True) + + #branch2 + conv_pw = self.conv_bn_layer( + input=input, + num_filters=oup_inc, + filter_size=1, + stride=1, + padding=0, + num_groups=1, + if_act=True) + + conv_dw = self.conv_bn_layer( + input=conv_pw, + num_filters=oup_inc, + filter_size=3, + stride=stride, + padding=1, + num_groups=oup_inc, + if_act=False) + + conv_linear_2 = self.conv_bn_layer( + input=conv_dw, + num_filters=oup_inc, + filter_size=1, + stride=1, + padding=0, + num_groups=1, + if_act=True) + out = fluid.layers.concat([conv_linear_1, conv_linear_2], axis=1) + + return self.channel_shuffle(out, 2) + + +def ShuffleNetV2_x0_5(): + model = ShuffleNetV2(scale=0.5) + return model + + +def ShuffleNetV2_x1_0(): + model = ShuffleNetV2(scale=1.0) + return model + + +def ShuffleNetV2_x1_5(): + model = ShuffleNetV2(scale=1.5) + return model + + +def ShuffleNetV2_x2_0(): + model = ShuffleNetV2(scale=2.0) + return model diff --git a/fluid/PaddleCV/image_classification/models_name/__init__.py b/fluid/PaddleCV/image_classification/models_name/__init__.py new file mode 100644 index 00000000..ea0216e0 --- /dev/null +++ b/fluid/PaddleCV/image_classification/models_name/__init__.py @@ -0,0 +1,10 @@ +from .alexnet import AlexNet +from .mobilenet import MobileNet +from .mobilenet_v2 import MobileNetV2 +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 +from .dpn import DPN68, DPN92, DPN98, DPN107, DPN131 +from .shufflenet_v2 import ShuffleNetV2_x0_5, ShuffleNetV2_x1_0, ShuffleNetV2_x1_5, ShuffleNetV2_x2_0 diff --git a/fluid/PaddleCV/image_classification/models_name/alexnet.py b/fluid/PaddleCV/image_classification/models_name/alexnet.py new file mode 100644 index 00000000..3dfaa25f --- /dev/null +++ b/fluid/PaddleCV/image_classification/models_name/alexnet.py @@ -0,0 +1,169 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +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=1000): + stdv = 1.0 / math.sqrt(input.shape[1] * 11 * 11) + layer_name = [ + "conv1", "conv2", "conv3", "conv4", "conv5", "fc6", "fc7", "fc8" + ] + 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), + name=layer_name[0] + "_offset"), + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv), + name=layer_name[0] + "_weights")) + 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), + name=layer_name[1] + "_offset"), + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv), + name=layer_name[1] + "_weights")) + 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), + name=layer_name[2] + "_offset"), + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv), + name=layer_name[2] + "_weights")) + + 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), + name=layer_name[3] + "_offset"), + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv), + name=layer_name[3] + "_weights")) + + 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), + name=layer_name[4] + "_offset"), + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv), + name=layer_name[4] + "_weights")) + 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), + name=layer_name[5] + "_offset"), + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv), + name=layer_name[5] + "_weights")) + + 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), + name=layer_name[6] + "_offset"), + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv), + name=layer_name[6] + "_weights")) + + 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), + name=layer_name[7] + "_offset"), + param_attr=fluid.param_attr.ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv), + name=layer_name[7] + "_weights")) + return out diff --git a/fluid/PaddleCV/image_classification/models_name/dpn.py b/fluid/PaddleCV/image_classification/models_name/dpn.py new file mode 100644 index 00000000..a39d9072 --- /dev/null +++ b/fluid/PaddleCV/image_classification/models_name/dpn.py @@ -0,0 +1,334 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +import os +import numpy as np +import time +import sys +import paddle.fluid as fluid +import math +from paddle.fluid.param_attr import ParamAttr + +__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, + name="conv1", + param_attr=ParamAttr(name="conv1_weights"), ) + + conv1_x_1 = fluid.layers.batch_norm( + input=conv1_x_1, + act='relu', + is_test=False, + name="conv1_bn", + param_attr=ParamAttr(name='conv1_bn_scale'), + bias_attr=ParamAttr('conv1_bn_offset'), + moving_mean_name='conv1_bn_mean', + moving_variance_name='conv1_bn_variance', ) + + convX_x_x = fluid.layers.pool2d( + input=conv1_x_1, + pool_size=3, + pool_stride=2, + pool_padding=1, + pool_type='max', + name="pool1") + + #conv2 - conv5 + match_list, num = [], 0 + 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' + match = 1 + else: + _type1 = 'down' + _type2 = 'normal' + match = match + k_sec[gc - 1] + match_list.append(match) + + convX_x_x = self.dual_path_factory( + convX_x_x, R, R, bw, inc, G, _type1, name="dpn" + str(match)) + for i_ly in range(2, k_sec[gc] + 1): + num += 1 + if num in match_list: + num += 1 + convX_x_x = self.dual_path_factory( + convX_x_x, R, R, bw, inc, G, _type2, name="dpn" + str(num)) + + 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, + name="final_concat_bn", + param_attr=ParamAttr(name='final_concat_bn_scale'), + bias_attr=ParamAttr('final_concat_bn_offset'), + moving_mean_name='final_concat_bn_mean', + moving_variance_name='final_concat_bn_variance', ) + pool5 = fluid.layers.pool2d( + input=conv5_x_x, + pool_size=7, + pool_stride=1, + pool_padding=0, + pool_type='avg', ) + + 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, + name="fc6") + + 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 + net_arg = { + 'k_r': k_r, + 'G': G, + 'k_sec': k_sec, + 'inc_sec': inc_sec, + 'bw': bw, + 'r': r + } + 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', + name=None): + 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), + name=name + "_match") + data_o1, data_o2 = fluid.layers.split( + c1x1_w, + num_or_sections=[num_1x1_c, 2 * inc], + dim=1, + name=name + "_match_conv_Slice") + 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), + name=name + "_conv1") + 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, + name=name + "_conv2") + c1x1_c = self.bn_ac_conv( + data=c3x3_b, + num_filter=(num_1x1_c + inc), + kernel=(1, 1), + pad=(0, 0), + name=name + "_conv3") + + c1x1_c1, c1x1_c2 = fluid.layers.split( + c1x1_c, + num_or_sections=[num_1x1_c, inc], + dim=1, + name=name + "_conv3_Slice") + + # OUTPUTS + summ = fluid.layers.elementwise_add( + x=data_o1, y=c1x1_c1, name=name + "_elewise") + dense = fluid.layers.concat( + [data_o2, c1x1_c2], axis=1, name=name + "_concat") + + return [summ, dense] + + def bn_ac_conv(self, + data, + num_filter, + kernel, + pad, + stride=(1, 1), + num_group=1, + name=None): + bn_ac = fluid.layers.batch_norm( + input=data, + act='relu', + is_test=False, + name=name + '.output.1', + param_attr=ParamAttr(name=name + '_bn_scale'), + bias_attr=ParamAttr(name + '_bn_offset'), + moving_mean_name=name + '_bn_mean', + moving_variance_name=name + '_bn_variance', ) + 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, + param_attr=ParamAttr(name=name + "_weights")) + return bn_ac_conv + + +def DPN68(): + model = DPN(layers=68) + return model + + +def DPN92(): + onvodel = 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/PaddleCV/image_classification/models_name/googlenet.py b/fluid/PaddleCV/image_classification/models_name/googlenet.py new file mode 100644 index 00000000..bd9040c5 --- /dev/null +++ b/fluid/PaddleCV/image_classification/models_name/googlenet.py @@ -0,0 +1,233 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +import paddle +import paddle.fluid as fluid +from paddle.fluid.param_attr import ParamAttr + +__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, 70, 100], + "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, + name=None): + channels = input.shape[1] + stdv = (3.0 / (filter_size**2 * channels))**0.5 + param_attr = ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv), + name=name + "_weights") + 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, + name=name) + return conv + + def xavier(self, channels, filter_size, name): + stdv = (3.0 / (filter_size**2 * channels))**0.5 + param_attr = ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv), + name=name + "_weights") + + return param_attr + + def inception(self, + input, + channels, + filter1, + filter3R, + filter3, + filter5R, + filter5, + proj, + name=None): + conv1 = self.conv_layer( + input=input, + num_filters=filter1, + filter_size=1, + stride=1, + act=None, + name="inception_" + name + "_1x1") + conv3r = self.conv_layer( + input=input, + num_filters=filter3R, + filter_size=1, + stride=1, + act=None, + name="inception_" + name + "_3x3_reduce") + conv3 = self.conv_layer( + input=conv3r, + num_filters=filter3, + filter_size=3, + stride=1, + act=None, + name="inception_" + name + "_3x3") + conv5r = self.conv_layer( + input=input, + num_filters=filter5R, + filter_size=1, + stride=1, + act=None, + name="inception_" + name + "_5x5_reduce") + conv5 = self.conv_layer( + input=conv5r, + num_filters=filter5, + filter_size=5, + stride=1, + act=None, + name="inception_" + name + "_5x5") + 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, + name="inception_" + name + "_3x3_proj", + param_attr=ParamAttr( + name="inception_" + name + "_3x3_proj_weights"), + bias_attr=False) + 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): + conv = self.conv_layer( + input=input, + num_filters=64, + filter_size=7, + stride=2, + act=None, + name="conv1") + 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, + name="conv2_1x1") + conv = self.conv_layer( + input=conv, + num_filters=192, + filter_size=3, + stride=1, + act=None, + name="conv2_3x3") + pool = fluid.layers.pool2d( + input=conv, pool_size=3, pool_type='max', pool_stride=2) + + ince3a = self.inception(pool, 192, 64, 96, 128, 16, 32, 32, "ince3a") + ince3b = self.inception(ince3a, 256, 128, 128, 192, 32, 96, 64, + "ince3b") + pool3 = fluid.layers.pool2d( + input=ince3b, pool_size=3, pool_type='max', pool_stride=2) + + ince4a = self.inception(pool3, 480, 192, 96, 208, 16, 48, 64, "ince4a") + ince4b = self.inception(ince4a, 512, 160, 112, 224, 24, 64, 64, + "ince4b") + ince4c = self.inception(ince4b, 512, 128, 128, 256, 24, 64, 64, + "ince4c") + ince4d = self.inception(ince4c, 512, 112, 144, 288, 32, 64, 64, + "ince4d") + ince4e = self.inception(ince4d, 528, 256, 160, 320, 32, 128, 128, + "ince4e") + pool4 = fluid.layers.pool2d( + input=ince4e, pool_size=3, pool_type='max', pool_stride=2) + + ince5a = self.inception(pool4, 832, 256, 160, 320, 32, 128, 128, + "ince5a") + ince5b = self.inception(ince5a, 832, 384, 192, 384, 48, 128, 128, + "ince5b") + 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', + param_attr=self.xavier(1024, 1, "out"), + name="out", + bias_attr=ParamAttr(name="out_offset")) + + 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, + name="conv_o1") + fc_o1 = fluid.layers.fc(input=conv_o1, + size=1024, + act='relu', + param_attr=self.xavier(2048, 1, "fc_o1"), + name="fc_o1", + bias_attr=ParamAttr(name="fc_o1_offset")) + dropout_o1 = fluid.layers.dropout(x=fc_o1, dropout_prob=0.7) + out1 = fluid.layers.fc(input=dropout_o1, + size=class_dim, + act='softmax', + param_attr=self.xavier(1024, 1, "out1"), + name="out1", + bias_attr=ParamAttr(name="out1_offset")) + + 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, + name="conv_o2") + fc_o2 = fluid.layers.fc(input=conv_o2, + size=1024, + act='relu', + param_attr=self.xavier(2048, 1, "fc_o2"), + name="fc_o2", + bias_attr=ParamAttr(name="fc_o2_offset")) + dropout_o2 = fluid.layers.dropout(x=fc_o2, dropout_prob=0.7) + out2 = fluid.layers.fc(input=dropout_o2, + size=class_dim, + act='softmax', + param_attr=self.xavier(1024, 1, "out2"), + name="out2", + bias_attr=ParamAttr(name="out2_offset")) + + # last fc layer is "out" + return out, out1, out2 diff --git a/fluid/PaddleCV/image_classification/models_name/inception_v4.py b/fluid/PaddleCV/image_classification/models_name/inception_v4.py new file mode 100644 index 00000000..7b857d45 --- /dev/null +++ b/fluid/PaddleCV/image_classification/models_name/inception_v4.py @@ -0,0 +1,341 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +import paddle +import paddle.fluid as fluid +import math +from paddle.fluid.param_attr import ParamAttr + +__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=1000): + x = self.inception_stem(input) + + for i in range(4): + x = self.inceptionA(x, name=str(i + 1)) + x = self.reductionA(x) + + for i in range(7): + x = self.inceptionB(x, name=str(i + 1)) + x = self.reductionB(x) + + for i in range(3): + x = self.inceptionC(x, name=str(i + 1)) + + 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=ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv), + name="final_fc_weights"), + bias_attr=ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv), + name="final_fc_offset")) + return out + + def conv_bn_layer(self, + data, + num_filters, + filter_size, + stride=1, + padding=0, + groups=1, + act='relu', + name=None): + conv = fluid.layers.conv2d( + input=data, + num_filters=num_filters, + filter_size=filter_size, + stride=stride, + padding=padding, + groups=groups, + act=None, + param_attr=ParamAttr(name=name + "_weights"), + bias_attr=False, + name=name) + bn_name = name + "_bn" + return fluid.layers.batch_norm( + input=conv, + act=act, + name=bn_name, + param_attr=ParamAttr(name=bn_name + "_scale"), + bias_attr=ParamAttr(name=bn_name + "_offset"), + moving_mean_name=bn_name + '_mean', + moving_variance_name=bn_name + '_variance') + + def inception_stem(self, data, name=None): + conv = self.conv_bn_layer( + data, 32, 3, stride=2, act='relu', name="conv1_3x3_s2") + conv = self.conv_bn_layer(conv, 32, 3, act='relu', name="conv2_3x3_s1") + conv = self.conv_bn_layer( + conv, 64, 3, padding=1, act='relu', name="conv3_3x3_s1") + + 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', name="inception_stem1_3x3_s2") + concat = fluid.layers.concat([pool1, conv2], axis=1) + + conv1 = self.conv_bn_layer( + concat, 64, 1, act='relu', name="inception_stem2_3x3_reduce") + conv1 = self.conv_bn_layer( + conv1, 96, 3, act='relu', name="inception_stem2_3x3") + + conv2 = self.conv_bn_layer( + concat, 64, 1, act='relu', name="inception_stem2_1x7_reduce") + conv2 = self.conv_bn_layer( + conv2, + 64, (7, 1), + padding=(3, 0), + act='relu', + name="inception_stem2_1x7") + conv2 = self.conv_bn_layer( + conv2, + 64, (1, 7), + padding=(0, 3), + act='relu', + name="inception_stem2_7x1") + conv2 = self.conv_bn_layer( + conv2, 96, 3, act='relu', name="inception_stem2_3x3_2") + + concat = fluid.layers.concat([conv1, conv2], axis=1) + + conv1 = self.conv_bn_layer( + concat, 192, 3, stride=2, act='relu', name="inception_stem3_3x3_s2") + 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, name=None): + 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', name="inception_a" + name + "_1x1") + + conv2 = self.conv_bn_layer( + data, 96, 1, act='relu', name="inception_a" + name + "_1x1_2") + + conv3 = self.conv_bn_layer( + data, 64, 1, act='relu', name="inception_a" + name + "_3x3_reduce") + conv3 = self.conv_bn_layer( + conv3, + 96, + 3, + padding=1, + act='relu', + name="inception_a" + name + "_3x3") + + conv4 = self.conv_bn_layer( + data, + 64, + 1, + act='relu', + name="inception_a" + name + "_3x3_2_reduce") + conv4 = self.conv_bn_layer( + conv4, + 96, + 3, + padding=1, + act='relu', + name="inception_a" + name + "_3x3_2") + conv4 = self.conv_bn_layer( + conv4, + 96, + 3, + padding=1, + act='relu', + name="inception_a" + name + "_3x3_3") + + concat = fluid.layers.concat([conv1, conv2, conv3, conv4], axis=1) + + return concat + + def reductionA(self, data, name=None): + 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', name="reduction_a_3x3") + + conv3 = self.conv_bn_layer( + data, 192, 1, act='relu', name="reduction_a_3x3_2_reduce") + conv3 = self.conv_bn_layer( + conv3, 224, 3, padding=1, act='relu', name="reduction_a_3x3_2") + conv3 = self.conv_bn_layer( + conv3, 256, 3, stride=2, act='relu', name="reduction_a_3x3_3") + + concat = fluid.layers.concat([pool1, conv2, conv3], axis=1) + + return concat + + def inceptionB(self, data, name=None): + 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', name="inception_b" + name + "_1x1") + + conv2 = self.conv_bn_layer( + data, 384, 1, act='relu', name="inception_b" + name + "_1x1_2") + + conv3 = self.conv_bn_layer( + data, 192, 1, act='relu', name="inception_b" + name + "_1x7_reduce") + conv3 = self.conv_bn_layer( + conv3, + 224, (1, 7), + padding=(0, 3), + act='relu', + name="inception_b" + name + "_1x7") + conv3 = self.conv_bn_layer( + conv3, + 256, (7, 1), + padding=(3, 0), + act='relu', + name="inception_b" + name + "_7x1") + + conv4 = self.conv_bn_layer( + data, + 192, + 1, + act='relu', + name="inception_b" + name + "_7x1_2_reduce") + conv4 = self.conv_bn_layer( + conv4, + 192, (1, 7), + padding=(0, 3), + act='relu', + name="inception_b" + name + "_1x7_2") + conv4 = self.conv_bn_layer( + conv4, + 224, (7, 1), + padding=(3, 0), + act='relu', + name="inception_b" + name + "_7x1_2") + conv4 = self.conv_bn_layer( + conv4, + 224, (1, 7), + padding=(0, 3), + act='relu', + name="inception_b" + name + "_1x7_3") + conv4 = self.conv_bn_layer( + conv4, + 256, (7, 1), + padding=(3, 0), + act='relu', + name="inception_b" + name + "_7x1_3") + + concat = fluid.layers.concat([conv1, conv2, conv3, conv4], axis=1) + + return concat + + def reductionB(self, data, name=None): + 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', name="reduction_b_3x3_reduce") + conv2 = self.conv_bn_layer( + conv2, 192, 3, stride=2, act='relu', name="reduction_b_3x3") + + conv3 = self.conv_bn_layer( + data, 256, 1, act='relu', name="reduction_b_1x7_reduce") + conv3 = self.conv_bn_layer( + conv3, + 256, (1, 7), + padding=(0, 3), + act='relu', + name="reduction_b_1x7") + conv3 = self.conv_bn_layer( + conv3, + 320, (7, 1), + padding=(3, 0), + act='relu', + name="reduction_b_7x1") + conv3 = self.conv_bn_layer( + conv3, 320, 3, stride=2, act='relu', name="reduction_b_3x3_2") + + concat = fluid.layers.concat([pool1, conv2, conv3], axis=1) + + return concat + + def inceptionC(self, data, name=None): + 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', name="inception_c" + name + "_1x1") + + conv2 = self.conv_bn_layer( + data, 256, 1, act='relu', name="inception_c" + name + "_1x1_2") + + conv3 = self.conv_bn_layer( + data, 384, 1, act='relu', name="inception_c" + name + "_1x1_3") + conv3_1 = self.conv_bn_layer( + conv3, + 256, (1, 3), + padding=(0, 1), + act='relu', + name="inception_c" + name + "_1x3") + conv3_2 = self.conv_bn_layer( + conv3, + 256, (3, 1), + padding=(1, 0), + act='relu', + name="inception_c" + name + "_3x1") + + conv4 = self.conv_bn_layer( + data, 384, 1, act='relu', name="inception_c" + name + "_1x1_4") + conv4 = self.conv_bn_layer( + conv4, + 448, (1, 3), + padding=(0, 1), + act='relu', + name="inception_c" + name + "_1x3_2") + conv4 = self.conv_bn_layer( + conv4, + 512, (3, 1), + padding=(1, 0), + act='relu', + name="inception_c" + name + "_3x1_2") + conv4_1 = self.conv_bn_layer( + conv4, + 256, (1, 3), + padding=(0, 1), + act='relu', + name="inception_c" + name + "_1x3_3") + conv4_2 = self.conv_bn_layer( + conv4, + 256, (3, 1), + padding=(1, 0), + act='relu', + name="inception_c" + name + "_3x1_3") + + concat = fluid.layers.concat( + [conv1, conv2, conv3_1, conv3_2, conv4_1, conv4_2], axis=1) + + return concat diff --git a/fluid/PaddleCV/image_classification/models_name/mobilenet.py b/fluid/PaddleCV/image_classification/models_name/mobilenet.py new file mode 100644 index 00000000..2ac6b46a --- /dev/null +++ b/fluid/PaddleCV/image_classification/models_name/mobilenet.py @@ -0,0 +1,196 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +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=1000, 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, + name="conv1") + + # 56x56 + input = self.depthwise_separable( + input, + num_filters1=32, + num_filters2=64, + num_groups=32, + stride=1, + scale=scale, + name="conv2_1") + + input = self.depthwise_separable( + input, + num_filters1=64, + num_filters2=128, + num_groups=64, + stride=2, + scale=scale, + name="conv2_2") + + # 28x28 + input = self.depthwise_separable( + input, + num_filters1=128, + num_filters2=128, + num_groups=128, + stride=1, + scale=scale, + name="conv3_1") + + input = self.depthwise_separable( + input, + num_filters1=128, + num_filters2=256, + num_groups=128, + stride=2, + scale=scale, + name="conv3_2") + + # 14x14 + input = self.depthwise_separable( + input, + num_filters1=256, + num_filters2=256, + num_groups=256, + stride=1, + scale=scale, + name="conv4_1") + + input = self.depthwise_separable( + input, + num_filters1=256, + num_filters2=512, + num_groups=256, + stride=2, + scale=scale, + name="conv4_2") + + # 14x14 + for i in range(5): + input = self.depthwise_separable( + input, + num_filters1=512, + num_filters2=512, + num_groups=512, + stride=1, + scale=scale, + name="conv5" + "_" + str(i + 1)) + # 7x7 + input = self.depthwise_separable( + input, + num_filters1=512, + num_filters2=1024, + num_groups=512, + stride=2, + scale=scale, + name="conv5_6") + + input = self.depthwise_separable( + input, + num_filters1=1024, + num_filters2=1024, + num_groups=1024, + stride=1, + scale=scale, + name="conv6") + + 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(), name="fc7_weights"), + bias_attr=ParamAttr(name="fc7_offset")) + return output + + def conv_bn_layer(self, + input, + filter_size, + num_filters, + stride, + padding, + channels=None, + num_groups=1, + act='relu', + use_cudnn=True, + name=None): + 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(), name=name + "_weights"), + bias_attr=False) + bn_name = name + "_bn" + return fluid.layers.batch_norm( + input=conv, + act=act, + param_attr=ParamAttr(name=bn_name + "_scale"), + bias_attr=ParamAttr(name=bn_name + "_offset"), + moving_mean_name=bn_name + '_mean', + moving_variance_name=bn_name + '_variance') + + def depthwise_separable(self, + input, + num_filters1, + num_filters2, + num_groups, + stride, + scale, + name=None): + 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, + name=name + "_dw") + + pointwise_conv = self.conv_bn_layer( + input=depthwise_conv, + filter_size=1, + num_filters=int(num_filters2 * scale), + stride=1, + padding=0, + name=name + "_sep") + return pointwise_conv diff --git a/fluid/PaddleCV/image_classification/models_name/mobilenet_v2.py b/fluid/PaddleCV/image_classification/models_name/mobilenet_v2.py new file mode 100644 index 00000000..442bd67f --- /dev/null +++ b/fluid/PaddleCV/image_classification/models_name/mobilenet_v2.py @@ -0,0 +1,199 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +import paddle.fluid as fluid +from paddle.fluid.initializer import MSRA +from paddle.fluid.param_attr import ParamAttr + +__all__ = ['MobileNetV2'] + +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 MobileNetV2(): + def __init__(self): + self.params = train_parameters + + def net(self, input, class_dim=1000, scale=1.0): + + bottleneck_params_list = [ + (1, 16, 1, 1), + (6, 24, 2, 2), + (6, 32, 3, 2), + (6, 64, 4, 2), + (6, 96, 3, 1), + (6, 160, 3, 2), + (6, 320, 1, 1), + ] + + #conv1 + input = self.conv_bn_layer( + input, + num_filters=int(32 * scale), + filter_size=3, + stride=2, + padding=1, + if_act=True, + name='conv1_1') + + # bottleneck sequences + i = 1 + in_c = int(32 * scale) + for layer_setting in bottleneck_params_list: + t, c, n, s = layer_setting + i += 1 + input = self.invresi_blocks( + input=input, + in_c=in_c, + t=t, + c=int(c * scale), + n=n, + s=s, + name='conv' + str(i)) + in_c = int(c * scale) + #last_conv + input = self.conv_bn_layer( + input=input, + num_filters=int(1280 * scale) if scale > 1.0 else 1280, + filter_size=1, + stride=1, + padding=0, + if_act=True, + name='conv9') + + input = fluid.layers.pool2d( + input=input, + pool_size=7, + pool_stride=1, + pool_type='avg', + global_pooling=True) + + output = fluid.layers.fc(input=input, + size=class_dim, + act='softmax', + param_attr=ParamAttr(name='fc10_weights'), + bias_attr=ParamAttr(name='fc10_offset')) + return output + + def conv_bn_layer(self, + input, + filter_size, + num_filters, + stride, + padding, + channels=None, + num_groups=1, + if_act=True, + name=None, + 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(name=name + '_weights'), + bias_attr=False) + bn_name = name + '_bn' + bn = fluid.layers.batch_norm( + input=conv, + param_attr=ParamAttr(name=bn_name + "_scale"), + bias_attr=ParamAttr(name=bn_name + "_offset"), + moving_mean_name=bn_name + '_mean', + moving_variance_name=bn_name + '_variance') + if if_act: + return fluid.layers.relu6(bn) + else: + return bn + + def shortcut(self, input, data_residual): + return fluid.layers.elementwise_add(input, data_residual) + + def inverted_residual_unit(self, + input, + num_in_filter, + num_filters, + ifshortcut, + stride, + filter_size, + padding, + expansion_factor, + name=None): + num_expfilter = int(round(num_in_filter * expansion_factor)) + + channel_expand = self.conv_bn_layer( + input=input, + num_filters=num_expfilter, + filter_size=1, + stride=1, + padding=0, + num_groups=1, + if_act=True, + name=name + '_expand') + + bottleneck_conv = self.conv_bn_layer( + input=channel_expand, + num_filters=num_expfilter, + filter_size=filter_size, + stride=stride, + padding=padding, + num_groups=num_expfilter, + if_act=True, + name=name + '_dwise', + use_cudnn=False) + + linear_out = self.conv_bn_layer( + input=bottleneck_conv, + num_filters=num_filters, + filter_size=1, + stride=1, + padding=0, + num_groups=1, + if_act=False, + name=name + '_linear') + if ifshortcut: + out = self.shortcut(input=input, data_residual=linear_out) + return out + else: + return linear_out + + def invresi_blocks(self, input, in_c, t, c, n, s, name=None): + first_block = self.inverted_residual_unit( + input=input, + num_in_filter=in_c, + num_filters=c, + ifshortcut=False, + stride=s, + filter_size=3, + padding=1, + expansion_factor=t, + name=name + '_1') + + last_residual_block = first_block + last_c = c + + for i in range(1, n): + last_residual_block = self.inverted_residual_unit( + input=last_residual_block, + num_in_filter=last_c, + num_filters=c, + ifshortcut=True, + stride=1, + filter_size=3, + padding=1, + expansion_factor=t, + name=name + '_' + str(i + 1)) + return last_residual_block diff --git a/fluid/PaddleCV/image_classification/models_name/resnet.py b/fluid/PaddleCV/image_classification/models_name/resnet.py new file mode 100644 index 00000000..095bd155 --- /dev/null +++ b/fluid/PaddleCV/image_classification/models_name/resnet.py @@ -0,0 +1,162 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +import paddle +import paddle.fluid as fluid +import math +from paddle.fluid.param_attr import ParamAttr + +__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=1000): + 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', + name="conv1") + 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]): + if layers in [101, 152] and block == 2: + if i == 0: + conv_name = "res" + str(block + 2) + "a" + else: + conv_name = "res" + str(block + 2) + "b" + str(i) + else: + conv_name = "res" + str(block + 2) + chr(97 + i) + conv = self.bottleneck_block( + input=conv, + num_filters=num_filters[block], + stride=2 if i == 0 and block != 0 else 1, + name=conv_name) + + 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, + name=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, + param_attr=ParamAttr(name=name + "_weights"), + bias_attr=False, + name=name + '.conv2d.output.1') + if name == "conv1": + bn_name = "bn_" + name + else: + bn_name = "bn" + name[3:] + return fluid.layers.batch_norm( + input=conv, + act=act, + name=bn_name + '.output.1', + param_attr=ParamAttr(name=bn_name + '_scale'), + bias_attr=ParamAttr(bn_name + '_offset'), + moving_mean_name=bn_name + '_mean', + moving_variance_name=bn_name + '_variance', ) + + def shortcut(self, input, ch_out, stride, name): + ch_in = input.shape[1] + if ch_in != ch_out or stride != 1: + return self.conv_bn_layer(input, ch_out, 1, stride, name=name) + else: + return input + + def bottleneck_block(self, input, num_filters, stride, name): + conv0 = self.conv_bn_layer( + input=input, + num_filters=num_filters, + filter_size=1, + act='relu', + name=name + "_branch2a") + conv1 = self.conv_bn_layer( + input=conv0, + num_filters=num_filters, + filter_size=3, + stride=stride, + act='relu', + name=name + "_branch2b") + conv2 = self.conv_bn_layer( + input=conv1, + num_filters=num_filters * 4, + filter_size=1, + act=None, + name=name + "_branch2c") + + short = self.shortcut( + input, num_filters * 4, stride, name=name + "_branch1") + + return fluid.layers.elementwise_add( + x=short, y=conv2, act='relu', name=name + ".add.output.5") + + +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/PaddleCV/image_classification/models_name/se_resnext.py b/fluid/PaddleCV/image_classification/models_name/se_resnext.py new file mode 100644 index 00000000..e083c524 --- /dev/null +++ b/fluid/PaddleCV/image_classification/models_name/se_resnext.py @@ -0,0 +1,247 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +import paddle +import paddle.fluid as fluid +import math +from paddle.fluid.param_attr import ParamAttr + +__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], + "dropout_seed": None, + "learning_strategy": { + "name": "piecewise_decay", + "batch_size": 256, + "epochs": [40, 80, 100], + "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=1000): + 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', + name='conv1', ) + 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', + name="conv1", ) + 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', + name='conv1') + conv = self.conv_bn_layer( + input=conv, + num_filters=64, + filter_size=3, + stride=1, + act='relu', + name='conv2') + conv = self.conv_bn_layer( + input=conv, + num_filters=128, + filter_size=3, + stride=1, + act='relu', + name='conv3') + conv = fluid.layers.pool2d( + input=conv, pool_size=3, pool_stride=2, pool_padding=1, \ + pool_type='max') + n = 1 if layers == 50 or layers == 101 else 3 + for block in range(len(depth)): + n += 1 + 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, + name=str(n) + '_' + str(i + 1)) + + 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, seed=self.params['dropout_seed']) + stdv = 1.0 / math.sqrt(drop.shape[1] * 1.0) + out = fluid.layers.fc( + input=drop, + size=class_dim, + act='softmax', + param_attr=ParamAttr( + initializer=fluid.initializer.Uniform(-stdv, stdv), + name='fc6_weights'), + bias_attr=ParamAttr(name='fc6_offset')) + return out + + def shortcut(self, input, ch_out, stride, name): + 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, name='conv' + name + '_prj') + else: + return input + + def bottleneck_block(self, + input, + num_filters, + stride, + cardinality, + reduction_ratio, + name=None): + conv0 = self.conv_bn_layer( + input=input, + num_filters=num_filters, + filter_size=1, + act='relu', + name='conv' + name + '_x1') + conv1 = self.conv_bn_layer( + input=conv0, + num_filters=num_filters, + filter_size=3, + stride=stride, + groups=cardinality, + act='relu', + name='conv' + name + '_x2') + conv2 = self.conv_bn_layer( + input=conv1, + num_filters=num_filters * 2, + filter_size=1, + act=None, + name='conv' + name + '_x3') + scale = self.squeeze_excitation( + input=conv2, + num_channels=num_filters * 2, + reduction_ratio=reduction_ratio, + name='fc' + name) + + short = self.shortcut(input, num_filters * 2, stride, name=name) + + 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, + name=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, + param_attr=ParamAttr(name=name + '_weights'), ) + bn_name = name + "_bn" + return fluid.layers.batch_norm( + input=conv, + act=act, + param_attr=ParamAttr(name=bn_name + '_scale'), + bias_attr=ParamAttr(bn_name + '_offset'), + moving_mean_name=bn_name + '_mean', + moving_variance_name=bn_name + '_variance') + + def squeeze_excitation(self, + input, + num_channels, + reduction_ratio, + name=None): + 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), + name=name + '_sqz_weights'), + bias_attr=ParamAttr(name=name + '_sqz_offset')) + 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), + name=name + '_exc_weights'), + bias_attr=ParamAttr(name=name + '_exc_offset')) + 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/PaddleCV/image_classification/models_name/shufflenet_v2.py b/fluid/PaddleCV/image_classification/models_name/shufflenet_v2.py new file mode 100644 index 00000000..1cd4767e --- /dev/null +++ b/fluid/PaddleCV/image_classification/models_name/shufflenet_v2.py @@ -0,0 +1,289 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +import paddle.fluid as fluid +from paddle.fluid.initializer import MSRA +from paddle.fluid.param_attr import ParamAttr + +__all__ = [ + 'ShuffleNetV2', 'ShuffleNetV2_x0_5', 'ShuffleNetV2_x1_0', + 'ShuffleNetV2_x1_5', 'ShuffleNetV2_x2_0' +] + +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 ShuffleNetV2(): + def __init__(self, scale=1.0): + self.params = train_parameters + self.scale = scale + + def net(self, input, class_dim=1000): + scale = self.scale + stage_repeats = [4, 8, 4] + + if scale == 0.5: + stage_out_channels = [-1, 24, 48, 96, 192, 1024] + elif scale == 1.0: + stage_out_channels = [-1, 24, 116, 232, 464, 1024] + elif scale == 1.5: + stage_out_channels = [-1, 24, 176, 352, 704, 1024] + elif scale == 2.0: + stage_out_channels = [-1, 24, 224, 488, 976, 2048] + else: + raise ValueError("""{} groups is not supported for + 1x1 Grouped Convolutions""".format(num_groups)) + + #conv1 + + input_channel = stage_out_channels[1] + conv1 = self.conv_bn_layer( + input=input, + filter_size=3, + num_filters=input_channel, + padding=1, + stride=2, + name='stage1_conv') + pool1 = fluid.layers.pool2d( + input=conv1, + pool_size=3, + pool_stride=2, + pool_padding=1, + pool_type='max') + conv = pool1 + # bottleneck sequences + for idxstage in range(len(stage_repeats)): + numrepeat = stage_repeats[idxstage] + output_channel = stage_out_channels[idxstage + 2] + for i in range(numrepeat): + if i == 0: + conv = self.inverted_residual_unit( + input=conv, + num_filters=output_channel, + stride=2, + benchmodel=2, + name=str(idxstage + 2) + '_' + str(i + 1)) + else: + conv = self.inverted_residual_unit( + input=conv, + num_filters=output_channel, + stride=1, + benchmodel=1, + name=str(idxstage + 2) + '_' + str(i + 1)) + + conv_last = self.conv_bn_layer( + input=conv, + filter_size=1, + num_filters=stage_out_channels[-1], + padding=0, + stride=1, + name='conv5') + pool_last = fluid.layers.pool2d( + input=conv_last, + pool_size=7, + pool_stride=1, + pool_padding=0, + pool_type='avg') + + output = fluid.layers.fc(input=pool_last, + size=class_dim, + act='softmax', + param_attr=ParamAttr( + initializer=MSRA(), name='fc6_weights'), + bias_attr=ParamAttr(name='fc6_offset')) + return output + + def conv_bn_layer(self, + input, + filter_size, + num_filters, + stride, + padding, + num_groups=1, + use_cudnn=True, + if_act=True, + name=None): + # print(num_groups) + 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(), name=name + '_weights'), + bias_attr=False) + bn_name = name + '_bn' + if if_act: + return fluid.layers.batch_norm( + input=conv, + act='relu', + param_attr=ParamAttr(name=bn_name + "_scale"), + bias_attr=ParamAttr(name=bn_name + "_offset"), + moving_mean_name=bn_name + '_mean', + moving_variance_name=bn_name + '_variance') + else: + return fluid.layers.batch_norm( + input=conv, + param_attr=ParamAttr(name=bn_name + "_scale"), + bias_attr=ParamAttr(name=bn_name + "_offset"), + moving_mean_name=bn_name + '_mean', + moving_variance_name=bn_name + '_variance') + + def channel_shuffle(self, x, groups): + batchsize, num_channels, height, width = x.shape[0], x.shape[ + 1], x.shape[2], x.shape[3] + channels_per_group = num_channels // groups + + # reshape + x = fluid.layers.reshape( + x=x, shape=[batchsize, groups, channels_per_group, height, width]) + + x = fluid.layers.transpose(x=x, perm=[0, 2, 1, 3, 4]) + + # flatten + x = fluid.layers.reshape( + x=x, shape=[batchsize, num_channels, height, width]) + + return x + + def inverted_residual_unit(self, + input, + num_filters, + stride, + benchmodel, + name=None): + assert stride in [1, 2], \ + "supported stride are {} but your stride is {}".format([1,2], stride) + + oup_inc = num_filters // 2 + inp = input.shape[1] + + if benchmodel == 1: + x1, x2 = fluid.layers.split( + input, + num_or_sections=[input.shape[1] // 2, input.shape[1] // 2], + dim=1) + # x1 = input[:, :(input.shape[1]//2), :, :] + # x2 = input[:, (input.shape[1]//2):, :, :] + + conv_pw = self.conv_bn_layer( + input=x2, + num_filters=oup_inc, + filter_size=1, + stride=1, + padding=0, + num_groups=1, + if_act=True, + name='stage_' + name + '_conv1') + + conv_dw = self.conv_bn_layer( + input=conv_pw, + num_filters=oup_inc, + filter_size=3, + stride=stride, + padding=1, + num_groups=oup_inc, + if_act=False, + name='stage_' + name + '_conv2') + + conv_linear = self.conv_bn_layer( + input=conv_dw, + num_filters=oup_inc, + filter_size=1, + stride=1, + padding=0, + num_groups=1, + if_act=True, + name='stage_' + name + '_conv3') + + out = fluid.layers.concat([x1, conv_linear], axis=1) + + else: + #branch1 + conv_dw_1 = self.conv_bn_layer( + input=input, + num_filters=inp, + filter_size=3, + stride=stride, + padding=1, + num_groups=inp, + if_act=False, + name='stage_' + name + '_conv4') + + conv_linear_1 = self.conv_bn_layer( + input=conv_dw_1, + num_filters=oup_inc, + filter_size=1, + stride=1, + padding=0, + num_groups=1, + if_act=True, + name='stage_' + name + '_conv5') + + #branch2 + conv_pw_2 = self.conv_bn_layer( + input=input, + num_filters=oup_inc, + filter_size=1, + stride=1, + padding=0, + num_groups=1, + if_act=True, + name='stage_' + name + '_conv1') + + conv_dw_2 = self.conv_bn_layer( + input=conv_pw_2, + num_filters=oup_inc, + filter_size=3, + stride=stride, + padding=1, + num_groups=oup_inc, + if_act=False, + name='stage_' + name + '_conv2') + + conv_linear_2 = self.conv_bn_layer( + input=conv_dw_2, + num_filters=oup_inc, + filter_size=1, + stride=1, + padding=0, + num_groups=1, + if_act=True, + name='stage_' + name + '_conv3') + out = fluid.layers.concat([conv_linear_1, conv_linear_2], axis=1) + + return self.channel_shuffle(out, 2) + + +def ShuffleNetV2_x0_5(): + model = ShuffleNetV2(scale=0.5) + return model + + +def ShuffleNetV2_x1_0(): + model = ShuffleNetV2(scale=1.0) + return model + + +def ShuffleNetV2_x1_5(): + model = ShuffleNetV2(scale=1.5) + return model + + +def ShuffleNetV2_x2_0(): + model = ShuffleNetV2(scale=2.0) + return model diff --git a/fluid/PaddleCV/image_classification/models_name/vgg.py b/fluid/PaddleCV/image_classification/models_name/vgg.py new file mode 100644 index 00000000..ac26791a --- /dev/null +++ b/fluid/PaddleCV/image_classification/models_name/vgg.py @@ -0,0 +1,105 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +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=1000): + 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], name="conv1_") + conv2 = self.conv_block(conv1, 128, nums[1], name="conv2_") + conv3 = self.conv_block(conv2, 256, nums[2], name="conv3_") + conv4 = self.conv_block(conv3, 512, nums[3], name="conv4_") + conv5 = self.conv_block(conv4, 512, nums[4], name="conv5_") + + fc_dim = 4096 + fc_name = ["fc6", "fc7", "fc8"] + fc1 = fluid.layers.fc( + input=conv5, + size=fc_dim, + act='relu', + param_attr=fluid.param_attr.ParamAttr(name=fc_name[0] + "_weights"), + bias_attr=fluid.param_attr.ParamAttr(name=fc_name[0] + "_offset")) + 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(name=fc_name[1] + "_weights"), + bias_attr=fluid.param_attr.ParamAttr(name=fc_name[1] + "_offset")) + 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(name=fc_name[2] + "_weights"), + bias_attr=fluid.param_attr.ParamAttr(name=fc_name[2] + "_offset")) + + return out + + def conv_block(self, input, num_filter, groups, name=None): + 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( + name=name + str(i + 1) + "_weights"), + bias_attr=fluid.param_attr.ParamAttr( + name=name + str(i + 1) + "_offset")) + 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/PaddleCV/image_classification/reader.py b/fluid/PaddleCV/image_classification/reader.py index 639b0b01..316b956a 100644 --- a/fluid/PaddleCV/image_classification/reader.py +++ b/fluid/PaddleCV/image_classification/reader.py @@ -54,7 +54,7 @@ def random_crop(img, size, scale=[0.08, 1.0], ratio=[3. / 4., 4. / 3.]): scale_min = min(scale[0], bound) target_area = img.size[0] * img.size[1] * np.random.uniform(scale_min, - scale_max) + scale_max) target_size = math.sqrt(target_area) w = int(target_size * w) h = int(target_size * h) @@ -169,7 +169,12 @@ def _reader_creator(file_list, def train(data_dir=DATA_DIR): file_list = os.path.join(data_dir, 'train_list.txt') return _reader_creator( - file_list, 'train', shuffle=True, color_jitter=False, rotate=False, data_dir=data_dir) + file_list, + 'train', + shuffle=True, + color_jitter=False, + rotate=False, + data_dir=data_dir) def val(data_dir=DATA_DIR): diff --git a/fluid/PaddleCV/image_classification/run.sh b/fluid/PaddleCV/image_classification/run.sh new file mode 100644 index 00000000..da50b49d --- /dev/null +++ b/fluid/PaddleCV/image_classification/run.sh @@ -0,0 +1,80 @@ +#Hyperparameters config +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 +# >log_SE_ResNeXt50_32x4d.txt 2>&1 & + +#AlexNet: +#python train.py \ +# --model=AlexNet \ +# --batch_size=256 \ +# --total_images=1281167 \ +# --class_dim=1000 \ +# --image_shape=3,224,224 \ +# --model_save_dir=output/ \ +# --with_mem_opt=False \ +# --lr_strategy=piecewise_decay \ +# --num_epochs=120 \ +# --lr=0.01 + +#VGG11: +#python train.py \ +# --model=VGG11 \ +# --batch_size=512 \ +# --total_images=1281167 \ +# --class_dim=1000 \ +# --image_shape=3,224,224 \ +# --model_save_dir=output/ \ +# --with_mem_opt=False \ +# --lr_strategy=piecewise_decay \ +# --num_epochs=120 \ +# --lr=0.1 + + +#MobileNet v1: +#python train.py \ +# --model=MobileNet \ +# --batch_size=256 \ +# --total_images=1281167 \ +# --class_dim=1000 \ +# --image_shape=3,224,224 \ +# --model_save_dir=output/ \ +# --with_mem_opt=False \ +# --lr_strategy=piecewise_decay \ +# --num_epochs=120 \ +# --lr=0.1 + + +#ResNet50: +#python train.py \ +# --model=ResNet50 \ +# --batch_size=256 \ +# --total_images=1281167 \ +# --class_dim=1000 \ +# --image_shape=3,224,224 \ +# --model_save_dir=output/ \ +# --with_mem_opt=False \ +# --lr_strategy=piecewise_decay \ +# --num_epochs=120 \ +# --lr=0.1 + +#ResNet101: +#python train.py \ +# --model=ResNet101 \ +# --batch_size=256 \ +# --total_images=1281167 \ +# --class_dim=1000 \ +# --image_shape=3,224,224 \ +# --model_save_dir=output/ \ +# --with_mem_opt=False \ +# --lr_strategy=piecewise_decay \ +# --num_epochs=120 \ +# --lr=0.1 + diff --git a/fluid/PaddleCV/image_classification/train.py b/fluid/PaddleCV/image_classification/train.py index 238c322b..e658a311 100644 --- a/fluid/PaddleCV/image_classification/train.py +++ b/fluid/PaddleCV/image_classification/train.py @@ -13,8 +13,13 @@ import paddle.dataset.flowers as flowers import models import reader import argparse -from models.learning_rate import cosine_decay +import functools +import subprocess +import utils +from utils.learning_rate import cosine_decay from utility import add_arguments, print_arguments +import models +import models_name parser = argparse.ArgumentParser(description=__doc__) add_arg = functools.partial(add_arguments, argparser=parser) @@ -34,20 +39,25 @@ add_arg('lr_strategy', str, "piecewise_decay", "Set the learning rate add_arg('model', str, "SE_ResNeXt50_32x4d", "Set the network to use.") add_arg('enable_ce', bool, False, "If set True, enable continuous evaluation job.") add_arg('data_dir', str, "./data/ILSVRC2012", "The ImageNet dataset root dir.") -# yapf: enable +add_arg('model_category', str, "models", "Whether to use models_name or not, valid value:'models','models_name'" ) +# yapf: enabl -model_list = [m for m in dir(models) if "__" not in m] + +def set_models(model): + global models + if model == "models": + models = models + else: + models = models_name 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"] - batch_size = ls["batch_size"] step = int(total_images / batch_size + 1) @@ -60,6 +70,7 @@ def optimizer_setting(params): boundaries=bd, values=lr), momentum=0.9, regularization=fluid.regularizer.L2Decay(1e-4)) + elif ls["name"] == "cosine_decay": if "total_images" not in params: total_images = 1281167 @@ -76,7 +87,29 @@ def optimizer_setting(params): learning_rate=cosine_decay( learning_rate=lr, step_each_epoch=step, epochs=num_epochs), momentum=0.9, - regularization=fluid.regularizer.L2Decay(1e-4)) + regularization=fluid.regularizer.L2Decay(4e-5)) + elif ls["name"] == "exponential_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"] + learning_decay_rate_factor=ls["learning_decay_rate_factor"] + num_epochs_per_decay = ls["num_epochs_per_decay"] + NUM_GPUS = 1 + + optimizer = fluid.optimizer.Momentum( + learning_rate=fluid.layers.exponential_decay( + learning_rate = lr * NUM_GPUS, + decay_steps = step * num_epochs_per_decay / NUM_GPUS, + decay_rate = learning_decay_rate_factor), + momentum=0.9, + + regularization = fluid.regularizer.L2Decay(4e-5)) + else: lr = params["lr"] optimizer = fluid.optimizer.Momentum( @@ -86,29 +119,16 @@ def optimizer_setting(params): return optimizer +def net_config(image, label, model, args): + model_list = [m for m in dir(models) if "__" not in m] + assert args.model in model_list,"{} is not lists: {}".format( + args.model, model_list) -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(",")] - - 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') - - # model definition - model = models.__dict__[model_name]() if args.enable_ce: assert model_name == "SE_ResNeXt50_32x4d" - fluid.default_startup_program().random_seed = 1000 model.params["dropout_seed"] = 100 class_dim = 102 @@ -132,42 +152,101 @@ def train(args): 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) + return avg_cost, acc_top1, acc_top5 + + +def build_program(is_train, main_prog, startup_prog, args): + image_shape = [int(m) for m in args.image_shape.split(",")] + model_name = args.model + model_list = [m for m in dir(models) if "__" not in m] + assert model_name in model_list, "{} is not in lists: {}".format(args.model, + model_list) + model = models.__dict__[model_name]() + with fluid.program_guard(main_prog, startup_prog): + py_reader = fluid.layers.py_reader( + capacity=16, + shapes=[[-1] + image_shape, [-1, 1]], + lod_levels=[0, 0], + dtypes=["float32", "int64"], + use_double_buffer=True) + with fluid.unique_name.guard(): + image, label = fluid.layers.read_file(py_reader) + avg_cost, acc_top1, acc_top5 = net_config(image, label, model, args) + avg_cost.persistable = True + acc_top1.persistable = True + acc_top5.persistable = True + if is_train: + 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 + + optimizer = optimizer_setting(params) + optimizer.minimize(avg_cost) + + return py_reader, avg_cost, acc_top1, acc_top5 + + +def train(args): + # parameters from arguments + 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 - # 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 + startup_prog = fluid.Program() + train_prog = fluid.Program() + test_prog = fluid.Program() - # initialize optimizer - optimizer = optimizer_setting(params) - opts = optimizer.minimize(avg_cost) + if args.enable_ce: + startup_prog.random_seed = 1000 + train_prog.random_seed = 1000 + + train_py_reader, train_cost, train_acc1, train_acc5 = build_program( + is_train=True, + main_prog=train_prog, + startup_prog=startup_prog, + args=args) + test_py_reader, test_cost, test_acc1, test_acc5 = build_program( + is_train=False, + main_prog=test_prog, + startup_prog=startup_prog, + args=args) + test_prog = test_prog.clone(for_test=True) if with_memory_optimization: - fluid.memory_optimize(fluid.default_main_program()) + fluid.memory_optimize(train_prog) + fluid.memory_optimize(test_prog) place = fluid.CUDAPlace(0) if args.use_gpu else fluid.CPUPlace() exe = fluid.Executor(place) - exe.run(fluid.default_startup_program()) + exe.run(startup_prog) if checkpoint is not None: - fluid.io.load_persistables(exe, checkpoint) + fluid.io.load_persistables(exe, checkpoint, main_program=train_prog) 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) + fluid.io.load_vars( + exe, pretrained_model, main_program=train_prog, predicate=if_exist) - train_batch_size = args.batch_size - test_batch_size = 16 + visible_device = os.getenv('CUDA_VISIBLE_DEVICES') + if visible_device: + device_num = len(visible_device.split(',')) + else: + device_num = subprocess.check_output(['nvidia-smi', '-L']).count('\n') + train_batch_size = args.batch_size / device_num + test_batch_size = 8 if not args.enable_ce: - train_reader = paddle.batch(reader.train(), batch_size=train_batch_size) + train_reader = paddle.batch( + reader.train(), batch_size=train_batch_size, drop_last=True) test_reader = paddle.batch(reader.val(), batch_size=test_batch_size) else: # use flowers dataset for CE and set use_xmap False to avoid disorder data @@ -176,89 +255,105 @@ def train(args): random.seed(0) np.random.seed(0) train_reader = paddle.batch( - flowers.train(use_xmap=False), batch_size=train_batch_size) + flowers.train(use_xmap=False), + batch_size=train_batch_size, + drop_last=True) test_reader = paddle.batch( flowers.test(use_xmap=False), batch_size=test_batch_size) - feeder = fluid.DataFeeder(place=place, feed_list=[image, label]) - + train_py_reader.decorate_paddle_reader(train_reader) + test_py_reader.decorate_paddle_reader(test_reader) train_exe = fluid.ParallelExecutor( - use_cuda=True if args.use_gpu else False, loss_name=avg_cost.name) + main_program=train_prog, + use_cuda=bool(args.use_gpu), + loss_name=train_cost.name) + + train_fetch_list = [train_cost.name, train_acc1.name, train_acc5.name] + test_fetch_list = [test_cost.name, test_acc1.name, test_acc5.name] - fetch_list = [avg_cost.name, acc_top1.name, acc_top5.name] + params = models.__dict__[args.model]().params - gpu = os.getenv("CUDA_VISIBLE_DEVICES") or "" - gpu_nums = len(gpu.split(",")) for pass_id in range(params["num_epochs"]): + + train_py_reader.start() + train_info = [[], [], []] test_info = [[], [], []] train_time = [] - for batch_id, data in enumerate(train_reader()): - t1 = time.time() - loss, acc1, acc5 = train_exe.run(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)) - train_info[0].append(loss) - train_info[1].append(acc1) - train_info[2].append(acc5) - train_time.append(period) - if batch_id % 10 == 0: - print("Pass {0}, trainbatch {1}, loss {2}, \ - acc1 {3}, acc5 {4} time {5}" - .format(pass_id, \ - batch_id, loss, acc1, acc5, \ - "%2.2f sec" % period)) - sys.stdout.flush() + batch_id = 0 + try: + while True: + t1 = time.time() + loss, acc1, acc5 = train_exe.run(fetch_list=train_fetch_list) + t2 = time.time() + period = t2 - t1 + loss = np.mean(np.array(loss)) + acc1 = np.mean(np.array(acc1)) + acc5 = np.mean(np.array(acc5)) + train_info[0].append(loss) + train_info[1].append(acc1) + train_info[2].append(acc5) + train_time.append(period) + if batch_id % 10 == 0: + print("Pass {0}, trainbatch {1}, loss {2}, \ + acc1 {3}, acc5 {4} time {5}" + .format(pass_id, batch_id, loss, acc1, acc5, + "%2.2f sec" % period)) + sys.stdout.flush() + batch_id += 1 + except fluid.core.EOFException: + train_py_reader.reset() train_loss = np.array(train_info[0]).mean() train_acc1 = np.array(train_info[1]).mean() train_acc5 = np.array(train_info[2]).mean() train_speed = np.array(train_time).mean() / train_batch_size - 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(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, \ - test_batch_id, loss, acc1, acc5, \ - "%2.2f sec" % period)) - sys.stdout.flush() - - test_loss = np.sum(test_info[0]) / cnt - test_acc1 = np.sum(test_info[1]) / cnt - test_acc5 = np.sum(test_info[2]) / cnt + + test_py_reader.start() + + test_batch_id = 0 + try: + while True: + t1 = time.time() + loss, acc1, acc5 = exe.run(program=test_prog, + fetch_list=test_fetch_list) + t2 = time.time() + period = t2 - t1 + loss = np.mean(loss) + acc1 = np.mean(acc1) + acc5 = np.mean(acc5) + test_info[0].append(loss) + test_info[1].append(acc1) + test_info[2].append(acc5) + if test_batch_id % 10 == 0: + print("Pass {0},testbatch {1},loss {2}, \ + acc1 {3},acc5 {4},time {5}" + .format(pass_id, test_batch_id, loss, acc1, acc5, + "%2.2f sec" % period)) + sys.stdout.flush() + test_batch_id += 1 + except fluid.core.EOFException: + test_py_reader.reset() + + 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, \ - train_loss, train_acc1, train_acc5, test_loss, test_acc1, \ - test_acc5)) + "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 + '/' + model_name, str(pass_id)) if not os.path.isdir(model_path): os.makedirs(model_path) - fluid.io.save_persistables(exe, model_path) + fluid.io.save_persistables(exe, model_path, main_program=train_prog) # This is for continuous evaluation only if args.enable_ce and pass_id == args.num_epochs - 1: - if gpu_nums == 1: + if device_num == 1: # Use the mean cost/acc for training print("kpis train_cost %s" % train_loss) print("kpis train_acc_top1 %s" % train_acc1) @@ -270,18 +365,24 @@ def train(args): print("kpis train_speed %s" % train_speed) else: # Use the mean cost/acc for training - print("kpis train_cost_card%s %s" % (gpu_nums, train_loss)) - print("kpis train_acc_top1_card%s %s" % (gpu_nums, train_acc1)) - print("kpis train_acc_top5_card%s %s" % (gpu_nums, train_acc5)) + print("kpis train_cost_card%s %s" % (device_num, train_loss)) + print("kpis train_acc_top1_card%s %s" % + (device_num, train_acc1)) + print("kpis train_acc_top5_card%s %s" % + (device_num, train_acc5)) # Use the mean cost/acc for testing - print("kpis test_cost_card%s %s" % (gpu_nums, test_loss)) - print("kpis test_acc_top1_card%s %s" % (gpu_nums, test_acc1)) - print("kpis test_acc_top5_card%s %s" % (gpu_nums, test_acc5)) - print("kpis train_speed_card%s %s" % (gpu_nums, train_speed)) + print("kpis test_cost_card%s %s" % (device_num, test_loss)) + print("kpis test_acc_top1_card%s %s" % (device_num, test_acc1)) + print("kpis test_acc_top5_card%s %s" % (device_num, test_acc5)) + print("kpis train_speed_card%s %s" % (device_num, train_speed)) def main(): args = parser.parse_args() + models_now = args.model_category + assert models_now in ["models", "models_name"], "{} is not in lists: {}".format( + models_now, ["models", "models_name"]) + set_models(models_now) print_arguments(args) train(args) diff --git a/fluid/PaddleCV/image_classification/utils/__init__.py b/fluid/PaddleCV/image_classification/utils/__init__.py new file mode 100644 index 00000000..f59e4baf --- /dev/null +++ b/fluid/PaddleCV/image_classification/utils/__init__.py @@ -0,0 +1 @@ +from .learning_rate import cosine_decay, lr_warmup diff --git a/fluid/PaddleCV/image_classification/models/learning_rate.py b/fluid/PaddleCV/image_classification/utils/learning_rate.py similarity index 90% rename from fluid/PaddleCV/image_classification/models/learning_rate.py rename to fluid/PaddleCV/image_classification/utils/learning_rate.py index 01922eb3..15f7f6e5 100644 --- a/fluid/PaddleCV/image_classification/models/learning_rate.py +++ b/fluid/PaddleCV/image_classification/utils/learning_rate.py @@ -27,8 +27,8 @@ def lr_warmup(learning_rate, warmup_steps, start_lr, end_lr): Argument learning_rate can be float or a Variable lr = lr + (warmup_rate * step / warmup_steps) """ - assert(isinstance(end_lr, float)) - assert(isinstance(start_lr, float)) + assert (isinstance(end_lr, float)) + assert (isinstance(start_lr, float)) linear_step = end_lr - start_lr with fluid.default_main_program()._lr_schedule_guard(): lr = fluid.layers.tensor.create_global_var( @@ -42,9 +42,10 @@ def lr_warmup(learning_rate, warmup_steps, start_lr, end_lr): with fluid.layers.control_flow.Switch() as switch: with switch.case(global_step < warmup_steps): - decayed_lr = start_lr + linear_step * (global_step / warmup_steps) + decayed_lr = start_lr + linear_step * (global_step / + warmup_steps) fluid.layers.tensor.assign(decayed_lr, lr) with switch.default(): fluid.layers.tensor.assign(learning_rate, lr) - return lr \ No newline at end of file + return lr -- GitLab