├── .gitattributes ├── .gitignore ├── models ├── detnet.py ├── res2net.py ├── __init__.py ├── lenet.py ├── vgg.py ├── mobilenet.py ├── darknet_19.py ├── darknet_53.py ├── mobilenetv2.py ├── squeezenext.py ├── shufflenet.py ├── densenet.py ├── senet.py ├── resnet.py ├── dpn.py ├── preact_resnet.py ├── pnasnet.py ├── googlenet_v2.py ├── igcv3.py ├── shufflenetv2.py ├── peleenet.py ├── resnext.py ├── squeezenet.py ├── googlenet_v1.py ├── dlanet.py ├── googlenet_v4.py ├── googlenet_v3.py └── efficientnet.py ├── dataset └── unzip.sh ├── config.py ├── train.py ├── README.md └── calculate_params.py /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sh linguist-language=python 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .idea 3 | checkpoint 4 | 5 | .DS_Store -------------------------------------------------------------------------------- /models/detnet.py: -------------------------------------------------------------------------------- 1 | ''' DetNet in Pytorch 2 | 3 | ECCV 2018 4 | 5 | Reference: 6 | [1] DetNet: A Backbone network for Object Detection 7 | Zeming Li, Chao Peng, Gang Yu, Xiangyu Zhang, Yangdong Deng, Jian Sun 8 | ''' -------------------------------------------------------------------------------- /models/res2net.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Res2Net in Pytorch 3 | TPAMI 2021 4 | Res2Net: A New Multi-Scale Backbone Architecture 5 | ''' 6 | 7 | import torch 8 | import torch.nn as nn 9 | import torch.nn.functional as F 10 | 11 | -------------------------------------------------------------------------------- /dataset/unzip.sh: -------------------------------------------------------------------------------- 1 | dir=/data/srd/data/Image/ImageNet/train 2 | 3 | for x in `ls $dir/*tar` 4 | do 5 | filename=`basename $x .tar` 6 | mkdir $dir/$filename 7 | tar -xvf $x -C $dir/$filename 8 | done 9 | 10 | rm *.tar -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | '''ImageNet dataset Path''' 2 | traindir = '/home/user/Downloads/ILSVRC2012/train' 3 | valdir = '/home/user/Downloads/ILSVRC2012/val' 4 | 5 | '''Parameter setting''' 6 | input_size = 224 # Input image size 7 | batch_size = 128 # Number of input images 8 | n_worker = 4 # Multiple threads 9 | lr = 0.1 # Learning rate -------------------------------------------------------------------------------- /models/__init__.py: -------------------------------------------------------------------------------- 1 | from .vgg import * 2 | from .dpn import * 3 | from .lenet import * 4 | from .senet import * 5 | from .pnasnet import * 6 | from .densenet import * 7 | from .googlenet_v1 import * 8 | from .googlenet_v2 import * 9 | from .googlenet_v3 import * 10 | from .googlenet_v4 import * 11 | from .shufflenet import * 12 | from .shufflenetv2 import * 13 | from .resnet import * 14 | from .resnext import * 15 | from .preact_resnet import * 16 | from .mobilenet import * 17 | from .mobilenetv2 import * 18 | from .efficientnet import * 19 | from .darknet_53 import * 20 | from .darknet_19 import * 21 | from .peleenet import * 22 | from .dlanet import * 23 | from .squeezenet import * 24 | from .squeezenext import * 25 | from .igcv3 import * -------------------------------------------------------------------------------- /models/lenet.py: -------------------------------------------------------------------------------- 1 | '''LeNet in PyTorch.''' 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | 5 | class LeNet(nn.Module): 6 | def __init__(self): 7 | super(LeNet, self).__init__() 8 | self.conv1 = nn.Conv2d(3, 6, 5) 9 | self.conv2 = nn.Conv2d(6, 16, 5) 10 | self.fc1 = nn.Linear(16*5*5, 120) 11 | self.fc2 = nn.Linear(120, 84) 12 | self.fc3 = nn.Linear(84, 10) 13 | 14 | def forward(self, x): 15 | out = F.relu(self.conv1(x)) 16 | out = F.max_pool2d(out, 2) 17 | out = F.relu(self.conv2(out)) 18 | out = F.max_pool2d(out, 2) 19 | out = out.view(out.size(0), -1) 20 | out = F.relu(self.fc1(out)) 21 | out = F.relu(self.fc2(out)) 22 | out = self.fc3(out) 23 | return out 24 | -------------------------------------------------------------------------------- /models/vgg.py: -------------------------------------------------------------------------------- 1 | '''VGG11/13/16/19 in Pytorch.''' 2 | import torch 3 | import torch.nn as nn 4 | 5 | 6 | cfg = { 7 | 'VGG11': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'], 8 | 'VGG13': [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'], 9 | 'VGG16': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M'], 10 | 'VGG19': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M'], 11 | } 12 | 13 | class VGG(nn.Module): 14 | def __init__(self, vgg_name, num_classes=1000): 15 | super(VGG, self).__init__() 16 | self.features = self._make_layers(cfg[vgg_name]) 17 | self.classifier = nn.Linear(512, num_classes) 18 | 19 | def forward(self, x): 20 | out = self.features(x) 21 | out = out.view(out.size(0), -1) 22 | out = self.classifier(out) 23 | return out 24 | 25 | def _make_layers(self, cfg): 26 | layers = [] 27 | in_channels = 3 28 | for x in cfg: 29 | if x == 'M': 30 | layers += [nn.MaxPool2d(kernel_size=2, stride=2)] 31 | else: 32 | layers += [nn.Conv2d(in_channels, x, kernel_size=3, padding=1), 33 | nn.BatchNorm2d(x), 34 | nn.ReLU(inplace=True)] 35 | in_channels = x 36 | layers += [nn.AvgPool2d(kernel_size=7, stride=1)] 37 | return nn.Sequential(*layers) 38 | 39 | 40 | def test(): 41 | net = VGG('VGG19') 42 | x = torch.randn(1,3,224,224) 43 | y = net(x) 44 | print(y.size()) 45 | 46 | # test() 47 | -------------------------------------------------------------------------------- /models/mobilenet.py: -------------------------------------------------------------------------------- 1 | '''MobileNet in PyTorch. 2 | 3 | See the paper "MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications" 4 | for more details. 5 | ''' 6 | import torch 7 | import torch.nn as nn 8 | import torch.nn.functional as F 9 | 10 | 11 | class Block(nn.Module): 12 | '''Depthwise conv + Pointwise conv''' 13 | def __init__(self, in_planes, out_planes, stride=1): 14 | super(Block, self).__init__() 15 | self.conv1 = nn.Conv2d(in_planes, in_planes, kernel_size=3, stride=stride, padding=1, groups=in_planes, bias=False) 16 | self.bn1 = nn.BatchNorm2d(in_planes) 17 | self.conv2 = nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False) 18 | self.bn2 = nn.BatchNorm2d(out_planes) 19 | 20 | def forward(self, x): 21 | out = F.relu(self.bn1(self.conv1(x))) 22 | out = F.relu(self.bn2(self.conv2(out))) 23 | return out 24 | 25 | 26 | class MobileNet(nn.Module): 27 | # (128,2) means conv planes=128, conv stride=2, by default conv stride=1 28 | cfg = [64, (128,2), 128, (256,2), 256, (512,2), 512, 512, 512, 512, 512, (1024,2), 1024] 29 | 30 | def __init__(self, num_classes=1000): 31 | super(MobileNet, self).__init__() 32 | self.conv1 = nn.Conv2d(3, 32, kernel_size=3, stride=2, padding=1, bias=False) 33 | self.bn1 = nn.BatchNorm2d(32) 34 | self.layers = self._make_layers(in_planes=32) 35 | self.linear = nn.Linear(1024, num_classes) 36 | 37 | def _make_layers(self, in_planes): 38 | layers = [] 39 | for x in self.cfg: 40 | out_planes = x if isinstance(x, int) else x[0] 41 | stride = 1 if isinstance(x, int) else x[1] 42 | layers.append(Block(in_planes, out_planes, stride)) 43 | in_planes = out_planes 44 | return nn.Sequential(*layers) 45 | 46 | def forward(self, x): 47 | out = F.relu(self.bn1(self.conv1(x))) 48 | out = self.layers(out) 49 | out = F.avg_pool2d(out, 7) 50 | out = out.view(out.size(0), -1) 51 | out = self.linear(out) 52 | return out 53 | 54 | 55 | def test(): 56 | net = MobileNet() 57 | x = torch.randn(1,3,224,224) 58 | y = net(x) 59 | print(y.size()) 60 | 61 | # test() 62 | -------------------------------------------------------------------------------- /models/darknet_19.py: -------------------------------------------------------------------------------- 1 | ''' DarkNet-19 in Pytorch 2 | 3 | YOLOv2 4 | 5 | Reference: 6 | [1] Joseph Redmon, Ali Farhadi 7 | YOLO9000: Better, Faster, Stronger 8 | ''' 9 | import torch 10 | import torch.nn as nn 11 | import torch.nn.functional as F 12 | 13 | class Conv_bn_relu(nn.Module): 14 | def __init__(self, inp, oup, kernel_size=3, stride=1, pad=1): 15 | super(Conv_bn_relu, self).__init__() 16 | self.convs = nn.Sequential( 17 | nn.Conv2d(inp, oup, kernel_size, stride, pad, bias=False), 18 | nn.BatchNorm2d(oup), 19 | nn.ReLU(inplace=True), 20 | ) 21 | def forward(self, x): 22 | out = self.convs(x) 23 | return out 24 | 25 | class BasicBlock(nn.Module): 26 | def __init__(self, inp, num): 27 | super(BasicBlock, self).__init__() 28 | self.conv1 = Conv_bn_relu(inp // 2, inp, kernel_size=3, stride=1) 29 | self.conv2 = Conv_bn_relu(inp, inp // 2, kernel_size=1, stride=1, pad=0) 30 | self.layers = self._make_layer(num) 31 | 32 | def _make_layer(self, num): 33 | layers = [] 34 | for i in range(num): 35 | if(i%2==0): 36 | layers.append(self.conv1) 37 | else: 38 | layers.append(self.conv2) 39 | return nn.Sequential(*layers) 40 | 41 | def forward(self, x): 42 | out = self.layers(x) 43 | return out 44 | 45 | class DarkNet_19(nn.Module): 46 | def __init__(self, growth_rate=2, num_blocks=[1,1,3,3,5,5], num_classes=1000): 47 | super(DarkNet_19, self).__init__() 48 | self.in_planes = 32 49 | 50 | self.layer1 = Conv_bn_relu(3, 32, kernel_size=3, stride=1) 51 | self.layer2 = BasicBlock(64, num_blocks[1]) 52 | self.layer3 = BasicBlock(128, num_blocks[2]) 53 | self.layer4 = BasicBlock(256, num_blocks[3]) 54 | self.layer5 = BasicBlock(512, num_blocks[4]) 55 | self.layer6 = BasicBlock(1024, num_blocks[5]) 56 | self.linear = nn.Linear(1024, num_classes) 57 | 58 | 59 | def forward(self, x): 60 | out = self.layer1(x) 61 | out = F.max_pool2d(out, kernel_size=2, stride=2) 62 | out = self.layer2(out) 63 | out = F.max_pool2d(out, kernel_size=2, stride=2) 64 | out = self.layer3(out) 65 | out = F.max_pool2d(out, kernel_size=2, stride=2) 66 | out = self.layer4(out) 67 | out = F.max_pool2d(out, kernel_size=2, stride=2) 68 | out = self.layer5(out) 69 | out = F.max_pool2d(out, kernel_size=2, stride=2) 70 | out = self.layer6(out) 71 | out = F.avg_pool2d(out, 7) 72 | out = out.view(out.size(0), -1) 73 | out = self.linear(out) 74 | return out 75 | 76 | 77 | def test(): 78 | net = DarkNet_19() 79 | x = torch.randn(1,3,224,224) 80 | y = net(x) 81 | print(y.size()) 82 | 83 | # test() -------------------------------------------------------------------------------- /models/darknet_53.py: -------------------------------------------------------------------------------- 1 | '''DarkNet-53 in PyTorch. 2 | 3 | YOLOv3 4 | 5 | Reference: 6 | [1] Joseph Redmon, Ali Farhadi 7 | YOLOv3: An Incremental Improvement 8 | ''' 9 | import torch 10 | import torch.nn as nn 11 | import torch.nn.functional as F 12 | 13 | class Conv_bn_relu(nn.Module): 14 | def __init__(self, inp, oup, kernel_size=3, stride=1, pad=1): 15 | super(Conv_bn_relu, self).__init__() 16 | self.convs = nn.Sequential( 17 | nn.Conv2d(inp, oup, kernel_size, stride, pad, bias=False), 18 | nn.BatchNorm2d(oup), 19 | nn.ReLU(inplace=True), 20 | ) 21 | def forward(self, x): 22 | out = self.convs(x) 23 | return out 24 | 25 | class BasicBlock(nn.Module): 26 | def __init__(self, inp): 27 | super(BasicBlock, self).__init__() 28 | 29 | self.conv1 = Conv_bn_relu(inp, inp//2, kernel_size=1, stride=1, pad=0) 30 | self.conv2 = Conv_bn_relu(inp//2, inp, kernel_size=3, stride=1) 31 | 32 | 33 | def forward(self, x): 34 | out = self.conv1(x) 35 | out = self.conv2(out) 36 | out += x 37 | out = F.relu(out) 38 | return out 39 | 40 | class DarkNet_53(nn.Module): 41 | def __init__(self, num_blocks=[1,2,8,8,4], num_classes=1000): 42 | super(DarkNet_53, self).__init__() 43 | self.in_planes = 32 44 | 45 | self.conv1 = Conv_bn_relu(3, 32, kernel_size=3, stride=1) 46 | self.conv2 = Conv_bn_relu(32, 64, kernel_size=3, stride=2) 47 | self.resblock1 = self._make_layer(BasicBlock, 64, num_blocks[0]) 48 | self.conv3 = Conv_bn_relu(64, 128, kernel_size=3, stride=2) 49 | self.resblock2 = self._make_layer(BasicBlock, 128, num_blocks[1]) 50 | self.conv4 = Conv_bn_relu(128, 256, kernel_size=3, stride=2) 51 | self.resblock3 = self._make_layer(BasicBlock, 256, num_blocks[2]) 52 | self.conv5 = Conv_bn_relu(256, 512, kernel_size=3, stride=2) 53 | self.resblock4 = self._make_layer(BasicBlock, 512, num_blocks[3]) 54 | self.conv6 = Conv_bn_relu(512, 1024, kernel_size=3, stride=2) 55 | self.resblock5 = self._make_layer(BasicBlock, 1024, num_blocks[4]) 56 | self.linear = nn.Linear(1024, num_classes) 57 | 58 | def _make_layer(self, block, planes, num_blocks): 59 | layers = [] 60 | for i in range(num_blocks): 61 | layers.append(block(planes)) 62 | return nn.Sequential(*layers) 63 | 64 | def forward(self, x): 65 | out = self.conv1(x) 66 | out = self.conv2(out) 67 | out = self.resblock1(out) 68 | out = self.conv3(out) 69 | out = self.resblock2(out) 70 | out = self.conv4(out) 71 | out = self.resblock3(out) 72 | out = self.conv5(out) 73 | out = self.resblock4(out) 74 | out = self.conv6(out) 75 | out = self.resblock5(out) 76 | out = F.avg_pool2d(out, 7) 77 | out = out.view(out.size(0), -1) 78 | out = self.linear(out) 79 | return out 80 | 81 | 82 | def test(): 83 | net = DarkNet_53() 84 | x = torch.randn(1,3,224,224) 85 | y = net(x) 86 | print(y.size()) 87 | 88 | # test() -------------------------------------------------------------------------------- /models/mobilenetv2.py: -------------------------------------------------------------------------------- 1 | '''MobileNetV2 in PyTorch. 2 | 3 | CVPR 2018 4 | 5 | See the paper "Inverted Residuals and Linear Bottlenecks: 6 | Mobile Networks for Classification, Detection and Segmentation" for more details. 7 | ''' 8 | import torch 9 | import torch.nn as nn 10 | import torch.nn.functional as F 11 | 12 | 13 | class Block(nn.Module): 14 | '''expand + depthwise + pointwise''' 15 | def __init__(self, in_planes, out_planes, expansion, stride): 16 | super(Block, self).__init__() 17 | self.stride = stride 18 | 19 | planes = expansion * in_planes 20 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, stride=1, padding=0, bias=False) 21 | self.bn1 = nn.BatchNorm2d(planes) 22 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, groups=planes, bias=False) 23 | self.bn2 = nn.BatchNorm2d(planes) 24 | self.conv3 = nn.Conv2d(planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False) 25 | self.bn3 = nn.BatchNorm2d(out_planes) 26 | 27 | self.shortcut = nn.Sequential() 28 | if stride == 1 and in_planes != out_planes: 29 | self.shortcut = nn.Sequential( 30 | nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False), 31 | nn.BatchNorm2d(out_planes), 32 | ) 33 | 34 | def forward(self, x): 35 | out = F.relu(self.bn1(self.conv1(x))) 36 | out = F.relu(self.bn2(self.conv2(out))) 37 | out = self.bn3(self.conv3(out)) 38 | out = out + self.shortcut(x) if self.stride==1 else out 39 | return out 40 | 41 | 42 | class MobileNetV2(nn.Module): 43 | # (expansion, out_planes, num_blocks, stride) 44 | cfg = [(1, 16, 1, 1), 45 | (6, 24, 2, 2), # NOTE: change stride 2 -> 1 for CIFAR10 46 | (6, 32, 3, 2), 47 | (6, 64, 4, 2), 48 | (6, 96, 3, 1), 49 | (6, 160, 3, 2), 50 | (6, 320, 1, 1)] 51 | 52 | def __init__(self, num_classes=1000): 53 | super(MobileNetV2, self).__init__() 54 | # NOTE: change conv1 stride 2 -> 1 for CIFAR10 55 | self.conv1 = nn.Conv2d(3, 32, kernel_size=3, stride=2, padding=1, bias=False) 56 | self.bn1 = nn.BatchNorm2d(32) 57 | self.layers = self._make_layers(in_planes=32) 58 | self.conv2 = nn.Conv2d(320, 1280, kernel_size=1, stride=1, padding=0, bias=False) 59 | self.bn2 = nn.BatchNorm2d(1280) 60 | self.linear = nn.Linear(1280, num_classes) 61 | 62 | def _make_layers(self, in_planes): 63 | layers = [] 64 | for expansion, out_planes, num_blocks, stride in self.cfg: 65 | strides = [stride] + [1]*(num_blocks-1) 66 | for stride in strides: 67 | layers.append(Block(in_planes, out_planes, expansion, stride)) 68 | in_planes = out_planes 69 | return nn.Sequential(*layers) 70 | 71 | def forward(self, x): 72 | out = F.relu(self.bn1(self.conv1(x))) 73 | out = self.layers(out) 74 | out = F.relu(self.bn2(self.conv2(out))) 75 | # NOTE: change pooling kernel_size 7 -> 4 for CIFAR10 76 | out = F.avg_pool2d(out, 7) 77 | out = out.view(out.size(0), -1) 78 | out = self.linear(out) 79 | return out 80 | 81 | 82 | def test(): 83 | net = MobileNetV2() 84 | x = torch.randn(1, 3, 224, 224) 85 | y = net(x) 86 | print(y.size()) 87 | 88 | # test() 89 | -------------------------------------------------------------------------------- /models/squeezenext.py: -------------------------------------------------------------------------------- 1 | ''' SqueezeNext in Pytorch 2 | 3 | Reference: 4 | [1] Amir Gholami, Kiseok Kwon, Bichen Wu, Zizheng Tai, Xiangyu Yue, Peter Jin, Sicheng Zhao, Kurt Keutzer 5 | SqueezeNext: Hardware-Aware Neural Network Design 6 | ''' 7 | 8 | import torch 9 | import torch.nn as nn 10 | import torch.nn.functional as F 11 | 12 | class Conv_bn_relu(nn.Module): 13 | def __init__(self, inp, oup, kernel_size=1, stride=1, pad=0): 14 | super(Conv_bn_relu, self).__init__() 15 | self.convs = nn.Sequential( 16 | nn.Conv2d(inp, oup, kernel_size, stride, pad, bias=False), 17 | nn.BatchNorm2d(oup), 18 | nn.ReLU(inplace=True), 19 | ) 20 | def forward(self, x): 21 | out = self.convs(x) 22 | return out 23 | 24 | class BasicBlock(nn.Module): 25 | def __init__(self, inp, oup, res=False): 26 | super(BasicBlock, self).__init__() 27 | self.inp = inp 28 | self.oup = oup 29 | self.res = res 30 | self.layer1 = Conv_bn_relu(inp, oup//2) 31 | self.layer2 = Conv_bn_relu(oup//2, oup//4) 32 | self.layer3 = Conv_bn_relu(oup//4, oup//2) 33 | self.layer4 = Conv_bn_relu(oup//2, oup//2) 34 | self.layer5 = Conv_bn_relu(oup//2, oup) 35 | self.layer6 = Conv_bn_relu(inp, oup) 36 | self.relu = nn.ReLU(inplace=True) 37 | 38 | def forward(self, x): 39 | out = self.layer1(x) 40 | out = self.layer2(out) 41 | out = self.layer3(out) 42 | out = self.layer4(out) 43 | out = self.layer5(out) 44 | if self.inp != self.oup or self.res: 45 | out = self.relu(self.layer6(x) + out) 46 | return out 47 | 48 | class SqueezeNext(nn.Module): 49 | def __init__(self, num_block=[6,6,8,1], channel=[32,64,128,256], num_classes=1000): 50 | super(SqueezeNext, self).__init__() 51 | self.conv1 = Conv_bn_relu(3, 64, kernel_size=7, stride=2, pad=3) 52 | self.layer1 = self._make_layer(64, channel[0], num_block[0]) 53 | self.layer2 = self._make_layer(channel[0], channel[1], num_block[1]) 54 | self.layer3 = self._make_layer(channel[1], channel[2], num_block[2]) 55 | self.layer4 = self._make_layer(channel[2], channel[3], num_block[3]) 56 | self.conv2 = Conv_bn_relu(channel[3], 128) 57 | self.avgpool = nn.AvgPool2d(kernel_size=7) 58 | self.maxpool = nn.MaxPool2d(kernel_size=2, stride=2) 59 | self.linear = nn.Linear(128, num_classes) 60 | 61 | def _make_layer(self, inp, oup, num_block): 62 | layers = [] 63 | for i in range(num_block): 64 | if i == 0: 65 | layers.append(BasicBlock(inp, oup, res=True)) 66 | else: 67 | layers.append(BasicBlock(oup, oup)) 68 | return nn.Sequential(*layers) 69 | 70 | def forward(self, x): 71 | out = self.conv1(x) 72 | out = self.maxpool(out) 73 | out = self.layer1(out) 74 | out = self.maxpool(out) 75 | out = self.layer2(out) 76 | out = self.maxpool(out) 77 | out = self.layer3(out) 78 | out = self.maxpool(out) 79 | out = self.layer4(out) 80 | out = self.conv2(out) 81 | out = self.avgpool(out) 82 | out = out.view(out.size(0), -1) 83 | out = self.linear(out) 84 | return out 85 | 86 | def SqNxt_x1_23(): 87 | return SqueezeNext([6,6,8,1], [32,64,128,256]) 88 | 89 | def SqNxt_x1_23v5(): 90 | return SqueezeNext([2,4,14,1], [32,64,128,256]) 91 | 92 | def SqNxt_x2_23(): 93 | return SqueezeNext([6,6,8,1], [64,128,256,512]) 94 | 95 | def SqNxt_x2_23v5(): 96 | return SqueezeNext([2,4,14,1], [64,128,256,512]) 97 | 98 | def test(): 99 | net = SqNxt_x2_23() 100 | x = torch.randn(1,3,224,224) 101 | y = net(x) 102 | print(y.size()) 103 | 104 | # test() -------------------------------------------------------------------------------- /models/shufflenet.py: -------------------------------------------------------------------------------- 1 | '''ShuffleNet in PyTorch. 2 | 3 | See the paper "ShuffleNet: An Extremely Efficient Convolutional Neural Network for Mobile Devices" for more details. 4 | ''' 5 | import torch 6 | import torch.nn as nn 7 | import torch.nn.functional as F 8 | 9 | 10 | class ShuffleBlock(nn.Module): 11 | def __init__(self, groups): 12 | super(ShuffleBlock, self).__init__() 13 | self.groups = groups 14 | 15 | def forward(self, x): 16 | '''Channel shuffle: [N,C,H,W] -> [N,g,C/g,H,W] -> [N,C/g,g,H,w] -> [N,C,H,W]''' 17 | N,C,H,W = x.size() 18 | g = self.groups 19 | return x.view(N,g,C//g,H,W).permute(0,2,1,3,4).reshape(N,C,H,W) 20 | 21 | 22 | class Bottleneck(nn.Module): 23 | def __init__(self, in_planes, out_planes, stride, groups): 24 | super(Bottleneck, self).__init__() 25 | self.stride = stride 26 | 27 | mid_planes = out_planes//4 28 | g = 1 if in_planes==24 else groups 29 | self.conv1 = nn.Conv2d(in_planes, mid_planes, kernel_size=1, groups=g, bias=False) 30 | self.bn1 = nn.BatchNorm2d(mid_planes) 31 | self.shuffle1 = ShuffleBlock(groups=g) 32 | self.conv2 = nn.Conv2d(mid_planes, mid_planes, kernel_size=3, stride=stride, padding=1, groups=mid_planes, bias=False) 33 | self.bn2 = nn.BatchNorm2d(mid_planes) 34 | self.conv3 = nn.Conv2d(mid_planes, out_planes, kernel_size=1, groups=groups, bias=False) 35 | self.bn3 = nn.BatchNorm2d(out_planes) 36 | 37 | self.shortcut = nn.Sequential() 38 | if stride == 2: 39 | self.shortcut = nn.Sequential(nn.AvgPool2d(3, stride=2, padding=1)) 40 | 41 | def forward(self, x): 42 | out = F.relu(self.bn1(self.conv1(x))) 43 | out = self.shuffle1(out) 44 | out = F.relu(self.bn2(self.conv2(out))) 45 | out = self.bn3(self.conv3(out)) 46 | res = self.shortcut(x) 47 | out = F.relu(torch.cat([out,res], 1)) if self.stride==2 else F.relu(out+res) 48 | return out 49 | 50 | 51 | class ShuffleNet(nn.Module): 52 | def __init__(self, cfg): 53 | super(ShuffleNet, self).__init__() 54 | out_planes = cfg['out_planes'] 55 | num_blocks = cfg['num_blocks'] 56 | groups = cfg['groups'] 57 | 58 | self.conv1 = nn.Conv2d(3, 24, kernel_size=1, bias=False) 59 | self.bn1 = nn.BatchNorm2d(24) 60 | self.in_planes = 24 61 | self.layer1 = self._make_layer(out_planes[0], num_blocks[0], groups) 62 | self.layer2 = self._make_layer(out_planes[1], num_blocks[1], groups) 63 | self.layer3 = self._make_layer(out_planes[2], num_blocks[2], groups) 64 | self.linear = nn.Linear(out_planes[2], 10) 65 | 66 | def _make_layer(self, out_planes, num_blocks, groups): 67 | layers = [] 68 | for i in range(num_blocks): 69 | stride = 2 if i == 0 else 1 70 | cat_planes = self.in_planes if i == 0 else 0 71 | layers.append(Bottleneck(self.in_planes, out_planes-cat_planes, stride=stride, groups=groups)) 72 | self.in_planes = out_planes 73 | return nn.Sequential(*layers) 74 | 75 | def forward(self, x): 76 | out = F.relu(self.bn1(self.conv1(x))) 77 | out = self.layer1(out) 78 | out = self.layer2(out) 79 | out = self.layer3(out) 80 | out = F.avg_pool2d(out, 4) 81 | out = out.view(out.size(0), -1) 82 | out = self.linear(out) 83 | return out 84 | 85 | 86 | def ShuffleNetG2(): 87 | cfg = { 88 | 'out_planes': [200,400,800], 89 | 'num_blocks': [4,8,4], 90 | 'groups': 2 91 | } 92 | return ShuffleNet(cfg) 93 | 94 | def ShuffleNetG3(): 95 | cfg = { 96 | 'out_planes': [240,480,960], 97 | 'num_blocks': [4,8,4], 98 | 'groups': 3 99 | } 100 | return ShuffleNet(cfg) 101 | 102 | 103 | def test(): 104 | net = ShuffleNetG2() 105 | x = torch.randn(1,3,32,32) 106 | y = net(x) 107 | print(y) 108 | 109 | # test() 110 | -------------------------------------------------------------------------------- /train.py: -------------------------------------------------------------------------------- 1 | '''Train ImageNet with PyTorch.''' 2 | import torch 3 | import torch.nn as nn 4 | import torch.optim as optim 5 | import torch.nn.functional as F 6 | import torch.backends.cudnn as cudnn 7 | 8 | import torchvision 9 | import torchvision.transforms as transforms 10 | 11 | import os 12 | import argparse 13 | 14 | from models import * 15 | import config as cfg 16 | 17 | os.environ["CUDA_VISIBLE_DEVICES"] = '0' 18 | 19 | device = 'cuda' if torch.cuda.is_available() else 'cpu' 20 | best_acc = 0 21 | start_epoch = 0 22 | resume = False 23 | 24 | normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], 25 | std=[0.229, 0.224, 0.225]) 26 | 27 | train_loader = torch.utils.data.DataLoader( 28 | torchvision.datasets.ImageFolder( 29 | cfg.traindir, transforms.Compose([ 30 | transforms.RandomResizedCrop(cfg.input_size), 31 | transforms.RandomHorizontalFlip(), 32 | transforms.ToTensor(), 33 | normalize, 34 | ])), 35 | batch_size=cfg.batch_size, shuffle=True, 36 | num_workers=cfg.n_worker, pin_memory=True) 37 | 38 | val_loader = torch.utils.data.DataLoader( 39 | torchvision.datasets.ImageFolder(cfg.valdir, transforms.Compose([ 40 | transforms.Resize(int(cfg.input_size/0.875)), 41 | transforms.CenterCrop(cfg.input_size), 42 | transforms.ToTensor(), 43 | normalize, 44 | ])), 45 | batch_size=cfg.batch_size, shuffle=False, 46 | num_workers=cfg.n_worker, pin_memory=True) 47 | 48 | print('==> Building model..') 49 | net = ResNet50() 50 | net = net.to(device) 51 | 52 | if device == 'cuda': 53 | net = torch.nn.DataParallel(net) 54 | cudnn.benchmark = True 55 | 56 | if resume: 57 | # Load checkpoint. 58 | print('==> Resuming from checkpoint..') 59 | assert os.path.isdir('checkpoint'), 'Error: no checkpoint directory found!' 60 | checkpoint = torch.load('./checkpoint/ckpt.pth') 61 | net.load_state_dict(checkpoint['net']) 62 | best_acc = checkpoint['acc'] 63 | start_epoch = checkpoint['epoch'] 64 | 65 | criterion = nn.CrossEntropyLoss() 66 | optimizer = optim.SGD(net.parameters(), lr=cfg.lr, momentum=0.9, weight_decay=5e-4) 67 | 68 | def train(epoch): 69 | print('\nEpoch: %d' % epoch) 70 | net.train() 71 | train_loss = 0 72 | correct = 0 73 | total = 0 74 | for batch_idx, (inputs, targets) in enumerate(train_loader): 75 | inputs, targets = inputs.to(device), targets.to(device) 76 | optimizer.zero_grad() 77 | outputs = net(inputs) 78 | loss = criterion(outputs, targets) 79 | loss.backward() 80 | optimizer.step() 81 | 82 | train_loss += loss.item() 83 | _, predicted = outputs.max(1) 84 | total += targets.size(0) 85 | correct += predicted.eq(targets).sum().item() 86 | 87 | print('Lrate: %.5f | Loss: %.5f | Acc: %.5f%% (%d/%d)' % (cfg.lr, train_loss/(batch_idx+1), 100.*correct/total, correct, total)) 88 | 89 | def val(epoch): 90 | global best_acc 91 | net.eval() 92 | correct = 0 93 | total = 0 94 | with torch.no_grad(): 95 | for batch_idx, (inputs, targets) in enumerate(val_loader): 96 | inputs, targets = inputs.to(device), targets.to(device) 97 | outputs = net(inputs) 98 | 99 | _, predicted = outputs.max(1) 100 | total += targets.size(0) 101 | correct += predicted.eq(targets).sum().item() 102 | 103 | # Save checkpoint. 104 | acc = 100. * correct / total 105 | print("Correct Accuracy: %.5f | Best Accuracy: %.5f" % (acc, best_acc)) 106 | 107 | if acc > best_acc: 108 | print('Saving..') 109 | state = { 110 | 'net': net.state_dict(), 111 | 'acc': acc, 112 | 'epoch': epoch, 113 | } 114 | if not os.path.isdir('checkpoint'): 115 | os.mkdir('checkpoint') 116 | torch.save(state, './checkpoint/ckpt.pth') 117 | best_acc = acc 118 | 119 | for epoch in range(start_epoch, start_epoch+2): 120 | train(epoch) 121 | print('Valing...') 122 | val(epoch) -------------------------------------------------------------------------------- /models/densenet.py: -------------------------------------------------------------------------------- 1 | '''DenseNet in PyTorch.''' 2 | import math 3 | 4 | import torch 5 | import torch.nn as nn 6 | import torch.nn.functional as F 7 | 8 | 9 | class Bottleneck(nn.Module): 10 | def __init__(self, in_planes, growth_rate): 11 | super(Bottleneck, self).__init__() 12 | self.bn1 = nn.BatchNorm2d(in_planes) 13 | self.conv1 = nn.Conv2d(in_planes, 4*growth_rate, kernel_size=1, bias=False) 14 | self.bn2 = nn.BatchNorm2d(4*growth_rate) 15 | self.conv2 = nn.Conv2d(4*growth_rate, growth_rate, kernel_size=3, padding=1, bias=False) 16 | 17 | def forward(self, x): 18 | out = self.conv1(F.relu(self.bn1(x))) 19 | out = self.conv2(F.relu(self.bn2(out))) 20 | out = torch.cat([out,x], 1) 21 | return out 22 | 23 | 24 | class Transition(nn.Module): 25 | def __init__(self, in_planes, out_planes): 26 | super(Transition, self).__init__() 27 | self.bn = nn.BatchNorm2d(in_planes) 28 | self.conv = nn.Conv2d(in_planes, out_planes, kernel_size=1, bias=False) 29 | 30 | def forward(self, x): 31 | out = self.conv(F.relu(self.bn(x))) 32 | out = F.avg_pool2d(out, 2) 33 | return out 34 | 35 | 36 | class DenseNet(nn.Module): 37 | def __init__(self, block, nblocks, growth_rate=12, reduction=0.5, num_classes=1000): 38 | super(DenseNet, self).__init__() 39 | self.growth_rate = growth_rate 40 | 41 | num_planes = 2*growth_rate 42 | self.bn1 = nn.BatchNorm2d(3) 43 | self.conv1 = nn.Conv2d(3, num_planes, kernel_size=7, stride=2, padding=3, bias=False) 44 | 45 | self.dense1 = self._make_dense_layers(block, num_planes, nblocks[0]) 46 | num_planes += nblocks[0]*growth_rate 47 | out_planes = int(math.floor(num_planes*reduction)) 48 | self.trans1 = Transition(num_planes, out_planes) 49 | num_planes = out_planes 50 | 51 | self.dense2 = self._make_dense_layers(block, num_planes, nblocks[1]) 52 | num_planes += nblocks[1]*growth_rate 53 | out_planes = int(math.floor(num_planes*reduction)) 54 | self.trans2 = Transition(num_planes, out_planes) 55 | num_planes = out_planes 56 | 57 | self.dense3 = self._make_dense_layers(block, num_planes, nblocks[2]) 58 | num_planes += nblocks[2]*growth_rate 59 | out_planes = int(math.floor(num_planes*reduction)) 60 | self.trans3 = Transition(num_planes, out_planes) 61 | num_planes = out_planes 62 | 63 | self.dense4 = self._make_dense_layers(block, num_planes, nblocks[3]) 64 | num_planes += nblocks[3]*growth_rate 65 | 66 | self.bn = nn.BatchNorm2d(num_planes) 67 | self.linear = nn.Linear(num_planes, num_classes) 68 | 69 | def _make_dense_layers(self, block, in_planes, nblock): 70 | layers = [] 71 | for i in range(nblock): 72 | layers.append(block(in_planes, self.growth_rate)) 73 | in_planes += self.growth_rate 74 | return nn.Sequential(*layers) 75 | 76 | def forward(self, x): 77 | out = self.conv1(F.relu(self.bn1(x))) 78 | out = F.max_pool2d(out, kernel_size=3, stride=2, padding=1) 79 | out = self.trans1(self.dense1(out)) 80 | out = self.trans2(self.dense2(out)) 81 | out = self.trans3(self.dense3(out)) 82 | out = self.dense4(out) 83 | # out = F.avg_pool2d(F.relu(self.bn(out)), 7) 84 | # out = out.view(out.size(0), -1) 85 | # out = self.linear(out) 86 | return out 87 | 88 | def DenseNet121(): 89 | return DenseNet(Bottleneck, [6,12,24,16], growth_rate=32) 90 | 91 | def DenseNet169(): 92 | return DenseNet(Bottleneck, [6,12,32,32], growth_rate=32) 93 | 94 | def DenseNet201(): 95 | return DenseNet(Bottleneck, [6,12,48,32], growth_rate=32) 96 | 97 | def DenseNet264(): 98 | return DenseNet(Bottleneck, [6,12,64,48], growth_rate=32) 99 | 100 | def DenseNet161(): 101 | return DenseNet(Bottleneck, [6,12,36,24], growth_rate=48) 102 | 103 | def test(): 104 | net = DenseNet201() 105 | x = torch.randn(1, 3, 224, 224) 106 | y = net(x) 107 | print(y.size()) 108 | 109 | # test() 110 | -------------------------------------------------------------------------------- /models/senet.py: -------------------------------------------------------------------------------- 1 | '''SENet in PyTorch. 2 | 3 | SENet is the winner of ImageNet-2017. The paper is not released yet. 4 | ''' 5 | import torch 6 | import torch.nn as nn 7 | import torch.nn.functional as F 8 | 9 | 10 | class BasicBlock(nn.Module): 11 | def __init__(self, in_planes, planes, stride=1): 12 | super(BasicBlock, self).__init__() 13 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) 14 | self.bn1 = nn.BatchNorm2d(planes) 15 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False) 16 | self.bn2 = nn.BatchNorm2d(planes) 17 | 18 | self.shortcut = nn.Sequential() 19 | if stride != 1 or in_planes != planes: 20 | self.shortcut = nn.Sequential( 21 | nn.Conv2d(in_planes, planes, kernel_size=1, stride=stride, bias=False), 22 | nn.BatchNorm2d(planes) 23 | ) 24 | 25 | # SE layers 26 | self.fc1 = nn.Conv2d(planes, planes//16, kernel_size=1) # Use nn.Conv2d instead of nn.Linear 27 | self.fc2 = nn.Conv2d(planes//16, planes, kernel_size=1) 28 | 29 | def forward(self, x): 30 | out = F.relu(self.bn1(self.conv1(x))) 31 | out = self.bn2(self.conv2(out)) 32 | 33 | # Squeeze 34 | w = F.avg_pool2d(out, out.size(2)) 35 | w = F.relu(self.fc1(w)) 36 | w = torch.sigmoid(self.fc2(w)) 37 | # Excitation 38 | out = out * w # New broadcasting feature from v0.2! 39 | 40 | out += self.shortcut(x) 41 | out = F.relu(out) 42 | return out 43 | 44 | 45 | class PreActBlock(nn.Module): 46 | def __init__(self, in_planes, planes, stride=1): 47 | super(PreActBlock, self).__init__() 48 | self.bn1 = nn.BatchNorm2d(in_planes) 49 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) 50 | self.bn2 = nn.BatchNorm2d(planes) 51 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False) 52 | 53 | if stride != 1 or in_planes != planes: 54 | self.shortcut = nn.Sequential( 55 | nn.Conv2d(in_planes, planes, kernel_size=1, stride=stride, bias=False) 56 | ) 57 | 58 | # SE layers 59 | self.fc1 = nn.Conv2d(planes, planes//16, kernel_size=1) 60 | self.fc2 = nn.Conv2d(planes//16, planes, kernel_size=1) 61 | 62 | def forward(self, x): 63 | out = F.relu(self.bn1(x)) 64 | shortcut = self.shortcut(out) if hasattr(self, 'shortcut') else x 65 | out = self.conv1(out) 66 | out = self.conv2(F.relu(self.bn2(out))) 67 | 68 | # Squeeze 69 | w = F.avg_pool2d(out, out.size(2)) 70 | w = F.relu(self.fc1(w)) 71 | w = torch.sigmoid(self.fc2(w)) 72 | # Excitation 73 | out = out * w 74 | 75 | out += shortcut 76 | return out 77 | 78 | 79 | class SENet(nn.Module): 80 | def __init__(self, block, num_blocks, num_classes=10): 81 | super(SENet, self).__init__() 82 | self.in_planes = 64 83 | 84 | self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False) 85 | self.bn1 = nn.BatchNorm2d(64) 86 | self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1) 87 | self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2) 88 | self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2) 89 | self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2) 90 | self.linear = nn.Linear(512, num_classes) 91 | 92 | def _make_layer(self, block, planes, num_blocks, stride): 93 | strides = [stride] + [1]*(num_blocks-1) 94 | layers = [] 95 | for stride in strides: 96 | layers.append(block(self.in_planes, planes, stride)) 97 | self.in_planes = planes 98 | return nn.Sequential(*layers) 99 | 100 | def forward(self, x): 101 | out = F.relu(self.bn1(self.conv1(x))) 102 | out = self.layer1(out) 103 | out = self.layer2(out) 104 | out = self.layer3(out) 105 | out = self.layer4(out) 106 | out = F.avg_pool2d(out, 4) 107 | out = out.view(out.size(0), -1) 108 | out = self.linear(out) 109 | return out 110 | 111 | 112 | def SENet18(): 113 | return SENet(PreActBlock, [2,2,2,2]) 114 | 115 | 116 | def test(): 117 | net = SENet18() 118 | y = net(torch.randn(1,3,32,32)) 119 | print(y.size()) 120 | 121 | # test() 122 | -------------------------------------------------------------------------------- /models/resnet.py: -------------------------------------------------------------------------------- 1 | '''ResNet in PyTorch. 2 | 3 | For Pre-activation ResNet, see 'preact_resnet.py'. 4 | 5 | CVPR 2016 Best Paper 6 | 7 | Reference: 8 | [1] Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun 9 | Deep Residual Learning for Image Recognition. arXiv:1512.03385 10 | ''' 11 | import torch 12 | import torch.nn as nn 13 | import torch.nn.functional as F 14 | 15 | 16 | class BasicBlock(nn.Module): 17 | expansion = 1 18 | 19 | def __init__(self, in_planes, planes, stride=1): 20 | super(BasicBlock, self).__init__() 21 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) 22 | self.bn1 = nn.BatchNorm2d(planes) 23 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False) 24 | self.bn2 = nn.BatchNorm2d(planes) 25 | 26 | self.shortcut = nn.Sequential() 27 | if stride != 1 or in_planes != self.expansion*planes: 28 | self.shortcut = nn.Sequential( 29 | nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False), 30 | nn.BatchNorm2d(self.expansion*planes) 31 | ) 32 | 33 | def forward(self, x): 34 | out = F.relu(self.bn1(self.conv1(x))) 35 | out = self.bn2(self.conv2(out)) 36 | out += self.shortcut(x) 37 | out = F.relu(out) 38 | return out 39 | 40 | 41 | class Bottleneck(nn.Module): 42 | expansion = 4 43 | 44 | def __init__(self, in_planes, planes, stride=1): 45 | super(Bottleneck, self).__init__() 46 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False) 47 | self.bn1 = nn.BatchNorm2d(planes) 48 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) 49 | self.bn2 = nn.BatchNorm2d(planes) 50 | self.conv3 = nn.Conv2d(planes, self.expansion*planes, kernel_size=1, bias=False) 51 | self.bn3 = nn.BatchNorm2d(self.expansion*planes) 52 | 53 | self.shortcut = nn.Sequential() 54 | if stride != 1 or in_planes != self.expansion*planes: 55 | self.shortcut = nn.Sequential( 56 | nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False), 57 | nn.BatchNorm2d(self.expansion*planes) 58 | ) 59 | 60 | def forward(self, x): 61 | out = F.relu(self.bn1(self.conv1(x))) 62 | out = F.relu(self.bn2(self.conv2(out))) 63 | out = self.bn3(self.conv3(out)) 64 | out += self.shortcut(x) 65 | out = F.relu(out) 66 | return out 67 | 68 | 69 | class ResNet(nn.Module): 70 | def __init__(self, block, num_blocks, num_classes=1000): 71 | super(ResNet, self).__init__() 72 | self.in_planes = 64 73 | 74 | self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False) 75 | self.bn1 = nn.BatchNorm2d(64) 76 | self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=2) 77 | self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2) 78 | self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2) 79 | self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2) 80 | self.linear = nn.Linear(512*block.expansion, num_classes) 81 | 82 | def _make_layer(self, block, planes, num_blocks, stride): 83 | strides = [stride] + [1]*(num_blocks-1) 84 | layers = [] 85 | for stride in strides: 86 | layers.append(block(self.in_planes, planes, stride)) 87 | self.in_planes = planes * block.expansion 88 | return nn.Sequential(*layers) 89 | 90 | def forward(self, x): 91 | out = F.relu(self.bn1(self.conv1(x))) 92 | out = self.layer1(out) 93 | out = self.layer2(out) 94 | out = self.layer3(out) 95 | out = self.layer4(out) 96 | out = F.avg_pool2d(out, 7) 97 | out = out.view(out.size(0), -1) 98 | out = self.linear(out) 99 | return out 100 | 101 | 102 | def ResNet18(): 103 | return ResNet(BasicBlock, [2,2,2,2]) 104 | 105 | def ResNet34(): 106 | return ResNet(BasicBlock, [3,4,6,3]) 107 | 108 | def ResNet50(): 109 | return ResNet(Bottleneck, [3,4,6,3]) 110 | 111 | def ResNet101(): 112 | return ResNet(Bottleneck, [3,4,23,3]) 113 | 114 | def ResNet152(): 115 | return ResNet(Bottleneck, [3,8,36,3]) 116 | 117 | 118 | def test(): 119 | net = ResNet152() 120 | y = net(torch.randn(1,3,224,224)) 121 | print(y.size()) 122 | 123 | # test() 124 | -------------------------------------------------------------------------------- /models/dpn.py: -------------------------------------------------------------------------------- 1 | '''Dual Path Networks in PyTorch.''' 2 | import torch 3 | import torch.nn as nn 4 | import torch.nn.functional as F 5 | 6 | 7 | class Bottleneck(nn.Module): 8 | def __init__(self, last_planes, in_planes, out_planes, dense_depth, stride, groups, first_layer): 9 | super(Bottleneck, self).__init__() 10 | self.out_planes = out_planes 11 | self.dense_depth = dense_depth 12 | 13 | self.conv1 = nn.Conv2d(last_planes, in_planes, kernel_size=1, bias=False) 14 | self.bn1 = nn.BatchNorm2d(in_planes) 15 | self.conv2 = nn.Conv2d(in_planes, in_planes, kernel_size=3, stride=stride, padding=1, groups=groups, bias=False) 16 | self.bn2 = nn.BatchNorm2d(in_planes) 17 | self.conv3 = nn.Conv2d(in_planes, out_planes+dense_depth, kernel_size=1, bias=False) 18 | self.bn3 = nn.BatchNorm2d(out_planes+dense_depth) 19 | 20 | self.shortcut = nn.Sequential() 21 | if first_layer: 22 | self.shortcut = nn.Sequential( 23 | nn.Conv2d(last_planes, out_planes+dense_depth, kernel_size=1, stride=stride, bias=False), 24 | nn.BatchNorm2d(out_planes+dense_depth) 25 | ) 26 | 27 | def forward(self, x): 28 | out = F.relu(self.bn1(self.conv1(x))) 29 | out = F.relu(self.bn2(self.conv2(out))) 30 | out = self.bn3(self.conv3(out)) 31 | x = self.shortcut(x) 32 | d = self.out_planes 33 | out = torch.cat([x[:,:d,:,:]+out[:,:d,:,:], x[:,d:,:,:], out[:,d:,:,:]], 1) 34 | out = F.relu(out) 35 | return out 36 | 37 | 38 | class DPN(nn.Module): 39 | def __init__(self, cfg, num_classes=1000): 40 | super(DPN, self).__init__() 41 | in_planes, out_planes = cfg['in_planes'], cfg['out_planes'] 42 | num_blocks, dense_depth = cfg['num_blocks'], cfg['dense_depth'] 43 | groups = cfg['groups'] 44 | 45 | # conv 1 46 | self.conv1 = nn.Conv2d(3, cfg['num_init_features'], kernel_size=7, stride=2, padding=3, bias=False) 47 | self.bn1 = nn.BatchNorm2d(cfg['num_init_features']) 48 | self.maxpool1 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) 49 | 50 | # conv 2 51 | self.last_planes = cfg['num_init_features'] 52 | self.layer1 = self._make_layer(in_planes[0], out_planes[0], num_blocks[0], dense_depth[0], stride=1, groups=groups) 53 | 54 | # conv3 55 | self.layer2 = self._make_layer(in_planes[1], out_planes[1], num_blocks[1], dense_depth[1], stride=2, groups=groups) 56 | 57 | # conv4 58 | self.layer3 = self._make_layer(in_planes[2], out_planes[2], num_blocks[2], dense_depth[2], stride=2, groups=groups) 59 | 60 | # conv5 61 | self.layer4 = self._make_layer(in_planes[3], out_planes[3], num_blocks[3], dense_depth[3], stride=2, groups=groups) 62 | 63 | 64 | self.linear = nn.Linear(out_planes[3]+(num_blocks[3]+1)*dense_depth[3], num_classes) 65 | 66 | def _make_layer(self, in_planes, out_planes, num_blocks, dense_depth, stride, groups): 67 | strides = [stride] + [1]*(num_blocks-1) 68 | layers = [] 69 | for i,stride in enumerate(strides): 70 | layers.append(Bottleneck(self.last_planes, in_planes, out_planes, dense_depth, stride, groups, i==0)) 71 | self.last_planes = out_planes + (i+2) * dense_depth 72 | return nn.Sequential(*layers) 73 | 74 | def forward(self, x): 75 | out = F.relu(self.bn1(self.conv1(x))) 76 | out = self.maxpool1(out) 77 | out = self.layer1(out) 78 | out = self.layer2(out) 79 | out = self.layer3(out) 80 | out = self.layer4(out) 81 | out = F.avg_pool2d(out, 7) 82 | out = out.view(out.size(0), -1) 83 | out = self.linear(out) 84 | return out 85 | 86 | 87 | def DPN92(): 88 | cfg = { 89 | 'num_init_features': 64, 90 | 'groups': 32, 91 | 'in_planes': (96,192,384,768), 92 | 'out_planes': (256,512,1024,2048), 93 | 'num_blocks': (3,4,20,3), 94 | 'dense_depth': (16,32,24,128) 95 | } 96 | return DPN(cfg) 97 | 98 | 99 | def DPN98(): 100 | cfg = { 101 | 'num_init_features': 96, 102 | 'groups': 40, 103 | 'in_planes': (160, 320, 640, 1280), 104 | 'out_planes': (256, 512, 1024, 2048), 105 | 'num_blocks': (3, 6, 20, 3), 106 | 'dense_depth': (16, 32, 32, 128) 107 | } 108 | return DPN(cfg) 109 | 110 | 111 | def test(): 112 | net = DPN98() 113 | x = torch.randn(1,3,224,224) 114 | y = net(x) 115 | print(y.size()) 116 | 117 | # test() 118 | -------------------------------------------------------------------------------- /models/preact_resnet.py: -------------------------------------------------------------------------------- 1 | '''Pre-activation ResNet in PyTorch. 2 | 3 | ECCV 2016 4 | 5 | Reference: 6 | [1] Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun 7 | Identity Mappings in Deep Residual Networks. arXiv:1603.05027 8 | ''' 9 | import torch 10 | import torch.nn as nn 11 | import torch.nn.functional as F 12 | 13 | 14 | class PreActBlock(nn.Module): 15 | '''Pre-activation version of the BasicBlock.''' 16 | expansion = 1 17 | 18 | def __init__(self, in_planes, planes, stride=1): 19 | super(PreActBlock, self).__init__() 20 | self.bn1 = nn.BatchNorm2d(in_planes) 21 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) 22 | self.bn2 = nn.BatchNorm2d(planes) 23 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False) 24 | 25 | if stride != 1 or in_planes != self.expansion*planes: 26 | self.shortcut = nn.Sequential( 27 | nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False) 28 | ) 29 | 30 | def forward(self, x): 31 | out = F.relu(self.bn1(x)) 32 | shortcut = self.shortcut(out) if hasattr(self, 'shortcut') else x 33 | out = self.conv1(out) 34 | out = self.conv2(F.relu(self.bn2(out))) 35 | out += shortcut 36 | return out 37 | 38 | 39 | class PreActBottleneck(nn.Module): 40 | '''Pre-activation version of the original Bottleneck module.''' 41 | expansion = 4 42 | 43 | def __init__(self, in_planes, planes, stride=1): 44 | super(PreActBottleneck, self).__init__() 45 | self.bn1 = nn.BatchNorm2d(in_planes) 46 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False) 47 | self.bn2 = nn.BatchNorm2d(planes) 48 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) 49 | self.bn3 = nn.BatchNorm2d(planes) 50 | self.conv3 = nn.Conv2d(planes, self.expansion*planes, kernel_size=1, bias=False) 51 | 52 | if stride != 1 or in_planes != self.expansion*planes: 53 | self.shortcut = nn.Sequential( 54 | nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False) 55 | ) 56 | 57 | def forward(self, x): 58 | out = F.relu(self.bn1(x)) 59 | shortcut = self.shortcut(out) if hasattr(self, 'shortcut') else x 60 | out = self.conv1(out) 61 | out = self.conv2(F.relu(self.bn2(out))) 62 | out = self.conv3(F.relu(self.bn3(out))) 63 | out += shortcut 64 | return out 65 | 66 | 67 | class PreActResNet(nn.Module): 68 | def __init__(self, block, num_blocks, num_classes=1000): 69 | super(PreActResNet, self).__init__() 70 | self.in_planes = 64 71 | 72 | self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False) 73 | self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=2) 74 | self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2) 75 | self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2) 76 | self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2) 77 | self.linear = nn.Linear(512*block.expansion, num_classes) 78 | 79 | def _make_layer(self, block, planes, num_blocks, stride): 80 | strides = [stride] + [1]*(num_blocks-1) 81 | layers = [] 82 | for stride in strides: 83 | layers.append(block(self.in_planes, planes, stride)) 84 | self.in_planes = planes * block.expansion 85 | return nn.Sequential(*layers) 86 | 87 | def forward(self, x): 88 | out = self.conv1(x) 89 | out = self.layer1(out) 90 | out = self.layer2(out) 91 | out = self.layer3(out) 92 | out = self.layer4(out) 93 | out = F.avg_pool2d(out, 7) 94 | out = out.view(out.size(0), -1) 95 | out = self.linear(out) 96 | return out 97 | 98 | 99 | def PreActResNet18(): 100 | return PreActResNet(PreActBlock, [2,2,2,2]) 101 | 102 | def PreActResNet34(): 103 | return PreActResNet(PreActBlock, [3,4,6,3]) 104 | 105 | def PreActResNet50(): 106 | return PreActResNet(PreActBottleneck, [3,4,6,3]) 107 | 108 | def PreActResNet101(): 109 | return PreActResNet(PreActBottleneck, [3,4,23,3]) 110 | 111 | def PreActResNet152(): 112 | return PreActResNet(PreActBottleneck, [3,8,36,3]) 113 | 114 | 115 | def test(): 116 | net = PreActResNet18() 117 | y = net((torch.randn(1,3,224,224))) 118 | print(y.size()) 119 | 120 | # test() 121 | -------------------------------------------------------------------------------- /models/pnasnet.py: -------------------------------------------------------------------------------- 1 | '''PNASNet in PyTorch. 2 | 3 | Paper: Progressive Neural Architecture Search 4 | ''' 5 | import torch 6 | import torch.nn as nn 7 | import torch.nn.functional as F 8 | 9 | 10 | class SepConv(nn.Module): 11 | '''Separable Convolution.''' 12 | def __init__(self, in_planes, out_planes, kernel_size, stride): 13 | super(SepConv, self).__init__() 14 | self.conv1 = nn.Conv2d(in_planes, out_planes, 15 | kernel_size, stride, 16 | padding=(kernel_size-1)//2, 17 | bias=False, groups=in_planes) 18 | self.bn1 = nn.BatchNorm2d(out_planes) 19 | 20 | def forward(self, x): 21 | return self.bn1(self.conv1(x)) 22 | 23 | 24 | class CellA(nn.Module): 25 | def __init__(self, in_planes, out_planes, stride=1): 26 | super(CellA, self).__init__() 27 | self.stride = stride 28 | self.sep_conv1 = SepConv(in_planes, out_planes, kernel_size=7, stride=stride) 29 | if stride==2: 30 | self.conv1 = nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False) 31 | self.bn1 = nn.BatchNorm2d(out_planes) 32 | 33 | def forward(self, x): 34 | y1 = self.sep_conv1(x) 35 | y2 = F.max_pool2d(x, kernel_size=3, stride=self.stride, padding=1) 36 | if self.stride==2: 37 | y2 = self.bn1(self.conv1(y2)) 38 | return F.relu(y1+y2) 39 | 40 | class CellB(nn.Module): 41 | def __init__(self, in_planes, out_planes, stride=1): 42 | super(CellB, self).__init__() 43 | self.stride = stride 44 | # Left branch 45 | self.sep_conv1 = SepConv(in_planes, out_planes, kernel_size=7, stride=stride) 46 | self.sep_conv2 = SepConv(in_planes, out_planes, kernel_size=3, stride=stride) 47 | # Right branch 48 | self.sep_conv3 = SepConv(in_planes, out_planes, kernel_size=5, stride=stride) 49 | if stride==2: 50 | self.conv1 = nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False) 51 | self.bn1 = nn.BatchNorm2d(out_planes) 52 | # Reduce channels 53 | self.conv2 = nn.Conv2d(2*out_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False) 54 | self.bn2 = nn.BatchNorm2d(out_planes) 55 | 56 | def forward(self, x): 57 | # Left branch 58 | y1 = self.sep_conv1(x) 59 | y2 = self.sep_conv2(x) 60 | # Right branch 61 | y3 = F.max_pool2d(x, kernel_size=3, stride=self.stride, padding=1) 62 | if self.stride==2: 63 | y3 = self.bn1(self.conv1(y3)) 64 | y4 = self.sep_conv3(x) 65 | # Concat & reduce channels 66 | b1 = F.relu(y1+y2) 67 | b2 = F.relu(y3+y4) 68 | y = torch.cat([b1,b2], 1) 69 | return F.relu(self.bn2(self.conv2(y))) 70 | 71 | class PNASNet(nn.Module): 72 | def __init__(self, cell_type, num_cells, num_planes): 73 | super(PNASNet, self).__init__() 74 | self.in_planes = num_planes 75 | self.cell_type = cell_type 76 | 77 | self.conv1 = nn.Conv2d(3, num_planes, kernel_size=3, stride=1, padding=1, bias=False) 78 | self.bn1 = nn.BatchNorm2d(num_planes) 79 | 80 | self.layer1 = self._make_layer(num_planes, num_cells=6) 81 | self.layer2 = self._downsample(num_planes*2) 82 | self.layer3 = self._make_layer(num_planes*2, num_cells=6) 83 | self.layer4 = self._downsample(num_planes*4) 84 | self.layer5 = self._make_layer(num_planes*4, num_cells=6) 85 | 86 | self.linear = nn.Linear(num_planes*4, 10) 87 | 88 | def _make_layer(self, planes, num_cells): 89 | layers = [] 90 | for _ in range(num_cells): 91 | layers.append(self.cell_type(self.in_planes, planes, stride=1)) 92 | self.in_planes = planes 93 | return nn.Sequential(*layers) 94 | 95 | def _downsample(self, planes): 96 | layer = self.cell_type(self.in_planes, planes, stride=2) 97 | self.in_planes = planes 98 | return layer 99 | 100 | def forward(self, x): 101 | out = F.relu(self.bn1(self.conv1(x))) 102 | out = self.layer1(out) 103 | out = self.layer2(out) 104 | out = self.layer3(out) 105 | out = self.layer4(out) 106 | out = self.layer5(out) 107 | out = F.avg_pool2d(out, 8) 108 | out = self.linear(out.view(out.size(0), -1)) 109 | return out 110 | 111 | 112 | def PNASNetA(): 113 | return PNASNet(CellA, num_cells=6, num_planes=44) 114 | 115 | def PNASNetB(): 116 | return PNASNet(CellB, num_cells=6, num_planes=32) 117 | 118 | 119 | def test(): 120 | net = PNASNetB() 121 | x = torch.randn(1,3,32,32) 122 | y = net(x) 123 | print(y) 124 | 125 | # test() 126 | -------------------------------------------------------------------------------- /models/googlenet_v2.py: -------------------------------------------------------------------------------- 1 | '''GoogleNet Inception-V2 in PyTorch. 2 | 2015 3 | 4 | Reference: 5 | [1] Sergey Ioffe, Christian Szegedy 6 | Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift 7 | ''' 8 | import torch 9 | import torch.nn as nn 10 | import torch.nn.functional as F 11 | 12 | class Inception(nn.Module): 13 | def __init__(self, in_planes, n1x1, n3x3red, n3x3, n5x5red, n5x5, pool_planes): 14 | super(Inception, self).__init__() 15 | # 1x1 conv branch 16 | self.b1 = nn.Sequential( 17 | nn.Conv2d(in_planes, n1x1, kernel_size=1), 18 | nn.BatchNorm2d(n1x1), 19 | nn.ReLU(True), 20 | ) 21 | 22 | # 1x1 conv -> 3x3 conv branch 23 | self.b2 = nn.Sequential( 24 | nn.Conv2d(in_planes, n3x3red, kernel_size=1), 25 | nn.BatchNorm2d(n3x3red), 26 | nn.ReLU(True), 27 | nn.Conv2d(n3x3red, n3x3, kernel_size=3, padding=1), 28 | nn.BatchNorm2d(n3x3), 29 | nn.ReLU(True), 30 | ) 31 | 32 | # 1x1 conv -> 3x3 conv -> 3x3 conv branch 33 | self.b3 = nn.Sequential( 34 | nn.Conv2d(in_planes, n5x5red, kernel_size=1), 35 | nn.BatchNorm2d(n5x5red), 36 | nn.ReLU(True), 37 | nn.Conv2d(n5x5red, n5x5, kernel_size=3, padding=1), 38 | nn.BatchNorm2d(n5x5), 39 | nn.ReLU(True), 40 | nn.Conv2d(n5x5, n5x5, kernel_size=3, padding=1), 41 | nn.BatchNorm2d(n5x5), 42 | nn.ReLU(True), 43 | ) 44 | 45 | # 3x3 pool -> 1x1 conv branch 46 | self.b4 = nn.Sequential( 47 | nn.AvgPool2d(kernel_size=3, stride=1, padding=1), 48 | nn.Conv2d(in_planes, pool_planes, kernel_size=1), 49 | nn.BatchNorm2d(pool_planes), 50 | nn.ReLU(True), 51 | ) 52 | 53 | def forward(self, x): 54 | y1 = self.b1(x) 55 | y2 = self.b2(x) 56 | y3 = self.b3(x) 57 | y4 = self.b4(x) 58 | y = torch.cat([y1, y2, y3, y4], 1) 59 | return y 60 | 61 | class Inception_S2(nn.Module): 62 | def __init__(self, in_planes, n3x3red, n3x3, n5x5red, n5x5): 63 | super(Inception_S2, self).__init__() 64 | 65 | # 1x1 conv -> 3x3 conv branch 66 | self.b1 = nn.Sequential( 67 | nn.Conv2d(in_planes, n3x3red, kernel_size=1), 68 | nn.BatchNorm2d(n3x3red), 69 | nn.ReLU(True), 70 | nn.Conv2d(n3x3red, n3x3, kernel_size=3, stride=2, padding=1), 71 | nn.BatchNorm2d(n3x3), 72 | nn.ReLU(True), 73 | ) 74 | 75 | # 1x1 conv -> 3x3 conv -> 3x3 conv branch 76 | self.b2 = nn.Sequential( 77 | nn.Conv2d(in_planes, n5x5red, kernel_size=1), 78 | nn.BatchNorm2d(n5x5red), 79 | nn.ReLU(True), 80 | nn.Conv2d(n5x5red, n5x5, kernel_size=3, padding=1), 81 | nn.BatchNorm2d(n5x5), 82 | nn.ReLU(True), 83 | nn.Conv2d(n5x5, n5x5, kernel_size=3, stride=2, padding=1), 84 | nn.BatchNorm2d(n5x5), 85 | nn.ReLU(True), 86 | ) 87 | 88 | # 3x3 pool branch 89 | self.b3 = nn.MaxPool2d(3, stride=2, padding=1) 90 | 91 | def forward(self, x): 92 | y1 = self.b1(x) 93 | y2 = self.b2(x) 94 | y3 = self.b3(x) 95 | y = torch.cat([y1, y2, y3], 1) 96 | return y 97 | 98 | class GoogleNetV2(nn.Module): 99 | def __init__(self, num_classes=1000): 100 | super(GoogleNetV2, self).__init__() 101 | self.pre_layers_1 = nn.Sequential( 102 | nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3), 103 | nn.BatchNorm2d(64), 104 | nn.ReLU(inplace=True) 105 | ) 106 | 107 | self.pre_layers_2 = nn.Sequential( 108 | nn.Conv2d(64, 64, kernel_size=1), 109 | nn.BatchNorm2d(64), 110 | nn.ReLU(inplace=True), 111 | nn.Conv2d(64, 192, kernel_size=3, padding=1), 112 | nn.BatchNorm2d(192), 113 | nn.ReLU(inplace=True) 114 | ) 115 | 116 | self.a3 = Inception(192, 64, 64, 64, 64, 96, 32) 117 | self.b3 = Inception(256, 64, 64, 96, 64, 96, 64) 118 | self.c3 = Inception_S2(320, 128, 160, 64, 96) 119 | 120 | self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) 121 | 122 | self.a4 = Inception(576, 224, 64, 96, 96, 128, 128) 123 | self.b4 = Inception(576, 192, 96, 128, 96, 128, 128) 124 | self.c4 = Inception(576, 160, 128, 160, 128, 160, 96) 125 | self.d4 = Inception(576, 96, 128, 192, 160, 192, 96) 126 | self.e4 = Inception_S2(576, 128, 192, 192, 256) 127 | 128 | self.a5 = Inception(1024, 352, 192, 320, 160, 224, 128) 129 | self.b5 = Inception(1024, 352, 192, 320, 192, 224, 128) 130 | 131 | self.avgpool = nn.AvgPool2d(7, stride=1) 132 | self.linear = nn.Linear(1024, num_classes) 133 | 134 | def forward(self, x): 135 | x = self.pre_layers_1(x) 136 | x = self.maxpool(x) 137 | x = self.pre_layers_2(x) 138 | x = self.maxpool(x) 139 | x = self.a3(x) 140 | x = self.b3(x) 141 | x = self.c3(x) 142 | 143 | x = self.a4(x) 144 | x = self.b4(x) 145 | x = self.c4(x) 146 | x = self.d4(x) 147 | x = self.e4(x) 148 | 149 | x = self.a5(x) 150 | x = self.b5(x) 151 | x = self.avgpool(x) 152 | x = x.view(x.size(0), -1) 153 | x = self.linear(x) 154 | return x 155 | 156 | def test(): 157 | x = torch.randn(1,3,224,224) 158 | net = GoogleNetV2() 159 | y = net(x) 160 | print(y.size()) 161 | 162 | # test() -------------------------------------------------------------------------------- /models/igcv3.py: -------------------------------------------------------------------------------- 1 | ''' IGCV3 in PyTorch 2 | 3 | BMVC 2018 4 | 5 | Reference: 6 | [1] Ke Sun. Mingjie Li. Dong Liu & Jingdong Wang 7 | IGCV3: Interleaved Low-Rank Group Convolutions for Efficient Deep Neural Networks. 8 | ''' 9 | 10 | import torch 11 | import torch.nn as nn 12 | import torch.nn.functional as F 13 | 14 | def conv_bn(inp, oup, stride ): 15 | return nn.Sequential( 16 | nn.Conv2d(inp, oup,kernel_size= 3, stride= stride, padding= 1, bias=False), 17 | nn.BatchNorm2d(oup), 18 | nn.ReLU6(inplace=True) 19 | ) 20 | 21 | 22 | def conv_1x1_bn(inp, oup): 23 | return nn.Sequential( 24 | nn.Conv2d(inp, oup, kernel_size = 1, stride= 1, padding= 0, bias=False), 25 | nn.BatchNorm2d(oup), 26 | nn.ReLU6(inplace=True) 27 | ) 28 | 29 | class PermutationBlock(nn.Module): 30 | def __init__(self, groups): 31 | super(PermutationBlock, self).__init__() 32 | self.groups = groups 33 | 34 | def forward(self, input): 35 | n, c, h, w = input.size() 36 | G = self.groups 37 | #直接就是mxnet实现的permutation操作 38 | # def permutation(data, groups): 39 | #举例说明:当groups = 2时,输入:nx144x56x56 40 | # data = mx.sym.reshape(data, shape=(0, -4, groups, -1, -2)) 41 | # 输出:nx2x72x56x56 42 | # data = mx.sym.swapaxes(data, 1, 2) 43 | # 输出:nx72x2x56x56 44 | # data = mx.sym.reshape(data, shape=(0, -3, -2)) 45 | # 输出:nx144x56x56 46 | # return data 47 | output = input.view(n, G, c // G, h, w).permute(0, 2, 1, 3, 4).contiguous().view(n, c, h, w) 48 | return output 49 | 50 | class InvertedResidual(nn.Module): 51 | def __init__(self, inp, oup, stride, expand_ratio): 52 | super(InvertedResidual, self).__init__() 53 | self.stride = stride 54 | assert stride in [1, 2] 55 | 56 | self.use_res_connect = self.stride == 1 and inp == oup 57 | 58 | self.conv = nn.Sequential( 59 | # pw 60 | nn.Conv2d(inp, inp * expand_ratio,kernel_size = 1, stride= 1, padding=0,groups = 2, bias=False), 61 | nn.BatchNorm2d(inp * expand_ratio), 62 | nn.ReLU6(inplace=True), 63 | #permutation 64 | PermutationBlock(groups=2), 65 | # dw 66 | nn.Conv2d(inp * expand_ratio, inp * expand_ratio, kernel_size =3, stride= stride, padding=1, groups=inp * expand_ratio, bias=False), 67 | nn.BatchNorm2d(inp * expand_ratio), 68 | nn.ReLU6(inplace=True), 69 | # pw-linear 70 | nn.Conv2d(inp * expand_ratio, oup, kernel_size =1, stride= 1, padding=0,groups = 2, bias=False), 71 | nn.BatchNorm2d(oup), 72 | # permutation 73 | PermutationBlock(groups= int(round((oup/2)))), 74 | ) 75 | 76 | def forward(self, x): 77 | if self.use_res_connect: 78 | return x + self.conv(x) 79 | else: 80 | return self.conv(x) 81 | 82 | class IGCV3(nn.Module): 83 | def __init__(self, width_multiplier=1.0): 84 | ''' 85 | 86 | :param width_multiplier: means scaling the number of filters in IGCV (1.0) by beita times. 87 | ''' 88 | super(IGCV3, self).__init__() 89 | ''' 90 | network_settings网络的相关配置,从该参数可以看出,Mobile-Net由9个部分组成, 91 | 姑且叫做Mobile block。 92 | network_settings中: 93 | 't'表示Inverted Residuals的扩征系数 94 | 'c'表示该block输出的通道数 95 | ‘n’表示当前block由几个残差单元组成 96 | 's'表示当前block的stride 97 | ''' 98 | # setting of inverted residual blocks 99 | self.interverted_residual_setting = [ 100 | # t, c, n, s 101 | [1, 16, 1, 1], 102 | [6, 24, 4, 2], 103 | [6, 32, 6, 2], 104 | [6, 64, 8, 2], 105 | [6, 96, 6, 1], 106 | [6, 160, 6, 2], 107 | [6, 320, 1, 1], 108 | ] 109 | 110 | input_channel = int(32 * width_multiplier) 111 | # keep number of channel is even. 112 | if input_channel % 2: 113 | input_channel += 1 114 | self.last_channel = int(1280 * width_multiplier) if width_multiplier > 1.0 else 1280 115 | #第一层, 116 | self.features = [conv_bn(inp=3, oup=input_channel, stride=2)] 117 | #中间block,一共7个, 118 | # Layers from 1 to 7 119 | # building inverted residual blocks 120 | for t, c, n, s in self.interverted_residual_setting: 121 | output_channel = int(c * width_multiplier) 122 | if output_channel % 2: 123 | output_channel += 1 124 | if int(c * width_multiplier)%2: 125 | output_channel 126 | for i in range(n): 127 | if i == 0: 128 | self.features.append(InvertedResidual(input_channel, output_channel, s, t)) 129 | else: 130 | self.features.append(InvertedResidual(input_channel, output_channel, 1, t)) 131 | input_channel = output_channel 132 | 133 | # make it nn.Sequential 134 | self.features = nn.Sequential(*self.features) 135 | 136 | # building last several layers 137 | self.conv1 = conv_1x1_bn(input_channel, self.last_channel) 138 | self.avgpool = nn.AvgPool2d(kernel_size=7) 139 | 140 | # building classifier 141 | self.classifier = nn.Sequential( 142 | nn.Dropout(), 143 | nn.Linear(self.last_channel,1000), 144 | ) 145 | 146 | def forward(self, x): 147 | x = self.features(x) 148 | # x = self.conv1(x) 149 | # x = self.avgpool(x) 150 | # x = x.view(-1, self.last_channel) 151 | # x = self.classifier(x) 152 | return x 153 | 154 | def test(): 155 | x = torch.randn(1,3,224,224) 156 | net = IGCV3(1.4) 157 | y = net(x) 158 | print(y.size()) 159 | 160 | # test() -------------------------------------------------------------------------------- /models/shufflenetv2.py: -------------------------------------------------------------------------------- 1 | '''ShuffleNetV2 in PyTorch. 2 | 3 | See the paper "ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" for more details. 4 | ''' 5 | import torch 6 | import torch.nn as nn 7 | import torch.nn.functional as F 8 | 9 | 10 | class ShuffleBlock(nn.Module): 11 | def __init__(self, groups=2): 12 | super(ShuffleBlock, self).__init__() 13 | self.groups = groups 14 | 15 | def forward(self, x): 16 | '''Channel shuffle: [N,C,H,W] -> [N,g,C/g,H,W] -> [N,C/g,g,H,w] -> [N,C,H,W]''' 17 | N, C, H, W = x.size() 18 | g = self.groups 19 | return x.view(N, g, C//g, H, W).permute(0, 2, 1, 3, 4).reshape(N, C, H, W) 20 | 21 | 22 | class SplitBlock(nn.Module): 23 | def __init__(self, ratio): 24 | super(SplitBlock, self).__init__() 25 | self.ratio = ratio 26 | 27 | def forward(self, x): 28 | c = int(x.size(1) * self.ratio) 29 | return x[:, :c, :, :], x[:, c:, :, :] 30 | 31 | 32 | class BasicBlock(nn.Module): 33 | def __init__(self, in_channels, split_ratio=0.5): 34 | super(BasicBlock, self).__init__() 35 | self.split = SplitBlock(split_ratio) 36 | in_channels = int(in_channels * split_ratio) 37 | self.conv1 = nn.Conv2d(in_channels, in_channels, 38 | kernel_size=1, bias=False) 39 | self.bn1 = nn.BatchNorm2d(in_channels) 40 | self.conv2 = nn.Conv2d(in_channels, in_channels, 41 | kernel_size=3, stride=1, padding=1, groups=in_channels, bias=False) 42 | self.bn2 = nn.BatchNorm2d(in_channels) 43 | self.conv3 = nn.Conv2d(in_channels, in_channels, 44 | kernel_size=1, bias=False) 45 | self.bn3 = nn.BatchNorm2d(in_channels) 46 | self.shuffle = ShuffleBlock() 47 | 48 | def forward(self, x): 49 | x1, x2 = self.split(x) 50 | out = F.relu(self.bn1(self.conv1(x2))) 51 | out = self.bn2(self.conv2(out)) 52 | out = F.relu(self.bn3(self.conv3(out))) 53 | out = torch.cat([x1, out], 1) 54 | out = self.shuffle(out) 55 | return out 56 | 57 | 58 | class DownBlock(nn.Module): 59 | def __init__(self, in_channels, out_channels): 60 | super(DownBlock, self).__init__() 61 | mid_channels = out_channels // 2 62 | # left 63 | self.conv1 = nn.Conv2d(in_channels, in_channels, 64 | kernel_size=3, stride=2, padding=1, groups=in_channels, bias=False) 65 | self.bn1 = nn.BatchNorm2d(in_channels) 66 | self.conv2 = nn.Conv2d(in_channels, mid_channels, 67 | kernel_size=1, bias=False) 68 | self.bn2 = nn.BatchNorm2d(mid_channels) 69 | # right 70 | self.conv3 = nn.Conv2d(in_channels, mid_channels, 71 | kernel_size=1, bias=False) 72 | self.bn3 = nn.BatchNorm2d(mid_channels) 73 | self.conv4 = nn.Conv2d(mid_channels, mid_channels, 74 | kernel_size=3, stride=2, padding=1, groups=mid_channels, bias=False) 75 | self.bn4 = nn.BatchNorm2d(mid_channels) 76 | self.conv5 = nn.Conv2d(mid_channels, mid_channels, 77 | kernel_size=1, bias=False) 78 | self.bn5 = nn.BatchNorm2d(mid_channels) 79 | 80 | self.shuffle = ShuffleBlock() 81 | 82 | def forward(self, x): 83 | # left 84 | out1 = self.bn1(self.conv1(x)) 85 | out1 = F.relu(self.bn2(self.conv2(out1))) 86 | # right 87 | out2 = F.relu(self.bn3(self.conv3(x))) 88 | out2 = self.bn4(self.conv4(out2)) 89 | out2 = F.relu(self.bn5(self.conv5(out2))) 90 | # concat 91 | out = torch.cat([out1, out2], 1) 92 | out = self.shuffle(out) 93 | return out 94 | 95 | 96 | class ShuffleNetV2(nn.Module): 97 | def __init__(self, net_size): 98 | super(ShuffleNetV2, self).__init__() 99 | out_channels = configs[net_size]['out_channels'] 100 | num_blocks = configs[net_size]['num_blocks'] 101 | 102 | self.conv1 = nn.Conv2d(3, 24, kernel_size=3, 103 | stride=1, padding=1, bias=False) 104 | self.bn1 = nn.BatchNorm2d(24) 105 | self.in_channels = 24 106 | self.layer1 = self._make_layer(out_channels[0], num_blocks[0]) 107 | self.layer2 = self._make_layer(out_channels[1], num_blocks[1]) 108 | self.layer3 = self._make_layer(out_channels[2], num_blocks[2]) 109 | self.conv2 = nn.Conv2d(out_channels[2], out_channels[3], 110 | kernel_size=1, stride=1, padding=0, bias=False) 111 | self.bn2 = nn.BatchNorm2d(out_channels[3]) 112 | self.linear = nn.Linear(out_channels[3], 10) 113 | 114 | def _make_layer(self, out_channels, num_blocks): 115 | layers = [DownBlock(self.in_channels, out_channels)] 116 | for i in range(num_blocks): 117 | layers.append(BasicBlock(out_channels)) 118 | self.in_channels = out_channels 119 | return nn.Sequential(*layers) 120 | 121 | def forward(self, x): 122 | out = F.relu(self.bn1(self.conv1(x))) 123 | # out = F.max_pool2d(out, 3, stride=2, padding=1) 124 | out = self.layer1(out) 125 | out = self.layer2(out) 126 | out = self.layer3(out) 127 | out = F.relu(self.bn2(self.conv2(out))) 128 | out = F.avg_pool2d(out, 4) 129 | out = out.view(out.size(0), -1) 130 | out = self.linear(out) 131 | return out 132 | 133 | 134 | configs = { 135 | 0.5: { 136 | 'out_channels': (48, 96, 192, 1024), 137 | 'num_blocks': (3, 7, 3) 138 | }, 139 | 140 | 1: { 141 | 'out_channels': (116, 232, 464, 1024), 142 | 'num_blocks': (3, 7, 3) 143 | }, 144 | 1.5: { 145 | 'out_channels': (176, 352, 704, 1024), 146 | 'num_blocks': (3, 7, 3) 147 | }, 148 | 2: { 149 | 'out_channels': (224, 488, 976, 2048), 150 | 'num_blocks': (3, 7, 3) 151 | } 152 | } 153 | 154 | 155 | def test(): 156 | net = ShuffleNetV2(net_size=0.5) 157 | x = torch.randn(3, 3, 32, 32) 158 | y = net(x) 159 | print(y.shape) 160 | 161 | 162 | # test() 163 | -------------------------------------------------------------------------------- /models/peleenet.py: -------------------------------------------------------------------------------- 1 | ''' PeleeNet in PyTorch. 2 | 3 | NeurIPS 2018 4 | 5 | Reference: 6 | [1] Robert J. Wang, Xiang Li & Charles X. Ling 7 | Pelee: A Real-Time Object Detection System on Mobile Devices 8 | ''' 9 | 10 | import torch 11 | import torch.nn as nn 12 | import math 13 | import torch.nn.functional as F 14 | 15 | 16 | class Conv_bn_relu(nn.Module): 17 | def __init__(self, inp, oup, kernel_size=3, stride=1, pad=1): 18 | super(Conv_bn_relu, self).__init__() 19 | self.convs = nn.Sequential( 20 | nn.Conv2d(inp, oup, kernel_size, stride, pad, bias=False), 21 | nn.BatchNorm2d(oup), 22 | nn.ReLU(inplace=True), 23 | ) 24 | 25 | def forward(self, x): 26 | out = self.convs(x) 27 | return out 28 | 29 | 30 | class StemBlock(nn.Module): 31 | def __init__(self, inp=3, num_init_features=32): 32 | super(StemBlock, self).__init__() 33 | self.stem_1 = Conv_bn_relu(inp, num_init_features, 3, 2, 1) 34 | self.stem_2a = Conv_bn_relu(num_init_features, int(num_init_features / 2), 1, 1, 0) 35 | self.stem_2b = Conv_bn_relu(int(num_init_features / 2), num_init_features, 3, 2, 1) 36 | self.stem_2p = nn.MaxPool2d(kernel_size=2, stride=2) 37 | self.stem_3 = Conv_bn_relu(num_init_features * 2, num_init_features, 1, 1, 0) 38 | 39 | def forward(self, x): 40 | stem_1_out = self.stem_1(x) 41 | stem_2a_out = self.stem_2a(stem_1_out) 42 | stem_2b_out = self.stem_2b(stem_2a_out) 43 | stem_2p_out = self.stem_2p(stem_1_out) 44 | out = self.stem_3(torch.cat((stem_2b_out, stem_2p_out), 1)) 45 | 46 | return out 47 | 48 | 49 | class DenseBlock(nn.Module): 50 | def __init__(self, inp, inter_channel, growth_rate): 51 | super(DenseBlock, self).__init__() 52 | 53 | self.cb1_a = Conv_bn_relu(inp, inter_channel, 1, 1, 0) 54 | self.cb1_b = Conv_bn_relu(inter_channel, growth_rate, 3, 1, 1) 55 | 56 | self.cb2_a = Conv_bn_relu(inp, inter_channel, 1, 1, 0) 57 | self.cb2_b = Conv_bn_relu(inter_channel, growth_rate, 3, 1, 1) 58 | self.cb2_c = Conv_bn_relu(growth_rate, growth_rate, 3, 1, 1) 59 | 60 | def forward(self, x): 61 | cb1_a_out = self.cb1_a(x) 62 | cb1_b_out = self.cb1_b(cb1_a_out) 63 | 64 | cb2_a_out = self.cb2_a(x) 65 | cb2_b_out = self.cb2_b(cb2_a_out) 66 | cb2_c_out = self.cb2_c(cb2_b_out) 67 | 68 | out = torch.cat((x, cb1_b_out, cb2_c_out), 1) 69 | 70 | return out 71 | 72 | 73 | class TransitionBlock(nn.Module): 74 | def __init__(self, inp, oup, with_pooling=True): 75 | super(TransitionBlock, self).__init__() 76 | if with_pooling: 77 | self.tb = nn.Sequential(Conv_bn_relu(inp, oup, 1, 1, 0), 78 | nn.AvgPool2d(kernel_size=2, stride=2)) 79 | else: 80 | self.tb = Conv_bn_relu(inp, oup, 1, 1, 0) 81 | 82 | def forward(self, x): 83 | out = self.tb(x) 84 | return out 85 | 86 | 87 | class PeleeNet(nn.Module): 88 | # (expansion, out_planes, num_blocks, stride) 89 | cfg = [] 90 | 91 | def __init__(self, num_classes=1000, num_init_features=224, growthRate=32, nDenseBlocks=[3, 4, 8, 6], 92 | bottleneck_width=[1, 2, 4, 4]): 93 | super(PeleeNet, self).__init__() 94 | 95 | self.stage = nn.Sequential() 96 | self.num_classes = num_classes 97 | self.num_init_features = num_init_features 98 | 99 | inter_channel = list() 100 | total_filter = list() 101 | dense_inp = list() 102 | 103 | self.half_growth_rate = int(growthRate / 2) 104 | 105 | # building stemblock 106 | self.stage.add_module('stage_0', StemBlock(3, num_init_features)) 107 | 108 | # 109 | for i, b_w in enumerate(bottleneck_width): 110 | 111 | inter_channel.append(int(self.half_growth_rate * b_w / 4) * 4) 112 | 113 | if i == 0: 114 | total_filter.append(num_init_features + growthRate * nDenseBlocks[i]) 115 | dense_inp.append(self.num_init_features) 116 | else: 117 | total_filter.append(total_filter[i - 1] + growthRate * nDenseBlocks[i]) 118 | dense_inp.append(total_filter[i - 1]) 119 | 120 | if i == len(nDenseBlocks) - 1: 121 | with_pooling = False 122 | else: 123 | with_pooling = True 124 | 125 | # building middle stageblock 126 | self.stage.add_module('stage_{}'.format(i + 1), self._make_dense_transition(dense_inp[i], 127 | total_filter[i], 128 | inter_channel[i], 129 | nDenseBlocks[i], 130 | with_pooling=with_pooling)) 131 | 132 | # building classifier 133 | # self.classifier = nn.Sequential( 134 | # nn.Dropout(), 135 | # nn.Linear(total_filter[len(nDenseBlocks) - 1], self.num_classes) 136 | # ) 137 | self.linear = nn.Linear(total_filter[len(nDenseBlocks) - 1], self.num_classes) 138 | 139 | def _make_dense_transition(self, dense_inp, total_filter, inter_channel, ndenseblocks, with_pooling=True): 140 | layers = [] 141 | 142 | for i in range(ndenseblocks): 143 | layers.append(DenseBlock(dense_inp, inter_channel, self.half_growth_rate)) 144 | dense_inp += self.half_growth_rate * 2 145 | 146 | # Transition Layer without Compression 147 | layers.append(TransitionBlock(dense_inp, total_filter, with_pooling)) 148 | 149 | return nn.Sequential(*layers) 150 | 151 | def forward(self, x): 152 | x = self.stage(x) 153 | # global average pooling layer 154 | x = F.avg_pool2d(x, kernel_size=7) 155 | x = x.view(x.size(0), -1) 156 | x = self.linear(x) 157 | out = F.log_softmax(x, dim=1) 158 | 159 | return out 160 | 161 | def test(): 162 | net = PeleeNet() 163 | x = torch.randn(1,3,224,224) 164 | y = net(x) 165 | print(y.size()) 166 | 167 | # test() -------------------------------------------------------------------------------- /models/resnext.py: -------------------------------------------------------------------------------- 1 | """ 2 | ResNeXt in PyTorch. 3 | 4 | CVPR 2017 5 | 6 | Reference: 7 | [1] Aggregated Residual Transformations for Deep Neural Networks 8 | Saining Xie, Ross Girshick, Piotr Dollár, Zhuowen Tu, Kaiming He 9 | """ 10 | import torch 11 | import torch.nn as nn 12 | import torch.nn.functional as F 13 | 14 | import math 15 | 16 | class Bottleneck(nn.Module): 17 | """ 18 | RexNeXt bottleneck type C 19 | """ 20 | expansion = 4 21 | 22 | def __init__(self, inplanes, planes, baseWidth, cardinality, stride=1, downsample=None): 23 | """ Constructor 24 | Args: 25 | inplanes: input channel dimensionality 26 | planes: output channel dimensionality 27 | baseWidth: base width. 28 | cardinality: num of convolution groups. 29 | stride: conv stride. Replaces pooling layer. 30 | """ 31 | super(Bottleneck, self).__init__() 32 | 33 | D = int(math.floor(planes * (baseWidth / 64))) 34 | C = cardinality 35 | 36 | self.conv1 = nn.Conv2d(inplanes, D*C, kernel_size=1, stride=1, padding=0, bias=False) 37 | self.bn1 = nn.BatchNorm2d(D*C) 38 | self.conv2 = nn.Conv2d(D*C, D*C, kernel_size=3, stride=stride, padding=1, groups=C, bias=False) 39 | self.bn2 = nn.BatchNorm2d(D*C) 40 | self.conv3 = nn.Conv2d(D*C, planes * 4, kernel_size=1, stride=1, padding=0, bias=False) 41 | self.bn3 = nn.BatchNorm2d(planes * 4) 42 | self.relu = nn.ReLU(inplace=True) 43 | 44 | self.downsample = downsample 45 | 46 | def forward(self, x): 47 | residual = x 48 | 49 | out = self.conv1(x) 50 | out = self.bn1(out) 51 | out = self.relu(out) 52 | 53 | out = self.conv2(out) 54 | out = self.bn2(out) 55 | out = self.relu(out) 56 | 57 | out = self.conv3(out) 58 | out = self.bn3(out) 59 | 60 | if self.downsample is not None: 61 | residual = self.downsample(x) 62 | 63 | out += residual 64 | out = self.relu(out) 65 | 66 | return out 67 | 68 | 69 | class ResNeXt(nn.Module): 70 | """ 71 | ResNext optimized for the ImageNet dataset, as specified in 72 | https://arxiv.org/pdf/1611.05431.pdf 73 | """ 74 | def __init__(self, baseWidth, cardinality, layers, num_classes): 75 | """ Constructor 76 | Args: 77 | baseWidth: baseWidth for ResNeXt. 78 | cardinality: number of convolution groups. 79 | layers: config of layers, e.g., [3, 4, 6, 3] 80 | num_classes: number of classes 81 | """ 82 | super(ResNeXt, self).__init__() 83 | block = Bottleneck 84 | 85 | self.cardinality = cardinality 86 | self.baseWidth = baseWidth 87 | self.num_classes = num_classes 88 | self.inplanes = 64 89 | self.output_size = 64 90 | 91 | self.conv1 = nn.Conv2d(3, 64, 7, 2, 3, bias=False) 92 | self.bn1 = nn.BatchNorm2d(64) 93 | self.relu = nn.ReLU(inplace=True) 94 | self.maxpool1 = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) 95 | self.layer1 = self._make_layer(block, 64, layers[0]) 96 | self.layer2 = self._make_layer(block, 128, layers[1], 2) 97 | self.layer3 = self._make_layer(block, 256, layers[2], 2) 98 | self.layer4 = self._make_layer(block, 512, layers[3], 2) 99 | self.avgpool = nn.AvgPool2d(7) 100 | self.fc = nn.Linear(512 * block.expansion, num_classes) 101 | 102 | for m in self.modules(): 103 | if isinstance(m, nn.Conv2d): 104 | n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels 105 | m.weight.data.normal_(0, math.sqrt(2. / n)) 106 | elif isinstance(m, nn.BatchNorm2d): 107 | m.weight.data.fill_(1) 108 | m.bias.data.zero_() 109 | 110 | def _make_layer(self, block, planes, blocks, stride=1): 111 | """ Stack n bottleneck modules where n is inferred from the depth of the network. 112 | Args: 113 | block: block type used to construct ResNext 114 | planes: number of output channels (need to multiply by block.expansion) 115 | blocks: number of blocks to be built 116 | stride: factor to reduce the spatial dimensionality in the first bottleneck of the block. 117 | Returns: a Module consisting of n sequential bottlenecks. 118 | """ 119 | downsample = None 120 | if stride != 1 or self.inplanes != planes * block.expansion: 121 | downsample = nn.Sequential( 122 | nn.Conv2d(self.inplanes, planes * block.expansion, 123 | kernel_size=1, stride=stride, bias=False), 124 | nn.BatchNorm2d(planes * block.expansion), 125 | ) 126 | 127 | layers = [] 128 | layers.append(block(self.inplanes, planes, self.baseWidth, self.cardinality, stride, downsample)) 129 | self.inplanes = planes * block.expansion 130 | for i in range(1, blocks): 131 | layers.append(block(self.inplanes, planes, self.baseWidth, self.cardinality)) 132 | 133 | return nn.Sequential(*layers) 134 | 135 | def forward(self, x): 136 | x = self.conv1(x) 137 | x = self.bn1(x) 138 | x = self.relu(x) 139 | x = self.maxpool1(x) 140 | x = self.layer1(x) 141 | x = self.layer2(x) 142 | x = self.layer3(x) 143 | x = self.layer4(x) 144 | x = self.avgpool(x) 145 | x = x.view(x.size(0), -1) 146 | x = self.fc(x) 147 | 148 | return x 149 | 150 | 151 | def ResNeXt50(cardinality, baseWidth): 152 | """ 153 | Construct ResNeXt-50. 154 | """ 155 | model = ResNeXt(baseWidth, cardinality, [3, 4, 6, 3], 1000) 156 | return model 157 | 158 | 159 | def ResNeXt101(cardinality, baseWidth): 160 | """ 161 | Construct ResNeXt-101. 162 | """ 163 | model = ResNeXt(baseWidth, cardinality, [3, 4, 23, 3], 1000) 164 | return model 165 | 166 | 167 | def ResNeXt152(cardinality, baseWidth): 168 | """ 169 | Construct ResNeXt-152. 170 | """ 171 | model = ResNeXt(baseWidth, cardinality, [3, 8, 36, 3], 1000) 172 | return model 173 | 174 | def test(): 175 | x = torch.randn(1,3,224,224) 176 | net = resnext152(32, 4) 177 | y = net(x) 178 | print(y.size()) 179 | 180 | # test() -------------------------------------------------------------------------------- /models/squeezenet.py: -------------------------------------------------------------------------------- 1 | ''' SqueezeNet in PyTorch. 2 | 3 | ICLR 2017 4 | 5 | Reference: 6 | [1] Forrest N. Iandola, Song Han, Matthew W. Moskewicz, Khalid Ashraf, William J. Dally, Kurt Keutzer 7 | SqueezeNet: AlexNet-level accuracy with 50x fewer parameters and <0.5MB model size 8 | ''' 9 | import torch 10 | import torch.nn as nn 11 | import torch.nn.functional as F 12 | 13 | class Conv_bn_relu(nn.Module): 14 | def __init__(self, inp, oup, kernel=1, stride=1, pad=0, bias=False): 15 | super(Conv_bn_relu, self).__init__() 16 | self.conv = nn.Conv2d(inp, oup, kernel_size=kernel, stride=stride, padding=pad, bias=bias) 17 | self.bn = nn.BatchNorm2d(oup) 18 | self.relu = nn.ReLU(inplace=True) 19 | def forward(self, x): 20 | x = self.conv(x) 21 | x = self.bn(x) 22 | x = self.relu(x) 23 | return x 24 | 25 | class Fire(nn.Module): 26 | def __init__(self, inp, mip, oup): 27 | super(Fire, self).__init__() 28 | self.layer1 = Conv_bn_relu(inp, mip, kernel=1, stride=1) 29 | self.layer2 = Conv_bn_relu(mip, oup, kernel=1, stride=1) 30 | self.layer3 = Conv_bn_relu(mip, oup, kernel=3, stride=1, pad=1) 31 | 32 | def forward(self, x): 33 | x = self.layer1(x) 34 | out1 = self.layer2(x) 35 | out2 = self.layer3(x) 36 | out = torch.cat([out1, out2], 1) 37 | out = F.relu(out, inplace=True) 38 | return out 39 | 40 | class SqueezeNet(nn.Module): 41 | def __init__(self): 42 | super(SqueezeNet, self).__init__() 43 | self.conv1 = Conv_bn_relu(3, 96, kernel=7, stride=2, pad=2) 44 | self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2) 45 | self.fire2 = Fire(96, 16, 64) 46 | self.fire3 = Fire(128, 16, 64) 47 | self.fire4 = Fire(128, 32, 128) 48 | self.fire5 = Fire(256, 32, 128) 49 | self.fire6 = Fire(256, 48, 192) 50 | self.fire7 = Fire(384, 48, 192) 51 | self.fire8 = Fire(384, 64, 256) 52 | self.fire9 = Fire(512, 64, 256) 53 | self.conv2 = Conv_bn_relu(512, 1000, kernel=1, stride=1) 54 | self.avg_pool = nn.AvgPool2d(kernel_size=13) 55 | 56 | def forward(self, x): 57 | out = self.conv1(x) 58 | out = self.maxpool(out) 59 | out = self.fire2(out) 60 | out = self.fire3(out) 61 | out = self.fire4(out) 62 | out = self.maxpool(out) 63 | out = self.fire5(out) 64 | out = self.fire6(out) 65 | out = self.fire7(out) 66 | out = self.fire8(out) 67 | out = self.maxpool(out) 68 | out = self.fire9(out) 69 | out = self.conv2(out) 70 | out = self.avg_pool(out) 71 | out = out.view(out.size()[0], -1) 72 | return out 73 | 74 | class SqueezeNet_Simple(nn.Module): 75 | ''' 76 | Base on SqueezeNet, adding bypass connections around Fire modules 3,5,7 and 9 77 | output of Fire2 + output of Fire3, where the + operator is elementwise addition. 78 | ''' 79 | def __init__(self): 80 | super(SqueezeNet_Simple, self).__init__() 81 | self.conv1 = Conv_bn_relu(3, 96, kernel=7, stride=2, pad=2) 82 | self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2) 83 | self.fire2 = Fire(96, 16, 64) 84 | self.fire3 = Fire(128, 16, 64) 85 | self.fire4 = Fire(128, 32, 128) 86 | self.fire5 = Fire(256, 32, 128) 87 | self.fire6 = Fire(256, 48, 192) 88 | self.fire7 = Fire(384, 48, 192) 89 | self.fire8 = Fire(384, 64, 256) 90 | self.fire9 = Fire(512, 64, 256) 91 | self.conv2 = Conv_bn_relu(512, 1000, kernel=1, stride=1) 92 | self.avg_pool = nn.AvgPool2d(kernel_size=13) 93 | self.relu = nn.ReLU(inplace=True) 94 | 95 | def forward(self, x): 96 | out = self.conv1(x) 97 | out = self.maxpool(out) 98 | out = self.fire2(out) 99 | out_fire3_beg = out 100 | out = self.fire3(out) 101 | out_fire3_end = out 102 | out = self.relu(out_fire3_end + out_fire3_beg) 103 | out = self.fire4(out) 104 | out = self.maxpool(out) 105 | out_fire5_beg = out 106 | out = self.fire5(out) 107 | out_fire5_end = out 108 | out = self.relu(out_fire5_beg + out_fire5_end) 109 | out = self.fire6(out) 110 | out_fire7_beg = out 111 | out = self.fire7(out) 112 | out_fire7_end = out 113 | out = self.relu(out_fire7_beg + out_fire7_end) 114 | out = self.fire8(out) 115 | out = self.maxpool(out) 116 | out_fire9_beg = out 117 | out = self.fire9(out) 118 | out_fire9_end = out 119 | out = self.relu(out_fire9_beg + out_fire9_end) 120 | out = self.conv2(out) 121 | out = self.avg_pool(out) 122 | out = out.view(out.size()[0], -1) 123 | return out 124 | 125 | class SqueezeNet_Complex(nn.Module): 126 | def __init__(self): 127 | super(SqueezeNet_Complex, self).__init__() 128 | self.conv1 = Conv_bn_relu(3, 96, kernel=7, stride=2, pad=2) 129 | self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2) 130 | self.fire2 = Fire(96, 16, 64) 131 | self.conv_fire2 = Conv_bn_relu(96, 128, kernel=1, stride=1) 132 | self.fire3 = Fire(128, 16, 64) 133 | self.fire4 = Fire(128, 32, 128) 134 | self.conv_fire4 = Conv_bn_relu(128, 256, kernel=1, stride=1) 135 | self.fire5 = Fire(256, 32, 128) 136 | self.fire6 = Fire(256, 48, 192) 137 | self.conv_fire6 = Conv_bn_relu(256, 384, kernel=1, stride=1) 138 | self.fire7 = Fire(384, 48, 192) 139 | self.fire8 = Fire(384, 64, 256) 140 | self.conv_fire8 = Conv_bn_relu(384, 512, kernel=1, stride=1) 141 | self.fire9 = Fire(512, 64, 256) 142 | self.conv2 = Conv_bn_relu(512, 1000, kernel=1, stride=1) 143 | self.avg_pool = nn.AvgPool2d(kernel_size=13) 144 | self.relu = nn.ReLU(inplace=True) 145 | def forward(self, x): 146 | out = self.conv1(x) 147 | out = self.maxpool(out) 148 | out_2 = self.conv_fire2(out) 149 | out = self.fire2(out) 150 | out = self.relu(out + out_2) 151 | out_fire3_beg = out 152 | out = self.fire3(out) 153 | out_fire3_end = out 154 | out = self.relu(out_fire3_end + out_fire3_beg) 155 | out_4 = self.conv_fire4(out) 156 | out = self.fire4(out) 157 | out = self.relu(out + out_4) 158 | out = self.maxpool(out) 159 | out_fire5_beg = out 160 | out = self.fire5(out) 161 | out_fire5_end = out 162 | out = self.relu(out_fire5_beg + out_fire5_end) 163 | out_6 = self.conv_fire6(out) 164 | out = self.fire6(out) 165 | out = self.relu(out + out_6) 166 | out_fire7_beg = out 167 | out = self.fire7(out) 168 | out_fire7_end = out 169 | out = self.relu(out_fire7_beg + out_fire7_end) 170 | out_8 = self.conv_fire8(out) 171 | out = self.fire8(out) 172 | out = self.relu(out + out_8) 173 | out = self.maxpool(out) 174 | out_fire9_beg = out 175 | out = self.fire9(out) 176 | out_fire9_end = out 177 | out = self.relu(out_fire9_beg + out_fire9_end) 178 | out = self.conv2(out) 179 | out = self.avg_pool(out) 180 | out = out.view(out.size()[0], -1) 181 | return out 182 | 183 | def test(): 184 | # net = SqueezeNet() 185 | # net = SqueezeNet_Simple() 186 | net = SqueezeNet_Complex() 187 | x = torch.randn(1,3,224,224) 188 | y = net(x) 189 | print(y.size()) 190 | 191 | # test() 192 | -------------------------------------------------------------------------------- /models/googlenet_v1.py: -------------------------------------------------------------------------------- 1 | '''GoogleNet Inception-V1 in PyTorch. 2 | 2014 3 | 4 | Reference: 5 | [1] Christian Szegedy, Wei Liu, Yangqing Jia, Pierre Sermanet, Scott Reed, Dragomir Anguelov, Dumitru Erhan, Vincent Vanhoucke, Andrew Rabinovich 6 | Going Deeper with Convolutions 7 | ''' 8 | import torch 9 | import torch.nn as nn 10 | import torch.nn.functional as F 11 | 12 | class Inception_Bn(nn.Module): 13 | def __init__(self, in_planes, n1x1, n3x3red, n3x3, n5x5red, n5x5, pool_planes): 14 | super(Inception_Bn, self).__init__() 15 | # 1x1 conv branch 16 | self.b1 = nn.Sequential( 17 | nn.Conv2d(in_planes, n1x1, kernel_size=1), 18 | nn.BatchNorm2d(n1x1), 19 | nn.ReLU(True), 20 | ) 21 | 22 | # 1x1 conv -> 3x3 conv branch 23 | self.b2 = nn.Sequential( 24 | nn.Conv2d(in_planes, n3x3red, kernel_size=1), 25 | nn.BatchNorm2d(n3x3red), 26 | nn.ReLU(True), 27 | nn.Conv2d(n3x3red, n3x3, kernel_size=3, padding=1), 28 | nn.BatchNorm2d(n3x3), 29 | nn.ReLU(True), 30 | ) 31 | 32 | # 1x1 conv -> 5x5 conv branch 33 | self.b3 = nn.Sequential( 34 | nn.Conv2d(in_planes, n5x5red, kernel_size=1), 35 | nn.BatchNorm2d(n5x5red), 36 | nn.ReLU(True), 37 | nn.Conv2d(n5x5red, n5x5, kernel_size=5, padding=2), 38 | nn.BatchNorm2d(n5x5), 39 | nn.ReLU(True), 40 | ) 41 | 42 | # 3x3 pool -> 1x1 conv branch 43 | self.b4 = nn.Sequential( 44 | nn.MaxPool2d(3, stride=1, padding=1), 45 | nn.Conv2d(in_planes, pool_planes, kernel_size=1), 46 | nn.BatchNorm2d(pool_planes), 47 | nn.ReLU(True), 48 | ) 49 | 50 | def forward(self, x): 51 | y1 = self.b1(x) 52 | y2 = self.b2(x) 53 | y3 = self.b3(x) 54 | y4 = self.b4(x) 55 | y = torch.cat([y1, y2, y3, y4], 1) 56 | return y 57 | 58 | class Inception(nn.Module): 59 | def __init__(self, in_planes, n1x1, n3x3red, n3x3, n5x5red, n5x5, pool_planes): 60 | super(Inception, self).__init__() 61 | # 1x1 conv branch 62 | self.b1 = nn.Sequential( 63 | nn.Conv2d(in_planes, n1x1, kernel_size=1), 64 | nn.ReLU(True), 65 | ) 66 | 67 | # 1x1 conv -> 3x3 conv branch 68 | self.b2 = nn.Sequential( 69 | nn.Conv2d(in_planes, n3x3red, kernel_size=1), 70 | nn.ReLU(True), 71 | nn.Conv2d(n3x3red, n3x3, kernel_size=3, padding=1), 72 | nn.ReLU(True), 73 | ) 74 | 75 | # 1x1 conv -> 5x5 conv branch 76 | self.b3 = nn.Sequential( 77 | nn.Conv2d(in_planes, n5x5red, kernel_size=1), 78 | nn.ReLU(True), 79 | nn.Conv2d(n5x5red, n5x5, kernel_size=5, padding=2), 80 | nn.ReLU(True), 81 | ) 82 | 83 | # 3x3 pool -> 1x1 conv branch 84 | self.b4 = nn.Sequential( 85 | nn.MaxPool2d(3, stride=1, padding=1), 86 | nn.Conv2d(in_planes, pool_planes, kernel_size=1), 87 | nn.ReLU(True), 88 | ) 89 | 90 | def forward(self, x): 91 | y1 = self.b1(x) 92 | y2 = self.b2(x) 93 | y3 = self.b3(x) 94 | y4 = self.b4(x) 95 | y = torch.cat([y1, y2, y3, y4], 1) 96 | return y 97 | 98 | class GoogleNetV1_Bn(nn.Module): 99 | def __init__(self, num_classes=1000): 100 | super(GoogleNetV1_Bn, self).__init__() 101 | self.pre_layers_1 = nn.Sequential( 102 | nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3), 103 | nn.BatchNorm2d(64), 104 | nn.ReLU(inplace=True) 105 | ) 106 | 107 | self.pre_layers_2 = nn.Sequential( 108 | nn.Conv2d(64, 64, kernel_size=1), 109 | nn.BatchNorm2d(64), 110 | nn.ReLU(inplace=True), 111 | nn.Conv2d(64, 192, kernel_size=3, padding=1), 112 | nn.BatchNorm2d(192), 113 | nn.ReLU(inplace=True) 114 | ) 115 | 116 | self.a3 = Inception_Bn(192, 64, 96, 128, 16, 32, 32) 117 | self.b3 = Inception_Bn(256, 128, 128, 192, 32, 96, 64) 118 | 119 | self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) 120 | 121 | self.a4 = Inception_Bn(480, 192, 96, 208, 16, 48, 64) 122 | self.b4 = Inception_Bn(512, 160, 112, 224, 24, 64, 64) 123 | self.c4 = Inception_Bn(512, 128, 128, 256, 24, 64, 64) 124 | self.d4 = Inception_Bn(512, 112, 144, 288, 32, 64, 64) 125 | self.e4 = Inception_Bn(528, 256, 160, 320, 32, 128, 128) 126 | 127 | self.a5 = Inception_Bn(832, 256, 160, 320, 32, 128, 128) 128 | self.b5 = Inception_Bn(832, 384, 192, 384, 48, 128, 128) 129 | 130 | self.avgpool = nn.AvgPool2d(7, stride=1) 131 | self.linear = nn.Linear(1024, num_classes) 132 | 133 | def forward(self, x): 134 | x = self.pre_layers_1(x) 135 | x = self.maxpool(x) 136 | x = self.pre_layers_2(x) 137 | x = self.maxpool(x) 138 | x = self.a3(x) 139 | x = self.b3(x) 140 | x = self.maxpool(x) 141 | x = self.a4(x) 142 | x = self.b4(x) 143 | x = self.c4(x) 144 | x = self.d4(x) 145 | x = self.e4(x) 146 | x = self.maxpool(x) 147 | x = self.a5(x) 148 | x = self.b5(x) 149 | x = self.avgpool(x) 150 | x = x.view(x.size(0), -1) 151 | x = self.linear(x) 152 | return x 153 | 154 | class GoogleNetV1(nn.Module): 155 | def __init__(self, num_classes=1000): 156 | super(GoogleNetV1, self).__init__() 157 | self.pre_layers_1 = nn.Sequential( 158 | nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3), 159 | nn.ReLU(inplace=True) 160 | ) 161 | self.lrn = nn.LocalResponseNorm(size=5, alpha=9.99999974738e-05, 162 | beta=0.75, k=1.0) 163 | 164 | self.pre_layers_2 = nn.Sequential( 165 | nn.Conv2d(64, 64, kernel_size=1), 166 | nn.ReLU(inplace=True), 167 | nn.Conv2d(64, 192, kernel_size=3, padding=1), 168 | nn.ReLU(inplace=True) 169 | ) 170 | 171 | self.a3 = Inception(192, 64, 96, 128, 16, 32, 32) 172 | self.b3 = Inception(256, 128, 128, 192, 32, 96, 64) 173 | 174 | self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) 175 | 176 | self.a4 = Inception(480, 192, 96, 208, 16, 48, 64) 177 | self.b4 = Inception(512, 160, 112, 224, 24, 64, 64) 178 | self.c4 = Inception(512, 128, 128, 256, 24, 64, 64) 179 | self.d4 = Inception(512, 112, 144, 288, 32, 64, 64) 180 | self.e4 = Inception(528, 256, 160, 320, 32, 128, 128) 181 | 182 | self.a5 = Inception(832, 256, 160, 320, 32, 128, 128) 183 | self.b5 = Inception(832, 384, 192, 384, 48, 128, 128) 184 | 185 | self.avgpool = nn.AvgPool2d(7, stride=1) 186 | self.linear = nn.Linear(1024, num_classes) 187 | 188 | def forward(self, x): 189 | x = self.pre_layers_1(x) 190 | x = self.maxpool(x) 191 | # x = self.lrn(x) 192 | x = self.pre_layers_2(x) 193 | x = self.maxpool(x) 194 | # x = self.lrn(x) 195 | x = self.a3(x) 196 | x = self.b3(x) 197 | x = self.maxpool(x) 198 | x = self.a4(x) 199 | x = self.b4(x) 200 | x = self.c4(x) 201 | x = self.d4(x) 202 | x = self.e4(x) 203 | x = self.maxpool(x) 204 | x = self.a5(x) 205 | x = self.b5(x) 206 | x = self.avgpool(x) 207 | x = x.view(x.size(0), -1) 208 | x = self.linear(x) 209 | return x 210 | 211 | def test(): 212 | x = torch.randn([1,3,224,224]) 213 | net = GoogleNetV1() 214 | y = net(x) 215 | print(y.size()) 216 | 217 | # test() -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pytorch_model_integration 2 | The project is based on pytorch and integrates the current mainstream 3 | network architecture, including VGGnet, ResNet, DenseNet, 4 | MobileNet and DarkNet (YOLOv2 and YOLOv3). 5 | 6 | This project will fully comply with the relevant details mentioned in the paper. Since the structural details in some papers are incomplete, we have added some personal insights. The input size of all networks is uniformly set to (224, 224, 3) (H, W, C). 7 | 8 | ## Networks Result 9 | | Model | Params/Million | FLOPs/G | Time_cast/ms | Top-1 | Top-5 | 10 | | ----------- | -------------- | -------- | ------------ | ----- | ----- | 11 | | --- **2015** --- | 12 | | Vgg11 | 9.738984 | 15.02879 | 205.59 | 70.4 | 89.6 | 13 | | Vgg13 | 9.92388 | 22.45644 | 324.13 | 71.3 | 90.1 | 14 | | Vgg16 | 15.236136 | 30.78787 | 397.33 | 74.4 | 91.9 | 15 | | Vgg19 | 20.548392 | 39.11929 | 451.11 | 74.5 | 92.0 | 16 | | --- **2016** --- | 17 | | ResNet18 | 11.693736 | 3.65921 | 86.56 | | | 18 | | ResNet34 | 21.801896 | 7.36109 | 123.07 | 75.81 | 92.6 | 19 | | ResNet50 | 25.557032 | 8.27887 | 293.62 | 77.15 | 93.29 | 20 | | ResNet101 | 44.54916 | 15.71355 | 413.51 | 78.25 | 93.95 | 21 | | ResNet152 | 60.192808 | 23.15064 | 573.09 | 78.57 | 94.29 | 22 | | PreActResNet18 | 11.690792 | 3.65840 | 86.12 | | | 23 | | PreActResNet34 | 21.798952 | 7.36029 | 142.51 | | | 24 | | PreActResNet50 | 25.545256 | 8.27566 | 296.39 | | | 25 | | PreActResNet101 | 44.537384 | 15.71034 | 418.37 | | | 26 | | PreActResNet152 | 60.181032 | 23.14743 | 578.81 | 78.90 | 94.50 | 27 | | DarkNet19(YOLOv2) | 8.01556 | 10.90831 | 139.21 | | | 28 | | --- **2017** --- | 29 | | DenseNet121(k=32) | 7.978734 | 5.69836 | 286.45 | | | 30 | | DenseNet169(k=32) | 14.149358 | 6.75643 | 375.47 | | | 31 | | DenseNet201(k=32) | 20.013806 | 8.63084 | 486.14 | | | 32 | | DenseNet264(k=32) | 33.337582 | 11.57003 | 689.63 | | | 33 | | DenseNet161(k=48) | 28.680814 | 15.50790 | 708.36 ||| 34 | | DPN92 | 36.779704 | 12.77985 | 366.11 | 79.30 | 94.60 | 35 | | DPN98 | 60.21588 | 22.92897 | 573.04 | 79.80 | 94.80 | 36 | |ResNeXt50_2x40d|25.425|8.29756|364.24|77.00|| 37 | |ResNeXt50_4x24d|25.292968|8.37150|416.01|77.40|| 38 | |ResNeXt50_8x14d|25.603016|8.58994|444.33|77.70|| 39 | |ResNeXt50_32x4d|25.028904 | 8.51937|460.20|77.80|| 40 | |ResNeXt101_2x40d|44.456296|15.75783|640.83|78.3|| 41 | |ResNeXt101_4x24d| 44.363432| 15.84712|627.48|78.6|| 42 | |ResNeXt101_8x14d|45.104328|16.23445|870.31|78.7|| 43 | |ResNeXt101_32x4d|44.177704|16.02570|952.88|78.8|| 44 | | MobileNet | 4.231976 | 1.14757 | 100.45 | 70.60 | | 45 | | SqueezeNet | 1.2524 | 1.69362 | 90.97 | 57.50 | 80.30 | 46 | | SqueezeNet + Simple Bypass | 1.2524 | 1.69550 | 96.82|60.40| 82.50 | 47 | | SqueezeNet + Complex Bypass | 1.594928 | 2.40896 |130.98 |58.80| 82.00 | 48 | | --- **2018** --- | 49 | | PeleeNet | 4.51988 | 4.96656 | 237.18 | 72.6 | 90.6 | 50 | | 1.0-SqNxt-23 |0.690824 | 0.48130 | 69.93 | 59.05 | 82.60 | 51 | | 1.0-SqNxt-23v5|0.909704 | 0.47743 | 58.40 | 59.24 | 82.41 | 52 | | 2.0-SqNxt-23 |2.2474 | 1.12928 | 111.89 | 67.18 | 88.17 | 53 | | 2.0-SqNxt-23v5|3.11524 | 1.12155 | 93.54 | 67.44 | 88.20 | 54 | | MobileNetV2 | 3.56468 | 0.66214 | 138.15 | 74.07 | | 55 | | DarkNet53(YOLOv3)| 41.609928 | 14.25625 | 275.50 | | | 56 | | DLA-34 | 15.784869 | 2.27950 | 70.17 | | | 57 | | DLA-46-C | 1.310885 | 0.40895 | 40.29 | 64.9 | 86.7 | 58 | | DLA-60 | 22.335141 | 2.93399 | 110.80 | | | 59 | | DLA-102 | 33.732773 | 4.42848 | 154.27 | | | 60 | | DLA-169 | 53.990053 | 6.65083 | 230.39 | | | 61 | | DLA-X-46-C | 1.077925 | 0.37765 | 44.74 | 66.0 | 87.0 | 62 | | DLA-X-60-C | 1.337765 | 0.40313 | 50.84 | 68.0 | 88.4 | 63 | | DLA-X-60 | 17.650853 | 2.39033 | 131.93 | | | 64 | | DLA-X-102 | 26.773157 | 3.58778 | 164.93 | | | 65 | | IGCV3-D (0.7) |2.490294 |0.31910|165.14 |68.45| | 66 | | IGCV3-D (1.0) |3.491688 |0.60653|263.80 |72.20| | 67 | | IGCV3-D (1.4) |6.015164 |1.11491|318.40 |74.70| | 68 | | --- **2019** --- | 69 | | EfficientNet-B0 |5.288548 |0.01604 |186.61 |76.30|93.20| 70 | | EfficientNet-B1 |7.794184 |0.02124 |266.05 |78.80|94.40| 71 | | EfficientNet-B2 |9.109994 |0.02240 |277.94 |79.80|94.90| 72 | | EfficientNet-B3 |12.233232 |0.02905 | 376.24 |81.10|95.50| 73 | | EfficientNet-B4 |19.341616 |0.03762 |513.91 |82.60|96.30| 74 | | EfficientNet-B5 |30.389784 |0.05086 |721.95 |83.30|96.70| 75 | | EfficientNet-B6 |43.040704 |0.06443 |1062.64 |84.00|96.90| 76 | | EfficientNet-B7 |66.34796 |0.08516 |1520.88 |84.40|97.10| 77 | 78 | ### GoogleNet Inception V1-V4 79 | 80 | | Model | Params/Million | FLOPs/G | Time_cast/ms | Top-1 | Top-5 | 81 | | ----------- | -------------- | -------- | ------------ | ----- | ----- | 82 | | --- **2014** --- | 83 | | GoogleNet V1 |6.998552 |3.20387 |85.95||| 84 | | GoogleNet V1 (LRN)|6.998552 |3.20387 |192.64|71.00|90.80| 85 | | GoogleNet V1 (Bn)|7.013112|3.21032 |139.42|73.20|| 86 | | --- **2015** --- | 87 | | GoogleNet V2|11.204936|4.08437 |127.71|76.60|| 88 | | GoogleNet V3|23.834568|7.60887 |208.01|78.80|94.40| 89 | | --- **2016** --- | 90 | | GoogleNet V4|42.679816|12.31977 |324.36|80.00|95.10| 91 | 92 | Note: GoogleNet V1 does not include the Bn layer, but after the first two layers of convolution, LocalResponseNorm is added, 93 | this operation will increase the calculation time of the model. So we found that GoogleNet V1 is slower than GoogleNet V1_Bn. 94 | 95 | For Time_cast, we set the input size: (4, 3, 224, 224), and then test multiple rounds of averaging 96 | (time is susceptible to interference from CPU operating state). 97 | 98 | ## ImageNet数据准备 99 | ### Download 100 | http://www.image-net.org/challenges/LSVRC/2012/downloads 101 | 102 | 我们需要的是训练集与验证集(等同测试集),一般论文当中只展示验证集上的结果(Top-1 & Top-5)。 103 | 104 | Development kit (Task 1 & 2). 2.5MB. (这个并没有用到) 105 | 106 | Training images (Task 1 & 2). 138GB. MD5: 1d675b47d978889d74fa0da5fadfb00e 107 | 108 | Validation images (all tasks). 6.3GB. MD5: 29b22e2961454d5413ddabcf34fc5622 109 | 110 | ### 安装 111 | 方法一:https://github.com/pytorch/examples/blob/main/imagenet/extract_ILSVRC.sh 112 | 113 | 方法二: 114 | 115 | 解压下载的数据文件,这可能需要一段时间 116 | 117 | tar xvf ILSVRC2012_img_train.tar -C ./train 118 | 119 | tar xvf ILSVRC2012_img_val.tar -C ./val 120 | 121 | 对于train数据,解压后是1000个tar文件,需要再次解压,解压脚本dataset/unzip.sh如下 122 | 123 | dir=/data/srd/data/Image/ImageNet/train 124 | 125 | for x in `ls $dir/*tar` 126 | do 127 | filename=`basename $x .tar` 128 | mkdir $dir/$filename 129 | tar -xvf $x -C $dir/$filename 130 | done 131 | 132 | rm *.tar 133 | 134 | 注:将其中的'dir'修改为自己的文件目录 135 | 136 | 然后运行 137 | 138 | sh unzip.sh 139 | 140 | 对于val数据,解压之后是50000张图片,我们需要将每一个类的图片整理到一起,与train一致。将项目dataset/valprep.sh脚本放到val文件夹下运行 141 | 142 | sh valprep.sh 143 | 144 | 下载好的训练集下的每个文件夹是一类图片,文件夹名对应的标签在下载好的Development kit的标签文件meta.mat中,这是一个matlab文件,scipy.io.loadmat可以读取文件内容,验证集下是50000张图片,每张图片对应的标签在ILSVRC2012_validation_ground_truth.txt中。 145 | 146 | 数据增强:取图片时随机取,然后将图片放缩为短边为256,然后再随机裁剪224x224的图片, 147 | 再把每个通道减去相应通道的平均值,随机左右翻转。 148 | 149 | ## CROP-1, CROP-5 and CROP-10 test methods for ImageNet validation set. 150 | 151 | Due to the existence of a fully connected layers, we neeed to limit the size of the images in the input network. Set the size of the image input neural network to 224x224, but the size of the image in the test set is not fixed. It is difficult to completely cover the information of the target object in the image by only the center clipping method, so we crop the image at multiple locations. 152 | 153 | One-crop of an image is created by cropping one 224 × 224 regions from the center of a 256 × 256 image; Five-crop is five 224 × 224 sized image regions cropped from top left, top right, bottom left, bottom right and center of original image; Ten-crop is horizontally flipping each cropped region base on the results of five-crop. 154 | 155 | Use Pytorch, 156 | -------------------------------------------------------------------------------- /models/dlanet.py: -------------------------------------------------------------------------------- 1 | ''' DLANet in PyTorch. 2 | 3 | cvpr2018 4 | 5 | https://arxiv.org/abs/1707.06484 6 | 7 | Reference: 8 | [1] Fisher Yu Dequan Wang Evan Shelhamer Trevor Darrell 9 | Deep Layer Aggregation 10 | ''' 11 | import torch 12 | import torch.nn as nn 13 | import torch.nn.functional as F 14 | 15 | class BasicBlock(nn.Module): 16 | def __init__(self, inp, oup, stride=1, pad=1): 17 | super(BasicBlock, self).__init__() 18 | self.conv1 = nn.Conv2d(inp, oup, kernel_size=3, stride=stride, padding=pad, bias=False) 19 | self.bn1 = nn.BatchNorm2d(oup) 20 | self.relu = nn.ReLU(inplace=True) 21 | self.conv2 = nn.Conv2d(oup, oup, kernel_size=3, stride=1, padding=pad, bias=False) 22 | self.bn2 = nn.BatchNorm2d(oup) 23 | 24 | def forward(self, x, residual=None): 25 | if residual is None: 26 | residual = x 27 | out = self.conv1(x) 28 | out = self.bn1(out) 29 | out = self.relu(out) 30 | out = self.conv2(out) 31 | out = self.bn2(out) 32 | out += residual 33 | out = self.relu(out) 34 | return out 35 | 36 | class Bottleneck(nn.Module): 37 | expansion = 2 38 | def __init__(self, inp, oup, stride=1, pad=1): 39 | super(Bottleneck, self).__init__() 40 | expansion = Bottleneck.expansion 41 | bottle_planes = oup // expansion 42 | self.conv1 = nn.Conv2d(inp, bottle_planes, kernel_size=1, bias=False) 43 | self.bn1 = nn.BatchNorm2d(bottle_planes) 44 | self.conv2 = nn.Conv2d(bottle_planes, bottle_planes, kernel_size=3, stride=stride, padding=pad, bias=False) 45 | self.bn2 = nn.BatchNorm2d(bottle_planes) 46 | self.conv3 = nn.Conv2d(bottle_planes, oup, kernel_size=1, bias=False) 47 | self.bn3 = nn.BatchNorm2d(oup) 48 | self.relu = nn.ReLU(inplace=True) 49 | 50 | def forward(self, x, residual=None): 51 | if residual is None: 52 | residual = x 53 | out = self.conv1(x) 54 | out = self.bn1(out) 55 | out = self.relu(out) 56 | out = self.conv2(out) 57 | out = self.bn2(out) 58 | out = self.relu(out) 59 | out = self.conv3(out) 60 | out = self.bn3(out) 61 | out += residual 62 | out = self.relu(out) 63 | return out 64 | 65 | class BottleneckX(nn.Module): 66 | expansion = 2 67 | cardinality = 32 68 | def __init__(self, inp, oup, stride=1, pad=1): 69 | super(BottleneckX, self).__init__() 70 | cardinality = BottleneckX.cardinality 71 | bottle_planes = oup * cardinality // 32 # avoid 'oup' not enough to conv group 72 | 73 | self.conv1 = nn.Conv2d(inp, bottle_planes, kernel_size=1, bias=False) 74 | self.bn1 = nn.BatchNorm2d(bottle_planes) 75 | self.conv2 = nn.Conv2d(bottle_planes, bottle_planes, kernel_size=3, stride=stride, 76 | padding=pad, bias=False, groups=cardinality) 77 | self.bn2 = nn.BatchNorm2d(bottle_planes) 78 | self.conv3 = nn.Conv2d(bottle_planes, oup, kernel_size=1, bias=False) 79 | self.bn3 = nn.BatchNorm2d(oup) 80 | self.relu = nn.ReLU(inplace=True) 81 | 82 | def forward(self, x, residual=None): 83 | if residual is None: 84 | residual = x 85 | out = self.conv1(x) 86 | out = self.bn1(out) 87 | out = self.relu(out) 88 | out = self.conv2(out) 89 | out = self.bn2(out) 90 | out = self.relu(out) 91 | out = self.conv3(out) 92 | out = self.bn3(out) 93 | out += residual 94 | out = self.relu(out) 95 | return out 96 | 97 | class Root(nn.Module): 98 | def __init__(self, inp, oup, kernel_size, residual): 99 | super(Root, self).__init__() 100 | self.conv = nn.Conv2d( 101 | inp, oup, kernel_size, 102 | stride=1, bias=False, padding=(kernel_size - 1) // 2) 103 | self.bn = nn.BatchNorm2d(oup) 104 | self.relu = nn.ReLU(inplace=True) 105 | self.residual = residual 106 | 107 | def forward(self, *x): 108 | children = x 109 | x = self.conv(torch.cat(x, 1)) 110 | x = self.bn(x) 111 | if self.residual: 112 | x += children[0] 113 | x = self.relu(x) 114 | return x 115 | 116 | 117 | class Tree(nn.Module): 118 | def __init__(self, levels, block, inp, oup, stride=1, 119 | level_root=False, root_dim=0, root_kernel_size=1, 120 | pad=1, root_residual=False): 121 | super(Tree, self).__init__() 122 | if root_dim == 0: 123 | root_dim = 2 * oup 124 | if level_root: 125 | root_dim += inp 126 | if levels == 1: 127 | self.tree1 = block(inp, oup, stride=stride, pad=pad) 128 | self.tree2 = block(oup, oup, stride=1, pad=pad) 129 | else: 130 | self.tree1 = Tree(levels-1, block, inp, oup, 131 | stride, root_dim=0, 132 | root_kernel_size=root_kernel_size, 133 | pad=pad, root_residual=root_residual) 134 | self.tree2 = Tree(levels-1, block, oup, oup, 135 | root_dim=root_dim+oup, 136 | root_kernel_size=root_kernel_size, 137 | pad=pad, root_residual=root_residual) 138 | if levels == 1: 139 | self.root = Root(root_dim, oup, root_kernel_size, 140 | root_residual) 141 | self.level_root = level_root 142 | self.root_dim = root_dim 143 | self.downsample = None 144 | self.project = None 145 | self.levels = levels 146 | if stride > 1: 147 | self.downsample = nn.MaxPool2d(stride, stride=stride) 148 | if inp != oup: 149 | self.project = nn.Sequential( 150 | nn.Conv2d(inp, oup, kernel_size=1, stride=1, bias=False), 151 | nn.BatchNorm2d(oup) 152 | ) 153 | def forward(self, x, residual=None, children=None): 154 | children = [] if children is None else children 155 | bottom = self.downsample(x) if self.downsample else x 156 | residual = self.project(bottom) if self.project else bottom 157 | if self.level_root: 158 | children.append(bottom) 159 | x1 = self.tree1(x, residual) 160 | if self.levels == 1: 161 | x2 = self.tree2(x1) 162 | x = self.root(x2, x1, *children) 163 | else: 164 | children.append(x1) 165 | x = self.tree2(x1, children=children) 166 | return x 167 | 168 | class DLANet(nn.Module): 169 | def __init__(self, levels, channels, num_classes=1000, block=BasicBlock, 170 | residual_root=False): 171 | super(DLANet, self).__init__() 172 | 173 | self.base_layer = nn.Sequential( 174 | nn.Conv2d(3, 3, kernel_size=7, stride=1, padding=3, bias=False), 175 | nn.BatchNorm2d(3), 176 | nn.ReLU(inplace=True), 177 | ) 178 | self.level0 = self._make_layer(3, channels[0]) 179 | self.level1 = self._make_layer(channels[0], channels[1]) 180 | self.level2 = Tree(levels[2], block, channels[1], channels[2], 181 | stride=2, level_root=False, 182 | root_residual=residual_root) 183 | self.level3 = Tree(levels[3], block, channels[2], channels[3], 184 | stride=2, level_root=True, 185 | root_residual=residual_root) 186 | self.level4 = Tree(levels[4], block, channels[3], channels[4], 187 | stride=2, level_root=True, 188 | root_residual=residual_root) 189 | self.level5 = Tree(levels[5], block, channels[4], channels[5], 190 | stride=1, level_root=True, 191 | root_residual=residual_root) 192 | 193 | self.linear = nn.Linear(channels[5], num_classes) 194 | 195 | def _make_layer(self, inp, oup, stride=1, pad=1): 196 | modules = [] 197 | modules.append(BasicBlock(inp, inp, stride=stride, pad=pad)) 198 | modules.append(nn.Sequential( 199 | nn.Conv2d(inp, oup, kernel_size=3, stride=2, padding=1, bias=False), 200 | nn.BatchNorm2d(oup), 201 | nn.ReLU(inplace=True), 202 | )) 203 | # modules.append(nn.MaxPool2d(kernel_size=2, stride=2)) 204 | return nn.Sequential(*modules) 205 | 206 | def forward(self, x): 207 | out = self.base_layer(x) 208 | out = self.level0(out) 209 | out = self.level1(out) 210 | out = self.level2(out) 211 | out = self.level3(out) 212 | out = self.level4(out) 213 | out = self.level5(out) 214 | return out 215 | 216 | def DLANet34(): 217 | return DLANet([1,1,1,2,2,1], [16,32,64,128,256,512], block=BasicBlock) 218 | 219 | def DLANet46_C(): 220 | return DLANet([1, 1, 1, 2, 2, 1], [16, 32, 64, 64, 128, 256], block=Bottleneck) 221 | 222 | def DLANet60(): 223 | return DLANet([1, 1, 1, 2, 3, 1],[16, 32, 128, 256, 512, 1024], block=Bottleneck) 224 | 225 | def DLANet102(): 226 | return DLANet([1, 1, 1, 3, 4, 1],[16, 32, 128, 256, 512, 1024], block=Bottleneck) 227 | 228 | def DLANet169(): 229 | return DLANet([1, 1, 2, 3, 5, 1], [16, 32, 128, 256, 512, 1024], block=Bottleneck) 230 | 231 | def DLANetX46_C(): 232 | return DLANet([1, 1, 1, 2, 2, 1], [16, 32, 64, 64, 128, 256], block=BottleneckX) 233 | 234 | def DLANetX60_C(): 235 | return DLANet([1, 1, 1, 2, 3, 1], [16, 32, 64, 64, 128, 256], block=BottleneckX) 236 | 237 | def DLANetX60(): 238 | return DLANet([1, 1, 1, 2, 3, 1], [16, 32, 128, 256, 512, 1024], block=BottleneckX) 239 | 240 | def DLANetX102(): 241 | return DLANet([1, 1, 1, 3, 4, 1], [16, 32, 128, 256, 512, 1024], block=BottleneckX) 242 | 243 | def test(): 244 | net = DLANetX60_C() 245 | x = torch.randn(1,3,224,224) 246 | y = net(x) 247 | print(y.size()) 248 | 249 | # test() -------------------------------------------------------------------------------- /models/googlenet_v4.py: -------------------------------------------------------------------------------- 1 | '''GoogleNet Inception-V4 in PyTorch. 2 | 2016 3 | 4 | Reference: 5 | [1] Christian Szegedy, Sergey Ioffe, Vincent Vanhoucke, Alex Alemi 6 | Inception-v4, Inception-ResNet and the Impact of Residual Connections on Learning 7 | ''' 8 | 9 | import torch 10 | import torch.nn as nn 11 | 12 | class BasicConv2d(nn.Module): 13 | 14 | def __init__(self, in_planes, out_planes, kernel_size, stride, padding=0): 15 | super(BasicConv2d, self).__init__() 16 | self.conv = nn.Conv2d(in_planes, out_planes, 17 | kernel_size=kernel_size, stride=stride, 18 | padding=padding, bias=False) # verify bias false 19 | self.bn = nn.BatchNorm2d(out_planes, 20 | eps=0.001, # value found in tensorflow 21 | momentum=0.1, # default pytorch value 22 | affine=True) 23 | self.relu = nn.ReLU(inplace=True) 24 | 25 | def forward(self, x): 26 | x = self.conv(x) 27 | x = self.bn(x) 28 | x = self.relu(x) 29 | return x 30 | 31 | 32 | class Mixed_3a(nn.Module): 33 | 34 | def __init__(self): 35 | super(Mixed_3a, self).__init__() 36 | self.maxpool = nn.MaxPool2d(3, stride=2) 37 | self.conv = BasicConv2d(64, 96, kernel_size=3, stride=2) 38 | 39 | def forward(self, x): 40 | x0 = self.maxpool(x) 41 | x1 = self.conv(x) 42 | out = torch.cat((x0, x1), 1) 43 | return out 44 | 45 | 46 | class Mixed_4a(nn.Module): 47 | 48 | def __init__(self): 49 | super(Mixed_4a, self).__init__() 50 | 51 | self.branch0 = nn.Sequential( 52 | BasicConv2d(160, 64, kernel_size=1, stride=1), 53 | BasicConv2d(64, 96, kernel_size=3, stride=1) 54 | ) 55 | 56 | self.branch1 = nn.Sequential( 57 | BasicConv2d(160, 64, kernel_size=1, stride=1), 58 | BasicConv2d(64, 64, kernel_size=(1, 7), stride=1, padding=(0, 3)), 59 | BasicConv2d(64, 64, kernel_size=(7, 1), stride=1, padding=(3, 0)), 60 | BasicConv2d(64, 96, kernel_size=(3, 3), stride=1) 61 | ) 62 | 63 | def forward(self, x): 64 | x0 = self.branch0(x) 65 | x1 = self.branch1(x) 66 | out = torch.cat((x0, x1), 1) 67 | return out 68 | 69 | 70 | class Mixed_5a(nn.Module): 71 | 72 | def __init__(self): 73 | super(Mixed_5a, self).__init__() 74 | self.conv = BasicConv2d(192, 192, kernel_size=3, stride=2) 75 | self.maxpool = nn.MaxPool2d(3, stride=2) 76 | 77 | def forward(self, x): 78 | x0 = self.conv(x) 79 | x1 = self.maxpool(x) 80 | out = torch.cat((x0, x1), 1) 81 | return out 82 | 83 | 84 | class Inception_A(nn.Module): 85 | 86 | def __init__(self): 87 | super(Inception_A, self).__init__() 88 | self.branch0 = BasicConv2d(384, 96, kernel_size=1, stride=1) 89 | 90 | self.branch1 = nn.Sequential( 91 | BasicConv2d(384, 64, kernel_size=1, stride=1), 92 | BasicConv2d(64, 96, kernel_size=3, stride=1, padding=1) 93 | ) 94 | 95 | self.branch2 = nn.Sequential( 96 | BasicConv2d(384, 64, kernel_size=1, stride=1), 97 | BasicConv2d(64, 96, kernel_size=3, stride=1, padding=1), 98 | BasicConv2d(96, 96, kernel_size=3, stride=1, padding=1) 99 | ) 100 | 101 | self.branch3 = nn.Sequential( 102 | nn.AvgPool2d(3, stride=1, padding=1, count_include_pad=False), 103 | BasicConv2d(384, 96, kernel_size=1, stride=1) 104 | ) 105 | 106 | def forward(self, x): 107 | x0 = self.branch0(x) 108 | x1 = self.branch1(x) 109 | x2 = self.branch2(x) 110 | x3 = self.branch3(x) 111 | out = torch.cat((x0, x1, x2, x3), 1) 112 | return out 113 | 114 | 115 | class Reduction_A(nn.Module): 116 | 117 | def __init__(self): 118 | super(Reduction_A, self).__init__() 119 | self.branch0 = BasicConv2d(384, 384, kernel_size=3, stride=2) 120 | 121 | self.branch1 = nn.Sequential( 122 | BasicConv2d(384, 192, kernel_size=1, stride=1), 123 | BasicConv2d(192, 224, kernel_size=3, stride=1, padding=1), 124 | BasicConv2d(224, 256, kernel_size=3, stride=2) 125 | ) 126 | 127 | self.branch2 = nn.MaxPool2d(3, stride=2) 128 | 129 | def forward(self, x): 130 | x0 = self.branch0(x) 131 | x1 = self.branch1(x) 132 | x2 = self.branch2(x) 133 | out = torch.cat((x0, x1, x2), 1) 134 | return out 135 | 136 | 137 | class Inception_B(nn.Module): 138 | 139 | def __init__(self): 140 | super(Inception_B, self).__init__() 141 | self.branch0 = BasicConv2d(1024, 384, kernel_size=1, stride=1) 142 | 143 | self.branch1 = nn.Sequential( 144 | BasicConv2d(1024, 192, kernel_size=1, stride=1), 145 | BasicConv2d(192, 224, kernel_size=(1, 7), stride=1, padding=(0, 3)), 146 | BasicConv2d(224, 256, kernel_size=(7, 1), stride=1, padding=(3, 0)) 147 | ) 148 | 149 | self.branch2 = nn.Sequential( 150 | BasicConv2d(1024, 192, kernel_size=1, stride=1), 151 | BasicConv2d(192, 192, kernel_size=(7, 1), stride=1, padding=(3, 0)), 152 | BasicConv2d(192, 224, kernel_size=(1, 7), stride=1, padding=(0, 3)), 153 | BasicConv2d(224, 224, kernel_size=(7, 1), stride=1, padding=(3, 0)), 154 | BasicConv2d(224, 256, kernel_size=(1, 7), stride=1, padding=(0, 3)) 155 | ) 156 | 157 | self.branch3 = nn.Sequential( 158 | nn.AvgPool2d(3, stride=1, padding=1, count_include_pad=False), 159 | BasicConv2d(1024, 128, kernel_size=1, stride=1) 160 | ) 161 | 162 | def forward(self, x): 163 | x0 = self.branch0(x) 164 | x1 = self.branch1(x) 165 | x2 = self.branch2(x) 166 | x3 = self.branch3(x) 167 | out = torch.cat((x0, x1, x2, x3), 1) 168 | return out 169 | 170 | 171 | class Reduction_B(nn.Module): 172 | 173 | def __init__(self): 174 | super(Reduction_B, self).__init__() 175 | 176 | self.branch0 = nn.Sequential( 177 | BasicConv2d(1024, 192, kernel_size=1, stride=1), 178 | BasicConv2d(192, 192, kernel_size=3, stride=2) 179 | ) 180 | 181 | self.branch1 = nn.Sequential( 182 | BasicConv2d(1024, 256, kernel_size=1, stride=1), 183 | BasicConv2d(256, 256, kernel_size=(1, 7), stride=1, padding=(0, 3)), 184 | BasicConv2d(256, 320, kernel_size=(7, 1), stride=1, padding=(3, 0)), 185 | BasicConv2d(320, 320, kernel_size=3, stride=2) 186 | ) 187 | 188 | self.branch2 = nn.MaxPool2d(3, stride=2) 189 | 190 | def forward(self, x): 191 | x0 = self.branch0(x) 192 | x1 = self.branch1(x) 193 | x2 = self.branch2(x) 194 | out = torch.cat((x0, x1, x2), 1) 195 | return out 196 | 197 | 198 | class Inception_C(nn.Module): 199 | 200 | def __init__(self): 201 | super(Inception_C, self).__init__() 202 | 203 | self.branch0 = BasicConv2d(1536, 256, kernel_size=1, stride=1) 204 | 205 | self.branch1_0 = BasicConv2d(1536, 384, kernel_size=1, stride=1) 206 | self.branch1_1a = BasicConv2d(384, 256, kernel_size=(1, 3), stride=1, padding=(0, 1)) 207 | self.branch1_1b = BasicConv2d(384, 256, kernel_size=(3, 1), stride=1, padding=(1, 0)) 208 | 209 | self.branch2_0 = BasicConv2d(1536, 384, kernel_size=1, stride=1) 210 | self.branch2_1 = BasicConv2d(384, 448, kernel_size=(3, 1), stride=1, padding=(1, 0)) 211 | self.branch2_2 = BasicConv2d(448, 512, kernel_size=(1, 3), stride=1, padding=(0, 1)) 212 | self.branch2_3a = BasicConv2d(512, 256, kernel_size=(1, 3), stride=1, padding=(0, 1)) 213 | self.branch2_3b = BasicConv2d(512, 256, kernel_size=(3, 1), stride=1, padding=(1, 0)) 214 | 215 | self.branch3 = nn.Sequential( 216 | nn.AvgPool2d(3, stride=1, padding=1, count_include_pad=False), 217 | BasicConv2d(1536, 256, kernel_size=1, stride=1) 218 | ) 219 | 220 | def forward(self, x): 221 | x0 = self.branch0(x) 222 | 223 | x1_0 = self.branch1_0(x) 224 | x1_1a = self.branch1_1a(x1_0) 225 | x1_1b = self.branch1_1b(x1_0) 226 | x1 = torch.cat((x1_1a, x1_1b), 1) 227 | 228 | x2_0 = self.branch2_0(x) 229 | x2_1 = self.branch2_1(x2_0) 230 | x2_2 = self.branch2_2(x2_1) 231 | x2_3a = self.branch2_3a(x2_2) 232 | x2_3b = self.branch2_3b(x2_2) 233 | x2 = torch.cat((x2_3a, x2_3b), 1) 234 | 235 | x3 = self.branch3(x) 236 | 237 | out = torch.cat((x0, x1, x2, x3), 1) 238 | return out 239 | 240 | 241 | class GoogleNetV4(nn.Module): 242 | 243 | def __init__(self, num_classes=1000): 244 | super(GoogleNetV4, self).__init__() 245 | # Special attributs 246 | self.input_space = None 247 | self.input_size = (299, 299, 3) 248 | self.mean = None 249 | self.std = None 250 | # Modules 251 | self.features = nn.Sequential( 252 | BasicConv2d(3, 32, kernel_size=3, stride=2), 253 | BasicConv2d(32, 32, kernel_size=3, stride=1), 254 | BasicConv2d(32, 64, kernel_size=3, stride=1, padding=1), 255 | Mixed_3a(), 256 | Mixed_4a(), 257 | Mixed_5a(), 258 | Inception_A(), 259 | Inception_A(), 260 | Inception_A(), 261 | Inception_A(), 262 | Reduction_A(), # Mixed_6a 263 | Inception_B(), 264 | Inception_B(), 265 | Inception_B(), 266 | Inception_B(), 267 | Inception_B(), 268 | Inception_B(), 269 | Inception_B(), 270 | Reduction_B(), # Mixed_7a 271 | Inception_C(), 272 | Inception_C(), 273 | Inception_C() 274 | ) 275 | self.avg_pool = nn.AdaptiveAvgPool2d(1) 276 | self.fc = nn.Sequential( 277 | nn.Dropout(0.5), 278 | nn.Linear(1536, num_classes), 279 | ) 280 | 281 | def logits(self, features): 282 | x = self.avg_pool(features) 283 | x = x.view(x.size(0), -1) 284 | x = self.fc(x) 285 | return x 286 | 287 | def forward(self, input): 288 | x = self.features(input) 289 | x = self.logits(x) 290 | return x 291 | 292 | 293 | def test(): 294 | x = torch.randn(1,3,224,224) 295 | net = GoogleNetV4() 296 | y = net(x) 297 | print(y.size()) 298 | # test() -------------------------------------------------------------------------------- /models/googlenet_v3.py: -------------------------------------------------------------------------------- 1 | '''GoogleNet Inception-V3 in PyTorch. 2 | 2015 3 | 4 | Reference: 5 | [1] Christian Szegedy, Vincent Vanhoucke, Sergey Ioffe, Jonathon Shlens, Zbigniew Wojna 6 | Rethinking the Inception Architecture for Computer Vision 7 | ''' 8 | 9 | import torch 10 | import torch.nn as nn 11 | import torch.nn.functional as F 12 | 13 | class GoogleNetV3(nn.Module): 14 | 15 | def __init__(self, num_classes=1000): 16 | super(GoogleNetV3, self).__init__() 17 | self.Conv2d_1a_3x3 = BasicConv2d(3, 32, kernel_size=3, stride=2, padding=1) 18 | self.Conv2d_2a_3x3 = BasicConv2d(32, 32, kernel_size=3, stride=1, padding=1) 19 | self.Conv2d_2b_3x3 = BasicConv2d(32, 64, kernel_size=3, stride=1, padding=1) 20 | self.Conv2d_3b_1x1 = BasicConv2d(64, 80, kernel_size=1) 21 | self.Conv2d_4a_3x3 = BasicConv2d(80, 192, kernel_size=3, stride=1, padding=1) 22 | self.Mixed_5b = InceptionA(192, pool_features=32) 23 | self.Mixed_5c = InceptionA(256, pool_features=64) 24 | self.Mixed_5d = InceptionA(288, pool_features=64) 25 | self.Mixed_6a = InceptionB(288) 26 | self.Mixed_6b = InceptionC(768, channels_7x7=128) 27 | self.Mixed_6c = InceptionC(768, channels_7x7=160) 28 | self.Mixed_6d = InceptionC(768, channels_7x7=160) 29 | self.Mixed_6e = InceptionC(768, channels_7x7=192) 30 | self.Mixed_7a = InceptionD(768) 31 | self.Mixed_7b = InceptionE(1280) 32 | self.Mixed_7c = InceptionE(2048) 33 | self.fc = nn.Linear(2048, num_classes) 34 | 35 | def forward(self, x): 36 | # 224 x 224 x 3 37 | x = self.Conv2d_1a_3x3(x) 38 | # 112 x 112 x 32 39 | x = self.Conv2d_2a_3x3(x) 40 | # 112 x 112 x 32 41 | x = self.Conv2d_2b_3x3(x) 42 | # 112 x 112 x 64 43 | x = F.max_pool2d(x, kernel_size=3, stride=2, padding=1) 44 | # 56 x 56 x 64 45 | x = self.Conv2d_3b_1x1(x) 46 | # 56 x 56 x 80 47 | x = self.Conv2d_4a_3x3(x) 48 | # 56 x 56 x 192 49 | x = F.max_pool2d(x, kernel_size=3, stride=2, padding=1) 50 | # 28 x 28 x 192 51 | x = self.Mixed_5b(x) 52 | # 35 x 35 x 256 53 | x = self.Mixed_5c(x) 54 | # 35 x 35 x 288 55 | x = self.Mixed_5d(x) 56 | # 35 x 35 x 288 57 | x = self.Mixed_6a(x) 58 | # 17 x 17 x 768 59 | x = self.Mixed_6b(x) 60 | # 17 x 17 x 768 61 | x = self.Mixed_6c(x) 62 | # 17 x 17 x 768 63 | x = self.Mixed_6d(x) 64 | # 17 x 17 x 768 65 | x = self.Mixed_6e(x) 66 | # 17 x 17 x 768 67 | x = self.Mixed_7a(x) 68 | # 8 x 8 x 1280 69 | x = self.Mixed_7b(x) 70 | # 8 x 8 x 2048 71 | x = self.Mixed_7c(x) 72 | # 8 x 8 x 2048 73 | x = F.avg_pool2d(x, kernel_size=7) 74 | # 1 x 1 x 2048 75 | x = x.view(x.size(0), -1) 76 | # 2048 77 | x = self.fc(x) 78 | # 1000 (num_classes) 79 | return x 80 | 81 | 82 | class InceptionA(nn.Module): 83 | 84 | def __init__(self, in_channels, pool_features): 85 | super(InceptionA, self).__init__() 86 | self.branch1x1 = BasicConv2d(in_channels, 64, kernel_size=1) 87 | 88 | self.branch5x5_1 = BasicConv2d(in_channels, 48, kernel_size=1) 89 | self.branch5x5_2 = BasicConv2d(48, 64, kernel_size=5, padding=2) 90 | 91 | self.branch3x3dbl_1 = BasicConv2d(in_channels, 64, kernel_size=1) 92 | self.branch3x3dbl_2 = BasicConv2d(64, 96, kernel_size=3, padding=1) 93 | self.branch3x3dbl_3 = BasicConv2d(96, 96, kernel_size=3, padding=1) 94 | 95 | self.branch_pool = BasicConv2d(in_channels, pool_features, kernel_size=1) 96 | 97 | def forward(self, x): 98 | branch1x1 = self.branch1x1(x) 99 | 100 | branch5x5 = self.branch5x5_1(x) 101 | branch5x5 = self.branch5x5_2(branch5x5) 102 | 103 | branch3x3dbl = self.branch3x3dbl_1(x) 104 | branch3x3dbl = self.branch3x3dbl_2(branch3x3dbl) 105 | branch3x3dbl = self.branch3x3dbl_3(branch3x3dbl) 106 | 107 | branch_pool = F.avg_pool2d(x, kernel_size=3, stride=1, padding=1) 108 | branch_pool = self.branch_pool(branch_pool) 109 | 110 | outputs = [branch1x1, branch5x5, branch3x3dbl, branch_pool] 111 | return torch.cat(outputs, 1) 112 | 113 | 114 | class InceptionB(nn.Module): 115 | 116 | def __init__(self, in_channels): 117 | super(InceptionB, self).__init__() 118 | self.branch3x3 = BasicConv2d(in_channels, 384, kernel_size=3, stride=2, padding=1) 119 | 120 | self.branch3x3dbl_1 = BasicConv2d(in_channels, 64, kernel_size=1) 121 | self.branch3x3dbl_2 = BasicConv2d(64, 96, kernel_size=3, padding=1) 122 | self.branch3x3dbl_3 = BasicConv2d(96, 96, kernel_size=3, stride=2, padding=1) 123 | 124 | def forward(self, x): 125 | branch3x3 = self.branch3x3(x) 126 | 127 | branch3x3dbl = self.branch3x3dbl_1(x) 128 | branch3x3dbl = self.branch3x3dbl_2(branch3x3dbl) 129 | branch3x3dbl = self.branch3x3dbl_3(branch3x3dbl) 130 | 131 | branch_pool = F.max_pool2d(x, kernel_size=3, stride=2, padding=1) 132 | 133 | outputs = [branch3x3, branch3x3dbl, branch_pool] 134 | return torch.cat(outputs, 1) 135 | 136 | 137 | class InceptionC(nn.Module): 138 | 139 | def __init__(self, in_channels, channels_7x7): 140 | super(InceptionC, self).__init__() 141 | self.branch1x1 = BasicConv2d(in_channels, 192, kernel_size=1) 142 | 143 | c7 = channels_7x7 144 | self.branch7x7_1 = BasicConv2d(in_channels, c7, kernel_size=1) 145 | self.branch7x7_2 = BasicConv2d(c7, c7, kernel_size=(1, 7), padding=(0, 3)) 146 | self.branch7x7_3 = BasicConv2d(c7, 192, kernel_size=(7, 1), padding=(3, 0)) 147 | 148 | self.branch7x7dbl_1 = BasicConv2d(in_channels, c7, kernel_size=1) 149 | self.branch7x7dbl_2 = BasicConv2d(c7, c7, kernel_size=(7, 1), padding=(3, 0)) 150 | self.branch7x7dbl_3 = BasicConv2d(c7, c7, kernel_size=(1, 7), padding=(0, 3)) 151 | self.branch7x7dbl_4 = BasicConv2d(c7, c7, kernel_size=(7, 1), padding=(3, 0)) 152 | self.branch7x7dbl_5 = BasicConv2d(c7, 192, kernel_size=(1, 7), padding=(0, 3)) 153 | 154 | self.branch_pool = BasicConv2d(in_channels, 192, kernel_size=1) 155 | 156 | def forward(self, x): 157 | branch1x1 = self.branch1x1(x) 158 | 159 | branch7x7 = self.branch7x7_1(x) 160 | branch7x7 = self.branch7x7_2(branch7x7) 161 | branch7x7 = self.branch7x7_3(branch7x7) 162 | 163 | branch7x7dbl = self.branch7x7dbl_1(x) 164 | branch7x7dbl = self.branch7x7dbl_2(branch7x7dbl) 165 | branch7x7dbl = self.branch7x7dbl_3(branch7x7dbl) 166 | branch7x7dbl = self.branch7x7dbl_4(branch7x7dbl) 167 | branch7x7dbl = self.branch7x7dbl_5(branch7x7dbl) 168 | 169 | branch_pool = F.avg_pool2d(x, kernel_size=3, stride=1, padding=1) 170 | branch_pool = self.branch_pool(branch_pool) 171 | 172 | outputs = [branch1x1, branch7x7, branch7x7dbl, branch_pool] 173 | return torch.cat(outputs, 1) 174 | 175 | 176 | class InceptionD(nn.Module): 177 | 178 | def __init__(self, in_channels): 179 | super(InceptionD, self).__init__() 180 | self.branch3x3_1 = BasicConv2d(in_channels, 192, kernel_size=1) 181 | self.branch3x3_2 = BasicConv2d(192, 320, kernel_size=3, stride=2, padding=1) 182 | 183 | self.branch7x7x3_1 = BasicConv2d(in_channels, 192, kernel_size=1) 184 | self.branch7x7x3_2 = BasicConv2d(192, 192, kernel_size=(1, 7), padding=(0, 3)) 185 | self.branch7x7x3_3 = BasicConv2d(192, 192, kernel_size=(7, 1), padding=(3, 0)) 186 | self.branch7x7x3_4 = BasicConv2d(192, 192, kernel_size=3, stride=2, padding=1) 187 | 188 | def forward(self, x): 189 | branch3x3 = self.branch3x3_1(x) 190 | branch3x3 = self.branch3x3_2(branch3x3) 191 | 192 | branch7x7x3 = self.branch7x7x3_1(x) 193 | branch7x7x3 = self.branch7x7x3_2(branch7x7x3) 194 | branch7x7x3 = self.branch7x7x3_3(branch7x7x3) 195 | branch7x7x3 = self.branch7x7x3_4(branch7x7x3) 196 | 197 | branch_pool = F.max_pool2d(x, kernel_size=3, stride=2, padding=1) 198 | outputs = [branch3x3, branch7x7x3, branch_pool] 199 | return torch.cat(outputs, 1) 200 | 201 | 202 | class InceptionE(nn.Module): 203 | 204 | def __init__(self, in_channels): 205 | super(InceptionE, self).__init__() 206 | self.branch1x1 = BasicConv2d(in_channels, 320, kernel_size=1) 207 | 208 | self.branch3x3_1 = BasicConv2d(in_channels, 384, kernel_size=1) 209 | self.branch3x3_2a = BasicConv2d(384, 384, kernel_size=(1, 3), padding=(0, 1)) 210 | self.branch3x3_2b = BasicConv2d(384, 384, kernel_size=(3, 1), padding=(1, 0)) 211 | 212 | self.branch3x3dbl_1 = BasicConv2d(in_channels, 448, kernel_size=1) 213 | self.branch3x3dbl_2 = BasicConv2d(448, 384, kernel_size=3, padding=1) 214 | self.branch3x3dbl_3a = BasicConv2d(384, 384, kernel_size=(1, 3), padding=(0, 1)) 215 | self.branch3x3dbl_3b = BasicConv2d(384, 384, kernel_size=(3, 1), padding=(1, 0)) 216 | 217 | self.branch_pool = BasicConv2d(in_channels, 192, kernel_size=1) 218 | 219 | def forward(self, x): 220 | branch1x1 = self.branch1x1(x) 221 | 222 | branch3x3 = self.branch3x3_1(x) 223 | branch3x3 = [ 224 | self.branch3x3_2a(branch3x3), 225 | self.branch3x3_2b(branch3x3), 226 | ] 227 | branch3x3 = torch.cat(branch3x3, 1) 228 | 229 | branch3x3dbl = self.branch3x3dbl_1(x) 230 | branch3x3dbl = self.branch3x3dbl_2(branch3x3dbl) 231 | branch3x3dbl = [ 232 | self.branch3x3dbl_3a(branch3x3dbl), 233 | self.branch3x3dbl_3b(branch3x3dbl), 234 | ] 235 | branch3x3dbl = torch.cat(branch3x3dbl, 1) 236 | 237 | branch_pool = F.avg_pool2d(x, kernel_size=3, stride=1, padding=1) 238 | branch_pool = self.branch_pool(branch_pool) 239 | 240 | outputs = [branch1x1, branch3x3, branch3x3dbl, branch_pool] 241 | return torch.cat(outputs, 1) 242 | 243 | 244 | class BasicConv2d(nn.Module): 245 | 246 | def __init__(self, in_channels, out_channels, **kwargs): 247 | super(BasicConv2d, self).__init__() 248 | self.conv = nn.Conv2d(in_channels, out_channels, bias=False, **kwargs) 249 | self.bn = nn.BatchNorm2d(out_channels, eps=0.001) 250 | 251 | def forward(self, x): 252 | x = self.conv(x) 253 | x = self.bn(x) 254 | return F.relu(x, inplace=True) 255 | 256 | def test(): 257 | x = torch.randn(1,3,224,224) 258 | net = GoogleNetV3() 259 | y = net(x) 260 | print(y.size()) 261 | 262 | # test() -------------------------------------------------------------------------------- /calculate_params.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Calculate the number of parameters, time cast, and FLOPs of different networks. 3 | ''' 4 | from thop import profile 5 | from models import * 6 | import time 7 | import csv 8 | 9 | annotations_new = { 10 | # 'GoogleNetV1':GoogleNetV1(), 11 | # 'GooglrNetV1_Bn':GoogleNetV1_Bn(), 12 | # 'GoogleNetV2':GoogleNetV2(), 13 | # 'GoogleNetV3':GoogleNetV3(), 14 | # 'GoogleNetV4':GoogleNetV4(), 15 | # 'EfficientNetB0':EfficientNet_B0(), 16 | # 'EfficientNetB1':EfficientNet_B1(), 17 | # 'EfficientNetB2':EfficientNet_B2(), 18 | # 'EfficientNetB3':EfficientNet_B3(), 19 | # 'EfficientNetB4':EfficientNet_B4(), 20 | # 'EfficientNetB5':EfficientNet_B5(), 21 | # 'EfficientNetB6':EfficientNet_B6(), 22 | # 'EfficientNetB7':EfficientNet_B7(), 23 | # 'ResNeXt50_2x40d': ResNeXt50(2, 40), 24 | # 'ResNeXt50_4x24d': ResNeXt50(4, 24), 25 | # 'ResNeXt50_8x14d': ResNeXt50(8, 14), 26 | # 'ResNeXt50_32x4d': ResNeXt50(32, 4), 27 | # 'ResNeXt101_2x40d': ResNeXt101(2, 40), 28 | # 'ResNeXt101_4x24d': ResNeXt101(4, 24), 29 | # 'ResNeXt101_8x14d': ResNeXt101(8, 14), 30 | # 'ResNeXt101_32x4d': ResNeXt101(32, 4), 31 | # 'VGG11': VGG('VGG11'), 32 | # 'VGG13': VGG('VGG13'), 33 | # 'VGG16': VGG('VGG16'), 34 | # 'VGG19': VGG('VGG19'), 35 | 'ResNet18': ResNet18(), 36 | 'ResNet34': ResNet34(), 37 | # 'ResNet50': ResNet50(), 38 | # 'ResNet101': ResNet101(), 39 | # 'ResNet152': ResNet152(), 40 | # 'MobileNetV2': MobileNetV2(), 41 | # 'DarkNet53': DarkNet_53(), 42 | # 'DarkNet19': DarkNet_19(), 43 | # 'MobileNet': MobileNet(), 44 | # 'PeleeNet': PeleeNet(), 45 | 'DenseNet121': DenseNet121(), 46 | 'DenseNet169': DenseNet169(), 47 | 'DenseNet201': DenseNet201(), 48 | 'DenseNet264': DenseNet264(), 49 | 'DenseNet161': DenseNet161(), 50 | # 'DLANet34': DLANet34(), 51 | # 'DLANet46_C': DLANet46_C(), 52 | # 'DLANet60': DLANet60(), 53 | # 'DLANet102': DLANet102(), 54 | # 'DLANet169': DLANet169(), 55 | # 'DLANetX46_C': DLANetX46_C(), 56 | # 'DLANetX60_C': DLANetX60_C(), 57 | # 'DLANetX60': DLANetX60(), 58 | # 'DLANetX102': DLANetX102(), 59 | # 'SqueezeNet': SqueezeNet(), 60 | # 'SqueezeNet_Simple': SqueezeNet_Simple(), 61 | # 'SqueezeNet_Complex': SqueezeNet_Complex(), 62 | # '1.0-SqNxt-23': SqNxt_x1_23(), 63 | # '1.0-SqNxt-23v5': SqNxt_x1_23v5(), 64 | # '2.0-SqNxt-23': SqNxt_x2_23(), 65 | # '2.0-SqNxt-23v5': SqNxt_x2_23v5(), 66 | # '0.7-igcv3': IGCV3(0.7), 67 | # '1.0-igcv3': IGCV3(), 68 | # '1.4-igcv3': IGCV3(1.4), 69 | # 'PreActResNet18': PreActResNet18(), 70 | # 'PreActResNet34': PreActResNet34(), 71 | # 'PreActResNet50': PreActResNet50(), 72 | # 'PreActResNet101': PreActResNet101(), 73 | # 'PreActResNet152': PreActResNet152(), 74 | # 'DPN92': DPN92(), 75 | # 'DPN98': DPN98() 76 | } 77 | 78 | annotations = { 79 | 'SENet18': SENet18(), 80 | 'ShuffleNetG2': ShuffleNetG2(), 81 | 'ShuffleNetG3': ShuffleNetG3(), 82 | 'ShuffleNetV2': ShuffleNetV2(1), 83 | } 84 | 85 | def calculate_params_scale(model, name='model', format=''): 86 | scale = 0 87 | if isinstance(model, torch.nn.Module): 88 | # method 1 89 | scale = sum([param.nelement() for param in model.parameters()]) 90 | # model_parameters = filter(lambda p: p.requires_grad, model.parameters()) 91 | # scale = sum([np.prod(p.size()) for p in model_parameters]) 92 | elif isinstance(model, OrderedDict): 93 | # method 3 94 | for key, val in model.items(): 95 | if not isinstance(val, torch.Tensor): 96 | continue 97 | scale += val.numel() 98 | if format == 'million': # (百万) 99 | scale /= 1000000 100 | print("\n*** [%s] Number of params: " % name + str(scale) + '\tmillion...') 101 | return scale 102 | else: 103 | print("\n*** [%s] Number of params: " + str(scale) + '\t...') 104 | return scale 105 | 106 | def calculate_FLOPs_scale(model, inputs, multiply_adds=False, use_gpu=False): 107 | """ 108 | forked from FishNet @ github 109 | https://github.com/kevin-ssy/FishNet/blob/master/utils/profile.py 110 | another: https://github.com/Lyken17/pytorch-OpCounter 111 | no bias: K^2 * IO * HW 112 | multiply_adds : False in FishNet Paper, but True in DenseNet paper 113 | """ 114 | assert isinstance(model, torch.nn.Module) 115 | USE_GPU = use_gpu and torch.cuda.is_available() 116 | def conv_hook(self, input, output): 117 | batch_size, input_channels, input_height, input_width = input[0].size() 118 | output_channels, output_height, output_width = output[0].size() 119 | kernel_ops = self.kernel_size[0] * self.kernel_size[1] * (self.in_channels / self.groups) * ( 120 | 2 if multiply_adds else 1) 121 | bias_ops = 1 if self.bias is not None else 0 122 | params = output_channels * (kernel_ops + bias_ops) 123 | flops = batch_size * params * output_height * output_width 124 | list_conv.append(flops) 125 | def deconv_hook(self, input, output): 126 | batch_size, input_channels, input_height, input_width = input[0].size() 127 | output_channels, output_height, output_width = output[0].size() 128 | kernel_ops = self.kernel_size[0] * self.kernel_size[1] * (self.in_channels / self.groups) * ( 129 | 2 if multiply_adds else 1) 130 | bias_ops = 1 if self.bias is not None else 0 131 | params = output_channels * (kernel_ops + bias_ops) 132 | flops = batch_size * params * output_height * output_width 133 | list_deconv.append(flops) 134 | def linear_hook(self, input, output): 135 | batch_size = input[0].size(0) if input[0].dim() == 2 else 1 136 | weight_ops = self.weight.nelement() * (2 if multiply_adds else 1) 137 | bias_ops = self.bias.nelement() 138 | flops = batch_size * (weight_ops + bias_ops) 139 | list_linear.append(flops) 140 | def bn_hook(self, input, output): 141 | list_bn.append(input[0].nelement()) 142 | def relu_hook(self, input, output): 143 | list_relu.append(input[0].nelement()) 144 | def pooling_hook(self, input, output): 145 | batch_size, input_channels, input_height, input_width = input[0].size() 146 | output_channels, output_height, output_width = output[0].size() 147 | kernel_ops = self.kernel_size * self.kernel_size 148 | bias_ops = 0 149 | params = output_channels * (kernel_ops + bias_ops) 150 | flops = batch_size * params * output_height * output_width 151 | list_pooling.append(flops) 152 | def foo(net): 153 | childrens = list(net.children()) 154 | if not childrens: 155 | if isinstance(net, torch.nn.Conv2d): 156 | net.register_forward_hook(conv_hook) 157 | if isinstance(net, torch.nn.ConvTranspose2d): 158 | net.register_forward_hook(deconv_hook) 159 | if isinstance(net, torch.nn.Linear): 160 | net.register_forward_hook(linear_hook) 161 | if isinstance(net, torch.nn.BatchNorm2d): 162 | net.register_forward_hook(bn_hook) 163 | if isinstance(net, torch.nn.ReLU): 164 | net.register_forward_hook(relu_hook) 165 | if isinstance(net, torch.nn.MaxPool2d) or isinstance(net, torch.nn.AvgPool2d): 166 | net.register_forward_hook(pooling_hook) 167 | return 168 | for c in childrens: 169 | foo(c) 170 | multiply_adds = multiply_adds 171 | list_conv, list_deconv, list_bn, list_relu, list_linear, list_pooling = [], [], [], [], [], [] 172 | foo(model) 173 | if USE_GPU: 174 | inputs = inputs.cuda() 175 | model = model.cuda() 176 | _ = model(inputs) 177 | total_flops = (sum(list_conv) + sum(list_deconv) + sum(list_linear) 178 | + sum(list_bn) + sum(list_relu) + sum(list_pooling)) 179 | print(' + Number of FLOPs: %.5fG' % (total_flops / 1e9 / 2)) 180 | return '%.5f' % (total_flops / 1e9 / 2) 181 | 182 | def calculate_layers_num(model, layers=('conv2d', 'classifier')): 183 | assert isinstance(model, torch.nn.Module) 184 | type_dict = {'conv2d': torch.nn.Conv2d, 185 | 'bnorm2d': torch.nn.BatchNorm2d, 186 | 'relu': torch.nn.ReLU, 187 | 'fc': torch.nn.Linear, 188 | 'classifier': torch.nn.Linear, 189 | 'linear': torch.nn.Linear, 190 | 'deconv2d': torch.nn.ConvTranspose2d} 191 | nums_list = [] 192 | def foo(net): 193 | childrens = list(net.children()) 194 | if not childrens: 195 | if isinstance(net, type_dict[layer]): 196 | pass 197 | return 1 198 | count = 0 199 | for c in childrens: 200 | count += foo(c) 201 | return count 202 | def foo2(net, layer): 203 | count = 0 204 | for n, m in net.named_modules(): 205 | if isinstance(m, type_dict[layer]): 206 | count += 1 207 | return count 208 | for layer in layers: 209 | # nums_list.append(foo(model)) 210 | nums_list.append(foo2(model, layer)) 211 | total = sum(nums_list) 212 | strtip = '' 213 | for layer, nums in zip(list(layers), nums_list): 214 | strtip += ', %s: %s' % (layer, nums) 215 | print(' + Number of layers: %s %s ...' % (total, strtip)) 216 | return total 217 | 218 | def calculate_time_cost(model, inputs, toc=1, use_gpu=False, pritout=False): 219 | if not use_gpu: 220 | tic, toc = time.time(), toc 221 | y = [model(inputs) for _ in range(toc)][0] 222 | toc = (time.time() - tic) / toc 223 | toc = toc * 1000 224 | # print(' + time cost: %.2f ms\t' % toc) 225 | # if not isinstance(y, (list, tuple)): 226 | # y = [y] 227 | # if pritout: 228 | # print(' + preditions: %s xfc.' % len(y), [yy.max(1) for yy in y]) 229 | return toc 230 | else: 231 | assert torch.cuda.is_available() 232 | model, x = model.cuda(), inputs.cuda() 233 | tic, toc = time.time(), toc 234 | y = [model(x) for _ in range(toc)][0] 235 | toc = (time.time() - tic) / toc 236 | toc = toc * 1000 237 | # print(' + time cost: %.2f ms\t' % toc) 238 | # if not isinstance(y, (list, tuple)): 239 | # y = [y] 240 | # if pritout: 241 | # print(' + preditions: %s 个xfc.' % len(y), [yy.max(1) for yy in y]) 242 | return toc 243 | 244 | if __name__ == '__main__': 245 | inputs = torch.randn(4, 3, 224, 224) 246 | for key,value in annotations_new.items(): 247 | net = value 248 | calculate_params_scale(net, name=key, format='million') 249 | calculate_FLOPs_scale(net, inputs, use_gpu=False, multiply_adds=False) 250 | calculate_layers_num(net) 251 | sum_time = 0 252 | for i in range(20): 253 | sum_time += calculate_time_cost(net, inputs, use_gpu=False, toc=1, pritout=False) 254 | print(' + time cost: %.2f ms\t' % (sum_time/20)) 255 | -------------------------------------------------------------------------------- /models/efficientnet.py: -------------------------------------------------------------------------------- 1 | ''' 2 | EfficientNet in Pytorch 3 | ICML 2019 4 | EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks 5 | ''' 6 | 7 | import re 8 | import math 9 | import collections 10 | from functools import partial 11 | 12 | import torch 13 | from torch import nn 14 | from torch.nn import functional as F 15 | 16 | # Parameters for the entire model (stem, all blocks, and head) 17 | GlobalParams = collections.namedtuple('GlobalParams', [ 18 | 'batch_norm_momentum', 'batch_norm_epsilon', 'dropout_rate', 19 | 'num_classes', 'width_coefficient', 'depth_coefficient', 20 | 'depth_divisor', 'min_depth', 'drop_connect_rate', 'image_size']) 21 | 22 | # Parameters for an individual model block 23 | BlockArgs = collections.namedtuple('BlockArgs', [ 24 | 'kernel_size', 'num_repeat', 'input_filters', 'output_filters', 25 | 'expand_ratio', 'id_skip', 'stride', 'se_ratio']) 26 | 27 | # Change namedtuple defaults 28 | GlobalParams.__new__.__defaults__ = (None,) * len(GlobalParams._fields) 29 | BlockArgs.__new__.__defaults__ = (None,) * len(BlockArgs._fields) 30 | 31 | def efficientnet_params(model_name): 32 | """ Map EfficientNet model name to parameter coefficients. """ 33 | params_dict = { 34 | # Coefficients: width,depth,res,dropout 35 | 'efficientnet-b0': (1.0, 1.0, 224, 0.2), 36 | 'efficientnet-b1': (1.0, 1.1, 240, 0.2), 37 | 'efficientnet-b2': (1.1, 1.2, 260, 0.3), 38 | 'efficientnet-b3': (1.2, 1.4, 300, 0.3), 39 | 'efficientnet-b4': (1.4, 1.8, 380, 0.4), 40 | 'efficientnet-b5': (1.6, 2.2, 456, 0.4), 41 | 'efficientnet-b6': (1.8, 2.6, 528, 0.5), 42 | 'efficientnet-b7': (2.0, 3.1, 600, 0.5), 43 | } 44 | return params_dict[model_name] 45 | 46 | def efficientnet(width_coefficient=None, depth_coefficient=None, dropout_rate=0.2, 47 | drop_connect_rate=0.2, image_size=None, num_classes=1000): 48 | """ Creates a efficientnet model. """ 49 | 50 | blocks_args = [ 51 | 'r1_k3_s11_e1_i32_o16_se0.25', 'r2_k3_s22_e6_i16_o24_se0.25', 52 | 'r2_k5_s22_e6_i24_o40_se0.25', 'r3_k3_s22_e6_i40_o80_se0.25', 53 | 'r3_k5_s11_e6_i80_o112_se0.25', 'r4_k5_s22_e6_i112_o192_se0.25', 54 | 'r1_k3_s11_e6_i192_o320_se0.25', 55 | ] 56 | blocks_args = BlockDecoder.decode(blocks_args) 57 | 58 | global_params = GlobalParams( 59 | batch_norm_momentum=0.99, 60 | batch_norm_epsilon=1e-3, 61 | dropout_rate=dropout_rate, 62 | drop_connect_rate=drop_connect_rate, 63 | # data_format='channels_last', # removed, this is always true in PyTorch 64 | num_classes=num_classes, 65 | width_coefficient=width_coefficient, 66 | depth_coefficient=depth_coefficient, 67 | depth_divisor=8, 68 | min_depth=None, 69 | image_size=image_size, 70 | ) 71 | 72 | return blocks_args, global_params 73 | 74 | class BlockDecoder(object): 75 | """ Block Decoder for readability, straight from the official TensorFlow repository """ 76 | 77 | @staticmethod 78 | def _decode_block_string(block_string): 79 | """ Gets a block through a string notation of arguments. """ 80 | assert isinstance(block_string, str) 81 | 82 | ops = block_string.split('_') 83 | options = {} 84 | for op in ops: 85 | splits = re.split(r'(\d.*)', op) 86 | if len(splits) >= 2: 87 | key, value = splits[:2] 88 | options[key] = value 89 | 90 | # Check stride 91 | assert (('s' in options and len(options['s']) == 1) or 92 | (len(options['s']) == 2 and options['s'][0] == options['s'][1])) 93 | 94 | return BlockArgs( 95 | kernel_size=int(options['k']), 96 | num_repeat=int(options['r']), 97 | input_filters=int(options['i']), 98 | output_filters=int(options['o']), 99 | expand_ratio=int(options['e']), 100 | id_skip=('noskip' not in block_string), 101 | se_ratio=float(options['se']) if 'se' in options else None, 102 | stride=[int(options['s'][0])]) 103 | 104 | @staticmethod 105 | def _encode_block_string(block): 106 | """Encodes a block to a string.""" 107 | args = [ 108 | 'r%d' % block.num_repeat, 109 | 'k%d' % block.kernel_size, 110 | 's%d%d' % (block.strides[0], block.strides[1]), 111 | 'e%s' % block.expand_ratio, 112 | 'i%d' % block.input_filters, 113 | 'o%d' % block.output_filters 114 | ] 115 | if 0 < block.se_ratio <= 1: 116 | args.append('se%s' % block.se_ratio) 117 | if block.id_skip is False: 118 | args.append('noskip') 119 | return '_'.join(args) 120 | 121 | @staticmethod 122 | def decode(string_list): 123 | """ 124 | Decodes a list of string notations to specify blocks inside the network. 125 | 126 | :param string_list: a list of strings, each string is a notation of block 127 | :return: a list of BlockArgs namedtuples of block args 128 | """ 129 | assert isinstance(string_list, list) 130 | blocks_args = [] 131 | for block_string in string_list: 132 | blocks_args.append(BlockDecoder._decode_block_string(block_string)) 133 | return blocks_args 134 | 135 | @staticmethod 136 | def encode(blocks_args): 137 | """ 138 | Encodes a list of BlockArgs to a list of strings. 139 | 140 | :param blocks_args: a list of BlockArgs namedtuples of block args 141 | :return: a list of strings, each string is a notation of block 142 | """ 143 | block_strings = [] 144 | for block in blocks_args: 145 | block_strings.append(BlockDecoder._encode_block_string(block)) 146 | return block_strings 147 | 148 | class SwishImplementation(torch.autograd.Function): 149 | @staticmethod 150 | def forward(ctx, i): 151 | result = i * torch.sigmoid(i) 152 | ctx.save_for_backward(i) 153 | return result 154 | 155 | @staticmethod 156 | def backward(ctx, grad_output): 157 | i = ctx.saved_variables[0] 158 | sigmoid_i = torch.sigmoid(i) 159 | return grad_output * (sigmoid_i * (1 + i * (1 - sigmoid_i))) 160 | 161 | def round_filters(filters, global_params): 162 | """ Calculate and round number of filters based on depth multiplier. """ 163 | multiplier = global_params.width_coefficient 164 | if not multiplier: 165 | return filters 166 | divisor = global_params.depth_divisor 167 | min_depth = global_params.min_depth 168 | filters *= multiplier 169 | min_depth = min_depth or divisor 170 | new_filters = max(min_depth, int(filters + divisor / 2) // divisor * divisor) 171 | if new_filters < 0.9 * filters: # prevent rounding by more than 10% 172 | new_filters += divisor 173 | return int(new_filters) 174 | 175 | def round_repeats(repeats, global_params): 176 | """ Round number of filters based on depth multiplier. """ 177 | multiplier = global_params.depth_coefficient 178 | if not multiplier: 179 | return repeats 180 | return int(math.ceil(multiplier * repeats)) 181 | 182 | def drop_connect(inputs, p, training): 183 | """ Drop connect. """ 184 | if not training: return inputs 185 | batch_size = inputs.shape[0] 186 | keep_prob = 1 - p 187 | random_tensor = keep_prob 188 | random_tensor += torch.rand([batch_size, 1, 1, 1], dtype=inputs.dtype, device=inputs.device) 189 | binary_tensor = torch.floor(random_tensor) 190 | output = inputs / keep_prob * binary_tensor 191 | return output 192 | 193 | def get_model_params(model_name): 194 | """ Get the block args and global params for a given model """ 195 | w, d, s, p = efficientnet_params(model_name) 196 | # note: all models have drop connect rate = 0.2 197 | blocks_args, global_params = efficientnet( 198 | width_coefficient=w, depth_coefficient=d, dropout_rate=p, image_size=s) 199 | return blocks_args, global_params 200 | 201 | class Conv2dDynamicSamePadding(nn.Conv2d): 202 | """ 2D Convolutions like TensorFlow, for a dynamic image size """ 203 | 204 | def __init__(self, in_channels, out_channels, kernel_size, stride=1, dilation=1, groups=1, bias=True): 205 | super().__init__(in_channels, out_channels, kernel_size, stride, 0, dilation, groups, bias) 206 | self.stride = self.stride if len(self.stride) == 2 else [self.stride[0]] * 2 207 | 208 | def forward(self, x): 209 | ih, iw = x.size()[-2:] 210 | kh, kw = self.weight.size()[-2:] 211 | sh, sw = self.stride 212 | oh, ow = math.ceil(ih / sh), math.ceil(iw / sw) 213 | pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0) 214 | pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0) 215 | if pad_h > 0 or pad_w > 0: 216 | x = F.pad(x, [pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2]) 217 | return F.conv2d(x, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups) 218 | 219 | class Conv2dStaticSamePadding(nn.Conv2d): 220 | """ 2D Convolutions like TensorFlow, for a fixed image size""" 221 | 222 | def __init__(self, in_channels, out_channels, kernel_size, image_size=None, **kwargs): 223 | super().__init__(in_channels, out_channels, kernel_size, **kwargs) 224 | self.stride = self.stride if len(self.stride) == 2 else [self.stride[0]] * 2 225 | 226 | # Calculate padding based on image size and save it 227 | assert image_size is not None 228 | ih, iw = image_size if type(image_size) == list else [image_size, image_size] 229 | kh, kw = self.weight.size()[-2:] 230 | sh, sw = self.stride 231 | oh, ow = math.ceil(ih / sh), math.ceil(iw / sw) 232 | pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0) 233 | pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0) 234 | if pad_h > 0 or pad_w > 0: 235 | self.static_padding = nn.ZeroPad2d((pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2)) 236 | else: 237 | self.static_padding = Identity() 238 | 239 | def forward(self, x): 240 | x = self.static_padding(x) 241 | x = F.conv2d(x, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups) 242 | return x 243 | 244 | class Identity(nn.Module): 245 | def __init__(self, ): 246 | super(Identity, self).__init__() 247 | 248 | def forward(self, input): 249 | return input 250 | 251 | def get_same_padding_conv2d(image_size=None): 252 | """ Chooses static padding if you have specified an image size, and dynamic padding otherwise. 253 | Static padding is necessary for ONNX exporting of models. """ 254 | if image_size is None: 255 | return Conv2dDynamicSamePadding 256 | else: 257 | return partial(Conv2dStaticSamePadding, image_size=image_size) 258 | 259 | class Swish(nn.Module): 260 | def forward(self, x): 261 | return x * torch.sigmoid(x) 262 | 263 | class MemoryEfficientSwish(nn.Module): 264 | def forward(self, x): 265 | return SwishImplementation.apply(x) 266 | 267 | class MBConvBlock(nn.Module): 268 | """ 269 | Mobile Inverted Residual Bottleneck Block 270 | 271 | Args: 272 | block_args (namedtuple): BlockArgs, see above 273 | global_params (namedtuple): GlobalParam, see above 274 | 275 | Attributes: 276 | has_se (bool): Whether the block contains a Squeeze and Excitation layer. 277 | """ 278 | 279 | def __init__(self, block_args, global_params): 280 | super().__init__() 281 | self._block_args = block_args 282 | self._bn_mom = 1 - global_params.batch_norm_momentum 283 | self._bn_eps = global_params.batch_norm_epsilon 284 | self.has_se = (self._block_args.se_ratio is not None) and (0 < self._block_args.se_ratio <= 1) 285 | self.id_skip = block_args.id_skip # skip connection and drop connect 286 | 287 | # Get static or dynamic convolution depending on image size 288 | Conv2d = get_same_padding_conv2d(image_size=global_params.image_size) 289 | 290 | # Expansion phase 291 | inp = self._block_args.input_filters # number of input channels 292 | oup = self._block_args.input_filters * self._block_args.expand_ratio # number of output channels 293 | if self._block_args.expand_ratio != 1: 294 | self._expand_conv = Conv2d(in_channels=inp, out_channels=oup, kernel_size=1, bias=False) 295 | self._bn0 = nn.BatchNorm2d(num_features=oup, momentum=self._bn_mom, eps=self._bn_eps) 296 | 297 | # Depthwise convolution phase 298 | k = self._block_args.kernel_size 299 | s = self._block_args.stride 300 | self._depthwise_conv = Conv2d( 301 | in_channels=oup, out_channels=oup, groups=oup, # groups makes it depthwise 302 | kernel_size=k, stride=s, bias=False) 303 | self._bn1 = nn.BatchNorm2d(num_features=oup, momentum=self._bn_mom, eps=self._bn_eps) 304 | 305 | # Squeeze and Excitation layer, if desired 306 | if self.has_se: 307 | num_squeezed_channels = max(1, int(self._block_args.input_filters * self._block_args.se_ratio)) 308 | self._se_reduce = Conv2d(in_channels=oup, out_channels=num_squeezed_channels, kernel_size=1) 309 | self._se_expand = Conv2d(in_channels=num_squeezed_channels, out_channels=oup, kernel_size=1) 310 | 311 | # Output phase 312 | final_oup = self._block_args.output_filters 313 | self._project_conv = Conv2d(in_channels=oup, out_channels=final_oup, kernel_size=1, bias=False) 314 | self._bn2 = nn.BatchNorm2d(num_features=final_oup, momentum=self._bn_mom, eps=self._bn_eps) 315 | self._swish = MemoryEfficientSwish() 316 | 317 | def forward(self, inputs, drop_connect_rate=None): 318 | """ 319 | :param inputs: input tensor 320 | :param drop_connect_rate: drop connect rate (float, between 0 and 1) 321 | :return: output of block 322 | """ 323 | 324 | # Expansion and Depthwise Convolution 325 | x = inputs 326 | if self._block_args.expand_ratio != 1: 327 | x = self._swish(self._bn0(self._expand_conv(inputs))) 328 | x = self._swish(self._bn1(self._depthwise_conv(x))) 329 | 330 | # Squeeze and Excitation 331 | if self.has_se: 332 | x_squeezed = F.adaptive_avg_pool2d(x, 1) 333 | x_squeezed = self._se_expand(self._swish(self._se_reduce(x_squeezed))) 334 | x = torch.sigmoid(x_squeezed) * x 335 | 336 | x = self._bn2(self._project_conv(x)) 337 | 338 | # Skip connection and drop connect 339 | input_filters, output_filters = self._block_args.input_filters, self._block_args.output_filters 340 | if self.id_skip and self._block_args.stride == 1 and input_filters == output_filters: 341 | if drop_connect_rate: 342 | x = drop_connect(x, p=drop_connect_rate, training=self.training) 343 | x = x + inputs # skip connection 344 | return x 345 | 346 | def set_swish(self, memory_efficient=True): 347 | """Sets swish function as memory efficient (for training) or standard (for export)""" 348 | self._swish = MemoryEfficientSwish() if memory_efficient else Swish() 349 | 350 | 351 | class EfficientNet(nn.Module): 352 | """ 353 | An EfficientNet model. Most easily loaded with the .from_name or .from_pretrained methods 354 | 355 | Args: 356 | blocks_args (list): A list of BlockArgs to construct blocks 357 | global_params (namedtuple): A set of GlobalParams shared between blocks 358 | 359 | Example: 360 | model = EfficientNet.from_pretrained('efficientnet-b0') 361 | 362 | """ 363 | 364 | def __init__(self, blocks_args=None, global_params=None): 365 | super().__init__() 366 | assert isinstance(blocks_args, list), 'blocks_args should be a list' 367 | assert len(blocks_args) > 0, 'block args must be greater than 0' 368 | self._global_params = global_params 369 | self._blocks_args = blocks_args 370 | 371 | # Get static or dynamic convolution depending on image size 372 | Conv2d = get_same_padding_conv2d(image_size=global_params.image_size) 373 | 374 | # Batch norm parameters 375 | bn_mom = 1 - self._global_params.batch_norm_momentum 376 | bn_eps = self._global_params.batch_norm_epsilon 377 | 378 | # Stem 379 | in_channels = 3 # rgb 380 | out_channels = round_filters(32, self._global_params) # number of output channels 381 | self._conv_stem = Conv2d(in_channels, out_channels, kernel_size=3, stride=2, bias=False) 382 | self._bn0 = nn.BatchNorm2d(num_features=out_channels, momentum=bn_mom, eps=bn_eps) 383 | 384 | # Build blocks 385 | self._blocks = nn.ModuleList([]) 386 | for block_args in self._blocks_args: 387 | 388 | # Update block input and output filters based on depth multiplier. 389 | block_args = block_args._replace( 390 | input_filters=round_filters(block_args.input_filters, self._global_params), 391 | output_filters=round_filters(block_args.output_filters, self._global_params), 392 | num_repeat=round_repeats(block_args.num_repeat, self._global_params) 393 | ) 394 | 395 | # The first block needs to take care of stride and filter size increase. 396 | self._blocks.append(MBConvBlock(block_args, self._global_params)) 397 | if block_args.num_repeat > 1: 398 | block_args = block_args._replace(input_filters=block_args.output_filters, stride=1) 399 | for _ in range(block_args.num_repeat - 1): 400 | self._blocks.append(MBConvBlock(block_args, self._global_params)) 401 | 402 | # Head 403 | in_channels = block_args.output_filters # output of final block 404 | out_channels = round_filters(1280, self._global_params) 405 | self._conv_head = Conv2d(in_channels, out_channels, kernel_size=1, bias=False) 406 | self._bn1 = nn.BatchNorm2d(num_features=out_channels, momentum=bn_mom, eps=bn_eps) 407 | 408 | # Final linear layer 409 | self._avg_pooling = nn.AdaptiveAvgPool2d(1) 410 | self._dropout = nn.Dropout(self._global_params.dropout_rate) 411 | self._fc = nn.Linear(out_channels, self._global_params.num_classes) 412 | self._swish = MemoryEfficientSwish() 413 | 414 | def set_swish(self, memory_efficient=True): 415 | """Sets swish function as memory efficient (for training) or standard (for export)""" 416 | self._swish = MemoryEfficientSwish() if memory_efficient else Swish() 417 | for block in self._blocks: 418 | block.set_swish(memory_efficient) 419 | 420 | 421 | def extract_features(self, inputs): 422 | """ Returns output of the final convolution layer """ 423 | 424 | # Stem 425 | x = self._bn0(self._conv_stem(inputs)) 426 | x = self._swish(x) 427 | # x = self._bn0(self._conv_stem(inputs)) 428 | 429 | 430 | # Blocks 431 | for idx, block in enumerate(self._blocks): 432 | drop_connect_rate = self._global_params.drop_connect_rate 433 | if drop_connect_rate: 434 | drop_connect_rate *= float(idx) / len(self._blocks) 435 | x = block(x, drop_connect_rate=drop_connect_rate) 436 | # Head 437 | x = self._swish(self._bn1(self._conv_head(x))) 438 | 439 | return x 440 | 441 | def forward(self, inputs): 442 | """ Calls extract_features to extract features, applies final linear layer, and returns logits. """ 443 | bs = inputs.size(0) 444 | # Convolution layers 445 | x = self.extract_features(inputs) 446 | # Pooling and final linear layer 447 | x = self._avg_pooling(x) 448 | x = x.view(bs, -1) 449 | x = self._dropout(x) 450 | x = self._fc(x) 451 | return x 452 | 453 | def EfficientNet_B0(): 454 | blocks_args, global_params = get_model_params('efficientnet-b0') 455 | return EfficientNet(blocks_args, global_params) 456 | 457 | def EfficientNet_B1(): 458 | blocks_args, global_params = get_model_params('efficientnet-b1') 459 | return EfficientNet(blocks_args, global_params) 460 | 461 | def EfficientNet_B2(): 462 | blocks_args, global_params = get_model_params('efficientnet-b2') 463 | return EfficientNet(blocks_args, global_params) 464 | 465 | def EfficientNet_B3(): 466 | blocks_args, global_params = get_model_params('efficientnet-b3') 467 | return EfficientNet(blocks_args, global_params) 468 | 469 | def EfficientNet_B4(): 470 | blocks_args, global_params = get_model_params('efficientnet-b4') 471 | return EfficientNet(blocks_args, global_params) 472 | 473 | def EfficientNet_B5(): 474 | blocks_args, global_params = get_model_params('efficientnet-b5') 475 | return EfficientNet(blocks_args, global_params) 476 | 477 | def EfficientNet_B6(): 478 | blocks_args, global_params = get_model_params('efficientnet-b6') 479 | return EfficientNet(blocks_args, global_params) 480 | 481 | def EfficientNet_B7(): 482 | blocks_args, global_params = get_model_params('efficientnet-b7') 483 | return EfficientNet(blocks_args, global_params) 484 | 485 | def test(): 486 | net = EfficientNet_B7() 487 | x = torch.randn(1,3,224,224) 488 | y = net(x) 489 | print(y.size()) 490 | 491 | # test() --------------------------------------------------------------------------------