├── README.md ├── mobiledet_dsp.py ├── mobiledet_tpu.py └── mobiledet_gpu.py /README.md: -------------------------------------------------------------------------------- 1 | ## MobileDet Backbones 2 | 3 | PyTorch implementation of MobileDet backbones introduced in [MobileDets: Searching for Object Detection Architectures for Mobile Accelerators](https://arxiv.org/abs/2004.14525v3). Ross Wightman's timm library has been used for some helper functions and inspiration for syntax style. The following are the main blocks used in the [tensorflow implementation](https://github.com/tensorflow/models/blob/420a7253e034a12ae2208e6ec94d3e4936177a53/research/object_detection/models/ssd_mobiledet_feature_extractor.py) and their corresponding blocks in the timm library: 4 | 5 | |Tensorflow|timm| 6 | |----------|----| 7 | |fused_conv|EdgeResidual| 8 | |inverterted_bottleneck|InvertedResidual| 9 | |inverted_bottleneck_no_expansion|DepthwiseSeparableConv| 10 | 11 | [tucker-conv package](https://pypi.org/project/tucker-conv/) is used for tucker_conv 12 | -------------------------------------------------------------------------------- /mobiledet_dsp.py: -------------------------------------------------------------------------------- 1 | from timm.models.efficientnet_blocks import * 2 | from tucker_conv.conv import TuckerConv 3 | 4 | # Target: Pixel-4 DSP 5 | class MobileDetDSP(nn.Module): 6 | def __init__(self): 7 | super(MobileDetDSP, self).__init__() 8 | 9 | # First block 10 | self.conv1 = nn.Conv2d(3, 32, 3, stride = 2) 11 | self.bn1 = nn.BatchNorm2d(32) 12 | self.act1 = nn.ReLU6() 13 | self.ibn_ne = DepthwiseSeparableConv(32, 24, act_layer = nn.ReLU6) 14 | 15 | # Second block 16 | self.fused1 = EdgeResidual(24, 32, exp_ratio = 4, stride = 2, act_layer = nn.ReLU6) 17 | self.fused2 = EdgeResidual(32, 32, exp_ratio = 4, act_layer = nn.ReLU6) 18 | self.ibn1 = InvertedResidual(32, 32, exp_ratio = 4) 19 | self.tucker1 = TuckerConv(32, 32) 20 | 21 | # Third block 22 | self.fused3 = EdgeResidual(32, 64, exp_ratio = 8, stride = 2, act_layer = nn.ReLU6) 23 | self.ibn2 = InvertedResidual(64, 64, exp_ratio = 4) 24 | self.fused4 = EdgeResidual(64, 64, exp_ratio = 4, act_layer = nn.ReLU6) 25 | self.fused5 = EdgeResidual(64, 64, exp_ratio = 4, act_layer = nn.ReLU6) 26 | 27 | # Fourth block 28 | self.fused6 = EdgeResidual(64, 120, exp_ratio = 8, stride = 2, act_layer = nn.ReLU6) 29 | self.ibn3 = InvertedResidual(120, 120, exp_ratio = 4) 30 | self.ibn4 = InvertedResidual(120, 120, exp_ratio = 8) 31 | self.ibn5 = InvertedResidual(120, 120, exp_ratio = 8) 32 | 33 | self.fused7 = EdgeResidual(120, 144, exp_ratio = 8, act_layer = nn.ReLU6) 34 | self.ibn6 = InvertedResidual(144, 144, exp_ratio = 8) 35 | self.ibn7 = InvertedResidual(144, 144, exp_ratio = 8) 36 | self.ibn8 = InvertedResidual(144, 144, exp_ratio = 8) 37 | 38 | # Fifth block 39 | self.ibn9 = InvertedResidual(144, 160, exp_ratio = 4, stride = 2) 40 | self.ibn10 = InvertedResidual(160, 160, exp_ratio = 4) 41 | self.fused8 = EdgeResidual(160, 160, exp_ratio = 4, act_layer = nn.ReLU6) 42 | self.tucker2 = TuckerConv(160, 160, in_comp_ratio = 0.75) 43 | self.ibn11 = InvertedResidual(160, 240, exp_ratio = 8) 44 | 45 | def forward(self, x): 46 | # First block 47 | x = self.conv1(x) 48 | x = self.bn1(x) 49 | x = self.act1(x) 50 | x = self.ibn_ne(x) 51 | c1 = x 52 | 53 | # Second block 54 | x = self.fused1(x) 55 | x = self.fused2(x) 56 | x = self.ibn1(x) 57 | x = self.tucker1(x) 58 | c2 = x 59 | 60 | # Third block 61 | x = self.fused3(x) 62 | x = self.ibn2(x) 63 | x = self.fused4(x) 64 | x = self.fused5(x) 65 | c3 = x 66 | 67 | # Fourth block 68 | x = self.fused6(x) 69 | x = self.ibn3(x) 70 | x = self.ibn4(x) 71 | x = self.ibn5(x) 72 | x = self.fused7(x) 73 | x = self.ibn6(x) 74 | x = self.ibn7(x) 75 | x = self.ibn8(x) 76 | c4 = x 77 | 78 | # Fifth block 79 | x = self.ibn9(x) 80 | x = self.ibn10(x) 81 | x = self.fused8(x) 82 | x = self.tucker2(x) 83 | x = self.ibn11(x) 84 | c5 = x 85 | 86 | return c1, c2, c3, c4, c5 -------------------------------------------------------------------------------- /mobiledet_tpu.py: -------------------------------------------------------------------------------- 1 | from timm.models.efficientnet_blocks import * 2 | from tucker_conv.conv import TuckerConv 3 | 4 | # Target: Pixel-4 EdgeTPU 5 | class MobileDetTPU(nn.Module): 6 | def __init__(self): 7 | super(MobileDetTPU, self).__init__() 8 | 9 | # First block 10 | self.conv1 = nn.Conv2d(3, 32, 3, stride = 2) 11 | self.bn1 = nn.BatchNorm2d(32) 12 | self.act1 = nn.ReLU6() 13 | self.tucker1 = TuckerConv(32, 16, residual = False) 14 | 15 | # Second block 16 | self.fused1 = EdgeResidual(16, 16, exp_ratio = 8, stride = 2, act_layer = nn.ReLU6) 17 | self.fused2 = EdgeResidual(16, 16, exp_ratio = 4, act_layer = nn.ReLU6) 18 | self.fused3 = EdgeResidual(16, 16, exp_ratio = 8, act_layer = nn.ReLU6) 19 | self.fused4 = EdgeResidual(16, 16, exp_ratio = 4, act_layer = nn.ReLU6) 20 | 21 | # Third block 22 | self.fused5 = EdgeResidual(16, 40, exp_kernel_size = 5, exp_ratio = 8, stride = 2, act_layer = nn.ReLU6) 23 | self.fused6 = EdgeResidual(40, 40, exp_ratio = 4, act_layer = nn.ReLU6) 24 | self.fused7 = EdgeResidual(40, 40, exp_ratio = 4, act_layer = nn.ReLU6) 25 | self.fused8 = EdgeResidual(40, 40, exp_ratio = 4, act_layer = nn.ReLU6) 26 | 27 | # Fourth block 28 | self.ibn1 = InvertedResidual(40, 72, exp_ratio = 8, stride = 2) 29 | self.ibn2 = InvertedResidual(72, 72, exp_ratio = 8) 30 | self.fused9 = EdgeResidual(72, 72, exp_ratio = 4, act_layer = nn.ReLU6) 31 | self.fused10 = EdgeResidual(72, 72, exp_ratio = 4, act_layer = nn.ReLU6) 32 | 33 | self.ibn3 = InvertedResidual(72, 96, dw_kernel_size = 5, exp_ratio = 8) 34 | self.ibn4 = InvertedResidual(96, 96, dw_kernel_size = 5, exp_ratio = 8) 35 | self.ibn5 = InvertedResidual(96, 96, exp_ratio = 8) 36 | self.ibn6 = InvertedResidual(96, 96, exp_ratio = 8) 37 | 38 | # Fifth block 39 | self.ibn7 = InvertedResidual(96, 120, dw_kernel_size = 5, exp_ratio = 8, stride = 2) 40 | self.ibn8 = InvertedResidual(120, 120, exp_ratio = 8) 41 | self.ibn9 = InvertedResidual(120, 120, dw_kernel_size = 5, exp_ratio = 4) 42 | self.ibn10 = InvertedResidual(120, 120, exp_ratio = 8) 43 | self.ibn11 = InvertedResidual(120, 384, dw_kernel_size = 5, exp_ratio = 8) 44 | 45 | def forward(self, x): 46 | # First block 47 | x = self.conv1(x) 48 | x = self.bn1(x) 49 | x = self.act1(x) 50 | x = self.tucker1(x) 51 | c1 = x 52 | 53 | # Second block 54 | x = self.fused1(x) 55 | x = self.fused2(x) 56 | x = self.fused3(x) 57 | x = self.fused4(x) 58 | c2 = x 59 | 60 | # Third block 61 | x = self.fused5(x) 62 | x = self.fused6(x) 63 | x = self.fused7(x) 64 | x = self.fused8(x) 65 | c3 = x 66 | 67 | # Fourth block 68 | x = self.ibn1(x) 69 | x = self.ibn2(x) 70 | x = self.fused9(x) 71 | x = self.fused10(x) 72 | x = self.ibn3(x) 73 | x = self.ibn4(x) 74 | x = self.ibn5(x) 75 | x = self.ibn6(x) 76 | c4 = x 77 | 78 | # Fifth block 79 | x = self.ibn7(x) 80 | x = self.ibn8(x) 81 | x = self.ibn9(x) 82 | x = self.ibn10(x) 83 | x = self.ibn11(x) 84 | c5 = x 85 | 86 | return c1, c2, c3, c4, c5 -------------------------------------------------------------------------------- /mobiledet_gpu.py: -------------------------------------------------------------------------------- 1 | from timm.models.efficientnet_blocks import * 2 | from tucker_conv.conv import TuckerConv 3 | 4 | # Target: Jetson Xavier GPU 5 | class MobileDetGPU(nn.Module): 6 | def __init__(self): 7 | super(MobileDetGPU, self).__init__() 8 | 9 | # First block 10 | self.conv1 = nn.Conv2d(3, 32, 3, stride = 2) 11 | self.bn1 = nn.BatchNorm2d(32) 12 | self.act1 = nn.ReLU6() 13 | self.tucker1 = TuckerConv(32, 16, residual = False) 14 | 15 | # Second block 16 | self.fused1 = EdgeResidual(16, 32, exp_ratio = 8, stride = 2, act_layer = nn.ReLU6) 17 | self.tucker2 = TuckerConv(32, 32, out_comp_ratio = 0.25) 18 | self.tucker3 = TuckerConv(32, 32, out_comp_ratio = 0.25) 19 | self.tucker4 = TuckerConv(32, 32, out_comp_ratio = 0.25) 20 | 21 | # Third block 22 | self.fused2 = EdgeResidual(32, 64, exp_ratio = 8, stride = 2, act_layer = nn.ReLU6) 23 | self.fused3 = EdgeResidual(64, 64, exp_ratio = 8, act_layer = nn.ReLU6) 24 | self.fused4 = EdgeResidual(64, 64, exp_ratio = 8, act_layer = nn.ReLU6) 25 | self.fused5 = EdgeResidual(64, 64, exp_ratio = 4, act_layer = nn.ReLU6) 26 | 27 | # Fourth block 28 | self.fused6 = EdgeResidual(64, 128, exp_ratio = 8, stride = 2, act_layer = nn.ReLU6) 29 | self.fused7 = EdgeResidual(128, 128, exp_ratio = 4, act_layer = nn.ReLU6) 30 | self.fused8 = EdgeResidual(128, 128, exp_ratio = 4, act_layer = nn.ReLU6) 31 | self.fused9 = EdgeResidual(128, 128, exp_ratio = 4, act_layer = nn.ReLU6) 32 | 33 | self.fused10 = EdgeResidual(128, 128, exp_ratio = 8, act_layer = nn.ReLU6) 34 | self.fused11 = EdgeResidual(128, 128, exp_ratio = 8, act_layer = nn.ReLU6) 35 | self.fused12 = EdgeResidual(128, 128, exp_ratio = 8, act_layer = nn.ReLU6) 36 | self.fused13 = EdgeResidual(128, 128, exp_ratio = 8, act_layer = nn.ReLU6) 37 | 38 | # Fifth block 39 | self.fused14 = EdgeResidual(128, 128, exp_ratio = 4, stride = 2, act_layer = nn.ReLU6) 40 | self.fused15 = EdgeResidual(128, 128, exp_ratio = 4, act_layer = nn.ReLU6) 41 | self.fused16 = EdgeResidual(128, 128, exp_ratio = 4, act_layer = nn.ReLU6) 42 | self.fused17 = EdgeResidual(128, 128, exp_ratio = 4, act_layer = nn.ReLU6) 43 | self.ibn1 = InvertedResidual(128, 384, exp_ratio = 8) 44 | 45 | def forward(self, x): 46 | # First block 47 | x = self.conv1(x) 48 | x = self.bn1(x) 49 | x = self.act1(x) 50 | x = self.tucker1(x) 51 | c1 = x 52 | 53 | # Second block 54 | x = self.fused1(x) 55 | x = self.tucker2(x) 56 | x = self.tucker3(x) 57 | x = self.tucker4(x) 58 | c2 = x 59 | 60 | # Third block 61 | x = self.fused2(x) 62 | x = self.fused3(x) 63 | x = self.fused4(x) 64 | x = self.fused5(x) 65 | c3 = x 66 | 67 | # Fourth block 68 | x = self.fused6(x) 69 | x = self.fused7(x) 70 | x = self.fused8(x) 71 | x = self.fused9(x) 72 | x = self.fused10(x) 73 | x = self.fused11(x) 74 | x = self.fused12(x) 75 | x = self.fused13(x) 76 | c4 = x 77 | 78 | # Fifth block 79 | x = self.fused14(x) 80 | x = self.fused15(x) 81 | x = self.fused16(x) 82 | x = self.fused17(x) 83 | x = self.ibn1(x) 84 | c5 = x 85 | 86 | return c1, c2, c3, c4, c5 --------------------------------------------------------------------------------