Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PaddlePaddle Hackathon] add DenseNet #36262

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion python/paddle/tests/test_vision_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,19 @@ def test_lenet(self):

x = np.array(np.random.random((2, 1, 28, 28)), dtype=np.float32)
lenet.predict_batch(x)


def test_densenet121(self):
self.models_infer('densenet121')

def test_densenet161(self):
self.models_infer('densenet161')

def test_densenet169(self):
self.models_infer('densenet169')

def test_densenet201(self):
self.models_infer('densenet201')


if __name__ == '__main__':
unittest.main()
5 changes: 5 additions & 0 deletions python/paddle/vision/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@
from .datasets import Cifar10 # noqa: F401
from .datasets import Cifar100 # noqa: F401
from .datasets import VOC2012 # noqa: F401
from .models import DenseNet # noqa: F401
from .models import densenet121 # noqa: F401
from .models import densenet161 # noqa: F401
from .models import densenet169 # noqa: F401
from .models import densenet201 # noqa: F401
from .models import ResNet # noqa: F401
from .models import resnet18 # noqa: F401
from .models import resnet34 # noqa: F401
Expand Down
10 changes: 10 additions & 0 deletions python/paddle/vision/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,18 @@
from .vgg import vgg16 # noqa: F401
from .vgg import vgg19 # noqa: F401
from .lenet import LeNet # noqa: F401
from .densenet import DenseNet # noqa: F401
from .densenet import densenet121
from .densenet import densenet161
from .densenet import densenet169
from .densenet import densenet201

__all__ = [ #noqa
'DenseNet',
'densenet121',
'densenet161',
'densenet169',
'densenet201',
'ResNet',
'resnet18',
'resnet34',
Expand Down
251 changes: 251 additions & 0 deletions python/paddle/vision/models/densenet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
import re
import paddle
import paddle.nn as nn
import paddle.nn.functional as F
from collections import OrderedDict
from paddle import Tensor
from typing import Any, List, Tuple
from paddle.utils.download import get_weights_path_from_url

__all__ = ['DenseNet', 'densenet121', 'densenet169', 'densenet201', 'densenet161']

model_urls = {
'densenet121': 'https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/DenseNet121_pretrained.pdparams',
'densenet169': 'https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/DenseNet169_pretrained.pdparams',
'densenet201': 'https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/DenseNet201_pretrained.pdparams',
'densenet161': 'https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/DenseNet161_pretrained.pdparams',
}


class _DenseLayer(nn.Layer):
def __init__(
self,
num_input_features: int,
growth_rate: int,
bn_size: int,
drop_rate: float,
memory_efficient: bool = False
) -> None:
super(_DenseLayer, self).__init__()
self.num_input_features = num_input_features
self.norm1 = nn.BatchNorm2D(num_input_features)
self.relu1 = nn.ReLU()
self.conv1 = nn.Conv2D(num_input_features, bn_size *
growth_rate, kernel_size=1, stride=1)
self.norm2 = nn.BatchNorm2D(bn_size * growth_rate)
self.relu2 = nn.ReLU()
self.conv2 = nn.Conv2D(bn_size * growth_rate, growth_rate,
kernel_size=3, stride=1, padding=1)
self.drop_rate = float(drop_rate)
self.memory_efficient = memory_efficient


def forward(self, input) -> Tensor: # noqa: F811

if isinstance(input, Tensor):
input = [input]
input = paddle.concat(input, 1)

# print(self.num_input_features)
# print(input.shape)
bottleneck_output = self.conv1(self.relu1(self.norm1(input)))
new_features = self.conv2(self.relu2(self.norm2(bottleneck_output)))
if self.drop_rate > 0:
new_features = F.dropout(new_features, p=self.drop_rate,
training=self.training)
return new_features


class _DenseBlock(nn.LayerDict):

def __init__(
self,
num_layers: int,
num_input_features: int,
bn_size: int,
growth_rate: int,
drop_rate: float,
memory_efficient: bool = False
) -> None:
super(_DenseBlock, self).__init__()

for i in range(num_layers):
layer = _DenseLayer(
num_input_features + i * growth_rate,
growth_rate=growth_rate,
bn_size=bn_size,
drop_rate=drop_rate,
memory_efficient=memory_efficient,
)
self.update([('denselayer%d' % (i + 1), layer)])


def forward(self, init_features: Tensor) -> Tensor:
features = [init_features]
for name, layer in self.items():
new_features = layer(features)
# print("DenseLayer Passed")
features.append(new_features)
return paddle.concat(features, 1)


class _Transition(nn.Layer):
def __init__(self, num_input_features: int, num_output_features: int) -> None:
super(_Transition, self).__init__()
self.seq = nn.Sequential(
('norm', nn.BatchNorm2D(num_input_features)),
('relu', nn.ReLU()),
('conv', nn.Conv2D(num_input_features, num_output_features,
kernel_size=1, stride=1)),
('pool', nn.AvgPool2D(kernel_size=2, stride=2))
)
def forward(self,x):
return self.seq(x)


class DenseNet(nn.Layer):
r"""Densenet-BC model class, based on
`"Densely Connected Convolutional Networks" <https://arxiv.org/pdf/1608.06993.pdf>`_.
Args:
growth_rate (int) - how many filters to add each layer (`k` in paper)
block_config (list of 4 ints) - how many layers in each pooling block
num_init_features (int) - the number of filters to learn in the first convolution layer
bn_size (int) - multiplicative factor for number of bottle neck layers
(i.e. bn_size * k features in the bottleneck layer)
drop_rate (float) - dropout rate after each dense layer
num_classes (int) - number of classification classes
memory_efficient (bool) - If True, uses checkpointing. Much more memory efficient,
but slower. Default: *False*. See `"paper" <https://arxiv.org/pdf/1707.06990.pdf>`_.
"""

def __init__(
self,
growth_rate: int = 32,
block_config: Tuple[int, int, int, int] = (6, 12, 24, 16),
num_init_features: int = 64,
bn_size: int = 4,
drop_rate: float = 0,
num_classes: int = 1000,
memory_efficient: bool = False
) -> None:

super(DenseNet, self).__init__()

# First convolution
self.features = nn.Sequential(
('conv0', nn.Conv2D(3, num_init_features, kernel_size=7, stride=2,
padding=3)),
('norm0', nn.BatchNorm2D(num_init_features)),
('relu0', nn.ReLU()),
('pool0', nn.MaxPool2D(kernel_size=3, stride=2, padding=1))
)

# Each denseblock
num_features = num_init_features
for i, num_layers in enumerate(block_config):
block = _DenseBlock(
num_layers=num_layers,
num_input_features=num_features,
bn_size=bn_size,
growth_rate=growth_rate,
drop_rate=drop_rate,
memory_efficient=memory_efficient
)
self.features.add_sublayer('denseblock%d' % (i + 1), block)
num_features = num_features + num_layers * growth_rate
if i != len(block_config) - 1:
trans = _Transition(num_input_features=num_features,
num_output_features=num_features // 2)
self.features.add_sublayer('transition%d' % (i + 1), trans)
num_features = num_features // 2

# Final batch norm
self.features.add_sublayer('norm5', nn.BatchNorm2D(num_features))

# Linear layer
self.classifier = nn.Linear(num_features, num_classes)



def forward(self, x: Tensor) -> Tensor:
features = self.features(x)
out = F.relu(features, inplace=True)
out = F.adaptive_avg_pool2d(out, (1, 1))
out = paddle.flatten(out, 1)
out = self.classifier(out)
return out

def _densenet(
arch: str,
growth_rate: int,
block_config: Tuple[int, int, int, int],
num_init_features: int,
pretrained: bool,
progress: bool,
**kwargs: Any
) -> DenseNet:
model = DenseNet(growth_rate, block_config, num_init_features, **kwargs)

if pretrained:
assert arch in model_urls, "{} model do not have a pretrained model now, you should set pretrained=False".format(
arch)
weight_path = get_weights_path_from_url(model_urls[arch])
param = paddle.load(weight_path)
model.set_dict(param)

return model

def densenet121(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> DenseNet:
r"""Densenet-121 model from
`"Densely Connected Convolutional Networks" <https://arxiv.org/pdf/1608.06993.pdf>`_.
The required minimum input size of the model is 29x29.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
memory_efficient (bool) - If True, uses checkpointing. Much more memory efficient,
but slower. Default: *False*. See `"paper" <https://arxiv.org/pdf/1707.06990.pdf>`_.
"""
return _densenet('densenet121', 32, (6, 12, 24, 16), 64, pretrained, progress,
**kwargs)


def densenet161(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> DenseNet:
r"""Densenet-161 model from
`"Densely Connected Convolutional Networks" <https://arxiv.org/pdf/1608.06993.pdf>`_.
The required minimum input size of the model is 29x29.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
memory_efficient (bool) - If True, uses checkpointing. Much more memory efficient,
but slower. Default: *False*. See `"paper" <https://arxiv.org/pdf/1707.06990.pdf>`_.
"""
return _densenet('densenet161', 48, (6, 12, 36, 24), 96, pretrained, progress,
**kwargs)


def densenet169(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> DenseNet:
r"""Densenet-169 model from
`"Densely Connected Convolutional Networks" <https://arxiv.org/pdf/1608.06993.pdf>`_.
The required minimum input size of the model is 29x29.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
memory_efficient (bool) - If True, uses checkpointing. Much more memory efficient,
but slower. Default: *False*. See `"paper" <https://arxiv.org/pdf/1707.06990.pdf>`_.
"""
return _densenet('densenet169', 32, (6, 12, 32, 32), 64, pretrained, progress,
**kwargs)


def densenet201(pretrained: bool = False, progress: bool = True, **kwargs: Any) -> DenseNet:
r"""Densenet-201 model from
`"Densely Connected Convolutional Networks" <https://arxiv.org/pdf/1608.06993.pdf>`_.
The required minimum input size of the model is 29x29.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
memory_efficient (bool) - If True, uses checkpointing. Much more memory efficient,
but slower. Default: *False*. See `"paper" <https://arxiv.org/pdf/1707.06990.pdf>`_.
"""
return _densenet('densenet201', 32, (6, 12, 48, 32), 64, pretrained, progress,
**kwargs)