|
a |
|
b/densenet.py |
|
|
1 |
import torch |
|
|
2 |
import torch.nn as nn |
|
|
3 |
import torch.nn.functional as F |
|
|
4 |
import torch.utils.model_zoo as model_zoo |
|
|
5 |
from collections import OrderedDict |
|
|
6 |
|
|
|
7 |
__all__ = ['DenseNet', 'densenet169'] |
|
|
8 |
|
|
|
9 |
|
|
|
10 |
model_urls = { |
|
|
11 |
'densenet169': 'https://download.pytorch.org/models/densenet169-b2777c0a.pth', |
|
|
12 |
} |
|
|
13 |
|
|
|
14 |
def densenet169(pretrained=False, **kwargs): |
|
|
15 |
r"""Densenet-169 model from |
|
|
16 |
`"Densely Connected Convolutional Networks" <https://arxiv.org/pdf/1608.06993.pdf>`_ |
|
|
17 |
|
|
|
18 |
Args: |
|
|
19 |
pretrained (bool): If True, returns a model pre-trained on ImageNet |
|
|
20 |
""" |
|
|
21 |
model = DenseNet(num_init_features=64, growth_rate=32, block_config=(6, 12, 32, 32), |
|
|
22 |
**kwargs) |
|
|
23 |
if pretrained: |
|
|
24 |
model.load_state_dict(model_zoo.load_url(model_urls['densenet169']), strict=False) |
|
|
25 |
return model |
|
|
26 |
|
|
|
27 |
class _DenseLayer(nn.Sequential): |
|
|
28 |
def __init__(self, num_input_features, growth_rate, bn_size, drop_rate): |
|
|
29 |
super(_DenseLayer, self).__init__() |
|
|
30 |
self.add_module('norm1', nn.BatchNorm2d(num_input_features)), |
|
|
31 |
self.add_module('relu1', nn.ReLU(inplace=True)), |
|
|
32 |
self.add_module('conv1', nn.Conv2d(num_input_features, bn_size * |
|
|
33 |
growth_rate, kernel_size=1, stride=1, bias=False)), |
|
|
34 |
self.add_module('norm2', nn.BatchNorm2d(bn_size * growth_rate)), |
|
|
35 |
self.add_module('relu2', nn.ReLU(inplace=True)), |
|
|
36 |
self.add_module('conv2', nn.Conv2d(bn_size * growth_rate, growth_rate, |
|
|
37 |
kernel_size=3, stride=1, padding=1, bias=False)), |
|
|
38 |
self.drop_rate = drop_rate |
|
|
39 |
|
|
|
40 |
def forward(self, x): |
|
|
41 |
new_features = super(_DenseLayer, self).forward(x) |
|
|
42 |
if self.drop_rate > 0: |
|
|
43 |
new_features = F.dropout(new_features, p=self.drop_rate, training=self.training) |
|
|
44 |
return torch.cat([x, new_features], 1) |
|
|
45 |
|
|
|
46 |
|
|
|
47 |
class _DenseBlock(nn.Sequential): |
|
|
48 |
def __init__(self, num_layers, num_input_features, bn_size, growth_rate, drop_rate): |
|
|
49 |
super(_DenseBlock, self).__init__() |
|
|
50 |
for i in range(num_layers): |
|
|
51 |
layer = _DenseLayer(num_input_features + i * growth_rate, growth_rate, bn_size, drop_rate) |
|
|
52 |
self.add_module('denselayer%d' % (i + 1), layer) |
|
|
53 |
|
|
|
54 |
|
|
|
55 |
class _Transition(nn.Sequential): |
|
|
56 |
def __init__(self, num_input_features, num_output_features): |
|
|
57 |
super(_Transition, self).__init__() |
|
|
58 |
self.add_module('norm', nn.BatchNorm2d(num_input_features)) |
|
|
59 |
self.add_module('relu', nn.ReLU(inplace=True)) |
|
|
60 |
self.add_module('conv', nn.Conv2d(num_input_features, num_output_features, |
|
|
61 |
kernel_size=1, stride=1, bias=False)) |
|
|
62 |
self.add_module('pool', nn.AvgPool2d(kernel_size=2, stride=2)) |
|
|
63 |
|
|
|
64 |
|
|
|
65 |
class DenseNet(nn.Module): |
|
|
66 |
r"""Densenet-BC model class, based on |
|
|
67 |
`"Densely Connected Convolutional Networks" <https://arxiv.org/pdf/1608.06993.pdf>`_ |
|
|
68 |
|
|
|
69 |
Args: |
|
|
70 |
growth_rate (int) - how many filters to add each layer (`k` in paper) |
|
|
71 |
block_config (list of 4 ints) - how many layers in each pooling block |
|
|
72 |
num_init_features (int) - the number of filters to learn in the first convolution layer |
|
|
73 |
bn_size (int) - multiplicative factor for number of bottle neck layers |
|
|
74 |
(i.e. bn_size * k features in the bottleneck layer) |
|
|
75 |
drop_rate (float) - dropout rate after each dense layer |
|
|
76 |
num_classes (int) - number of classification classes |
|
|
77 |
""" |
|
|
78 |
def __init__(self, growth_rate=32, block_config=(6, 12, 24, 16), |
|
|
79 |
num_init_features=64, bn_size=4, drop_rate=0, num_classes=1000): |
|
|
80 |
|
|
|
81 |
super(DenseNet, self).__init__() |
|
|
82 |
|
|
|
83 |
# First convolution |
|
|
84 |
self.features = nn.Sequential(OrderedDict([ |
|
|
85 |
('conv0', nn.Conv2d(3, num_init_features, kernel_size=7, stride=2, padding=3, bias=False)), |
|
|
86 |
('norm0', nn.BatchNorm2d(num_init_features)), |
|
|
87 |
('relu0', nn.ReLU(inplace=True)), |
|
|
88 |
('pool0', nn.MaxPool2d(kernel_size=3, stride=2, padding=1)), |
|
|
89 |
])) |
|
|
90 |
|
|
|
91 |
# Each denseblock |
|
|
92 |
num_features = num_init_features |
|
|
93 |
for i, num_layers in enumerate(block_config): |
|
|
94 |
block = _DenseBlock(num_layers=num_layers, num_input_features=num_features, |
|
|
95 |
bn_size=bn_size, growth_rate=growth_rate, drop_rate=drop_rate) |
|
|
96 |
self.features.add_module('denseblock%d' % (i + 1), block) |
|
|
97 |
num_features = num_features + num_layers * growth_rate |
|
|
98 |
if i != len(block_config) - 1: |
|
|
99 |
trans = _Transition(num_input_features=num_features, num_output_features=num_features // 2) |
|
|
100 |
self.features.add_module('transition%d' % (i + 1), trans) |
|
|
101 |
num_features = num_features // 2 |
|
|
102 |
|
|
|
103 |
# Final batch norm |
|
|
104 |
self.features.add_module('norm5', nn.BatchNorm2d(num_features)) |
|
|
105 |
|
|
|
106 |
# Linear layer |
|
|
107 |
# self.classifier = nn.Linear(num_features, 1000) |
|
|
108 |
# self.fc = nn.Linear(1000, 1) |
|
|
109 |
|
|
|
110 |
self.fc = nn.Linear(num_features, 1) |
|
|
111 |
|
|
|
112 |
# Official init from torch repo. |
|
|
113 |
for m in self.modules(): |
|
|
114 |
if isinstance(m, nn.Conv2d): |
|
|
115 |
nn.init.kaiming_normal(m.weight.data) |
|
|
116 |
elif isinstance(m, nn.BatchNorm2d): |
|
|
117 |
m.weight.data.fill_(1) |
|
|
118 |
m.bias.data.zero_() |
|
|
119 |
elif isinstance(m, nn.Linear): |
|
|
120 |
m.bias.data.zero_() |
|
|
121 |
|
|
|
122 |
def forward(self, x): |
|
|
123 |
features = self.features(x) |
|
|
124 |
out = F.relu(features, inplace=True) |
|
|
125 |
out = F.avg_pool2d(out, kernel_size=7, stride=1).view(features.size(0), -1) |
|
|
126 |
# out = F.relu(self.classifier(out)) |
|
|
127 |
out = F.sigmoid(self.fc(out)) |
|
|
128 |
return out |