chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:40:42 +08:00
commit e25996e7db
15472 changed files with 3536181 additions and 0 deletions
+116
View File
@@ -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',
]
+113
View File
@@ -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
+241
View File
@@ -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)
+571
View File
@@ -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)
+303
View File
@@ -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
+654
View File
@@ -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
+83
View File
@@ -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
+334
View File
@@ -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
+276
View File
@@ -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
+547
View File
@@ -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
+898
View File
@@ -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
)
+649
View File
@@ -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,
)
+320
View File
@@ -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)
+371
View File
@@ -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)