chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .alexnet import AlexNet, alexnet
|
||||
from .densenet import (
|
||||
DenseNet,
|
||||
densenet121,
|
||||
densenet161,
|
||||
densenet169,
|
||||
densenet201,
|
||||
densenet264,
|
||||
)
|
||||
from .googlenet import GoogLeNet, googlenet
|
||||
from .inceptionv3 import InceptionV3, inception_v3
|
||||
from .lenet import LeNet
|
||||
from .mobilenetv1 import MobileNetV1, mobilenet_v1
|
||||
from .mobilenetv2 import MobileNetV2, mobilenet_v2
|
||||
from .mobilenetv3 import (
|
||||
MobileNetV3Large,
|
||||
MobileNetV3Small,
|
||||
mobilenet_v3_large,
|
||||
mobilenet_v3_small,
|
||||
)
|
||||
from .resnet import (
|
||||
ResNet,
|
||||
resnet18,
|
||||
resnet34,
|
||||
resnet50,
|
||||
resnet101,
|
||||
resnet152,
|
||||
resnext50_32x4d,
|
||||
resnext50_64x4d,
|
||||
resnext101_32x4d,
|
||||
resnext101_64x4d,
|
||||
resnext152_32x4d,
|
||||
resnext152_64x4d,
|
||||
wide_resnet50_2,
|
||||
wide_resnet101_2,
|
||||
)
|
||||
from .shufflenetv2 import (
|
||||
ShuffleNetV2,
|
||||
shufflenet_v2_swish,
|
||||
shufflenet_v2_x0_5,
|
||||
shufflenet_v2_x0_25,
|
||||
shufflenet_v2_x0_33,
|
||||
shufflenet_v2_x1_0,
|
||||
shufflenet_v2_x1_5,
|
||||
shufflenet_v2_x2_0,
|
||||
)
|
||||
from .squeezenet import SqueezeNet, squeezenet1_0, squeezenet1_1
|
||||
from .vgg import VGG, vgg11, vgg13, vgg16, vgg19
|
||||
|
||||
__all__ = [
|
||||
'ResNet',
|
||||
'resnet18',
|
||||
'resnet34',
|
||||
'resnet50',
|
||||
'resnet101',
|
||||
'resnet152',
|
||||
'resnext50_32x4d',
|
||||
'resnext50_64x4d',
|
||||
'resnext101_32x4d',
|
||||
'resnext101_64x4d',
|
||||
'resnext152_32x4d',
|
||||
'resnext152_64x4d',
|
||||
'wide_resnet50_2',
|
||||
'wide_resnet101_2',
|
||||
'VGG',
|
||||
'vgg11',
|
||||
'vgg13',
|
||||
'vgg16',
|
||||
'vgg19',
|
||||
'MobileNetV1',
|
||||
'mobilenet_v1',
|
||||
'MobileNetV2',
|
||||
'mobilenet_v2',
|
||||
'MobileNetV3Small',
|
||||
'MobileNetV3Large',
|
||||
'mobilenet_v3_small',
|
||||
'mobilenet_v3_large',
|
||||
'LeNet',
|
||||
'DenseNet',
|
||||
'densenet121',
|
||||
'densenet161',
|
||||
'densenet169',
|
||||
'densenet201',
|
||||
'densenet264',
|
||||
'AlexNet',
|
||||
'alexnet',
|
||||
'InceptionV3',
|
||||
'inception_v3',
|
||||
'SqueezeNet',
|
||||
'squeezenet1_0',
|
||||
'squeezenet1_1',
|
||||
'GoogLeNet',
|
||||
'googlenet',
|
||||
'ShuffleNetV2',
|
||||
'shufflenet_v2_x0_25',
|
||||
'shufflenet_v2_x0_33',
|
||||
'shufflenet_v2_x0_5',
|
||||
'shufflenet_v2_x1_0',
|
||||
'shufflenet_v2_x1_5',
|
||||
'shufflenet_v2_x2_0',
|
||||
'shufflenet_v2_swish',
|
||||
]
|
||||
@@ -0,0 +1,113 @@
|
||||
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from __future__ import annotations
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
import paddle
|
||||
from paddle import nn
|
||||
|
||||
|
||||
def _make_divisible(v, divisor=8, min_value=None):
|
||||
"""
|
||||
This function ensures that all layers have a channel number that is divisible by divisor.
|
||||
You can also see at https://github.com/keras-team/keras/blob/8ecef127f70db723c158dbe9ed3268b3d610ab55/keras/applications/mobilenet_v2.py#L505
|
||||
|
||||
Args:
|
||||
divisor (int, optional): The divisor for number of channels. Default: 8.
|
||||
min_value (int, optional): The minimum value of number of channels, if it is None,
|
||||
the default is divisor. Default: None.
|
||||
"""
|
||||
if min_value is None:
|
||||
min_value = divisor
|
||||
new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
|
||||
# Make sure that round down does not go down by more than 10%.
|
||||
if new_v < 0.9 * v:
|
||||
new_v += divisor
|
||||
return new_v
|
||||
|
||||
|
||||
class IntermediateLayerGetter(nn.LayerDict):
|
||||
"""
|
||||
Layer wrapper that returns intermediate layers from a model.
|
||||
|
||||
It has a strong assumption that the layers have been registered into the model in the
|
||||
same order as they are used. This means that one should **not** reuse the same nn.Layer
|
||||
twice in the forward if you want this to work.
|
||||
|
||||
Additionally, it is only able to query sublayer that are directly assigned to the model.
|
||||
So if `model` is passed, `model.feature1` can be returned, but not `model.feature1.layer2`.
|
||||
|
||||
Args:
|
||||
|
||||
model (nn.Layer): Model on which we will extract the features.
|
||||
return_layers (Dict[name, new_name]): A dict containing the names of the layers for
|
||||
which the activations will be returned as the key of the dict, and the value of the
|
||||
dict is the name of the returned activation (which the user can specify).
|
||||
|
||||
Examples:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> m = paddle.vision.models.resnet18(pretrained=False)
|
||||
|
||||
>>> # extract layer1 and layer3, giving as names `feat1` and feat2`
|
||||
>>> new_m = paddle.vision.models._utils.IntermediateLayerGetter(
|
||||
... m,
|
||||
... {
|
||||
... 'layer1': 'feat1',
|
||||
... 'layer3': 'feat2',
|
||||
... },
|
||||
... )
|
||||
>>> out = new_m(paddle.rand([1, 3, 224, 224]))
|
||||
>>> print([(k, v.shape) for k, v in out.items()])
|
||||
[('feat1', [1, 64, 56, 56]), ('feat2', [1, 256, 14, 14])]
|
||||
"""
|
||||
|
||||
return_layers: dict[str, str]
|
||||
|
||||
def __init__(self, model: nn.Layer, return_layers: dict[str, str]) -> None:
|
||||
if not set(return_layers).issubset(
|
||||
[name for name, _ in model.named_children()]
|
||||
):
|
||||
raise ValueError("return_layers are not present in model")
|
||||
orig_return_layers = return_layers
|
||||
return_layers = {str(k): str(v) for k, v in return_layers.items()}
|
||||
layers = OrderedDict()
|
||||
for name, module in model.named_children():
|
||||
layers[name] = module
|
||||
if name in return_layers:
|
||||
del return_layers[name]
|
||||
if not return_layers:
|
||||
break
|
||||
|
||||
super().__init__(layers)
|
||||
self.return_layers = orig_return_layers
|
||||
|
||||
def forward(self, x):
|
||||
out = OrderedDict()
|
||||
for name, module in self.items():
|
||||
if (isinstance(module, nn.Linear) and x.ndim == 4) or (
|
||||
len(module.sublayers()) > 0
|
||||
and isinstance(module.sublayers()[0], nn.Linear)
|
||||
and x.ndim == 4
|
||||
):
|
||||
x = paddle.flatten(x, 1)
|
||||
|
||||
x = module(x)
|
||||
if name in self.return_layers:
|
||||
out_name = self.return_layers[name]
|
||||
out[out_name] = x
|
||||
return out
|
||||
@@ -0,0 +1,241 @@
|
||||
# copyright (c) 2022 PaddlePaddle Authors. All Rights Reserve.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
TypedDict,
|
||||
)
|
||||
|
||||
from typing_extensions import NotRequired, Unpack
|
||||
|
||||
import paddle
|
||||
import paddle.nn.functional as F
|
||||
from paddle import nn
|
||||
from paddle.base.param_attr import ParamAttr
|
||||
from paddle.nn import Conv2D, Dropout, Linear, MaxPool2D, ReLU
|
||||
from paddle.nn.initializer import Uniform
|
||||
from paddle.utils.download import get_weights_path_from_url
|
||||
|
||||
model_urls = {
|
||||
"alexnet": (
|
||||
"https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/AlexNet_pretrained.pdparams",
|
||||
"7f0f9f737132e02732d75a1459d98a43",
|
||||
)
|
||||
}
|
||||
|
||||
__all__ = []
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
from paddle._typing import Size2
|
||||
|
||||
class _AlexNetOptions(TypedDict):
|
||||
num_classes: NotRequired[int]
|
||||
|
||||
|
||||
class ConvPoolLayer(nn.Layer):
|
||||
def __init__(
|
||||
self,
|
||||
input_channels: int,
|
||||
output_channels: int,
|
||||
filter_size: Size2,
|
||||
stride: Size2,
|
||||
padding: Size2,
|
||||
stdv: float,
|
||||
groups: int = 1,
|
||||
act: str | None = None,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
|
||||
self.relu = ReLU() if act == "relu" else None
|
||||
|
||||
self._conv = Conv2D(
|
||||
in_channels=input_channels,
|
||||
out_channels=output_channels,
|
||||
kernel_size=filter_size,
|
||||
stride=stride,
|
||||
padding=padding,
|
||||
groups=groups,
|
||||
weight_attr=ParamAttr(initializer=Uniform(-stdv, stdv)),
|
||||
bias_attr=ParamAttr(initializer=Uniform(-stdv, stdv)),
|
||||
)
|
||||
self._pool = MaxPool2D(kernel_size=3, stride=2, padding=0)
|
||||
|
||||
def forward(self, inputs: Tensor) -> Tensor:
|
||||
x = self._conv(inputs)
|
||||
if self.relu is not None:
|
||||
x = self.relu(x)
|
||||
x = self._pool(x)
|
||||
return x
|
||||
|
||||
|
||||
class AlexNet(nn.Layer):
|
||||
"""AlexNet model from
|
||||
`"ImageNet Classification with Deep Convolutional Neural Networks"
|
||||
<https://proceedings.neurips.cc/paper/2012/file/c399862d3b9d6b76c8436e924a68c45b-Paper.pdf>`_.
|
||||
|
||||
Args:
|
||||
num_classes (int, optional): Output dim of last fc layer. If num_classes <= 0, last fc layer
|
||||
will not be defined. Default: 1000.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of AlexNet model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import AlexNet
|
||||
|
||||
>>> alexnet = AlexNet()
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = alexnet(x)
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
|
||||
num_classes: int
|
||||
|
||||
def __init__(self, num_classes: int = 1000) -> None:
|
||||
super().__init__()
|
||||
self.num_classes = num_classes
|
||||
stdv = 1.0 / math.sqrt(3 * 11 * 11)
|
||||
self._conv1 = ConvPoolLayer(3, 64, 11, 4, 2, stdv, act="relu")
|
||||
stdv = 1.0 / math.sqrt(64 * 5 * 5)
|
||||
self._conv2 = ConvPoolLayer(64, 192, 5, 1, 2, stdv, act="relu")
|
||||
stdv = 1.0 / math.sqrt(192 * 3 * 3)
|
||||
self._conv3 = Conv2D(
|
||||
192,
|
||||
384,
|
||||
3,
|
||||
stride=1,
|
||||
padding=1,
|
||||
weight_attr=ParamAttr(initializer=Uniform(-stdv, stdv)),
|
||||
bias_attr=ParamAttr(initializer=Uniform(-stdv, stdv)),
|
||||
)
|
||||
stdv = 1.0 / math.sqrt(384 * 3 * 3)
|
||||
self._conv4 = Conv2D(
|
||||
384,
|
||||
256,
|
||||
3,
|
||||
stride=1,
|
||||
padding=1,
|
||||
weight_attr=ParamAttr(initializer=Uniform(-stdv, stdv)),
|
||||
bias_attr=ParamAttr(initializer=Uniform(-stdv, stdv)),
|
||||
)
|
||||
stdv = 1.0 / math.sqrt(256 * 3 * 3)
|
||||
self._conv5 = ConvPoolLayer(256, 256, 3, 1, 1, stdv, act="relu")
|
||||
|
||||
if self.num_classes > 0:
|
||||
stdv = 1.0 / math.sqrt(256 * 6 * 6)
|
||||
self._drop1 = Dropout(p=0.5, mode="downscale_in_infer")
|
||||
self._fc6 = Linear(
|
||||
in_features=256 * 6 * 6,
|
||||
out_features=4096,
|
||||
weight_attr=ParamAttr(initializer=Uniform(-stdv, stdv)),
|
||||
bias_attr=ParamAttr(initializer=Uniform(-stdv, stdv)),
|
||||
)
|
||||
|
||||
self._drop2 = Dropout(p=0.5, mode="downscale_in_infer")
|
||||
self._fc7 = Linear(
|
||||
in_features=4096,
|
||||
out_features=4096,
|
||||
weight_attr=ParamAttr(initializer=Uniform(-stdv, stdv)),
|
||||
bias_attr=ParamAttr(initializer=Uniform(-stdv, stdv)),
|
||||
)
|
||||
self._fc8 = Linear(
|
||||
in_features=4096,
|
||||
out_features=num_classes,
|
||||
weight_attr=ParamAttr(initializer=Uniform(-stdv, stdv)),
|
||||
bias_attr=ParamAttr(initializer=Uniform(-stdv, stdv)),
|
||||
)
|
||||
|
||||
def forward(self, inputs: Tensor) -> Tensor:
|
||||
x = self._conv1(inputs)
|
||||
x = self._conv2(x)
|
||||
x = self._conv3(x)
|
||||
x = F.relu(x)
|
||||
x = self._conv4(x)
|
||||
x = F.relu(x)
|
||||
x = self._conv5(x)
|
||||
|
||||
if self.num_classes > 0:
|
||||
x = paddle.flatten(x, start_axis=1, stop_axis=-1)
|
||||
x = self._drop1(x)
|
||||
x = self._fc6(x)
|
||||
x = F.relu(x)
|
||||
x = self._drop2(x)
|
||||
x = self._fc7(x)
|
||||
x = F.relu(x)
|
||||
x = self._fc8(x)
|
||||
|
||||
return x
|
||||
|
||||
|
||||
def _alexnet(
|
||||
arch: str, pretrained: bool, **kwargs: Unpack[_AlexNetOptions]
|
||||
) -> AlexNet:
|
||||
model = AlexNet(**kwargs)
|
||||
|
||||
if pretrained:
|
||||
assert arch in model_urls, (
|
||||
f"{arch} model do not have a pretrained model now, you should set pretrained=False"
|
||||
)
|
||||
weight_path = get_weights_path_from_url(
|
||||
model_urls[arch][0], model_urls[arch][1]
|
||||
)
|
||||
|
||||
param = paddle.load(weight_path)
|
||||
model.load_dict(param)
|
||||
|
||||
return model
|
||||
|
||||
|
||||
def alexnet(
|
||||
pretrained: bool = False, **kwargs: Unpack[_AlexNetOptions]
|
||||
) -> AlexNet:
|
||||
"""AlexNet model from
|
||||
`"ImageNet Classification with Deep Convolutional Neural Networks"
|
||||
<https://proceedings.neurips.cc/paper/2012/file/c399862d3b9d6b76c8436e924a68c45b-Paper.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`AlexNet <api_paddle_vision_AlexNet>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of AlexNet model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import alexnet
|
||||
|
||||
>>> # Build model
|
||||
>>> model = alexnet()
|
||||
|
||||
>>> # Build model and load imagenet pretrained weight
|
||||
>>> # model = alexnet(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
return _alexnet('alexnet', pretrained, **kwargs)
|
||||
@@ -0,0 +1,571 @@
|
||||
# copyright (c) 2021 PaddlePaddle Authors. All Rights Reserve.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from typing_extensions import Unpack
|
||||
|
||||
import paddle
|
||||
from paddle import nn
|
||||
from paddle.base.param_attr import ParamAttr
|
||||
from paddle.nn import (
|
||||
AdaptiveAvgPool2D,
|
||||
AvgPool2D,
|
||||
BatchNorm,
|
||||
Conv2D,
|
||||
Dropout,
|
||||
Linear,
|
||||
MaxPool2D,
|
||||
)
|
||||
from paddle.nn.initializer import Uniform
|
||||
from paddle.utils.download import get_weights_path_from_url
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Literal, TypedDict
|
||||
|
||||
from typing_extensions import NotRequired
|
||||
|
||||
from paddle import Tensor
|
||||
from paddle._typing import Size2
|
||||
|
||||
_DenseNetArch = Literal[
|
||||
"densenet121",
|
||||
"densenet161",
|
||||
"densenet169",
|
||||
"densenet201",
|
||||
"densenet264",
|
||||
]
|
||||
|
||||
class _DenseNetOptions(TypedDict):
|
||||
bn_size: NotRequired[int]
|
||||
dropout: NotRequired[float]
|
||||
num_classes: NotRequired[int]
|
||||
with_pool: NotRequired[bool]
|
||||
|
||||
|
||||
__all__ = []
|
||||
|
||||
model_urls: dict[str, tuple[str, str]] = {
|
||||
'densenet121': (
|
||||
'https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/DenseNet121_pretrained.pdparams',
|
||||
'db1b239ed80a905290fd8b01d3af08e4',
|
||||
),
|
||||
'densenet161': (
|
||||
'https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/DenseNet161_pretrained.pdparams',
|
||||
'62158869cb315098bd25ddbfd308a853',
|
||||
),
|
||||
'densenet169': (
|
||||
'https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/DenseNet169_pretrained.pdparams',
|
||||
'82cc7c635c3f19098c748850efb2d796',
|
||||
),
|
||||
'densenet201': (
|
||||
'https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/DenseNet201_pretrained.pdparams',
|
||||
'16ca29565a7712329cf9e36e02caaf58',
|
||||
),
|
||||
'densenet264': (
|
||||
'https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/DenseNet264_pretrained.pdparams',
|
||||
'3270ce516b85370bba88cfdd9f60bff4',
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
class BNACConvLayer(nn.Layer):
|
||||
def __init__(
|
||||
self,
|
||||
num_channels: int,
|
||||
num_filters: int,
|
||||
filter_size: Size2,
|
||||
stride: Size2 = 1,
|
||||
pad: Size2 = 0,
|
||||
groups: int = 1,
|
||||
act: str = "relu",
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self._batch_norm = BatchNorm(num_channels, act=act)
|
||||
|
||||
self._conv = Conv2D(
|
||||
in_channels=num_channels,
|
||||
out_channels=num_filters,
|
||||
kernel_size=filter_size,
|
||||
stride=stride,
|
||||
padding=pad,
|
||||
groups=groups,
|
||||
weight_attr=ParamAttr(),
|
||||
bias_attr=False,
|
||||
)
|
||||
|
||||
def forward(self, input: Tensor) -> Tensor:
|
||||
y = self._batch_norm(input)
|
||||
y = self._conv(y)
|
||||
return y
|
||||
|
||||
|
||||
class DenseLayer(nn.Layer):
|
||||
dropout: float
|
||||
|
||||
def __init__(
|
||||
self, num_channels: int, growth_rate: int, bn_size: int, dropout: float
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.dropout = dropout
|
||||
|
||||
self.bn_ac_func1 = BNACConvLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=bn_size * growth_rate,
|
||||
filter_size=1,
|
||||
pad=0,
|
||||
stride=1,
|
||||
)
|
||||
|
||||
self.bn_ac_func2 = BNACConvLayer(
|
||||
num_channels=bn_size * growth_rate,
|
||||
num_filters=growth_rate,
|
||||
filter_size=3,
|
||||
pad=1,
|
||||
stride=1,
|
||||
)
|
||||
|
||||
if dropout:
|
||||
self.dropout_func = Dropout(p=dropout, mode="downscale_in_infer")
|
||||
|
||||
def forward(self, input: Tensor) -> Tensor:
|
||||
conv = self.bn_ac_func1(input)
|
||||
conv = self.bn_ac_func2(conv)
|
||||
if self.dropout:
|
||||
conv = self.dropout_func(conv)
|
||||
conv = paddle.concat([input, conv], axis=1)
|
||||
return conv
|
||||
|
||||
|
||||
class DenseBlock(nn.Layer):
|
||||
dropout: float
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
num_channels: int,
|
||||
num_layers: int,
|
||||
bn_size: int,
|
||||
growth_rate: int,
|
||||
dropout: float,
|
||||
name: str | None = None,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.dropout = dropout
|
||||
self.dense_layer_func = []
|
||||
|
||||
pre_channel = num_channels
|
||||
for layer in range(num_layers):
|
||||
self.dense_layer_func.append(
|
||||
self.add_sublayer(
|
||||
f"{name}_{layer + 1}",
|
||||
DenseLayer(
|
||||
num_channels=pre_channel,
|
||||
growth_rate=growth_rate,
|
||||
bn_size=bn_size,
|
||||
dropout=dropout,
|
||||
),
|
||||
)
|
||||
)
|
||||
pre_channel = pre_channel + growth_rate
|
||||
|
||||
def forward(self, input: Tensor) -> Tensor:
|
||||
conv = input
|
||||
for func in self.dense_layer_func:
|
||||
conv = func(conv)
|
||||
return conv
|
||||
|
||||
|
||||
class TransitionLayer(nn.Layer):
|
||||
def __init__(self, num_channels: int, num_output_features: int) -> None:
|
||||
super().__init__()
|
||||
|
||||
self.conv_ac_func = BNACConvLayer(
|
||||
num_channels=num_channels,
|
||||
num_filters=num_output_features,
|
||||
filter_size=1,
|
||||
pad=0,
|
||||
stride=1,
|
||||
)
|
||||
|
||||
self.pool2d_avg = AvgPool2D(kernel_size=2, stride=2, padding=0)
|
||||
|
||||
def forward(self, input: Tensor) -> Tensor:
|
||||
y = self.conv_ac_func(input)
|
||||
y = self.pool2d_avg(y)
|
||||
return y
|
||||
|
||||
|
||||
class ConvBNLayer(nn.Layer):
|
||||
def __init__(
|
||||
self,
|
||||
num_channels: int,
|
||||
num_filters: int,
|
||||
filter_size: Size2,
|
||||
stride: Size2 = 1,
|
||||
pad: Size2 = 0,
|
||||
groups: int = 1,
|
||||
act: str = "relu",
|
||||
) -> None:
|
||||
super().__init__()
|
||||
|
||||
self._conv = Conv2D(
|
||||
in_channels=num_channels,
|
||||
out_channels=num_filters,
|
||||
kernel_size=filter_size,
|
||||
stride=stride,
|
||||
padding=pad,
|
||||
groups=groups,
|
||||
weight_attr=ParamAttr(),
|
||||
bias_attr=False,
|
||||
)
|
||||
self._batch_norm = BatchNorm(num_filters, act=act)
|
||||
|
||||
def forward(self, input: Tensor) -> Tensor:
|
||||
y = self._conv(input)
|
||||
y = self._batch_norm(y)
|
||||
return y
|
||||
|
||||
|
||||
class DenseNet(nn.Layer):
|
||||
"""DenseNet model from
|
||||
`"Densely Connected Convolutional Networks" <https://arxiv.org/pdf/1608.06993.pdf>`_.
|
||||
|
||||
Args:
|
||||
layers (int, optional): Layers of DenseNet. Default: 121.
|
||||
bn_size (int, optional): Expansion of growth rate in the middle layer. Default: 4.
|
||||
dropout (float, optional): Dropout rate. Default: :math:`0.0`.
|
||||
num_classes (int, optional): Output dim of last fc layer. If num_classes <= 0, last fc layer
|
||||
will not be defined. Default: 1000.
|
||||
with_pool (bool, optional): Use pool before the last fc layer or not. Default: True.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of DenseNet model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import DenseNet
|
||||
|
||||
>>> # Build model
|
||||
>>> densenet = DenseNet()
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = densenet(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
|
||||
num_classes: int
|
||||
with_pool: bool
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
layers: int = 121,
|
||||
bn_size: int = 4,
|
||||
dropout: float = 0.0,
|
||||
num_classes: int = 1000,
|
||||
with_pool: bool = True,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.num_classes = num_classes
|
||||
self.with_pool = with_pool
|
||||
supported_layers = [121, 161, 169, 201, 264]
|
||||
assert layers in supported_layers, (
|
||||
f"supported layers are {supported_layers} but input layer is {layers}"
|
||||
)
|
||||
densenet_spec = {
|
||||
121: (64, 32, [6, 12, 24, 16]),
|
||||
161: (96, 48, [6, 12, 36, 24]),
|
||||
169: (64, 32, [6, 12, 32, 32]),
|
||||
201: (64, 32, [6, 12, 48, 32]),
|
||||
264: (64, 32, [6, 12, 64, 48]),
|
||||
}
|
||||
num_init_features, growth_rate, block_config = densenet_spec[layers]
|
||||
|
||||
self.conv1_func = ConvBNLayer(
|
||||
num_channels=3,
|
||||
num_filters=num_init_features,
|
||||
filter_size=7,
|
||||
stride=2,
|
||||
pad=3,
|
||||
act='relu',
|
||||
)
|
||||
self.pool2d_max = MaxPool2D(kernel_size=3, stride=2, padding=1)
|
||||
self.block_config = block_config
|
||||
self.dense_block_func_list = []
|
||||
self.transition_func_list = []
|
||||
pre_num_channels = num_init_features
|
||||
num_features = num_init_features
|
||||
for i, num_layers in enumerate(block_config):
|
||||
self.dense_block_func_list.append(
|
||||
self.add_sublayer(
|
||||
f"db_conv_{i + 2}",
|
||||
DenseBlock(
|
||||
num_channels=pre_num_channels,
|
||||
num_layers=num_layers,
|
||||
bn_size=bn_size,
|
||||
growth_rate=growth_rate,
|
||||
dropout=dropout,
|
||||
name='conv' + str(i + 2),
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
num_features = num_features + num_layers * growth_rate
|
||||
pre_num_channels = num_features
|
||||
|
||||
if i != len(block_config) - 1:
|
||||
self.transition_func_list.append(
|
||||
self.add_sublayer(
|
||||
f"tr_conv{i + 2}_blk",
|
||||
TransitionLayer(
|
||||
num_channels=pre_num_channels,
|
||||
num_output_features=num_features // 2,
|
||||
),
|
||||
)
|
||||
)
|
||||
pre_num_channels = num_features // 2
|
||||
num_features = num_features // 2
|
||||
|
||||
self.batch_norm = BatchNorm(num_features, act="relu")
|
||||
if self.with_pool:
|
||||
self.pool2d_avg = AdaptiveAvgPool2D(1)
|
||||
|
||||
if self.num_classes > 0:
|
||||
stdv = 1.0 / math.sqrt(num_features * 1.0)
|
||||
self.out = Linear(
|
||||
num_features,
|
||||
num_classes,
|
||||
weight_attr=ParamAttr(initializer=Uniform(-stdv, stdv)),
|
||||
bias_attr=ParamAttr(),
|
||||
)
|
||||
|
||||
def forward(self, input: Tensor) -> Tensor:
|
||||
conv = self.conv1_func(input)
|
||||
conv = self.pool2d_max(conv)
|
||||
|
||||
for i, num_layers in enumerate(self.block_config):
|
||||
conv = self.dense_block_func_list[i](conv)
|
||||
if i != len(self.block_config) - 1:
|
||||
conv = self.transition_func_list[i](conv)
|
||||
|
||||
conv = self.batch_norm(conv)
|
||||
|
||||
if self.with_pool:
|
||||
y = self.pool2d_avg(conv)
|
||||
|
||||
if self.num_classes > 0:
|
||||
y = paddle.flatten(y, start_axis=1, stop_axis=-1)
|
||||
y = self.out(y)
|
||||
|
||||
return y
|
||||
|
||||
|
||||
def _densenet(
|
||||
arch: _DenseNetArch,
|
||||
layers: int,
|
||||
pretrained: bool,
|
||||
**kwargs: Unpack[_DenseNetOptions],
|
||||
) -> DenseNet:
|
||||
model = DenseNet(layers=layers, **kwargs)
|
||||
if pretrained:
|
||||
assert arch in model_urls, (
|
||||
f"{arch} model do not have a pretrained model now, you should set pretrained=False"
|
||||
)
|
||||
weight_path = get_weights_path_from_url(
|
||||
model_urls[arch][0], model_urls[arch][1]
|
||||
)
|
||||
|
||||
param = paddle.load(weight_path)
|
||||
model.set_dict(param)
|
||||
|
||||
return model
|
||||
|
||||
|
||||
def densenet121(
|
||||
pretrained: bool = False, **kwargs: Unpack[_DenseNetOptions]
|
||||
) -> DenseNet:
|
||||
"""DenseNet 121-layer model from
|
||||
`"Densely Connected Convolutional Networks" <https://arxiv.org/pdf/1608.06993.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`DenseNet <api_paddle_vision_models_DenseNet>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of DenseNet 121-layer model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import densenet121
|
||||
|
||||
>>> # Build model
|
||||
>>> model = densenet121()
|
||||
|
||||
>>> # Build model and load imagenet pretrained weight
|
||||
>>> # model = densenet121(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
return _densenet('densenet121', 121, pretrained, **kwargs)
|
||||
|
||||
|
||||
def densenet161(
|
||||
pretrained: bool = False, **kwargs: Unpack[_DenseNetOptions]
|
||||
) -> DenseNet:
|
||||
"""DenseNet 161-layer model from
|
||||
`"Densely Connected Convolutional Networks" <https://arxiv.org/pdf/1608.06993.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`DenseNet <api_paddle_vision_models_DenseNet>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of DenseNet 161-layer model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import densenet161
|
||||
|
||||
>>> # Build model
|
||||
>>> model = densenet161()
|
||||
|
||||
>>> # Build model and load imagenet pretrained weight
|
||||
>>> # model = densenet161(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
return _densenet('densenet161', 161, pretrained, **kwargs)
|
||||
|
||||
|
||||
def densenet169(
|
||||
pretrained: bool = False, **kwargs: Unpack[_DenseNetOptions]
|
||||
) -> DenseNet:
|
||||
"""DenseNet 169-layer model from
|
||||
`"Densely Connected Convolutional Networks" <https://arxiv.org/pdf/1608.06993.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`DenseNet <api_paddle_vision_models_DenseNet>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of DenseNet 169-layer model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import densenet169
|
||||
|
||||
>>> # Build model
|
||||
>>> model = densenet169()
|
||||
|
||||
>>> # Build model and load imagenet pretrained weight
|
||||
>>> # model = densenet169(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
return _densenet('densenet169', 169, pretrained, **kwargs)
|
||||
|
||||
|
||||
def densenet201(
|
||||
pretrained: bool = False, **kwargs: Unpack[_DenseNetOptions]
|
||||
) -> DenseNet:
|
||||
"""DenseNet 201-layer model from
|
||||
`"Densely Connected Convolutional Networks" <https://arxiv.org/pdf/1608.06993.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`DenseNet <api_paddle_vision_models_DenseNet>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of DenseNet 201-layer model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import densenet201
|
||||
|
||||
>>> # Build model
|
||||
>>> model = densenet201()
|
||||
|
||||
>>> # Build model and load imagenet pretrained weight
|
||||
>>> # model = densenet201(pretrained=True)
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
return _densenet('densenet201', 201, pretrained, **kwargs)
|
||||
|
||||
|
||||
def densenet264(
|
||||
pretrained: bool = False, **kwargs: Unpack[_DenseNetOptions]
|
||||
) -> DenseNet:
|
||||
"""DenseNet 264-layer model from
|
||||
`"Densely Connected Convolutional Networks" <https://arxiv.org/pdf/1608.06993.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`DenseNet <api_paddle_vision_models_DenseNet>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of DenseNet 264-layer model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import densenet264
|
||||
|
||||
>>> # Build model
|
||||
>>> model = densenet264()
|
||||
|
||||
>>> # Build model and load imagenet pretrained weight
|
||||
>>> # model = densenet264(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
return _densenet('densenet264', 264, pretrained, **kwargs)
|
||||
@@ -0,0 +1,303 @@
|
||||
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
TypedDict,
|
||||
)
|
||||
|
||||
from typing_extensions import NotRequired, Unpack
|
||||
|
||||
import paddle
|
||||
import paddle.nn.functional as F
|
||||
from paddle import nn
|
||||
from paddle.base.param_attr import ParamAttr
|
||||
from paddle.nn import (
|
||||
AdaptiveAvgPool2D,
|
||||
AvgPool2D,
|
||||
Conv2D,
|
||||
Dropout,
|
||||
Linear,
|
||||
MaxPool2D,
|
||||
)
|
||||
from paddle.nn.initializer import Uniform
|
||||
from paddle.utils.download import get_weights_path_from_url
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
from paddle._typing import Size2
|
||||
|
||||
class _GoogLeNetOptions(TypedDict):
|
||||
num_classes: NotRequired[int]
|
||||
with_pool: NotRequired[bool]
|
||||
|
||||
|
||||
__all__ = []
|
||||
|
||||
model_urls = {
|
||||
"googlenet": (
|
||||
"https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/GoogLeNet_pretrained.pdparams",
|
||||
"80c06f038e905c53ab32c40eca6e26ae",
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
def xavier(channels: int, filter_size: int) -> ParamAttr:
|
||||
stdv = (3.0 / (filter_size**2 * channels)) ** 0.5
|
||||
param_attr = ParamAttr(initializer=Uniform(-stdv, stdv))
|
||||
return param_attr
|
||||
|
||||
|
||||
class ConvLayer(nn.Layer):
|
||||
def __init__(
|
||||
self,
|
||||
num_channels: int,
|
||||
num_filters: int,
|
||||
filter_size: int,
|
||||
stride: Size2 = 1,
|
||||
groups: int = 1,
|
||||
):
|
||||
super().__init__()
|
||||
|
||||
self._conv = Conv2D(
|
||||
in_channels=num_channels,
|
||||
out_channels=num_filters,
|
||||
kernel_size=filter_size,
|
||||
stride=stride,
|
||||
padding=(filter_size - 1) // 2,
|
||||
groups=groups,
|
||||
bias_attr=False,
|
||||
)
|
||||
|
||||
def forward(self, inputs: Tensor) -> Tensor:
|
||||
y = self._conv(inputs)
|
||||
return y
|
||||
|
||||
|
||||
class Inception(nn.Layer):
|
||||
def __init__(
|
||||
self,
|
||||
input_channels: int,
|
||||
output_channels: int,
|
||||
filter1: int,
|
||||
filter3R: int,
|
||||
filter3: int,
|
||||
filter5R: int,
|
||||
filter5: int,
|
||||
proj: int,
|
||||
):
|
||||
super().__init__()
|
||||
|
||||
self._conv1 = ConvLayer(input_channels, filter1, 1)
|
||||
self._conv3r = ConvLayer(input_channels, filter3R, 1)
|
||||
self._conv3 = ConvLayer(filter3R, filter3, 3)
|
||||
self._conv5r = ConvLayer(input_channels, filter5R, 1)
|
||||
self._conv5 = ConvLayer(filter5R, filter5, 5)
|
||||
self._pool = MaxPool2D(kernel_size=3, stride=1, padding=1)
|
||||
|
||||
self._convprj = ConvLayer(input_channels, proj, 1)
|
||||
|
||||
def forward(self, inputs: Tensor) -> Tensor:
|
||||
conv1 = self._conv1(inputs)
|
||||
|
||||
conv3r = self._conv3r(inputs)
|
||||
conv3 = self._conv3(conv3r)
|
||||
|
||||
conv5r = self._conv5r(inputs)
|
||||
conv5 = self._conv5(conv5r)
|
||||
|
||||
pool = self._pool(inputs)
|
||||
convprj = self._convprj(pool)
|
||||
|
||||
cat = paddle.concat([conv1, conv3, conv5, convprj], axis=1)
|
||||
cat = F.relu(cat)
|
||||
return cat
|
||||
|
||||
|
||||
class GoogLeNet(nn.Layer):
|
||||
"""GoogLeNet (Inception v1) model architecture from
|
||||
`"Going Deeper with Convolutions" <https://arxiv.org/pdf/1409.4842.pdf>`_.
|
||||
|
||||
Args:
|
||||
num_classes (int, optional): Output dim of last fc layer. If num_classes <= 0, last fc layer
|
||||
will not be defined. Default: 1000.
|
||||
with_pool (bool, optional): Use pool before the last fc layer or not. Default: True.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of GoogLeNet (Inception v1) model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import GoogLeNet
|
||||
|
||||
>>> # Build model
|
||||
>>> model = GoogLeNet()
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out, out1, out2 = model(x)
|
||||
|
||||
>>> print(out.shape, out1.shape, out2.shape)
|
||||
paddle.Size([1, 1000]) paddle.Size([1, 1000]) paddle.Size([1, 1000])
|
||||
"""
|
||||
|
||||
num_classes: int
|
||||
with_pool: bool
|
||||
|
||||
def __init__(self, num_classes: int = 1000, with_pool: bool = True) -> None:
|
||||
super().__init__()
|
||||
self.num_classes = num_classes
|
||||
self.with_pool = with_pool
|
||||
|
||||
self._conv = ConvLayer(3, 64, 7, 2)
|
||||
self._pool = MaxPool2D(kernel_size=3, stride=2)
|
||||
self._conv_1 = ConvLayer(64, 64, 1)
|
||||
self._conv_2 = ConvLayer(64, 192, 3)
|
||||
|
||||
self._ince3a = Inception(192, 192, 64, 96, 128, 16, 32, 32)
|
||||
self._ince3b = Inception(256, 256, 128, 128, 192, 32, 96, 64)
|
||||
|
||||
self._ince4a = Inception(480, 480, 192, 96, 208, 16, 48, 64)
|
||||
self._ince4b = Inception(512, 512, 160, 112, 224, 24, 64, 64)
|
||||
self._ince4c = Inception(512, 512, 128, 128, 256, 24, 64, 64)
|
||||
self._ince4d = Inception(512, 512, 112, 144, 288, 32, 64, 64)
|
||||
self._ince4e = Inception(528, 528, 256, 160, 320, 32, 128, 128)
|
||||
|
||||
self._ince5a = Inception(832, 832, 256, 160, 320, 32, 128, 128)
|
||||
self._ince5b = Inception(832, 832, 384, 192, 384, 48, 128, 128)
|
||||
|
||||
if with_pool:
|
||||
# out
|
||||
self._pool_5 = AdaptiveAvgPool2D(1)
|
||||
# out1
|
||||
self._pool_o1 = AvgPool2D(kernel_size=5, stride=3)
|
||||
# out2
|
||||
self._pool_o2 = AvgPool2D(kernel_size=5, stride=3)
|
||||
|
||||
if num_classes > 0:
|
||||
# out
|
||||
self._drop = Dropout(p=0.4, mode="downscale_in_infer")
|
||||
self._fc_out = Linear(
|
||||
1024, num_classes, weight_attr=xavier(1024, 1)
|
||||
)
|
||||
|
||||
# out1
|
||||
self._conv_o1 = ConvLayer(512, 128, 1)
|
||||
self._fc_o1 = Linear(1152, 1024, weight_attr=xavier(2048, 1))
|
||||
self._drop_o1 = Dropout(p=0.7, mode="downscale_in_infer")
|
||||
self._out1 = Linear(1024, num_classes, weight_attr=xavier(1024, 1))
|
||||
|
||||
# out2
|
||||
self._conv_o2 = ConvLayer(528, 128, 1)
|
||||
self._fc_o2 = Linear(1152, 1024, weight_attr=xavier(2048, 1))
|
||||
self._drop_o2 = Dropout(p=0.7, mode="downscale_in_infer")
|
||||
self._out2 = Linear(1024, num_classes, weight_attr=xavier(1024, 1))
|
||||
|
||||
def forward(self, inputs: Tensor) -> tuple[Tensor, Tensor, Tensor]:
|
||||
x = self._conv(inputs)
|
||||
x = self._pool(x)
|
||||
x = self._conv_1(x)
|
||||
x = self._conv_2(x)
|
||||
x = self._pool(x)
|
||||
|
||||
x = self._ince3a(x)
|
||||
x = self._ince3b(x)
|
||||
x = self._pool(x)
|
||||
|
||||
ince4a = self._ince4a(x)
|
||||
x = self._ince4b(ince4a)
|
||||
x = self._ince4c(x)
|
||||
ince4d = self._ince4d(x)
|
||||
x = self._ince4e(ince4d)
|
||||
x = self._pool(x)
|
||||
|
||||
x = self._ince5a(x)
|
||||
ince5b = self._ince5b(x)
|
||||
|
||||
out, out1, out2 = ince5b, ince4a, ince4d
|
||||
|
||||
if self.with_pool:
|
||||
out = self._pool_5(out)
|
||||
out1 = self._pool_o1(out1)
|
||||
out2 = self._pool_o2(out2)
|
||||
|
||||
if self.num_classes > 0:
|
||||
out = self._drop(out)
|
||||
out = paddle.squeeze(out, axis=[2, 3])
|
||||
out = self._fc_out(out)
|
||||
|
||||
out1 = self._conv_o1(out1)
|
||||
out1 = paddle.flatten(out1, start_axis=1, stop_axis=-1)
|
||||
out1 = self._fc_o1(out1)
|
||||
out1 = F.relu(out1)
|
||||
out1 = self._drop_o1(out1)
|
||||
out1 = self._out1(out1)
|
||||
|
||||
out2 = self._conv_o2(out2)
|
||||
out2 = paddle.flatten(out2, start_axis=1, stop_axis=-1)
|
||||
out2 = self._fc_o2(out2)
|
||||
out2 = self._drop_o2(out2)
|
||||
out2 = self._out2(out2)
|
||||
|
||||
return out, out1, out2
|
||||
|
||||
|
||||
def googlenet(
|
||||
pretrained: bool = False, **kwargs: Unpack[_GoogLeNetOptions]
|
||||
) -> GoogLeNet:
|
||||
"""GoogLeNet (Inception v1) model architecture from
|
||||
`"Going Deeper with Convolutions" <https://arxiv.org/pdf/1409.4842.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`GoogLeNet <api_paddle_vision_models_GoogLeNet>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of GoogLeNet (Inception v1) model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import googlenet
|
||||
|
||||
>>> # Build model
|
||||
>>> model = googlenet()
|
||||
|
||||
>>> # Build model and load imagenet pretrained weight
|
||||
>>> # model = googlenet(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out, out1, out2 = model(x)
|
||||
|
||||
>>> print(out.shape, out1.shape, out2.shape)
|
||||
paddle.Size([1, 1000]) paddle.Size([1, 1000]) paddle.Size([1, 1000])
|
||||
"""
|
||||
model = GoogLeNet(**kwargs)
|
||||
arch = "googlenet"
|
||||
if pretrained:
|
||||
assert arch in model_urls, (
|
||||
f"{arch} model do not have a pretrained model now, you should set pretrained=False"
|
||||
)
|
||||
weight_path = get_weights_path_from_url(
|
||||
model_urls[arch][0], model_urls[arch][1]
|
||||
)
|
||||
|
||||
param = paddle.load(weight_path)
|
||||
model.set_dict(param)
|
||||
return model
|
||||
@@ -0,0 +1,654 @@
|
||||
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
TypedDict,
|
||||
)
|
||||
|
||||
from typing_extensions import (
|
||||
NotRequired,
|
||||
Unpack,
|
||||
)
|
||||
|
||||
import paddle
|
||||
from paddle import nn
|
||||
from paddle.base.param_attr import ParamAttr
|
||||
from paddle.nn import AdaptiveAvgPool2D, AvgPool2D, Dropout, Linear, MaxPool2D
|
||||
from paddle.nn.initializer import Uniform
|
||||
from paddle.utils.download import get_weights_path_from_url
|
||||
|
||||
from ..ops import ConvNormActivation
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
class _InceptionV3Options(TypedDict):
|
||||
num_classes: NotRequired[int]
|
||||
with_pool: NotRequired[bool]
|
||||
|
||||
|
||||
__all__ = []
|
||||
|
||||
model_urls = {
|
||||
"inception_v3": (
|
||||
"https://paddle-hapi.bj.bcebos.com/models/inception_v3.pdparams",
|
||||
"649a4547c3243e8b59c656f41fe330b8",
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
class InceptionStem(nn.Layer):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.conv_1a_3x3 = ConvNormActivation(
|
||||
in_channels=3,
|
||||
out_channels=32,
|
||||
kernel_size=3,
|
||||
stride=2,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.conv_2a_3x3 = ConvNormActivation(
|
||||
in_channels=32,
|
||||
out_channels=32,
|
||||
kernel_size=3,
|
||||
stride=1,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.conv_2b_3x3 = ConvNormActivation(
|
||||
in_channels=32,
|
||||
out_channels=64,
|
||||
kernel_size=3,
|
||||
padding=1,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
|
||||
self.max_pool = MaxPool2D(kernel_size=3, stride=2, padding=0)
|
||||
self.conv_3b_1x1 = ConvNormActivation(
|
||||
in_channels=64,
|
||||
out_channels=80,
|
||||
kernel_size=1,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.conv_4a_3x3 = ConvNormActivation(
|
||||
in_channels=80,
|
||||
out_channels=192,
|
||||
kernel_size=3,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
|
||||
def forward(self, x: Tensor) -> Tensor:
|
||||
x = self.conv_1a_3x3(x)
|
||||
x = self.conv_2a_3x3(x)
|
||||
x = self.conv_2b_3x3(x)
|
||||
x = self.max_pool(x)
|
||||
x = self.conv_3b_1x1(x)
|
||||
x = self.conv_4a_3x3(x)
|
||||
x = self.max_pool(x)
|
||||
return x
|
||||
|
||||
|
||||
class InceptionA(nn.Layer):
|
||||
def __init__(self, num_channels: int, pool_features: int) -> None:
|
||||
super().__init__()
|
||||
self.branch1x1 = ConvNormActivation(
|
||||
in_channels=num_channels,
|
||||
out_channels=64,
|
||||
kernel_size=1,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
|
||||
self.branch5x5_1 = ConvNormActivation(
|
||||
in_channels=num_channels,
|
||||
out_channels=48,
|
||||
kernel_size=1,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.branch5x5_2 = ConvNormActivation(
|
||||
in_channels=48,
|
||||
out_channels=64,
|
||||
kernel_size=5,
|
||||
padding=2,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
|
||||
self.branch3x3dbl_1 = ConvNormActivation(
|
||||
in_channels=num_channels,
|
||||
out_channels=64,
|
||||
kernel_size=1,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.branch3x3dbl_2 = ConvNormActivation(
|
||||
in_channels=64,
|
||||
out_channels=96,
|
||||
kernel_size=3,
|
||||
padding=1,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.branch3x3dbl_3 = ConvNormActivation(
|
||||
in_channels=96,
|
||||
out_channels=96,
|
||||
kernel_size=3,
|
||||
padding=1,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
|
||||
self.branch_pool = AvgPool2D(
|
||||
kernel_size=3, stride=1, padding=1, exclusive=False
|
||||
)
|
||||
self.branch_pool_conv = ConvNormActivation(
|
||||
in_channels=num_channels,
|
||||
out_channels=pool_features,
|
||||
kernel_size=1,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
|
||||
def forward(self, x: Tensor) -> Tensor:
|
||||
branch1x1 = self.branch1x1(x)
|
||||
branch5x5 = self.branch5x5_1(x)
|
||||
branch5x5 = self.branch5x5_2(branch5x5)
|
||||
|
||||
branch3x3dbl = self.branch3x3dbl_1(x)
|
||||
branch3x3dbl = self.branch3x3dbl_2(branch3x3dbl)
|
||||
branch3x3dbl = self.branch3x3dbl_3(branch3x3dbl)
|
||||
|
||||
branch_pool = self.branch_pool(x)
|
||||
branch_pool = self.branch_pool_conv(branch_pool)
|
||||
x = paddle.concat(
|
||||
[branch1x1, branch5x5, branch3x3dbl, branch_pool], axis=1
|
||||
)
|
||||
return x
|
||||
|
||||
|
||||
class InceptionB(nn.Layer):
|
||||
def __init__(self, num_channels: int) -> None:
|
||||
super().__init__()
|
||||
self.branch3x3 = ConvNormActivation(
|
||||
in_channels=num_channels,
|
||||
out_channels=384,
|
||||
kernel_size=3,
|
||||
stride=2,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
|
||||
self.branch3x3dbl_1 = ConvNormActivation(
|
||||
in_channels=num_channels,
|
||||
out_channels=64,
|
||||
kernel_size=1,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.branch3x3dbl_2 = ConvNormActivation(
|
||||
in_channels=64,
|
||||
out_channels=96,
|
||||
kernel_size=3,
|
||||
padding=1,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.branch3x3dbl_3 = ConvNormActivation(
|
||||
in_channels=96,
|
||||
out_channels=96,
|
||||
kernel_size=3,
|
||||
stride=2,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
|
||||
self.branch_pool = MaxPool2D(kernel_size=3, stride=2)
|
||||
|
||||
def forward(self, x: Tensor) -> Tensor:
|
||||
branch3x3 = self.branch3x3(x)
|
||||
|
||||
branch3x3dbl = self.branch3x3dbl_1(x)
|
||||
branch3x3dbl = self.branch3x3dbl_2(branch3x3dbl)
|
||||
branch3x3dbl = self.branch3x3dbl_3(branch3x3dbl)
|
||||
|
||||
branch_pool = self.branch_pool(x)
|
||||
|
||||
x = paddle.concat([branch3x3, branch3x3dbl, branch_pool], axis=1)
|
||||
|
||||
return x
|
||||
|
||||
|
||||
class InceptionC(nn.Layer):
|
||||
def __init__(self, num_channels: int, channels_7x7: int) -> None:
|
||||
super().__init__()
|
||||
self.branch1x1 = ConvNormActivation(
|
||||
in_channels=num_channels,
|
||||
out_channels=192,
|
||||
kernel_size=1,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
|
||||
self.branch7x7_1 = ConvNormActivation(
|
||||
in_channels=num_channels,
|
||||
out_channels=channels_7x7,
|
||||
kernel_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.branch7x7_2 = ConvNormActivation(
|
||||
in_channels=channels_7x7,
|
||||
out_channels=channels_7x7,
|
||||
kernel_size=(1, 7),
|
||||
stride=1,
|
||||
padding=(0, 3),
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.branch7x7_3 = ConvNormActivation(
|
||||
in_channels=channels_7x7,
|
||||
out_channels=192,
|
||||
kernel_size=(7, 1),
|
||||
stride=1,
|
||||
padding=(3, 0),
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
|
||||
self.branch7x7dbl_1 = ConvNormActivation(
|
||||
in_channels=num_channels,
|
||||
out_channels=channels_7x7,
|
||||
kernel_size=1,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.branch7x7dbl_2 = ConvNormActivation(
|
||||
in_channels=channels_7x7,
|
||||
out_channels=channels_7x7,
|
||||
kernel_size=(7, 1),
|
||||
padding=(3, 0),
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.branch7x7dbl_3 = ConvNormActivation(
|
||||
in_channels=channels_7x7,
|
||||
out_channels=channels_7x7,
|
||||
kernel_size=(1, 7),
|
||||
padding=(0, 3),
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.branch7x7dbl_4 = ConvNormActivation(
|
||||
in_channels=channels_7x7,
|
||||
out_channels=channels_7x7,
|
||||
kernel_size=(7, 1),
|
||||
padding=(3, 0),
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.branch7x7dbl_5 = ConvNormActivation(
|
||||
in_channels=channels_7x7,
|
||||
out_channels=192,
|
||||
kernel_size=(1, 7),
|
||||
padding=(0, 3),
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
|
||||
self.branch_pool = AvgPool2D(
|
||||
kernel_size=3, stride=1, padding=1, exclusive=False
|
||||
)
|
||||
self.branch_pool_conv = ConvNormActivation(
|
||||
in_channels=num_channels,
|
||||
out_channels=192,
|
||||
kernel_size=1,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
|
||||
def forward(self, x: Tensor) -> Tensor:
|
||||
branch1x1 = self.branch1x1(x)
|
||||
|
||||
branch7x7 = self.branch7x7_1(x)
|
||||
branch7x7 = self.branch7x7_2(branch7x7)
|
||||
branch7x7 = self.branch7x7_3(branch7x7)
|
||||
|
||||
branch7x7dbl = self.branch7x7dbl_1(x)
|
||||
branch7x7dbl = self.branch7x7dbl_2(branch7x7dbl)
|
||||
branch7x7dbl = self.branch7x7dbl_3(branch7x7dbl)
|
||||
branch7x7dbl = self.branch7x7dbl_4(branch7x7dbl)
|
||||
branch7x7dbl = self.branch7x7dbl_5(branch7x7dbl)
|
||||
|
||||
branch_pool = self.branch_pool(x)
|
||||
branch_pool = self.branch_pool_conv(branch_pool)
|
||||
|
||||
x = paddle.concat(
|
||||
[branch1x1, branch7x7, branch7x7dbl, branch_pool], axis=1
|
||||
)
|
||||
|
||||
return x
|
||||
|
||||
|
||||
class InceptionD(nn.Layer):
|
||||
def __init__(self, num_channels: int) -> None:
|
||||
super().__init__()
|
||||
self.branch3x3_1 = ConvNormActivation(
|
||||
in_channels=num_channels,
|
||||
out_channels=192,
|
||||
kernel_size=1,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.branch3x3_2 = ConvNormActivation(
|
||||
in_channels=192,
|
||||
out_channels=320,
|
||||
kernel_size=3,
|
||||
stride=2,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
|
||||
self.branch7x7x3_1 = ConvNormActivation(
|
||||
in_channels=num_channels,
|
||||
out_channels=192,
|
||||
kernel_size=1,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.branch7x7x3_2 = ConvNormActivation(
|
||||
in_channels=192,
|
||||
out_channels=192,
|
||||
kernel_size=(1, 7),
|
||||
padding=(0, 3),
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.branch7x7x3_3 = ConvNormActivation(
|
||||
in_channels=192,
|
||||
out_channels=192,
|
||||
kernel_size=(7, 1),
|
||||
padding=(3, 0),
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.branch7x7x3_4 = ConvNormActivation(
|
||||
in_channels=192,
|
||||
out_channels=192,
|
||||
kernel_size=3,
|
||||
stride=2,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
|
||||
self.branch_pool = MaxPool2D(kernel_size=3, stride=2)
|
||||
|
||||
def forward(self, x: Tensor) -> Tensor:
|
||||
branch3x3 = self.branch3x3_1(x)
|
||||
branch3x3 = self.branch3x3_2(branch3x3)
|
||||
|
||||
branch7x7x3 = self.branch7x7x3_1(x)
|
||||
branch7x7x3 = self.branch7x7x3_2(branch7x7x3)
|
||||
branch7x7x3 = self.branch7x7x3_3(branch7x7x3)
|
||||
branch7x7x3 = self.branch7x7x3_4(branch7x7x3)
|
||||
|
||||
branch_pool = self.branch_pool(x)
|
||||
|
||||
x = paddle.concat([branch3x3, branch7x7x3, branch_pool], axis=1)
|
||||
return x
|
||||
|
||||
|
||||
class InceptionE(nn.Layer):
|
||||
def __init__(self, num_channels: int) -> None:
|
||||
super().__init__()
|
||||
self.branch1x1 = ConvNormActivation(
|
||||
in_channels=num_channels,
|
||||
out_channels=320,
|
||||
kernel_size=1,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.branch3x3_1 = ConvNormActivation(
|
||||
in_channels=num_channels,
|
||||
out_channels=384,
|
||||
kernel_size=1,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.branch3x3_2a = ConvNormActivation(
|
||||
in_channels=384,
|
||||
out_channels=384,
|
||||
kernel_size=(1, 3),
|
||||
padding=(0, 1),
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.branch3x3_2b = ConvNormActivation(
|
||||
in_channels=384,
|
||||
out_channels=384,
|
||||
kernel_size=(3, 1),
|
||||
padding=(1, 0),
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
|
||||
self.branch3x3dbl_1 = ConvNormActivation(
|
||||
in_channels=num_channels,
|
||||
out_channels=448,
|
||||
kernel_size=1,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.branch3x3dbl_2 = ConvNormActivation(
|
||||
in_channels=448,
|
||||
out_channels=384,
|
||||
kernel_size=3,
|
||||
padding=1,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.branch3x3dbl_3a = ConvNormActivation(
|
||||
in_channels=384,
|
||||
out_channels=384,
|
||||
kernel_size=(1, 3),
|
||||
padding=(0, 1),
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
self.branch3x3dbl_3b = ConvNormActivation(
|
||||
in_channels=384,
|
||||
out_channels=384,
|
||||
kernel_size=(3, 1),
|
||||
padding=(1, 0),
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
|
||||
self.branch_pool = AvgPool2D(
|
||||
kernel_size=3, stride=1, padding=1, exclusive=False
|
||||
)
|
||||
self.branch_pool_conv = ConvNormActivation(
|
||||
in_channels=num_channels,
|
||||
out_channels=192,
|
||||
kernel_size=1,
|
||||
padding=0,
|
||||
activation_layer=nn.ReLU,
|
||||
)
|
||||
|
||||
def forward(self, x: Tensor) -> Tensor:
|
||||
branch1x1 = self.branch1x1(x)
|
||||
|
||||
branch3x3 = self.branch3x3_1(x)
|
||||
branch3x3 = [
|
||||
self.branch3x3_2a(branch3x3),
|
||||
self.branch3x3_2b(branch3x3),
|
||||
]
|
||||
branch3x3 = paddle.concat(branch3x3, axis=1)
|
||||
|
||||
branch3x3dbl = self.branch3x3dbl_1(x)
|
||||
branch3x3dbl = self.branch3x3dbl_2(branch3x3dbl)
|
||||
branch3x3dbl = [
|
||||
self.branch3x3dbl_3a(branch3x3dbl),
|
||||
self.branch3x3dbl_3b(branch3x3dbl),
|
||||
]
|
||||
branch3x3dbl = paddle.concat(branch3x3dbl, axis=1)
|
||||
|
||||
branch_pool = self.branch_pool(x)
|
||||
branch_pool = self.branch_pool_conv(branch_pool)
|
||||
|
||||
x = paddle.concat(
|
||||
[branch1x1, branch3x3, branch3x3dbl, branch_pool], axis=1
|
||||
)
|
||||
return x
|
||||
|
||||
|
||||
class InceptionV3(nn.Layer):
|
||||
"""Inception v3 model from
|
||||
`"Rethinking the Inception Architecture for Computer Vision" <https://arxiv.org/pdf/1512.00567.pdf>`_.
|
||||
|
||||
Args:
|
||||
num_classes (int, optional): Output dim of last fc layer. If num_classes <= 0, last fc layer
|
||||
will not be defined. Default: 1000.
|
||||
with_pool (bool, optional): Use pool before the last fc layer or not. Default: True.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of Inception v3 model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import InceptionV3
|
||||
|
||||
>>> inception_v3 = InceptionV3()
|
||||
|
||||
>>> x = paddle.rand([1, 3, 299, 299])
|
||||
>>> out = inception_v3(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
|
||||
num_classes: int
|
||||
with_pool: bool
|
||||
|
||||
def __init__(self, num_classes: int = 1000, with_pool: bool = True) -> None:
|
||||
super().__init__()
|
||||
self.num_classes = num_classes
|
||||
self.with_pool = with_pool
|
||||
self.layers_config = {
|
||||
"inception_a": [[192, 256, 288], [32, 64, 64]],
|
||||
"inception_b": [288],
|
||||
"inception_c": [[768, 768, 768, 768], [128, 160, 160, 192]],
|
||||
"inception_d": [768],
|
||||
"inception_e": [1280, 2048],
|
||||
}
|
||||
|
||||
inception_a_list = self.layers_config["inception_a"]
|
||||
inception_c_list = self.layers_config["inception_c"]
|
||||
inception_b_list = self.layers_config["inception_b"]
|
||||
inception_d_list = self.layers_config["inception_d"]
|
||||
inception_e_list = self.layers_config["inception_e"]
|
||||
|
||||
self.inception_stem = InceptionStem()
|
||||
|
||||
self.inception_block_list = nn.LayerList()
|
||||
for i in range(len(inception_a_list[0])):
|
||||
inception_a = InceptionA(
|
||||
inception_a_list[0][i], inception_a_list[1][i]
|
||||
)
|
||||
self.inception_block_list.append(inception_a)
|
||||
|
||||
for i in range(len(inception_b_list)):
|
||||
inception_b = InceptionB(inception_b_list[i])
|
||||
self.inception_block_list.append(inception_b)
|
||||
|
||||
for i in range(len(inception_c_list[0])):
|
||||
inception_c = InceptionC(
|
||||
inception_c_list[0][i], inception_c_list[1][i]
|
||||
)
|
||||
self.inception_block_list.append(inception_c)
|
||||
|
||||
for i in range(len(inception_d_list)):
|
||||
inception_d = InceptionD(inception_d_list[i])
|
||||
self.inception_block_list.append(inception_d)
|
||||
|
||||
for i in range(len(inception_e_list)):
|
||||
inception_e = InceptionE(inception_e_list[i])
|
||||
self.inception_block_list.append(inception_e)
|
||||
|
||||
if with_pool:
|
||||
self.avg_pool = AdaptiveAvgPool2D(1)
|
||||
|
||||
if num_classes > 0:
|
||||
self.dropout = Dropout(p=0.2, mode="downscale_in_infer")
|
||||
stdv = 1.0 / math.sqrt(2048 * 1.0)
|
||||
self.fc = Linear(
|
||||
2048,
|
||||
num_classes,
|
||||
weight_attr=ParamAttr(initializer=Uniform(-stdv, stdv)),
|
||||
bias_attr=ParamAttr(),
|
||||
)
|
||||
|
||||
def forward(self, x: Tensor) -> Tensor:
|
||||
x = self.inception_stem(x)
|
||||
for inception_block in self.inception_block_list:
|
||||
x = inception_block(x)
|
||||
|
||||
if self.with_pool:
|
||||
x = self.avg_pool(x)
|
||||
|
||||
if self.num_classes > 0:
|
||||
x = paddle.reshape(x, shape=[-1, 2048])
|
||||
x = self.dropout(x)
|
||||
x = self.fc(x)
|
||||
return x
|
||||
|
||||
|
||||
def inception_v3(
|
||||
pretrained: bool = False, **kwargs: Unpack[_InceptionV3Options]
|
||||
) -> InceptionV3:
|
||||
"""Inception v3 model from
|
||||
`"Rethinking the Inception Architecture for Computer Vision" <https://arxiv.org/pdf/1512.00567.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`InceptionV3 <api_paddle_vision_models_InceptionV3>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of Inception v3 model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import inception_v3
|
||||
|
||||
>>> # Build model
|
||||
>>> model = inception_v3()
|
||||
|
||||
>>> # Build model and load imagenet pretrained weight
|
||||
>>> # model = inception_v3(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 299, 299])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
model = InceptionV3(**kwargs)
|
||||
arch = "inception_v3"
|
||||
if pretrained:
|
||||
assert arch in model_urls, (
|
||||
f"{arch} model do not have a pretrained model now, you should set pretrained=False"
|
||||
)
|
||||
weight_path = get_weights_path_from_url(
|
||||
model_urls[arch][0], model_urls[arch][1]
|
||||
)
|
||||
|
||||
param = paddle.load(weight_path)
|
||||
model.set_dict(param)
|
||||
return model
|
||||
@@ -0,0 +1,83 @@
|
||||
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
)
|
||||
|
||||
import paddle
|
||||
from paddle import nn
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
|
||||
__all__ = []
|
||||
|
||||
|
||||
class LeNet(nn.Layer):
|
||||
"""LeNet model from
|
||||
`"Gradient-based learning applied to document recognition" <https://ieeexplore.ieee.org/document/726791>`_.
|
||||
|
||||
Args:
|
||||
num_classes (int, optional): Output dim of last fc layer. If num_classes <= 0, last fc layer
|
||||
will not be defined. Default: 10.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of LeNet model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import LeNet
|
||||
|
||||
>>> model = LeNet()
|
||||
|
||||
>>> x = paddle.rand([1, 1, 28, 28])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 10])
|
||||
"""
|
||||
|
||||
num_classes: int
|
||||
|
||||
def __init__(self, num_classes: int = 10) -> None:
|
||||
super().__init__()
|
||||
self.num_classes = num_classes
|
||||
self.features = nn.Sequential(
|
||||
nn.Conv2D(1, 6, 3, stride=1, padding=1),
|
||||
nn.ReLU(),
|
||||
nn.MaxPool2D(2, 2),
|
||||
nn.Conv2D(6, 16, 5, stride=1, padding=0),
|
||||
nn.ReLU(),
|
||||
nn.MaxPool2D(2, 2),
|
||||
)
|
||||
|
||||
if num_classes > 0:
|
||||
self.fc = nn.Sequential(
|
||||
nn.Linear(400, 120),
|
||||
nn.Linear(120, 84),
|
||||
nn.Linear(84, num_classes),
|
||||
)
|
||||
|
||||
def forward(self, inputs: Tensor) -> Tensor:
|
||||
x = self.features(inputs)
|
||||
|
||||
if self.num_classes > 0:
|
||||
x = paddle.flatten(x, 1)
|
||||
x = self.fc(x)
|
||||
return x
|
||||
@@ -0,0 +1,334 @@
|
||||
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
TypedDict,
|
||||
)
|
||||
|
||||
from typing_extensions import NotRequired, Unpack
|
||||
|
||||
import paddle
|
||||
from paddle import nn
|
||||
from paddle.utils.download import get_weights_path_from_url
|
||||
|
||||
from ..ops import ConvNormActivation
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
from paddle._typing import Size2
|
||||
|
||||
class _MobileNetV1Options(TypedDict):
|
||||
num_classes: NotRequired[int]
|
||||
with_pool: NotRequired[bool]
|
||||
|
||||
|
||||
__all__ = []
|
||||
|
||||
|
||||
model_urls = {
|
||||
'mobilenetv1_1.0': (
|
||||
'https://paddle-hapi.bj.bcebos.com/models/mobilenetv1_1.0.pdparams',
|
||||
'3033ab1975b1670bef51545feb65fc45',
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
class DepthwiseSeparable(nn.Layer):
|
||||
def __init__(
|
||||
self,
|
||||
in_channels: int,
|
||||
out_channels1: int,
|
||||
out_channels2: int,
|
||||
num_groups: int,
|
||||
stride: Size2,
|
||||
scale: float,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
|
||||
self._depthwise_conv = ConvNormActivation(
|
||||
in_channels,
|
||||
int(out_channels1 * scale),
|
||||
kernel_size=3,
|
||||
stride=stride,
|
||||
padding=1,
|
||||
groups=int(num_groups * scale),
|
||||
)
|
||||
|
||||
self._pointwise_conv = ConvNormActivation(
|
||||
int(out_channels1 * scale),
|
||||
int(out_channels2 * scale),
|
||||
kernel_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
)
|
||||
|
||||
def forward(self, x: Tensor) -> Tensor:
|
||||
x = self._depthwise_conv(x)
|
||||
x = self._pointwise_conv(x)
|
||||
return x
|
||||
|
||||
|
||||
class MobileNetV1(nn.Layer):
|
||||
"""MobileNetV1 model from
|
||||
`"MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications" <https://arxiv.org/abs/1704.04861>`_.
|
||||
|
||||
Args:
|
||||
scale (float, optional): Scale of channels in each layer. Default: 1.0.
|
||||
num_classes (int, optional): Output dim of last fc layer. If num_classes <= 0, last fc layer
|
||||
will not be defined. Default: 1000.
|
||||
with_pool (bool, optional): Use pool before the last fc layer or not. Default: True.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of MobileNetV1 model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import MobileNetV1
|
||||
|
||||
>>> model = MobileNetV1()
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
|
||||
scale: float
|
||||
num_classes: int
|
||||
with_pool: bool
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
scale: float = 1.0,
|
||||
num_classes: int = 1000,
|
||||
with_pool: bool = True,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.scale = scale
|
||||
self.dwsl = []
|
||||
self.num_classes = num_classes
|
||||
self.with_pool = with_pool
|
||||
|
||||
self.conv1 = ConvNormActivation(
|
||||
in_channels=3,
|
||||
out_channels=int(32 * scale),
|
||||
kernel_size=3,
|
||||
stride=2,
|
||||
padding=1,
|
||||
)
|
||||
|
||||
dws21 = self.add_sublayer(
|
||||
sublayer=DepthwiseSeparable(
|
||||
in_channels=int(32 * scale),
|
||||
out_channels1=32,
|
||||
out_channels2=64,
|
||||
num_groups=32,
|
||||
stride=1,
|
||||
scale=scale,
|
||||
),
|
||||
name="conv2_1",
|
||||
)
|
||||
self.dwsl.append(dws21)
|
||||
|
||||
dws22 = self.add_sublayer(
|
||||
sublayer=DepthwiseSeparable(
|
||||
in_channels=int(64 * scale),
|
||||
out_channels1=64,
|
||||
out_channels2=128,
|
||||
num_groups=64,
|
||||
stride=2,
|
||||
scale=scale,
|
||||
),
|
||||
name="conv2_2",
|
||||
)
|
||||
self.dwsl.append(dws22)
|
||||
|
||||
dws31 = self.add_sublayer(
|
||||
sublayer=DepthwiseSeparable(
|
||||
in_channels=int(128 * scale),
|
||||
out_channels1=128,
|
||||
out_channels2=128,
|
||||
num_groups=128,
|
||||
stride=1,
|
||||
scale=scale,
|
||||
),
|
||||
name="conv3_1",
|
||||
)
|
||||
self.dwsl.append(dws31)
|
||||
|
||||
dws32 = self.add_sublayer(
|
||||
sublayer=DepthwiseSeparable(
|
||||
in_channels=int(128 * scale),
|
||||
out_channels1=128,
|
||||
out_channels2=256,
|
||||
num_groups=128,
|
||||
stride=2,
|
||||
scale=scale,
|
||||
),
|
||||
name="conv3_2",
|
||||
)
|
||||
self.dwsl.append(dws32)
|
||||
|
||||
dws41 = self.add_sublayer(
|
||||
sublayer=DepthwiseSeparable(
|
||||
in_channels=int(256 * scale),
|
||||
out_channels1=256,
|
||||
out_channels2=256,
|
||||
num_groups=256,
|
||||
stride=1,
|
||||
scale=scale,
|
||||
),
|
||||
name="conv4_1",
|
||||
)
|
||||
self.dwsl.append(dws41)
|
||||
|
||||
dws42 = self.add_sublayer(
|
||||
sublayer=DepthwiseSeparable(
|
||||
in_channels=int(256 * scale),
|
||||
out_channels1=256,
|
||||
out_channels2=512,
|
||||
num_groups=256,
|
||||
stride=2,
|
||||
scale=scale,
|
||||
),
|
||||
name="conv4_2",
|
||||
)
|
||||
self.dwsl.append(dws42)
|
||||
|
||||
for i in range(5):
|
||||
tmp = self.add_sublayer(
|
||||
sublayer=DepthwiseSeparable(
|
||||
in_channels=int(512 * scale),
|
||||
out_channels1=512,
|
||||
out_channels2=512,
|
||||
num_groups=512,
|
||||
stride=1,
|
||||
scale=scale,
|
||||
),
|
||||
name="conv5_" + str(i + 1),
|
||||
)
|
||||
self.dwsl.append(tmp)
|
||||
|
||||
dws56 = self.add_sublayer(
|
||||
sublayer=DepthwiseSeparable(
|
||||
in_channels=int(512 * scale),
|
||||
out_channels1=512,
|
||||
out_channels2=1024,
|
||||
num_groups=512,
|
||||
stride=2,
|
||||
scale=scale,
|
||||
),
|
||||
name="conv5_6",
|
||||
)
|
||||
self.dwsl.append(dws56)
|
||||
|
||||
dws6 = self.add_sublayer(
|
||||
sublayer=DepthwiseSeparable(
|
||||
in_channels=int(1024 * scale),
|
||||
out_channels1=1024,
|
||||
out_channels2=1024,
|
||||
num_groups=1024,
|
||||
stride=1,
|
||||
scale=scale,
|
||||
),
|
||||
name="conv6",
|
||||
)
|
||||
self.dwsl.append(dws6)
|
||||
|
||||
if with_pool:
|
||||
self.pool2d_avg = nn.AdaptiveAvgPool2D(1)
|
||||
|
||||
if num_classes > 0:
|
||||
self.fc = nn.Linear(int(1024 * scale), num_classes)
|
||||
|
||||
def forward(self, x: Tensor) -> Tensor:
|
||||
x = self.conv1(x)
|
||||
for dws in self.dwsl:
|
||||
x = dws(x)
|
||||
|
||||
if self.with_pool:
|
||||
x = self.pool2d_avg(x)
|
||||
|
||||
if self.num_classes > 0:
|
||||
x = paddle.flatten(x, 1)
|
||||
x = self.fc(x)
|
||||
return x
|
||||
|
||||
|
||||
def _mobilenet(
|
||||
arch: str, pretrained: bool = False, **kwargs: Unpack[_MobileNetV1Options]
|
||||
) -> MobileNetV1:
|
||||
model = MobileNetV1(**kwargs)
|
||||
if pretrained:
|
||||
assert arch in model_urls, (
|
||||
f"{arch} model do not have a pretrained model now, you should set pretrained=False"
|
||||
)
|
||||
weight_path = get_weights_path_from_url(
|
||||
model_urls[arch][0], model_urls[arch][1]
|
||||
)
|
||||
|
||||
param = paddle.load(weight_path)
|
||||
model.load_dict(param)
|
||||
|
||||
return model
|
||||
|
||||
|
||||
def mobilenet_v1(
|
||||
pretrained: bool = False,
|
||||
scale: float = 1.0,
|
||||
**kwargs: Unpack[_MobileNetV1Options],
|
||||
) -> MobileNetV1:
|
||||
"""MobileNetV1 from
|
||||
`"MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications" <https://arxiv.org/abs/1704.04861>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
scale (float, optional): Scale of channels in each layer. Default: 1.0.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`MobileNetV1 <api_paddle_vision_models_MobileNetV1>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of MobileNetV1 model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import mobilenet_v1
|
||||
|
||||
>>> # Build model
|
||||
>>> model = mobilenet_v1()
|
||||
|
||||
>>> # Build model and load imagenet pretrained weight
|
||||
>>> # model = mobilenet_v1(pretrained=True)
|
||||
|
||||
>>> # build mobilenet v1 with scale=0.5
|
||||
>>> model_scale = mobilenet_v1(scale=0.5)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
model = _mobilenet(
|
||||
'mobilenetv1_' + str(scale), pretrained, scale=scale, **kwargs
|
||||
)
|
||||
return model
|
||||
@@ -0,0 +1,276 @@
|
||||
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
TypedDict,
|
||||
)
|
||||
|
||||
from typing_extensions import NotRequired, Unpack
|
||||
|
||||
import paddle
|
||||
from paddle import nn
|
||||
from paddle.utils.download import get_weights_path_from_url
|
||||
|
||||
from ..ops import ConvNormActivation
|
||||
from ._utils import _make_divisible
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Callable
|
||||
|
||||
from paddle import Tensor
|
||||
|
||||
class _MobileNetV2Options(TypedDict):
|
||||
num_classes: NotRequired[int]
|
||||
with_pool: NotRequired[bool]
|
||||
|
||||
|
||||
__all__ = []
|
||||
|
||||
model_urls = {
|
||||
'mobilenetv2_1.0': (
|
||||
'https://paddle-hapi.bj.bcebos.com/models/mobilenet_v2_x1.0.pdparams',
|
||||
'0340af0a901346c8d46f4529882fb63d',
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
class InvertedResidual(nn.Layer):
|
||||
def __init__(
|
||||
self,
|
||||
inp: int,
|
||||
oup: int,
|
||||
stride: int,
|
||||
expand_ratio: float,
|
||||
norm_layer: Callable[..., nn.Layer] = nn.BatchNorm2D,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.stride = stride
|
||||
assert stride in [1, 2]
|
||||
|
||||
hidden_dim = int(round(inp * expand_ratio))
|
||||
self.use_res_connect = self.stride == 1 and inp == oup
|
||||
|
||||
layers = []
|
||||
if expand_ratio != 1:
|
||||
layers.append(
|
||||
ConvNormActivation(
|
||||
inp,
|
||||
hidden_dim,
|
||||
kernel_size=1,
|
||||
norm_layer=norm_layer,
|
||||
activation_layer=nn.ReLU6,
|
||||
)
|
||||
)
|
||||
layers.extend(
|
||||
[
|
||||
ConvNormActivation(
|
||||
hidden_dim,
|
||||
hidden_dim,
|
||||
stride=stride,
|
||||
groups=hidden_dim,
|
||||
norm_layer=norm_layer,
|
||||
activation_layer=nn.ReLU6,
|
||||
),
|
||||
nn.Conv2D(hidden_dim, oup, 1, 1, 0, bias_attr=False),
|
||||
norm_layer(oup),
|
||||
]
|
||||
)
|
||||
self.conv = nn.Sequential(*layers)
|
||||
|
||||
def forward(self, x: Tensor) -> Tensor:
|
||||
if self.use_res_connect:
|
||||
return x + self.conv(x)
|
||||
else:
|
||||
return self.conv(x)
|
||||
|
||||
|
||||
class MobileNetV2(nn.Layer):
|
||||
"""MobileNetV2 model from
|
||||
`"MobileNetV2: Inverted Residuals and Linear Bottlenecks" <https://arxiv.org/abs/1801.04381>`_.
|
||||
|
||||
Args:
|
||||
scale (float, optional): Scale of channels in each layer. Default: 1.0.
|
||||
num_classes (int, optional): Output dim of last fc layer. If num_classes <= 0, last fc layer
|
||||
will not be defined. Default: 1000.
|
||||
with_pool (bool, optional): Use pool before the last fc layer or not. Default: True.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of MobileNetV2 model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import MobileNetV2
|
||||
|
||||
>>> model = MobileNetV2()
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
|
||||
num_classes: int
|
||||
with_pool: bool
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
scale: float = 1.0,
|
||||
num_classes: int = 1000,
|
||||
with_pool: bool = True,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.num_classes = num_classes
|
||||
self.with_pool = with_pool
|
||||
input_channel = 32
|
||||
last_channel = 1280
|
||||
|
||||
block = InvertedResidual
|
||||
round_nearest = 8
|
||||
norm_layer = nn.BatchNorm2D
|
||||
inverted_residual_setting = [
|
||||
[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_channel = _make_divisible(input_channel * scale, round_nearest)
|
||||
self.last_channel = _make_divisible(
|
||||
last_channel * max(1.0, scale), round_nearest
|
||||
)
|
||||
features = [
|
||||
ConvNormActivation(
|
||||
3,
|
||||
input_channel,
|
||||
stride=2,
|
||||
norm_layer=norm_layer,
|
||||
activation_layer=nn.ReLU6,
|
||||
)
|
||||
]
|
||||
|
||||
for t, c, n, s in inverted_residual_setting:
|
||||
output_channel = _make_divisible(c * scale, round_nearest)
|
||||
for i in range(n):
|
||||
stride = s if i == 0 else 1
|
||||
features.append(
|
||||
block(
|
||||
input_channel,
|
||||
output_channel,
|
||||
stride,
|
||||
expand_ratio=t,
|
||||
norm_layer=norm_layer,
|
||||
)
|
||||
)
|
||||
input_channel = output_channel
|
||||
|
||||
features.append(
|
||||
ConvNormActivation(
|
||||
input_channel,
|
||||
self.last_channel,
|
||||
kernel_size=1,
|
||||
norm_layer=norm_layer,
|
||||
activation_layer=nn.ReLU6,
|
||||
)
|
||||
)
|
||||
|
||||
self.features = nn.Sequential(*features)
|
||||
|
||||
if with_pool:
|
||||
self.pool2d_avg = nn.AdaptiveAvgPool2D(1)
|
||||
|
||||
if self.num_classes > 0:
|
||||
self.classifier = nn.Sequential(
|
||||
nn.Dropout(0.2), nn.Linear(self.last_channel, num_classes)
|
||||
)
|
||||
|
||||
def forward(self, x: Tensor) -> Tensor:
|
||||
x = self.features(x)
|
||||
|
||||
if self.with_pool:
|
||||
x = self.pool2d_avg(x)
|
||||
|
||||
if self.num_classes > 0:
|
||||
x = paddle.flatten(x, 1)
|
||||
x = self.classifier(x)
|
||||
return x
|
||||
|
||||
|
||||
def _mobilenet(
|
||||
arch: str, pretrained: bool = False, **kwargs: Unpack[_MobileNetV2Options]
|
||||
) -> MobileNetV2:
|
||||
model = MobileNetV2(**kwargs)
|
||||
if pretrained:
|
||||
assert arch in model_urls, (
|
||||
f"{arch} model do not have a pretrained model now, you should set pretrained=False"
|
||||
)
|
||||
weight_path = get_weights_path_from_url(
|
||||
model_urls[arch][0], model_urls[arch][1]
|
||||
)
|
||||
|
||||
param = paddle.load(weight_path)
|
||||
model.load_dict(param)
|
||||
|
||||
return model
|
||||
|
||||
|
||||
def mobilenet_v2(
|
||||
pretrained: bool = False,
|
||||
scale: float = 1.0,
|
||||
**kwargs: Unpack[_MobileNetV2Options],
|
||||
) -> MobileNetV2:
|
||||
"""MobileNetV2 from
|
||||
`"MobileNetV2: Inverted Residuals and Linear Bottlenecks" <https://arxiv.org/abs/1801.04381>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained on ImageNet. Default: False.
|
||||
scale (float, optional): Scale of channels in each layer. Default: 1.0.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`MobileNetV2 <api_paddle_vision_models_MobileNetV2>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of MobileNetV2 model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import mobilenet_v2
|
||||
|
||||
>>> # Build model
|
||||
>>> model = mobilenet_v2()
|
||||
|
||||
>>> # Build model and load imagenet pretrained weight
|
||||
>>> # model = mobilenet_v2(pretrained=True)
|
||||
|
||||
>>> # Build mobilenet v2 with scale=0.5
|
||||
>>> model = mobilenet_v2(scale=0.5)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
model = _mobilenet(
|
||||
'mobilenetv2_' + str(scale), pretrained, scale=scale, **kwargs
|
||||
)
|
||||
return model
|
||||
@@ -0,0 +1,547 @@
|
||||
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from functools import partial
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
TypedDict,
|
||||
)
|
||||
|
||||
from typing_extensions import NotRequired, Unpack
|
||||
|
||||
import paddle
|
||||
from paddle import nn
|
||||
from paddle.utils.download import get_weights_path_from_url
|
||||
|
||||
from ..ops import ConvNormActivation
|
||||
from ._utils import _make_divisible
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Callable
|
||||
|
||||
from paddle import Tensor
|
||||
|
||||
class _MobileNetV3Options(TypedDict):
|
||||
num_classes: NotRequired[int]
|
||||
with_pool: NotRequired[bool]
|
||||
|
||||
|
||||
__all__ = []
|
||||
|
||||
model_urls = {
|
||||
"mobilenet_v3_small_x1.0": (
|
||||
"https://paddle-hapi.bj.bcebos.com/models/mobilenet_v3_small_x1.0.pdparams",
|
||||
"34fe0e7c1f8b00b2b056ad6788d0590c",
|
||||
),
|
||||
"mobilenet_v3_large_x1.0": (
|
||||
"https://paddle-hapi.bj.bcebos.com/models/mobilenet_v3_large_x1.0.pdparams",
|
||||
"118db5792b4e183b925d8e8e334db3df",
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
class SqueezeExcitation(nn.Layer):
|
||||
"""
|
||||
This block implements the Squeeze-and-Excitation block from https://arxiv.org/abs/1709.01507 (see Fig. 1).
|
||||
Parameters ``activation``, and ``scale_activation`` correspond to ``delta`` and ``sigma`` in eq. 3.
|
||||
This code is based on the torchvision code with modifications.
|
||||
You can also see at https://github.com/pytorch/vision/blob/main/torchvision/ops/misc.py#L127
|
||||
|
||||
Args:
|
||||
input_channels (int): Number of channels in the input image.
|
||||
squeeze_channels (int): Number of squeeze channels.
|
||||
activation (Callable[..., paddle.nn.Layer], optional): ``delta`` activation. Default: ``paddle.nn.ReLU``.
|
||||
scale_activation (Callable[..., paddle.nn.Layer]): ``sigma`` activation. Default: ``paddle.nn.Sigmoid``.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
input_channels: int,
|
||||
squeeze_channels: int,
|
||||
activation: Callable[..., nn.Layer] = nn.ReLU,
|
||||
scale_activation: Callable[..., nn.Layer] = nn.Sigmoid,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.avgpool = nn.AdaptiveAvgPool2D(1)
|
||||
self.fc1 = nn.Conv2D(input_channels, squeeze_channels, 1)
|
||||
self.fc2 = nn.Conv2D(squeeze_channels, input_channels, 1)
|
||||
self.activation = activation()
|
||||
self.scale_activation = scale_activation()
|
||||
|
||||
def _scale(self, input: Tensor) -> Tensor:
|
||||
scale = self.avgpool(input)
|
||||
scale = self.fc1(scale)
|
||||
scale = self.activation(scale)
|
||||
scale = self.fc2(scale)
|
||||
return self.scale_activation(scale)
|
||||
|
||||
def forward(self, input: Tensor) -> Tensor:
|
||||
scale = self._scale(input)
|
||||
return scale * input
|
||||
|
||||
|
||||
class InvertedResidualConfig:
|
||||
def __init__(
|
||||
self,
|
||||
in_channels: int,
|
||||
kernel: int,
|
||||
expanded_channels: int,
|
||||
out_channels: int,
|
||||
use_se: bool,
|
||||
activation: str,
|
||||
stride: int,
|
||||
scale: float = 1.0,
|
||||
):
|
||||
self.in_channels = self.adjust_channels(in_channels, scale=scale)
|
||||
self.kernel = kernel
|
||||
self.expanded_channels = self.adjust_channels(
|
||||
expanded_channels, scale=scale
|
||||
)
|
||||
self.out_channels = self.adjust_channels(out_channels, scale=scale)
|
||||
self.use_se = use_se
|
||||
if activation is None:
|
||||
self.activation_layer = None
|
||||
elif activation == "relu":
|
||||
self.activation_layer = nn.ReLU
|
||||
elif activation == "hardswish":
|
||||
self.activation_layer = nn.Hardswish
|
||||
else:
|
||||
raise RuntimeError(
|
||||
f"The activation function is not supported: {activation}"
|
||||
)
|
||||
self.stride = stride
|
||||
|
||||
@staticmethod
|
||||
def adjust_channels(channels, scale=1.0):
|
||||
return _make_divisible(channels * scale, 8)
|
||||
|
||||
|
||||
class InvertedResidual(nn.Layer):
|
||||
def __init__(
|
||||
self,
|
||||
in_channels: int,
|
||||
expanded_channels: int,
|
||||
out_channels: int,
|
||||
filter_size: int,
|
||||
stride: int,
|
||||
use_se: bool,
|
||||
activation_layer: Callable[..., nn.Layer],
|
||||
norm_layer: Callable[..., nn.Layer],
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.use_res_connect = stride == 1 and in_channels == out_channels
|
||||
self.use_se = use_se
|
||||
self.expand = in_channels != expanded_channels
|
||||
|
||||
if self.expand:
|
||||
self.expand_conv = ConvNormActivation(
|
||||
in_channels=in_channels,
|
||||
out_channels=expanded_channels,
|
||||
kernel_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
norm_layer=norm_layer,
|
||||
activation_layer=activation_layer,
|
||||
)
|
||||
|
||||
self.bottleneck_conv = ConvNormActivation(
|
||||
in_channels=expanded_channels,
|
||||
out_channels=expanded_channels,
|
||||
kernel_size=filter_size,
|
||||
stride=stride,
|
||||
padding=int((filter_size - 1) // 2),
|
||||
groups=expanded_channels,
|
||||
norm_layer=norm_layer,
|
||||
activation_layer=activation_layer,
|
||||
)
|
||||
|
||||
if self.use_se:
|
||||
self.mid_se = SqueezeExcitation(
|
||||
expanded_channels,
|
||||
_make_divisible(expanded_channels // 4),
|
||||
scale_activation=nn.Hardsigmoid,
|
||||
)
|
||||
|
||||
self.linear_conv = ConvNormActivation(
|
||||
in_channels=expanded_channels,
|
||||
out_channels=out_channels,
|
||||
kernel_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
norm_layer=norm_layer,
|
||||
activation_layer=None,
|
||||
)
|
||||
|
||||
def forward(self, x: Tensor) -> Tensor:
|
||||
identity = x
|
||||
if self.expand:
|
||||
x = self.expand_conv(x)
|
||||
x = self.bottleneck_conv(x)
|
||||
if self.use_se:
|
||||
x = self.mid_se(x)
|
||||
x = self.linear_conv(x)
|
||||
if self.use_res_connect:
|
||||
x = paddle.add(identity, x)
|
||||
return x
|
||||
|
||||
|
||||
class MobileNetV3(nn.Layer):
|
||||
"""MobileNetV3 model from
|
||||
`"Searching for MobileNetV3" <https://arxiv.org/abs/1905.02244>`_.
|
||||
|
||||
Args:
|
||||
config (list[InvertedResidualConfig]): MobileNetV3 depthwise blocks config.
|
||||
last_channel (int): The number of channels on the penultimate layer.
|
||||
scale (float, optional): Scale of channels in each layer. Default: 1.0.
|
||||
num_classes (int, optional): Output dim of last fc layer. If num_classes <=0, last fc layer
|
||||
will not be defined. Default: 1000.
|
||||
with_pool (bool, optional): Use pool before the last fc layer or not. Default: True.
|
||||
"""
|
||||
|
||||
scale: float
|
||||
num_classes: int
|
||||
with_pool: bool
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
config: list[InvertedResidualConfig],
|
||||
last_channel: int,
|
||||
scale: float = 1.0,
|
||||
num_classes: int = 1000,
|
||||
with_pool: bool = True,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
|
||||
self.config = config
|
||||
self.scale = scale
|
||||
self.last_channel = last_channel
|
||||
self.num_classes = num_classes
|
||||
self.with_pool = with_pool
|
||||
self.firstconv_in_channels = config[0].in_channels
|
||||
self.lastconv_in_channels = config[-1].in_channels
|
||||
self.lastconv_out_channels = self.lastconv_in_channels * 6
|
||||
norm_layer = partial(nn.BatchNorm2D, epsilon=0.001, momentum=0.99)
|
||||
|
||||
self.conv = ConvNormActivation(
|
||||
in_channels=3,
|
||||
out_channels=self.firstconv_in_channels,
|
||||
kernel_size=3,
|
||||
stride=2,
|
||||
padding=1,
|
||||
groups=1,
|
||||
activation_layer=nn.Hardswish,
|
||||
norm_layer=norm_layer,
|
||||
)
|
||||
|
||||
self.blocks = nn.Sequential(
|
||||
*[
|
||||
InvertedResidual(
|
||||
in_channels=cfg.in_channels,
|
||||
expanded_channels=cfg.expanded_channels,
|
||||
out_channels=cfg.out_channels,
|
||||
filter_size=cfg.kernel,
|
||||
stride=cfg.stride,
|
||||
use_se=cfg.use_se,
|
||||
activation_layer=cfg.activation_layer,
|
||||
norm_layer=norm_layer,
|
||||
)
|
||||
for cfg in self.config
|
||||
]
|
||||
)
|
||||
|
||||
self.lastconv = ConvNormActivation(
|
||||
in_channels=self.lastconv_in_channels,
|
||||
out_channels=self.lastconv_out_channels,
|
||||
kernel_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
groups=1,
|
||||
norm_layer=norm_layer,
|
||||
activation_layer=nn.Hardswish,
|
||||
)
|
||||
|
||||
if with_pool:
|
||||
self.avgpool = nn.AdaptiveAvgPool2D(1)
|
||||
|
||||
if num_classes > 0:
|
||||
self.classifier = nn.Sequential(
|
||||
nn.Linear(self.lastconv_out_channels, self.last_channel),
|
||||
nn.Hardswish(),
|
||||
nn.Dropout(p=0.2),
|
||||
nn.Linear(self.last_channel, num_classes),
|
||||
)
|
||||
|
||||
def forward(self, x: Tensor) -> Tensor:
|
||||
x = self.conv(x)
|
||||
x = self.blocks(x)
|
||||
x = self.lastconv(x)
|
||||
|
||||
if self.with_pool:
|
||||
x = self.avgpool(x)
|
||||
|
||||
if self.num_classes > 0:
|
||||
x = paddle.flatten(x, 1)
|
||||
x = self.classifier(x)
|
||||
|
||||
return x
|
||||
|
||||
|
||||
class MobileNetV3Small(MobileNetV3):
|
||||
"""MobileNetV3 Small architecture model from
|
||||
`"Searching for MobileNetV3" <https://arxiv.org/abs/1905.02244>`_.
|
||||
|
||||
Args:
|
||||
scale (float, optional): Scale of channels in each layer. Default: 1.0.
|
||||
num_classes (int, optional): Output dim of last fc layer. If num_classes <= 0, last fc layer
|
||||
will not be defined. Default: 1000.
|
||||
with_pool (bool, optional): Use pool before the last fc layer or not. Default: True.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of MobileNetV3 Small architecture model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import MobileNetV3Small
|
||||
|
||||
>>> # Build model
|
||||
>>> model = MobileNetV3Small(scale=1.0)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
scale: float = 1.0,
|
||||
num_classes: int = 1000,
|
||||
with_pool: bool = True,
|
||||
) -> None:
|
||||
config = [
|
||||
InvertedResidualConfig(16, 3, 16, 16, True, "relu", 2, scale),
|
||||
InvertedResidualConfig(16, 3, 72, 24, False, "relu", 2, scale),
|
||||
InvertedResidualConfig(24, 3, 88, 24, False, "relu", 1, scale),
|
||||
InvertedResidualConfig(24, 5, 96, 40, True, "hardswish", 2, scale),
|
||||
InvertedResidualConfig(40, 5, 240, 40, True, "hardswish", 1, scale),
|
||||
InvertedResidualConfig(40, 5, 240, 40, True, "hardswish", 1, scale),
|
||||
InvertedResidualConfig(40, 5, 120, 48, True, "hardswish", 1, scale),
|
||||
InvertedResidualConfig(48, 5, 144, 48, True, "hardswish", 1, scale),
|
||||
InvertedResidualConfig(48, 5, 288, 96, True, "hardswish", 2, scale),
|
||||
InvertedResidualConfig(96, 5, 576, 96, True, "hardswish", 1, scale),
|
||||
InvertedResidualConfig(96, 5, 576, 96, True, "hardswish", 1, scale),
|
||||
]
|
||||
last_channel = _make_divisible(1024 * scale, 8)
|
||||
super().__init__(
|
||||
config,
|
||||
last_channel=last_channel,
|
||||
scale=scale,
|
||||
with_pool=with_pool,
|
||||
num_classes=num_classes,
|
||||
)
|
||||
|
||||
|
||||
class MobileNetV3Large(MobileNetV3):
|
||||
"""MobileNetV3 Large architecture model from
|
||||
`"Searching for MobileNetV3" <https://arxiv.org/abs/1905.02244>`_.
|
||||
|
||||
Args:
|
||||
scale (float, optional): Scale of channels in each layer. Default: 1.0.
|
||||
num_classes (int, optional): Output dim of last fc layer. If num_classes <= 0, last fc layer
|
||||
will not be defined. Default: 1000.
|
||||
with_pool (bool, optional): Use pool before the last fc layer or not. Default: True.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of MobileNetV3 Large architecture model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import MobileNetV3Large
|
||||
|
||||
>>> # Build model
|
||||
>>> model = MobileNetV3Large(scale=1.0)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
scale: float = 1.0,
|
||||
num_classes: int = 1000,
|
||||
with_pool: bool = True,
|
||||
) -> None:
|
||||
config = [
|
||||
InvertedResidualConfig(16, 3, 16, 16, False, "relu", 1, scale),
|
||||
InvertedResidualConfig(16, 3, 64, 24, False, "relu", 2, scale),
|
||||
InvertedResidualConfig(24, 3, 72, 24, False, "relu", 1, scale),
|
||||
InvertedResidualConfig(24, 5, 72, 40, True, "relu", 2, scale),
|
||||
InvertedResidualConfig(40, 5, 120, 40, True, "relu", 1, scale),
|
||||
InvertedResidualConfig(40, 5, 120, 40, True, "relu", 1, scale),
|
||||
InvertedResidualConfig(
|
||||
40, 3, 240, 80, False, "hardswish", 2, scale
|
||||
),
|
||||
InvertedResidualConfig(
|
||||
80, 3, 200, 80, False, "hardswish", 1, scale
|
||||
),
|
||||
InvertedResidualConfig(
|
||||
80, 3, 184, 80, False, "hardswish", 1, scale
|
||||
),
|
||||
InvertedResidualConfig(
|
||||
80, 3, 184, 80, False, "hardswish", 1, scale
|
||||
),
|
||||
InvertedResidualConfig(
|
||||
80, 3, 480, 112, True, "hardswish", 1, scale
|
||||
),
|
||||
InvertedResidualConfig(
|
||||
112, 3, 672, 112, True, "hardswish", 1, scale
|
||||
),
|
||||
InvertedResidualConfig(
|
||||
112, 5, 672, 160, True, "hardswish", 2, scale
|
||||
),
|
||||
InvertedResidualConfig(
|
||||
160, 5, 960, 160, True, "hardswish", 1, scale
|
||||
),
|
||||
InvertedResidualConfig(
|
||||
160, 5, 960, 160, True, "hardswish", 1, scale
|
||||
),
|
||||
]
|
||||
last_channel = _make_divisible(1280 * scale, 8)
|
||||
super().__init__(
|
||||
config,
|
||||
last_channel=last_channel,
|
||||
scale=scale,
|
||||
with_pool=with_pool,
|
||||
num_classes=num_classes,
|
||||
)
|
||||
|
||||
|
||||
def _mobilenet_v3(
|
||||
arch: str,
|
||||
pretrained: bool = False,
|
||||
scale: float = 1.0,
|
||||
**kwargs: Unpack[_MobileNetV3Options],
|
||||
) -> MobileNetV3:
|
||||
if arch == "mobilenet_v3_large":
|
||||
model = MobileNetV3Large(scale=scale, **kwargs)
|
||||
else:
|
||||
model = MobileNetV3Small(scale=scale, **kwargs)
|
||||
if pretrained:
|
||||
arch = f"{arch}_x{scale}"
|
||||
assert arch in model_urls, (
|
||||
f"{arch} model do not have a pretrained model now, you should set pretrained=False"
|
||||
)
|
||||
weight_path = get_weights_path_from_url(
|
||||
model_urls[arch][0], model_urls[arch][1]
|
||||
)
|
||||
|
||||
param = paddle.load(weight_path)
|
||||
model.set_dict(param)
|
||||
return model
|
||||
|
||||
|
||||
def mobilenet_v3_small(
|
||||
pretrained: bool = False,
|
||||
scale: float = 1.0,
|
||||
**kwargs: Unpack[_MobileNetV3Options],
|
||||
) -> MobileNetV3Small:
|
||||
"""MobileNetV3 Small architecture model from
|
||||
`"Searching for MobileNetV3" <https://arxiv.org/abs/1905.02244>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained on ImageNet. Default: False.
|
||||
scale (float, optional): Scale of channels in each layer. Default: 1.0.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`MobileNetV3Small <api_paddle_vision_models_MobileNetV3Small>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of MobileNetV3 Small architecture model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import mobilenet_v3_small
|
||||
|
||||
>>> # Build model
|
||||
>>> model = mobilenet_v3_small()
|
||||
|
||||
>>> # Build model and load imagenet pretrained weight
|
||||
>>> # model = mobilenet_v3_small(pretrained=True)
|
||||
|
||||
>>> # Build mobilenet v3 small model with scale=0.5
|
||||
>>> model = mobilenet_v3_small(scale=0.5)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
model = _mobilenet_v3(
|
||||
"mobilenet_v3_small", scale=scale, pretrained=pretrained, **kwargs
|
||||
)
|
||||
return model
|
||||
|
||||
|
||||
def mobilenet_v3_large(
|
||||
pretrained: bool = False,
|
||||
scale: float = 1.0,
|
||||
**kwargs: Unpack[_MobileNetV3Options],
|
||||
) -> MobileNetV3Large:
|
||||
"""MobileNetV3 Large architecture model from
|
||||
`"Searching for MobileNetV3" <https://arxiv.org/abs/1905.02244>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained on ImageNet. Default: False.
|
||||
scale (float, optional): Scale of channels in each layer. Default: 1.0.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`MobileNetV3Large <api_paddle_vision_models_MobileNetV3Large>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of MobileNetV3 Large architecture model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import mobilenet_v3_large
|
||||
|
||||
>>> # Build model
|
||||
>>> model = mobilenet_v3_large()
|
||||
|
||||
>>> # Build model and load imagenet pretrained weight
|
||||
>>> # model = mobilenet_v3_large(pretrained=True)
|
||||
|
||||
>>> # Build mobilenet v3 large model with scale=0.5
|
||||
>>> model = mobilenet_v3_large(scale=0.5)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
model = _mobilenet_v3(
|
||||
"mobilenet_v3_large", scale=scale, pretrained=pretrained, **kwargs
|
||||
)
|
||||
return model
|
||||
@@ -0,0 +1,898 @@
|
||||
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import paddle
|
||||
from paddle import nn
|
||||
from paddle.utils.download import get_weights_path_from_url
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Callable
|
||||
from typing import Literal, TypedDict
|
||||
|
||||
from typing_extensions import NotRequired, Unpack
|
||||
|
||||
from paddle import Tensor
|
||||
from paddle._typing import Size2
|
||||
|
||||
_ResNetArch = Literal[
|
||||
'resnet18',
|
||||
'resnet34',
|
||||
'resnet50',
|
||||
'resnet101',
|
||||
'resnet152',
|
||||
'resnext50_32x4d',
|
||||
'resnext50_64x4d',
|
||||
'resnext101_32x4d',
|
||||
'resnext101_64x4d',
|
||||
'resnext152_32x4d',
|
||||
'resnext152_64x4d',
|
||||
'wide_resnet50_2',
|
||||
'wide_resnet101_2',
|
||||
]
|
||||
|
||||
class _ResNetOptions(TypedDict):
|
||||
width: NotRequired[int]
|
||||
num_classes: NotRequired[int]
|
||||
with_pool: NotRequired[bool]
|
||||
groups: NotRequired[int]
|
||||
|
||||
|
||||
__all__ = []
|
||||
|
||||
model_urls: dict[str, tuple[str, str]] = {
|
||||
'resnet18': (
|
||||
'https://paddle-hapi.bj.bcebos.com/models/resnet18.pdparams',
|
||||
'cf548f46534aa3560945be4b95cd11c4',
|
||||
),
|
||||
'resnet34': (
|
||||
'https://paddle-hapi.bj.bcebos.com/models/resnet34.pdparams',
|
||||
'8d2275cf8706028345f78ac0e1d31969',
|
||||
),
|
||||
'resnet50': (
|
||||
'https://paddle-hapi.bj.bcebos.com/models/resnet50.pdparams',
|
||||
'ca6f485ee1ab0492d38f323885b0ad80',
|
||||
),
|
||||
'resnet101': (
|
||||
'https://paddle-hapi.bj.bcebos.com/models/resnet101.pdparams',
|
||||
'02f35f034ca3858e1e54d4036443c92d',
|
||||
),
|
||||
'resnet152': (
|
||||
'https://paddle-hapi.bj.bcebos.com/models/resnet152.pdparams',
|
||||
'7ad16a2f1e7333859ff986138630fd7a',
|
||||
),
|
||||
'resnext50_32x4d': (
|
||||
'https://paddle-hapi.bj.bcebos.com/models/resnext50_32x4d.pdparams',
|
||||
'dc47483169be7d6f018fcbb7baf8775d',
|
||||
),
|
||||
"resnext50_64x4d": (
|
||||
'https://paddle-hapi.bj.bcebos.com/models/resnext50_64x4d.pdparams',
|
||||
'063d4b483e12b06388529450ad7576db',
|
||||
),
|
||||
'resnext101_32x4d': (
|
||||
'https://paddle-hapi.bj.bcebos.com/models/resnext101_32x4d.pdparams',
|
||||
'967b090039f9de2c8d06fe994fb9095f',
|
||||
),
|
||||
'resnext101_64x4d': (
|
||||
'https://paddle-hapi.bj.bcebos.com/models/resnext101_64x4d.pdparams',
|
||||
'98e04e7ca616a066699230d769d03008',
|
||||
),
|
||||
'resnext152_32x4d': (
|
||||
'https://paddle-hapi.bj.bcebos.com/models/resnext152_32x4d.pdparams',
|
||||
'18ff0beee21f2efc99c4b31786107121',
|
||||
),
|
||||
'resnext152_64x4d': (
|
||||
'https://paddle-hapi.bj.bcebos.com/models/resnext152_64x4d.pdparams',
|
||||
'77c4af00ca42c405fa7f841841959379',
|
||||
),
|
||||
'wide_resnet50_2': (
|
||||
'https://paddle-hapi.bj.bcebos.com/models/wide_resnet50_2.pdparams',
|
||||
'0282f804d73debdab289bd9fea3fa6dc',
|
||||
),
|
||||
'wide_resnet101_2': (
|
||||
'https://paddle-hapi.bj.bcebos.com/models/wide_resnet101_2.pdparams',
|
||||
'd4360a2d23657f059216f5d5a1a9ac93',
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
class BasicBlock(nn.Layer):
|
||||
expansion: int = 1
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
inplanes: int,
|
||||
planes: int,
|
||||
stride: Size2 = 1,
|
||||
downsample: nn.Layer | None = None,
|
||||
groups: int = 1,
|
||||
base_width: int = 64,
|
||||
dilation: int = 1,
|
||||
norm_layer: Callable[..., nn.Layer] | None = None,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
if norm_layer is None:
|
||||
norm_layer: type[nn.BatchNorm2D] = nn.BatchNorm2D
|
||||
|
||||
if dilation > 1:
|
||||
raise NotImplementedError(
|
||||
"Dilation > 1 not supported in BasicBlock"
|
||||
)
|
||||
|
||||
self.conv1 = nn.Conv2D(
|
||||
inplanes, planes, 3, padding=1, stride=stride, bias_attr=False
|
||||
)
|
||||
self.bn1 = norm_layer(planes)
|
||||
self.relu = nn.ReLU()
|
||||
self.conv2 = nn.Conv2D(planes, planes, 3, padding=1, bias_attr=False)
|
||||
self.bn2 = norm_layer(planes)
|
||||
self.downsample = downsample
|
||||
self.stride = stride
|
||||
|
||||
def forward(self, x: Tensor) -> Tensor:
|
||||
identity = x
|
||||
|
||||
out = self.conv1(x)
|
||||
out = self.bn1(out)
|
||||
out = self.relu(out)
|
||||
|
||||
out = self.conv2(out)
|
||||
out = self.bn2(out)
|
||||
|
||||
if self.downsample is not None:
|
||||
identity = self.downsample(x)
|
||||
|
||||
out += identity
|
||||
out = self.relu(out)
|
||||
|
||||
return out
|
||||
|
||||
|
||||
class BottleneckBlock(nn.Layer):
|
||||
expansion: int = 4
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
inplanes: int,
|
||||
planes: int,
|
||||
stride: Size2 = 1,
|
||||
downsample: nn.Layer | None = None,
|
||||
groups: int = 1,
|
||||
base_width: int = 64,
|
||||
dilation: int = 1,
|
||||
norm_layer: Callable[..., nn.Layer] | None = None,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
if norm_layer is None:
|
||||
norm_layer = nn.BatchNorm2D
|
||||
width = int(planes * (base_width / 64.0)) * groups
|
||||
|
||||
self.conv1 = nn.Conv2D(inplanes, width, 1, bias_attr=False)
|
||||
self.bn1 = norm_layer(width)
|
||||
|
||||
self.conv2 = nn.Conv2D(
|
||||
width,
|
||||
width,
|
||||
3,
|
||||
padding=dilation,
|
||||
stride=stride,
|
||||
groups=groups,
|
||||
dilation=dilation,
|
||||
bias_attr=False,
|
||||
)
|
||||
self.bn2 = norm_layer(width)
|
||||
|
||||
self.conv3 = nn.Conv2D(
|
||||
width, planes * self.expansion, 1, bias_attr=False
|
||||
)
|
||||
self.bn3 = norm_layer(planes * self.expansion)
|
||||
self.relu = nn.ReLU()
|
||||
self.downsample = downsample
|
||||
self.stride = stride
|
||||
|
||||
def forward(self, x: Tensor) -> Tensor:
|
||||
identity = x
|
||||
|
||||
out = self.conv1(x)
|
||||
out = self.bn1(out)
|
||||
out = self.relu(out)
|
||||
|
||||
out = self.conv2(out)
|
||||
out = self.bn2(out)
|
||||
out = self.relu(out)
|
||||
|
||||
out = self.conv3(out)
|
||||
out = self.bn3(out)
|
||||
|
||||
if self.downsample is not None:
|
||||
identity = self.downsample(x)
|
||||
|
||||
out += identity
|
||||
out = self.relu(out)
|
||||
|
||||
return out
|
||||
|
||||
|
||||
class ResNet(nn.Layer):
|
||||
"""ResNet model from
|
||||
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_.
|
||||
|
||||
Args:
|
||||
Block (BasicBlock|BottleneckBlock): Block module of model.
|
||||
depth (int, optional): Layers of ResNet, Default: 50.
|
||||
width (int, optional): Base width per convolution group for each convolution block, Default: 64.
|
||||
num_classes (int, optional): Output dim of last fc layer. If num_classes <= 0, last fc layer
|
||||
will not be defined. Default: 1000.
|
||||
with_pool (bool, optional): Use pool before the last fc layer or not. Default: True.
|
||||
groups (int, optional): Number of groups for each convolution block, Default: 1.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of ResNet model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import ResNet
|
||||
>>> from paddle.vision.models.resnet import (
|
||||
... BottleneckBlock,
|
||||
... BasicBlock,
|
||||
... )
|
||||
|
||||
>>> # build ResNet with 18 layers
|
||||
>>> resnet18 = ResNet(BasicBlock, 18)
|
||||
|
||||
>>> # build ResNet with 50 layers
|
||||
>>> resnet50 = ResNet(BottleneckBlock, 50)
|
||||
|
||||
>>> # build Wide ResNet model
|
||||
>>> wide_resnet50_2 = ResNet(BottleneckBlock, 50, width=64 * 2)
|
||||
|
||||
>>> # build ResNeXt model
|
||||
>>> resnext50_32x4d = ResNet(BottleneckBlock, 50, width=4, groups=32)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = resnet18(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
|
||||
groups: int
|
||||
base_width: int
|
||||
num_classes: int
|
||||
with_pool: bool
|
||||
inplanes: int
|
||||
dilation: int
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
block: type[BasicBlock | BottleneckBlock],
|
||||
depth: int = 50,
|
||||
width: int = 64,
|
||||
num_classes: int = 1000,
|
||||
with_pool: bool = True,
|
||||
groups: int = 1,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
layer_cfg = {
|
||||
18: [2, 2, 2, 2],
|
||||
34: [3, 4, 6, 3],
|
||||
50: [3, 4, 6, 3],
|
||||
101: [3, 4, 23, 3],
|
||||
152: [3, 8, 36, 3],
|
||||
}
|
||||
layers = layer_cfg[depth]
|
||||
self.groups = groups
|
||||
self.base_width = width
|
||||
self.num_classes = num_classes
|
||||
self.with_pool = with_pool
|
||||
self._norm_layer = nn.BatchNorm2D
|
||||
|
||||
self.inplanes = 64
|
||||
self.dilation = 1
|
||||
|
||||
self.conv1 = nn.Conv2D(
|
||||
3,
|
||||
self.inplanes,
|
||||
kernel_size=7,
|
||||
stride=2,
|
||||
padding=3,
|
||||
bias_attr=False,
|
||||
)
|
||||
self.bn1 = self._norm_layer(self.inplanes)
|
||||
self.relu = nn.ReLU()
|
||||
self.maxpool = nn.MaxPool2D(kernel_size=3, stride=2, padding=1)
|
||||
self.layer1 = self._make_layer(block, 64, layers[0])
|
||||
self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
|
||||
self.layer3 = self._make_layer(block, 256, layers[2], stride=2)
|
||||
self.layer4 = self._make_layer(block, 512, layers[3], stride=2)
|
||||
if with_pool:
|
||||
self.avgpool = nn.AdaptiveAvgPool2D((1, 1))
|
||||
|
||||
if num_classes > 0:
|
||||
self.fc = nn.Linear(512 * block.expansion, num_classes)
|
||||
|
||||
def _make_layer(
|
||||
self,
|
||||
block: type[BasicBlock | BottleneckBlock],
|
||||
planes: int,
|
||||
blocks: int,
|
||||
stride: int = 1,
|
||||
dilate: bool = False,
|
||||
) -> nn.Sequential:
|
||||
norm_layer = self._norm_layer
|
||||
downsample = None
|
||||
previous_dilation = self.dilation
|
||||
if dilate:
|
||||
self.dilation *= stride
|
||||
stride = 1
|
||||
if stride != 1 or self.inplanes != planes * block.expansion:
|
||||
downsample = nn.Sequential(
|
||||
nn.Conv2D(
|
||||
self.inplanes,
|
||||
planes * block.expansion,
|
||||
1,
|
||||
stride=stride,
|
||||
bias_attr=False,
|
||||
),
|
||||
norm_layer(planes * block.expansion),
|
||||
)
|
||||
|
||||
layers = []
|
||||
layers.append(
|
||||
block(
|
||||
self.inplanes,
|
||||
planes,
|
||||
stride,
|
||||
downsample,
|
||||
self.groups,
|
||||
self.base_width,
|
||||
previous_dilation,
|
||||
norm_layer,
|
||||
)
|
||||
)
|
||||
self.inplanes = planes * block.expansion
|
||||
for _ in range(1, blocks):
|
||||
layers.append(
|
||||
block(
|
||||
self.inplanes,
|
||||
planes,
|
||||
groups=self.groups,
|
||||
base_width=self.base_width,
|
||||
norm_layer=norm_layer,
|
||||
)
|
||||
)
|
||||
|
||||
return nn.Sequential(*layers)
|
||||
|
||||
def forward(self, x: Tensor) -> Tensor:
|
||||
x = self.conv1(x)
|
||||
x = self.bn1(x)
|
||||
x = self.relu(x)
|
||||
x = self.maxpool(x)
|
||||
x = self.layer1(x)
|
||||
x = self.layer2(x)
|
||||
x = self.layer3(x)
|
||||
x = self.layer4(x)
|
||||
|
||||
if self.with_pool:
|
||||
x = self.avgpool(x)
|
||||
|
||||
if self.num_classes > 0:
|
||||
x = paddle.flatten(x, 1)
|
||||
x = self.fc(x)
|
||||
|
||||
return x
|
||||
|
||||
|
||||
def _resnet(
|
||||
arch: _ResNetArch,
|
||||
Block: type[BasicBlock | BottleneckBlock],
|
||||
depth: int,
|
||||
pretrained: bool,
|
||||
**kwargs: Unpack[_ResNetOptions],
|
||||
) -> ResNet:
|
||||
model = ResNet(Block, depth, **kwargs)
|
||||
if pretrained:
|
||||
assert arch in model_urls, (
|
||||
f"{arch} model do not have a pretrained model now, you should set pretrained=False"
|
||||
)
|
||||
weight_path = get_weights_path_from_url(
|
||||
model_urls[arch][0], model_urls[arch][1]
|
||||
)
|
||||
|
||||
param = paddle.load(weight_path)
|
||||
model.set_dict(param)
|
||||
|
||||
return model
|
||||
|
||||
|
||||
def resnet18(pretrained=False, **kwargs: Unpack[_ResNetOptions]) -> ResNet:
|
||||
"""ResNet 18-layer model from
|
||||
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet <api_paddle_vision_models_ResNet>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of ResNet 18-layer model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import resnet18
|
||||
|
||||
>>> # build model
|
||||
>>> model = resnet18()
|
||||
|
||||
>>> # build model and load imagenet pretrained weight
|
||||
>>> # model = resnet18(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
return _resnet('resnet18', BasicBlock, 18, pretrained, **kwargs)
|
||||
|
||||
|
||||
def resnet34(
|
||||
pretrained: bool = False, **kwargs: Unpack[_ResNetOptions]
|
||||
) -> ResNet:
|
||||
"""ResNet 34-layer model from
|
||||
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet <api_paddle_vision_models_ResNet>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of ResNet 34-layer model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import resnet34
|
||||
|
||||
>>> # build model
|
||||
>>> model = resnet34()
|
||||
|
||||
>>> # build model and load imagenet pretrained weight
|
||||
>>> # model = resnet34(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
return _resnet('resnet34', BasicBlock, 34, pretrained, **kwargs)
|
||||
|
||||
|
||||
def resnet50(
|
||||
pretrained: bool = False, **kwargs: Unpack[_ResNetOptions]
|
||||
) -> ResNet:
|
||||
"""ResNet 50-layer model from
|
||||
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet <api_paddle_vision_models_ResNet>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of ResNet 50-layer model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import resnet50
|
||||
|
||||
>>> # build model
|
||||
>>> model = resnet50()
|
||||
|
||||
>>> # build model and load imagenet pretrained weight
|
||||
>>> # model = resnet50(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
return _resnet('resnet50', BottleneckBlock, 50, pretrained, **kwargs)
|
||||
|
||||
|
||||
def resnet101(
|
||||
pretrained: bool = False, **kwargs: Unpack[_ResNetOptions]
|
||||
) -> ResNet:
|
||||
"""ResNet 101-layer model from
|
||||
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet <api_paddle_vision_models_ResNet>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of ResNet 101-layer.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import resnet101
|
||||
|
||||
>>> # build model
|
||||
>>> model = resnet101()
|
||||
|
||||
>>> # build model and load imagenet pretrained weight
|
||||
>>> # model = resnet101(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
return _resnet('resnet101', BottleneckBlock, 101, pretrained, **kwargs)
|
||||
|
||||
|
||||
def resnet152(
|
||||
pretrained: bool = False, **kwargs: Unpack[_ResNetOptions]
|
||||
) -> ResNet:
|
||||
"""ResNet 152-layer model from
|
||||
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet <api_paddle_vision_models_ResNet>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of ResNet 152-layer model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import resnet152
|
||||
|
||||
>>> # build model
|
||||
>>> model = resnet152()
|
||||
|
||||
>>> # build model and load imagenet pretrained weight
|
||||
>>> # model = resnet152(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
return _resnet('resnet152', BottleneckBlock, 152, pretrained, **kwargs)
|
||||
|
||||
|
||||
def resnext50_32x4d(
|
||||
pretrained: bool = False, **kwargs: Unpack[_ResNetOptions]
|
||||
) -> ResNet:
|
||||
"""ResNeXt-50 32x4d model from
|
||||
`"Aggregated Residual Transformations for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet <api_paddle_vision_models_ResNet>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of ResNeXt-50 32x4d model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import resnext50_32x4d
|
||||
|
||||
>>> # build model
|
||||
>>> model = resnext50_32x4d()
|
||||
|
||||
>>> # build model and load imagenet pretrained weight
|
||||
>>> # model = resnext50_32x4d(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
kwargs['groups'] = 32
|
||||
kwargs['width'] = 4
|
||||
return _resnet('resnext50_32x4d', BottleneckBlock, 50, pretrained, **kwargs)
|
||||
|
||||
|
||||
def resnext50_64x4d(
|
||||
pretrained: bool = False, **kwargs: Unpack[_ResNetOptions]
|
||||
) -> ResNet:
|
||||
"""ResNeXt-50 64x4d model from
|
||||
`"Aggregated Residual Transformations for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet <api_paddle_vision_models_ResNet>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of ResNeXt-50 64x4d model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import resnext50_64x4d
|
||||
|
||||
>>> # build model
|
||||
>>> model = resnext50_64x4d()
|
||||
|
||||
>>> # build model and load imagenet pretrained weight
|
||||
>>> # model = resnext50_64x4d(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
kwargs['groups'] = 64
|
||||
kwargs['width'] = 4
|
||||
return _resnet('resnext50_64x4d', BottleneckBlock, 50, pretrained, **kwargs)
|
||||
|
||||
|
||||
def resnext101_32x4d(
|
||||
pretrained: bool = False, **kwargs: Unpack[_ResNetOptions]
|
||||
) -> ResNet:
|
||||
"""ResNeXt-101 32x4d model from
|
||||
`"Aggregated Residual Transformations for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet <api_paddle_vision_models_ResNet>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of ResNeXt-101 32x4d model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import resnext101_32x4d
|
||||
|
||||
>>> # build model
|
||||
>>> model = resnext101_32x4d()
|
||||
|
||||
>>> # build model and load imagenet pretrained weight
|
||||
>>> # model = resnext101_32x4d(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
kwargs['groups'] = 32
|
||||
kwargs['width'] = 4
|
||||
return _resnet(
|
||||
'resnext101_32x4d', BottleneckBlock, 101, pretrained, **kwargs
|
||||
)
|
||||
|
||||
|
||||
def resnext101_64x4d(
|
||||
pretrained: bool = False, **kwargs: Unpack[_ResNetOptions]
|
||||
) -> ResNet:
|
||||
"""ResNeXt-101 64x4d model from
|
||||
`"Aggregated Residual Transformations for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet <api_paddle_vision_models_ResNet>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of ResNeXt-101 64x4d model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import resnext101_64x4d
|
||||
|
||||
>>> # build model
|
||||
>>> model = resnext101_64x4d()
|
||||
|
||||
>>> # build model and load imagenet pretrained weight
|
||||
>>> # model = resnext101_64x4d(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
kwargs['groups'] = 64
|
||||
kwargs['width'] = 4
|
||||
return _resnet(
|
||||
'resnext101_64x4d', BottleneckBlock, 101, pretrained, **kwargs
|
||||
)
|
||||
|
||||
|
||||
def resnext152_32x4d(
|
||||
pretrained: bool = False, **kwargs: Unpack[_ResNetOptions]
|
||||
) -> ResNet:
|
||||
"""ResNeXt-152 32x4d model from
|
||||
`"Aggregated Residual Transformations for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet <api_paddle_vision_models_ResNet>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of ResNeXt-152 32x4d model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import resnext152_32x4d
|
||||
|
||||
>>> # build model
|
||||
>>> model = resnext152_32x4d()
|
||||
|
||||
>>> # build model and load imagenet pretrained weight
|
||||
>>> # model = resnext152_32x4d(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
kwargs['groups'] = 32
|
||||
kwargs['width'] = 4
|
||||
return _resnet(
|
||||
'resnext152_32x4d', BottleneckBlock, 152, pretrained, **kwargs
|
||||
)
|
||||
|
||||
|
||||
def resnext152_64x4d(
|
||||
pretrained: bool = False, **kwargs: Unpack[_ResNetOptions]
|
||||
) -> ResNet:
|
||||
"""ResNeXt-152 64x4d model from
|
||||
`"Aggregated Residual Transformations for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet <api_paddle_vision_models_ResNet>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of ResNeXt-152 64x4d model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import resnext152_64x4d
|
||||
|
||||
>>> # build model
|
||||
>>> model = resnext152_64x4d()
|
||||
|
||||
>>> # build model and load imagenet pretrained weight
|
||||
>>> # model = resnext152_64x4d(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
kwargs['groups'] = 64
|
||||
kwargs['width'] = 4
|
||||
return _resnet(
|
||||
'resnext152_64x4d', BottleneckBlock, 152, pretrained, **kwargs
|
||||
)
|
||||
|
||||
|
||||
def wide_resnet50_2(
|
||||
pretrained: bool = False, **kwargs: Unpack[_ResNetOptions]
|
||||
) -> ResNet:
|
||||
"""Wide ResNet-50-2 model from
|
||||
`"Wide Residual Networks" <https://arxiv.org/pdf/1605.07146.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet <api_paddle_vision_models_ResNet>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of Wide ResNet-50-2 model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import wide_resnet50_2
|
||||
|
||||
>>> # build model
|
||||
>>> model = wide_resnet50_2()
|
||||
|
||||
>>> # build model and load imagenet pretrained weight
|
||||
>>> # model = wide_resnet50_2(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
kwargs['width'] = 64 * 2
|
||||
return _resnet('wide_resnet50_2', BottleneckBlock, 50, pretrained, **kwargs)
|
||||
|
||||
|
||||
def wide_resnet101_2(
|
||||
pretrained: bool = False, **kwargs: Unpack[_ResNetOptions]
|
||||
) -> ResNet:
|
||||
"""Wide ResNet-101-2 model from
|
||||
`"Wide Residual Networks" <https://arxiv.org/pdf/1605.07146.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet <api_paddle_vision_models_ResNet>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of Wide ResNet-101-2 model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import wide_resnet101_2
|
||||
|
||||
>>> # build model
|
||||
>>> model = wide_resnet101_2()
|
||||
|
||||
>>> # build model and load imagenet pretrained weight
|
||||
>>> # model = wide_resnet101_2(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
kwargs['width'] = 64 * 2
|
||||
return _resnet(
|
||||
'wide_resnet101_2', BottleneckBlock, 101, pretrained, **kwargs
|
||||
)
|
||||
@@ -0,0 +1,649 @@
|
||||
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import paddle
|
||||
from paddle import nn
|
||||
from paddle.nn import AdaptiveAvgPool2D, Linear, MaxPool2D
|
||||
from paddle.utils.download import get_weights_path_from_url
|
||||
|
||||
from ..ops import ConvNormActivation
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Callable
|
||||
from typing import Literal, TypedDict
|
||||
|
||||
from typing_extensions import NotRequired, Unpack
|
||||
|
||||
from paddle import Tensor
|
||||
from paddle._typing import Size2
|
||||
|
||||
_ShuffleNetArch = Literal[
|
||||
'shufflenet_v2_x0_25',
|
||||
'shufflenet_v2_x0_33',
|
||||
'shufflenet_v2_x0_5',
|
||||
'shufflenet_v2_x1_0',
|
||||
'shufflenet_v2_x1_5',
|
||||
'shufflenet_v2_x2_0',
|
||||
'shufflenet_v2_swish',
|
||||
]
|
||||
|
||||
_ActivationType = Literal['relu', 'swish']
|
||||
|
||||
class _ShuffleNetOptions(TypedDict):
|
||||
act: NotRequired[_ActivationType | None]
|
||||
with_pool: NotRequired[bool]
|
||||
num_classes: NotRequired[int]
|
||||
|
||||
class _ShuffleNetSwishOptions(TypedDict):
|
||||
with_pool: NotRequired[bool]
|
||||
num_classes: NotRequired[int]
|
||||
|
||||
|
||||
__all__ = []
|
||||
|
||||
model_urls: dict[str, tuple[str, str]] = {
|
||||
"shufflenet_v2_x0_25": (
|
||||
"https://paddle-hapi.bj.bcebos.com/models/shufflenet_v2_x0_25.pdparams",
|
||||
"1e509b4c140eeb096bb16e214796d03b",
|
||||
),
|
||||
"shufflenet_v2_x0_33": (
|
||||
"https://paddle-hapi.bj.bcebos.com/models/shufflenet_v2_x0_33.pdparams",
|
||||
"3d7b3ab0eaa5c0927ff1026d31b729bd",
|
||||
),
|
||||
"shufflenet_v2_x0_5": (
|
||||
"https://paddle-hapi.bj.bcebos.com/models/shufflenet_v2_x0_5.pdparams",
|
||||
"5e5cee182a7793c4e4c73949b1a71bd4",
|
||||
),
|
||||
"shufflenet_v2_x1_0": (
|
||||
"https://paddle-hapi.bj.bcebos.com/models/shufflenet_v2_x1_0.pdparams",
|
||||
"122d42478b9e81eb49f8a9ede327b1a4",
|
||||
),
|
||||
"shufflenet_v2_x1_5": (
|
||||
"https://paddle-hapi.bj.bcebos.com/models/shufflenet_v2_x1_5.pdparams",
|
||||
"faced5827380d73531d0ee027c67826d",
|
||||
),
|
||||
"shufflenet_v2_x2_0": (
|
||||
"https://paddle-hapi.bj.bcebos.com/models/shufflenet_v2_x2_0.pdparams",
|
||||
"cd3dddcd8305e7bcd8ad14d1c69a5784",
|
||||
),
|
||||
"shufflenet_v2_swish": (
|
||||
"https://paddle-hapi.bj.bcebos.com/models/shufflenet_v2_swish.pdparams",
|
||||
"adde0aa3b023e5b0c94a68be1c394b84",
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def create_activation_layer(act: _ActivationType | None) -> nn.Layer | None:
|
||||
if act == "swish":
|
||||
return nn.Swish
|
||||
elif act == "relu":
|
||||
return nn.ReLU
|
||||
elif act is None:
|
||||
return None
|
||||
else:
|
||||
raise RuntimeError(f"The activation function is not supported: {act}")
|
||||
|
||||
|
||||
def channel_shuffle(x: Tensor, groups: int) -> Tensor:
|
||||
batch_size, num_channels, height, width = x.shape[0:4]
|
||||
channels_per_group = num_channels // groups
|
||||
|
||||
# reshape
|
||||
x = paddle.reshape(
|
||||
x, shape=[batch_size, groups, channels_per_group, height, width]
|
||||
)
|
||||
|
||||
# transpose
|
||||
x = paddle.transpose(x, perm=[0, 2, 1, 3, 4])
|
||||
|
||||
# flatten
|
||||
x = paddle.reshape(x, shape=[batch_size, num_channels, height, width])
|
||||
return x
|
||||
|
||||
|
||||
class InvertedResidual(nn.Layer):
|
||||
def __init__(
|
||||
self,
|
||||
in_channels: int,
|
||||
out_channels: int,
|
||||
stride: Size2,
|
||||
activation_layer: Callable[..., nn.Layer] = nn.ReLU,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self._conv_pw = ConvNormActivation(
|
||||
in_channels=in_channels // 2,
|
||||
out_channels=out_channels // 2,
|
||||
kernel_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
groups=1,
|
||||
activation_layer=activation_layer,
|
||||
)
|
||||
self._conv_dw = ConvNormActivation(
|
||||
in_channels=out_channels // 2,
|
||||
out_channels=out_channels // 2,
|
||||
kernel_size=3,
|
||||
stride=stride,
|
||||
padding=1,
|
||||
groups=out_channels // 2,
|
||||
activation_layer=None,
|
||||
)
|
||||
self._conv_linear = ConvNormActivation(
|
||||
in_channels=out_channels // 2,
|
||||
out_channels=out_channels // 2,
|
||||
kernel_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
groups=1,
|
||||
activation_layer=activation_layer,
|
||||
)
|
||||
|
||||
def forward(self, inputs: Tensor) -> Tensor:
|
||||
x1, x2 = paddle.split(
|
||||
inputs,
|
||||
num_or_sections=[inputs.shape[1] // 2, inputs.shape[1] // 2],
|
||||
axis=1,
|
||||
)
|
||||
x2 = self._conv_pw(x2)
|
||||
x2 = self._conv_dw(x2)
|
||||
x2 = self._conv_linear(x2)
|
||||
out = paddle.concat([x1, x2], axis=1)
|
||||
return channel_shuffle(out, 2)
|
||||
|
||||
|
||||
class InvertedResidualDS(nn.Layer):
|
||||
def __init__(
|
||||
self,
|
||||
in_channels: int,
|
||||
out_channels: int,
|
||||
stride: Size2,
|
||||
activation_layer: Callable[..., nn.Layer] = nn.ReLU,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
|
||||
# branch1
|
||||
self._conv_dw_1 = ConvNormActivation(
|
||||
in_channels=in_channels,
|
||||
out_channels=in_channels,
|
||||
kernel_size=3,
|
||||
stride=stride,
|
||||
padding=1,
|
||||
groups=in_channels,
|
||||
activation_layer=None,
|
||||
)
|
||||
self._conv_linear_1 = ConvNormActivation(
|
||||
in_channels=in_channels,
|
||||
out_channels=out_channels // 2,
|
||||
kernel_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
groups=1,
|
||||
activation_layer=activation_layer,
|
||||
)
|
||||
# branch2
|
||||
self._conv_pw_2 = ConvNormActivation(
|
||||
in_channels=in_channels,
|
||||
out_channels=out_channels // 2,
|
||||
kernel_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
groups=1,
|
||||
activation_layer=activation_layer,
|
||||
)
|
||||
self._conv_dw_2 = ConvNormActivation(
|
||||
in_channels=out_channels // 2,
|
||||
out_channels=out_channels // 2,
|
||||
kernel_size=3,
|
||||
stride=stride,
|
||||
padding=1,
|
||||
groups=out_channels // 2,
|
||||
activation_layer=None,
|
||||
)
|
||||
self._conv_linear_2 = ConvNormActivation(
|
||||
in_channels=out_channels // 2,
|
||||
out_channels=out_channels // 2,
|
||||
kernel_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
groups=1,
|
||||
activation_layer=activation_layer,
|
||||
)
|
||||
|
||||
def forward(self, inputs: Tensor) -> Tensor:
|
||||
x1 = self._conv_dw_1(inputs)
|
||||
x1 = self._conv_linear_1(x1)
|
||||
x2 = self._conv_pw_2(inputs)
|
||||
x2 = self._conv_dw_2(x2)
|
||||
x2 = self._conv_linear_2(x2)
|
||||
out = paddle.concat([x1, x2], axis=1)
|
||||
|
||||
return channel_shuffle(out, 2)
|
||||
|
||||
|
||||
class ShuffleNetV2(nn.Layer):
|
||||
"""ShuffleNetV2 model from
|
||||
`"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" <https://arxiv.org/pdf/1807.11164.pdf>`_.
|
||||
|
||||
Args:
|
||||
scale (float, optional): Scale of output channels. Default: True.
|
||||
act (str, optional): Activation function of neural network. Default: "relu".
|
||||
num_classes (int, optional): Output dim of last fc layer. If num_classes <= 0, last fc layer
|
||||
will not be defined. Default: 1000.
|
||||
with_pool (bool, optional): Use pool before the last fc layer or not. Default: True.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of ShuffleNetV2 model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import ShuffleNetV2
|
||||
|
||||
>>> shufflenet_v2_swish = ShuffleNetV2(scale=1.0, act="swish")
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = shufflenet_v2_swish(x)
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
|
||||
scale: float
|
||||
num_classes: int
|
||||
with_pool: bool
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
scale: float = 1.0,
|
||||
act: _ActivationType | None = "relu",
|
||||
num_classes: int = 1000,
|
||||
with_pool: bool = True,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.scale = scale
|
||||
self.num_classes = num_classes
|
||||
self.with_pool = with_pool
|
||||
stage_repeats = [4, 8, 4]
|
||||
activation_layer = create_activation_layer(act)
|
||||
|
||||
if scale == 0.25:
|
||||
stage_out_channels = [-1, 24, 24, 48, 96, 512]
|
||||
elif scale == 0.33:
|
||||
stage_out_channels = [-1, 24, 32, 64, 128, 512]
|
||||
elif 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 NotImplementedError(
|
||||
"This scale size:[" + str(scale) + "] is not implemented!"
|
||||
)
|
||||
# 1. conv1
|
||||
self._conv1 = ConvNormActivation(
|
||||
in_channels=3,
|
||||
out_channels=stage_out_channels[1],
|
||||
kernel_size=3,
|
||||
stride=2,
|
||||
padding=1,
|
||||
activation_layer=activation_layer,
|
||||
)
|
||||
self._max_pool = MaxPool2D(kernel_size=3, stride=2, padding=1)
|
||||
|
||||
# 2. bottleneck sequences
|
||||
self._block_list = []
|
||||
for stage_id, num_repeat in enumerate(stage_repeats):
|
||||
for i in range(num_repeat):
|
||||
if i == 0:
|
||||
block = self.add_sublayer(
|
||||
sublayer=InvertedResidualDS(
|
||||
in_channels=stage_out_channels[stage_id + 1],
|
||||
out_channels=stage_out_channels[stage_id + 2],
|
||||
stride=2,
|
||||
activation_layer=activation_layer,
|
||||
),
|
||||
name=str(stage_id + 2) + "_" + str(i + 1),
|
||||
)
|
||||
else:
|
||||
block = self.add_sublayer(
|
||||
sublayer=InvertedResidual(
|
||||
in_channels=stage_out_channels[stage_id + 2],
|
||||
out_channels=stage_out_channels[stage_id + 2],
|
||||
stride=1,
|
||||
activation_layer=activation_layer,
|
||||
),
|
||||
name=str(stage_id + 2) + "_" + str(i + 1),
|
||||
)
|
||||
self._block_list.append(block)
|
||||
# 3. last_conv
|
||||
self._last_conv = ConvNormActivation(
|
||||
in_channels=stage_out_channels[-2],
|
||||
out_channels=stage_out_channels[-1],
|
||||
kernel_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
activation_layer=activation_layer,
|
||||
)
|
||||
# 4. pool
|
||||
if with_pool:
|
||||
self._pool2d_avg = AdaptiveAvgPool2D(1)
|
||||
|
||||
# 5. fc
|
||||
if num_classes > 0:
|
||||
self._out_c = stage_out_channels[-1]
|
||||
self._fc = Linear(stage_out_channels[-1], num_classes)
|
||||
|
||||
def forward(self, inputs: Tensor) -> Tensor:
|
||||
x = self._conv1(inputs)
|
||||
x = self._max_pool(x)
|
||||
for inv in self._block_list:
|
||||
x = inv(x)
|
||||
x = self._last_conv(x)
|
||||
|
||||
if self.with_pool:
|
||||
x = self._pool2d_avg(x)
|
||||
|
||||
if self.num_classes > 0:
|
||||
x = paddle.flatten(x, start_axis=1, stop_axis=-1)
|
||||
x = self._fc(x)
|
||||
return x
|
||||
|
||||
|
||||
def _shufflenet_v2(
|
||||
arch: _ShuffleNetArch,
|
||||
pretrained: bool = False,
|
||||
scale: float = 1.0,
|
||||
**kwargs: Unpack[_ShuffleNetOptions],
|
||||
) -> ShuffleNetV2:
|
||||
model = ShuffleNetV2(scale=scale, **kwargs)
|
||||
if pretrained:
|
||||
assert arch in model_urls, (
|
||||
f"{arch} model do not have a pretrained model now, you should set pretrained=False"
|
||||
)
|
||||
weight_path = get_weights_path_from_url(
|
||||
model_urls[arch][0], model_urls[arch][1]
|
||||
)
|
||||
|
||||
param = paddle.load(weight_path)
|
||||
model.set_dict(param)
|
||||
return model
|
||||
|
||||
|
||||
def shufflenet_v2_x0_25(
|
||||
pretrained: bool = False, **kwargs: Unpack[_ShuffleNetOptions]
|
||||
) -> ShuffleNetV2:
|
||||
"""ShuffleNetV2 with 0.25x output channels, as described in
|
||||
`"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" <https://arxiv.org/pdf/1807.11164.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ShuffleNetV2 <api_paddle_vision_models_ShuffleNetV2>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of ShuffleNetV2 with 0.25x output channels.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import shufflenet_v2_x0_25
|
||||
|
||||
>>> # build model
|
||||
>>> model = shufflenet_v2_x0_25()
|
||||
|
||||
>>> # build model and load imagenet pretrained weight
|
||||
>>> # model = shufflenet_v2_x0_25(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
return _shufflenet_v2(
|
||||
"shufflenet_v2_x0_25", scale=0.25, pretrained=pretrained, **kwargs
|
||||
)
|
||||
|
||||
|
||||
def shufflenet_v2_x0_33(
|
||||
pretrained: bool = False, **kwargs: Unpack[_ShuffleNetOptions]
|
||||
) -> ShuffleNetV2:
|
||||
"""ShuffleNetV2 with 0.33x output channels, as described in
|
||||
`"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" <https://arxiv.org/pdf/1807.11164.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ShuffleNetV2 <api_paddle_vision_models_ShuffleNetV2>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of ShuffleNetV2 with 0.33x output channels.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import shufflenet_v2_x0_33
|
||||
|
||||
>>> # build model
|
||||
>>> model = shufflenet_v2_x0_33()
|
||||
|
||||
>>> # build model and load imagenet pretrained weight
|
||||
>>> # model = shufflenet_v2_x0_33(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
return _shufflenet_v2(
|
||||
"shufflenet_v2_x0_33", scale=0.33, pretrained=pretrained, **kwargs
|
||||
)
|
||||
|
||||
|
||||
def shufflenet_v2_x0_5(
|
||||
pretrained: bool = False, **kwargs: Unpack[_ShuffleNetOptions]
|
||||
) -> ShuffleNetV2:
|
||||
"""ShuffleNetV2 with 0.5x output channels, as described in
|
||||
`"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" <https://arxiv.org/pdf/1807.11164.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ShuffleNetV2 <api_paddle_vision_models_ShuffleNetV2>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of ShuffleNetV2 with 0.5x output channels.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import shufflenet_v2_x0_5
|
||||
|
||||
>>> # build model
|
||||
>>> model = shufflenet_v2_x0_5()
|
||||
|
||||
>>> # build model and load imagenet pretrained weight
|
||||
>>> # model = shufflenet_v2_x0_5(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
return _shufflenet_v2(
|
||||
"shufflenet_v2_x0_5", scale=0.5, pretrained=pretrained, **kwargs
|
||||
)
|
||||
|
||||
|
||||
def shufflenet_v2_x1_0(
|
||||
pretrained: bool = False, **kwargs: Unpack[_ShuffleNetOptions]
|
||||
) -> ShuffleNetV2:
|
||||
"""ShuffleNetV2 with 1.0x output channels, as described in
|
||||
`"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" <https://arxiv.org/pdf/1807.11164.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ShuffleNetV2 <api_paddle_vision_models_ShuffleNetV2>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of ShuffleNetV2 with 1.0x output channels.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import shufflenet_v2_x1_0
|
||||
|
||||
>>> # build model
|
||||
>>> model = shufflenet_v2_x1_0()
|
||||
|
||||
>>> # build model and load imagenet pretrained weight
|
||||
>>> # model = shufflenet_v2_x1_0(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
return _shufflenet_v2(
|
||||
"shufflenet_v2_x1_0", scale=1.0, pretrained=pretrained, **kwargs
|
||||
)
|
||||
|
||||
|
||||
def shufflenet_v2_x1_5(
|
||||
pretrained: bool = False, **kwargs: Unpack[_ShuffleNetOptions]
|
||||
) -> ShuffleNetV2:
|
||||
"""ShuffleNetV2 with 1.5x output channels, as described in
|
||||
`"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" <https://arxiv.org/pdf/1807.11164.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ShuffleNetV2 <api_paddle_vision_models_ShuffleNetV2>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of ShuffleNetV2 with 1.5x output channels.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import shufflenet_v2_x1_5
|
||||
|
||||
>>> # build model
|
||||
>>> model = shufflenet_v2_x1_5()
|
||||
|
||||
>>> # build model and load imagenet pretrained weight
|
||||
>>> # model = shufflenet_v2_x1_5(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
return _shufflenet_v2(
|
||||
"shufflenet_v2_x1_5", scale=1.5, pretrained=pretrained, **kwargs
|
||||
)
|
||||
|
||||
|
||||
def shufflenet_v2_x2_0(
|
||||
pretrained: bool = False, **kwargs: Unpack[_ShuffleNetOptions]
|
||||
) -> ShuffleNetV2:
|
||||
"""ShuffleNetV2 with 2.0x output channels, as described in
|
||||
`"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" <https://arxiv.org/pdf/1807.11164.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ShuffleNetV2 <api_paddle_vision_models_ShuffleNetV2>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of ShuffleNetV2 with 2.0x output channels.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import shufflenet_v2_x2_0
|
||||
|
||||
>>> # build model
|
||||
>>> model = shufflenet_v2_x2_0()
|
||||
|
||||
>>> # build model and load imagenet pretrained weight
|
||||
>>> # model = shufflenet_v2_x2_0(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
return _shufflenet_v2(
|
||||
"shufflenet_v2_x2_0", scale=2.0, pretrained=pretrained, **kwargs
|
||||
)
|
||||
|
||||
|
||||
def shufflenet_v2_swish(
|
||||
pretrained: bool = False, **kwargs: Unpack[_ShuffleNetSwishOptions]
|
||||
) -> ShuffleNetV2:
|
||||
"""ShuffleNetV2 with swish activation function, as described in
|
||||
`"ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" <https://arxiv.org/pdf/1807.11164.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ShuffleNetV2 <api_paddle_vision_models_ShuffleNetV2>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of ShuffleNetV2 with swish activation function.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import shufflenet_v2_swish
|
||||
|
||||
>>> # build model
|
||||
>>> model = shufflenet_v2_swish()
|
||||
|
||||
>>> # build model and load imagenet pretrained weight
|
||||
>>> # model = shufflenet_v2_swish(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
return _shufflenet_v2(
|
||||
"shufflenet_v2_swish",
|
||||
scale=1.0,
|
||||
act="swish",
|
||||
pretrained=pretrained,
|
||||
**kwargs,
|
||||
)
|
||||
@@ -0,0 +1,320 @@
|
||||
# copyright (c) 2021 PaddlePaddle Authors. All Rights Reserve.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
TypedDict,
|
||||
)
|
||||
|
||||
from typing_extensions import NotRequired, Unpack
|
||||
|
||||
import paddle
|
||||
import paddle.nn.functional as F
|
||||
from paddle import nn
|
||||
from paddle.base.param_attr import ParamAttr
|
||||
from paddle.nn import AdaptiveAvgPool2D, Conv2D, Dropout, MaxPool2D
|
||||
from paddle.utils.download import get_weights_path_from_url
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
from paddle._typing import Size2
|
||||
|
||||
class _SqueezeNetOptions(TypedDict):
|
||||
num_classes: NotRequired[int]
|
||||
with_pool: NotRequired[bool]
|
||||
|
||||
|
||||
__all__ = []
|
||||
|
||||
model_urls = {
|
||||
'squeezenet1_0': (
|
||||
'https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/SqueezeNet1_0_pretrained.pdparams',
|
||||
'30b95af60a2178f03cf9b66cd77e1db1',
|
||||
),
|
||||
'squeezenet1_1': (
|
||||
'https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/SqueezeNet1_1_pretrained.pdparams',
|
||||
'a11250d3a1f91d7131fd095ebbf09eee',
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
class MakeFireConv(nn.Layer):
|
||||
def __init__(
|
||||
self,
|
||||
input_channels: int,
|
||||
output_channels: int,
|
||||
filter_size: Size2,
|
||||
padding: Size2 = 0,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self._conv = Conv2D(
|
||||
input_channels,
|
||||
output_channels,
|
||||
filter_size,
|
||||
padding=padding,
|
||||
weight_attr=ParamAttr(),
|
||||
bias_attr=ParamAttr(),
|
||||
)
|
||||
|
||||
def forward(self, x: Tensor) -> Tensor:
|
||||
x = self._conv(x)
|
||||
x = F.relu(x)
|
||||
return x
|
||||
|
||||
|
||||
class MakeFire(nn.Layer):
|
||||
def __init__(
|
||||
self,
|
||||
input_channels: int,
|
||||
squeeze_channels: int,
|
||||
expand1x1_channels: int,
|
||||
expand3x3_channels: int,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self._conv = MakeFireConv(input_channels, squeeze_channels, 1)
|
||||
self._conv_path1 = MakeFireConv(squeeze_channels, expand1x1_channels, 1)
|
||||
self._conv_path2 = MakeFireConv(
|
||||
squeeze_channels, expand3x3_channels, 3, padding=1
|
||||
)
|
||||
|
||||
def forward(self, inputs: Tensor) -> Tensor:
|
||||
x = self._conv(inputs)
|
||||
x1 = self._conv_path1(x)
|
||||
x2 = self._conv_path2(x)
|
||||
return paddle.concat([x1, x2], axis=1)
|
||||
|
||||
|
||||
class SqueezeNet(nn.Layer):
|
||||
"""SqueezeNet model from
|
||||
`"SqueezeNet: AlexNet-level accuracy with 50x fewer parameters and <0.5MB model size"
|
||||
<https://arxiv.org/pdf/1602.07360.pdf>`_.
|
||||
|
||||
Args:
|
||||
version (str): Version of SqueezeNet, which can be "1.0" or "1.1".
|
||||
num_classes (int, optional): Output dim of last fc layer. If num_classes <= 0, last fc layer
|
||||
will not be defined. Default: 1000.
|
||||
with_pool (bool, optional): Use pool before the last fc layer or not. Default: True.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of SqueezeNet model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import SqueezeNet
|
||||
|
||||
>>> # build v1.0 model
|
||||
>>> model = SqueezeNet(version='1.0')
|
||||
|
||||
>>> # build v1.1 model
|
||||
>>> # model = SqueezeNet(version='1.1')
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
|
||||
version: str
|
||||
num_classes: int
|
||||
with_pool: bool
|
||||
|
||||
def __init__(
|
||||
self, version: str, num_classes: int = 1000, with_pool: bool = True
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.version = version
|
||||
self.num_classes = num_classes
|
||||
self.with_pool = with_pool
|
||||
|
||||
supported_versions = ['1.0', '1.1']
|
||||
assert version in supported_versions, (
|
||||
f"supported versions are {supported_versions} but input version is {version}"
|
||||
)
|
||||
|
||||
if self.version == "1.0":
|
||||
self._conv = Conv2D(
|
||||
3,
|
||||
96,
|
||||
7,
|
||||
stride=2,
|
||||
weight_attr=ParamAttr(),
|
||||
bias_attr=ParamAttr(),
|
||||
)
|
||||
self._pool = MaxPool2D(kernel_size=3, stride=2, padding=0)
|
||||
self._conv1 = MakeFire(96, 16, 64, 64)
|
||||
self._conv2 = MakeFire(128, 16, 64, 64)
|
||||
self._conv3 = MakeFire(128, 32, 128, 128)
|
||||
self._conv4 = MakeFire(256, 32, 128, 128)
|
||||
self._conv5 = MakeFire(256, 48, 192, 192)
|
||||
self._conv6 = MakeFire(384, 48, 192, 192)
|
||||
self._conv7 = MakeFire(384, 64, 256, 256)
|
||||
self._conv8 = MakeFire(512, 64, 256, 256)
|
||||
else:
|
||||
self._conv = Conv2D(
|
||||
3,
|
||||
64,
|
||||
3,
|
||||
stride=2,
|
||||
padding=1,
|
||||
weight_attr=ParamAttr(),
|
||||
bias_attr=ParamAttr(),
|
||||
)
|
||||
self._pool = MaxPool2D(kernel_size=3, stride=2, padding=0)
|
||||
self._conv1 = MakeFire(64, 16, 64, 64)
|
||||
self._conv2 = MakeFire(128, 16, 64, 64)
|
||||
self._conv3 = MakeFire(128, 32, 128, 128)
|
||||
self._conv4 = MakeFire(256, 32, 128, 128)
|
||||
self._conv5 = MakeFire(256, 48, 192, 192)
|
||||
self._conv6 = MakeFire(384, 48, 192, 192)
|
||||
self._conv7 = MakeFire(384, 64, 256, 256)
|
||||
self._conv8 = MakeFire(512, 64, 256, 256)
|
||||
|
||||
self._drop = Dropout(p=0.5, mode="downscale_in_infer")
|
||||
self._conv9 = Conv2D(
|
||||
512, num_classes, 1, weight_attr=ParamAttr(), bias_attr=ParamAttr()
|
||||
)
|
||||
self._avg_pool = AdaptiveAvgPool2D(1)
|
||||
|
||||
def forward(self, inputs: Tensor) -> Tensor:
|
||||
x = self._conv(inputs)
|
||||
x = F.relu(x)
|
||||
x = self._pool(x)
|
||||
if self.version == "1.0":
|
||||
x = self._conv1(x)
|
||||
x = self._conv2(x)
|
||||
x = self._conv3(x)
|
||||
x = self._pool(x)
|
||||
x = self._conv4(x)
|
||||
x = self._conv5(x)
|
||||
x = self._conv6(x)
|
||||
x = self._conv7(x)
|
||||
x = self._pool(x)
|
||||
x = self._conv8(x)
|
||||
else:
|
||||
x = self._conv1(x)
|
||||
x = self._conv2(x)
|
||||
x = self._pool(x)
|
||||
x = self._conv3(x)
|
||||
x = self._conv4(x)
|
||||
x = self._pool(x)
|
||||
x = self._conv5(x)
|
||||
x = self._conv6(x)
|
||||
x = self._conv7(x)
|
||||
x = self._conv8(x)
|
||||
if self.num_classes > 0:
|
||||
x = self._drop(x)
|
||||
x = self._conv9(x)
|
||||
if self.with_pool:
|
||||
x = F.relu(x)
|
||||
x = self._avg_pool(x)
|
||||
x = paddle.squeeze(x, axis=[2, 3])
|
||||
|
||||
return x
|
||||
|
||||
|
||||
def _squeezenet(
|
||||
arch: str,
|
||||
version: str,
|
||||
pretrained: bool,
|
||||
**kwargs: Unpack[_SqueezeNetOptions],
|
||||
) -> SqueezeNet:
|
||||
model = SqueezeNet(version, **kwargs)
|
||||
if pretrained:
|
||||
assert arch in model_urls, (
|
||||
f"{arch} model do not have a pretrained model now, you should set pretrained=False"
|
||||
)
|
||||
weight_path = get_weights_path_from_url(
|
||||
model_urls[arch][0], model_urls[arch][1]
|
||||
)
|
||||
param = paddle.load(weight_path)
|
||||
model.set_dict(param)
|
||||
|
||||
return model
|
||||
|
||||
|
||||
def squeezenet1_0(
|
||||
pretrained: bool = False, **kwargs: Unpack[_SqueezeNetOptions]
|
||||
) -> SqueezeNet:
|
||||
"""SqueezeNet v1.0 model from
|
||||
`"SqueezeNet: AlexNet-level accuracy with 50x fewer parameters and <0.5MB model size"
|
||||
<https://arxiv.org/pdf/1602.07360.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`SqueezeNet <api_paddle_vision_models_SqueezeNet>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of SqueezeNet v1.0 model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import squeezenet1_0
|
||||
|
||||
>>> # build model
|
||||
>>> model = squeezenet1_0()
|
||||
|
||||
>>> # build model and load imagenet pretrained weight
|
||||
>>> # model = squeezenet1_0(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
return _squeezenet('squeezenet1_0', '1.0', pretrained, **kwargs)
|
||||
|
||||
|
||||
def squeezenet1_1(
|
||||
pretrained: bool = False, **kwargs: Unpack[_SqueezeNetOptions]
|
||||
) -> SqueezeNet:
|
||||
"""SqueezeNet v1.1 model from
|
||||
`"SqueezeNet: AlexNet-level accuracy with 50x fewer parameters and <0.5MB model size"
|
||||
<https://arxiv.org/pdf/1602.07360.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`SqueezeNet <api_paddle_vision_models_SqueezeNet>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of SqueezeNet v1.1 model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import squeezenet1_1
|
||||
|
||||
>>> # build model
|
||||
>>> model = squeezenet1_1()
|
||||
|
||||
>>> # build model and load imagenet pretrained weight
|
||||
>>> # model = squeezenet1_1(pretrained=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
return _squeezenet('squeezenet1_1', '1.1', pretrained, **kwargs)
|
||||
@@ -0,0 +1,371 @@
|
||||
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Literal,
|
||||
TypedDict,
|
||||
)
|
||||
|
||||
from typing_extensions import NotRequired, Unpack
|
||||
|
||||
import paddle
|
||||
from paddle import nn
|
||||
from paddle.utils.download import get_weights_path_from_url
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from paddle import Tensor
|
||||
from paddle.nn import Layer, Sequential
|
||||
|
||||
class _VGGOptions(TypedDict):
|
||||
num_classes: NotRequired[int]
|
||||
with_pool: NotRequired[bool]
|
||||
|
||||
|
||||
__all__ = []
|
||||
|
||||
model_urls = {
|
||||
'vgg16': (
|
||||
'https://paddle-hapi.bj.bcebos.com/models/vgg16.pdparams',
|
||||
'89bbffc0f87d260be9b8cdc169c991c4',
|
||||
),
|
||||
'vgg19': (
|
||||
'https://paddle-hapi.bj.bcebos.com/models/vgg19.pdparams',
|
||||
'23b18bb13d8894f60f54e642be79a0dd',
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
class VGG(nn.Layer):
|
||||
"""VGG model from
|
||||
`"Very Deep Convolutional Networks For Large-Scale Image Recognition" <https://arxiv.org/pdf/1409.1556.pdf>`_.
|
||||
|
||||
Args:
|
||||
features (nn.Layer): Vgg features create by function make_layers.
|
||||
num_classes (int, optional): Output dim of last fc layer. If num_classes <= 0, last fc layer
|
||||
will not be defined. Default: 1000.
|
||||
with_pool (bool, optional): Use pool before the last three fc layer or not. Default: True.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of VGG model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import VGG
|
||||
>>> from paddle.vision.models.vgg import make_layers
|
||||
|
||||
>>> vgg11_cfg = [
|
||||
... 64,
|
||||
... 'M',
|
||||
... 128,
|
||||
... 'M',
|
||||
... 256,
|
||||
... 256,
|
||||
... 'M',
|
||||
... 512,
|
||||
... 512,
|
||||
... 'M',
|
||||
... 512,
|
||||
... 512,
|
||||
... 'M',
|
||||
... ]
|
||||
|
||||
>>> features = make_layers(vgg11_cfg) # type: ignore
|
||||
|
||||
>>> vgg11 = VGG(features)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = vgg11(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
|
||||
num_classes: int
|
||||
with_pool: bool
|
||||
|
||||
def __init__(
|
||||
self, features: Layer, num_classes: int = 1000, with_pool: bool = True
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.features = features
|
||||
self.num_classes = num_classes
|
||||
self.with_pool = with_pool
|
||||
|
||||
if with_pool:
|
||||
self.avgpool = nn.AdaptiveAvgPool2D((7, 7))
|
||||
|
||||
if num_classes > 0:
|
||||
self.classifier = nn.Sequential(
|
||||
nn.Linear(512 * 7 * 7, 4096),
|
||||
nn.ReLU(),
|
||||
nn.Dropout(),
|
||||
nn.Linear(4096, 4096),
|
||||
nn.ReLU(),
|
||||
nn.Dropout(),
|
||||
nn.Linear(4096, num_classes),
|
||||
)
|
||||
|
||||
def forward(self, x: Tensor) -> Tensor:
|
||||
x = self.features(x)
|
||||
|
||||
if self.with_pool:
|
||||
x = self.avgpool(x)
|
||||
|
||||
if self.num_classes > 0:
|
||||
x = paddle.flatten(x, 1)
|
||||
x = self.classifier(x)
|
||||
|
||||
return x
|
||||
|
||||
|
||||
def make_layers(
|
||||
cfg: list[int | Literal['M']], batch_norm: bool = False
|
||||
) -> Sequential:
|
||||
layers = []
|
||||
in_channels = 3
|
||||
for v in cfg:
|
||||
if v == 'M':
|
||||
layers += [nn.MaxPool2D(kernel_size=2, stride=2)]
|
||||
else:
|
||||
conv2d = nn.Conv2D(in_channels, v, kernel_size=3, padding=1)
|
||||
if batch_norm:
|
||||
layers += [conv2d, nn.BatchNorm2D(v), nn.ReLU()]
|
||||
else:
|
||||
layers += [conv2d, nn.ReLU()]
|
||||
in_channels = v
|
||||
return nn.Sequential(*layers)
|
||||
|
||||
|
||||
cfgs = {
|
||||
'A': [
|
||||
64, 'M',
|
||||
128, 'M',
|
||||
256, 256, 'M',
|
||||
512, 512, 'M',
|
||||
512, 512, 'M',
|
||||
],
|
||||
'B': [
|
||||
64, 64, 'M',
|
||||
128, 128, 'M',
|
||||
256, 256, 'M',
|
||||
512, 512, 'M',
|
||||
512, 512, 'M',
|
||||
],
|
||||
'D': [
|
||||
64, 64, 'M',
|
||||
128, 128, 'M',
|
||||
256, 256, 256, 'M',
|
||||
512, 512, 512, 'M',
|
||||
512, 512, 512, 'M',
|
||||
],
|
||||
'E': [
|
||||
64, 64, 'M',
|
||||
128, 128, 'M',
|
||||
256, 256, 256, 256, 'M',
|
||||
512, 512, 512, 512, 'M',
|
||||
512, 512, 512, 512, 'M',
|
||||
],
|
||||
} # fmt: skip
|
||||
|
||||
|
||||
def _vgg(
|
||||
arch: str,
|
||||
cfg: Literal["A", "B", "D", "E"],
|
||||
batch_norm: bool,
|
||||
pretrained: bool,
|
||||
**kwargs: Unpack[_VGGOptions],
|
||||
) -> VGG:
|
||||
model = VGG(make_layers(cfgs[cfg], batch_norm=batch_norm), **kwargs)
|
||||
|
||||
if pretrained:
|
||||
assert arch in model_urls, (
|
||||
f"{arch} model do not have a pretrained model now, you should set pretrained=False"
|
||||
)
|
||||
weight_path = get_weights_path_from_url(
|
||||
model_urls[arch][0], model_urls[arch][1]
|
||||
)
|
||||
|
||||
param = paddle.load(weight_path)
|
||||
model.load_dict(param)
|
||||
|
||||
return model
|
||||
|
||||
|
||||
def vgg11(
|
||||
pretrained: bool = False,
|
||||
batch_norm: bool = False,
|
||||
**kwargs: Unpack[_VGGOptions],
|
||||
) -> VGG:
|
||||
"""VGG 11-layer model from
|
||||
`"Very Deep Convolutional Networks For Large-Scale Image Recognition" <https://arxiv.org/pdf/1409.1556.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
batch_norm (bool, optional): If True, returns a model with batch_norm layer. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`VGG <api_paddle_vision_models_VGG>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of VGG 11-layer model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import vgg11
|
||||
|
||||
>>> # build model
|
||||
>>> model = vgg11()
|
||||
|
||||
>>> # build vgg11 model with batch_norm
|
||||
>>> model = vgg11(batch_norm=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
model_name = 'vgg11'
|
||||
if batch_norm:
|
||||
model_name += '_bn'
|
||||
return _vgg(model_name, 'A', batch_norm, pretrained, **kwargs)
|
||||
|
||||
|
||||
def vgg13(
|
||||
pretrained: bool = False,
|
||||
batch_norm: bool = False,
|
||||
**kwargs: Unpack[_VGGOptions],
|
||||
) -> VGG:
|
||||
"""VGG 13-layer model from
|
||||
`"Very Deep Convolutional Networks For Large-Scale Image Recognition" <https://arxiv.org/pdf/1409.1556.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
batch_norm (bool): If True, returns a model with batch_norm layer. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`VGG <api_paddle_vision_models_VGG>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of VGG 13-layer model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import vgg13
|
||||
|
||||
>>> # build model
|
||||
>>> model = vgg13()
|
||||
|
||||
>>> # build vgg13 model with batch_norm
|
||||
>>> model = vgg13(batch_norm=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
model_name = 'vgg13'
|
||||
if batch_norm:
|
||||
model_name += '_bn'
|
||||
return _vgg(model_name, 'B', batch_norm, pretrained, **kwargs)
|
||||
|
||||
|
||||
def vgg16(
|
||||
pretrained: bool = False,
|
||||
batch_norm: bool = False,
|
||||
**kwargs: Unpack[_VGGOptions],
|
||||
) -> VGG:
|
||||
"""VGG 16-layer model from
|
||||
`"Very Deep Convolutional Networks For Large-Scale Image Recognition" <https://arxiv.org/pdf/1409.1556.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
batch_norm (bool, optional): If True, returns a model with batch_norm layer. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`VGG <api_paddle_vision_models_VGG>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of VGG 16-layer model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import vgg16
|
||||
|
||||
>>> # build model
|
||||
>>> model = vgg16()
|
||||
|
||||
>>> # build vgg16 model with batch_norm
|
||||
>>> model = vgg16(batch_norm=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
model_name = 'vgg16'
|
||||
if batch_norm:
|
||||
model_name += '_bn'
|
||||
return _vgg(model_name, 'D', batch_norm, pretrained, **kwargs)
|
||||
|
||||
|
||||
def vgg19(
|
||||
pretrained: bool = False,
|
||||
batch_norm: bool = False,
|
||||
**kwargs: Unpack[_VGGOptions],
|
||||
) -> VGG:
|
||||
"""VGG 19-layer model from
|
||||
`"Very Deep Convolutional Networks For Large-Scale Image Recognition" <https://arxiv.org/pdf/1409.1556.pdf>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained
|
||||
on ImageNet. Default: False.
|
||||
batch_norm (bool, optional): If True, returns a model with batch_norm layer. Default: False.
|
||||
**kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`VGG <api_paddle_vision_models_VGG>`.
|
||||
|
||||
Returns:
|
||||
:ref:`api_paddle_nn_Layer`. An instance of VGG 19-layer model.
|
||||
|
||||
Examples:
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import paddle
|
||||
>>> from paddle.vision.models import vgg19
|
||||
|
||||
>>> # build model
|
||||
>>> model = vgg19()
|
||||
|
||||
>>> # build vgg19 model with batch_norm
|
||||
>>> model = vgg19(batch_norm=True)
|
||||
|
||||
>>> x = paddle.rand([1, 3, 224, 224])
|
||||
>>> out = model(x)
|
||||
|
||||
>>> print(out.shape)
|
||||
paddle.Size([1, 1000])
|
||||
"""
|
||||
model_name = 'vgg19'
|
||||
if batch_norm:
|
||||
model_name += '_bn'
|
||||
return _vgg(model_name, 'E', batch_norm, pretrained, **kwargs)
|
||||
Reference in New Issue
Block a user