Paper : Aggregated Residual Transformations for Deep Neural Networks.

Authors : Saining Xie, Ross Girshick, Piotr Dollár, Zhuowen Tu, Kaiming He. University of California San Diego, Facebook Research .

Published in : 2017 IEEE Conference on Computer Vision and Pattern Recognition (CVPR) .

Model Architecture :

Conv Block :

Identity Block :

keras :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
from keras.models import Model
from keras.layers import Conv2D , MaxPool2D , ZeroPadding2D, Input ,AveragePooling2D, Dense , Dropout ,Activation, Flatten , BatchNormalization
from keras.layers import Add

def IdentityBlock(prev_Layer , filters):
    
    f1 , f2 ,f3 = filters
    block = []
    
    for i in range(32):
        x = Conv2D(filters=f1, kernel_size = (1,1) , strides=(1,1), padding='valid')(prev_Layer)
        x = BatchNormalization(axis=3)(x)
        x = Activation(activation='relu')(x)
        
        x = Conv2D(filters=f2, kernel_size = (3,3) , strides=(1,1), padding='same')(x)
        x = BatchNormalization(axis=3)(x)
        x = Activation(activation='relu')(x)
        
        x = Conv2D(filters=f3, kernel_size = (1,1) , strides=(1,1), padding='valid')(x)
        x = BatchNormalization(axis=3)(x)
        x = Activation(activation='relu')(x)
        block.append(x)
        
    block.append(prev_Layer)
    x = Add()(block)
    x = Activation(activation='relu')(x)
    
    return x


def ConvBlock(prev_Layer , filters , strides):
    f1 , f2 , f3 = filters
    
    block = []
    
    for i in range(32):
        x = Conv2D(filters=f1, kernel_size = (1,1) ,padding='valid', strides=strides)(prev_Layer)
        x = BatchNormalization(axis=3)(x)
        x = Activation(activation='relu')(x)
        
        x = Conv2D(filters=f2, kernel_size = (3,3) , padding='same' , strides=(1 ,1))(x)
        x = BatchNormalization(axis=3)(x)
        x = Activation(activation='relu')(x)
        
        x = Conv2D(filters=f3, kernel_size = (1,1), padding='valid' , strides=(1 ,1))(x)
        x = BatchNormalization(axis=3)(x)
        x = Activation(activation='relu')(x)
        block.append(x)
    
    x2 = Conv2D(filters=f3, kernel_size=(1,1), padding='valid' , strides=strides)(prev_Layer)
    x2 = BatchNormalization(axis=3)(x2)
    
    block.append(x2)
    x = Add()(block)
    x = Activation(activation='relu')(x)
    return x


def ResNext():
    input_layer = Input(shape = (224, 224, 3))
    #Stage 1
    x = ZeroPadding2D((3, 3))(input_layer)
    x = Conv2D(filters = 64, kernel_size = (7,7), strides=(2,2)) (x)
    x = BatchNormalization(axis=3)(x)
    x = Activation(activation='relu')(x)
    x = MaxPool2D(pool_size=(3,3) , strides=(2,2))(x)
    
    #Stage 2
    x = ConvBlock(prev_Layer=x, filters = [128 , 128 , 256], strides = 1)
    x = IdentityBlock(prev_Layer=x, filters = [128 , 128 , 256])
    x = IdentityBlock(prev_Layer=x, filters = [128 , 128 , 256])
    
    #Stage 3
    x = ConvBlock(prev_Layer=x, filters = [256 , 256 , 512], strides = 2)
    x = IdentityBlock(prev_Layer=x, filters = [256 , 256 , 512])
    x = IdentityBlock(prev_Layer=x, filters = [256 , 256 , 512])
    x = IdentityBlock(prev_Layer=x, filters = [256 , 256 , 512])

    #Stage 4    
    x = ConvBlock(prev_Layer=x, filters = [512 , 512 , 1024], strides = 2)    
    x = IdentityBlock(prev_Layer=x, filters = [512 , 512 , 1024])
    x = IdentityBlock(prev_Layer=x, filters = [512 , 512 , 1024])
    x = IdentityBlock(prev_Layer=x, filters = [512 , 512 , 1024])
    x = IdentityBlock(prev_Layer=x, filters = [512 , 512 , 1024])
    x = IdentityBlock(prev_Layer=x, filters = [512 , 512 , 1024])
    
    #Stage 5
    x = ConvBlock(prev_Layer=x, filters = [1024 , 1024 , 2048], strides = 2)
    x = IdentityBlock(prev_Layer=x, filters = [1024 , 1024 , 2048])
    x = IdentityBlock(prev_Layer=x, filters = [1024 , 1024 , 2048])
    
    #Stage 6
    x = AveragePooling2D(pool_size=(7,7)) (x)
    
    x = Flatten()(x)
    x = Dense(units=1000, activation='softmax')(x)
    
    model = Model(inputs=input_layer , outputs = x , name='ResNet50')
    return model

pyTorch :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import torch
import torch.nn as nn
from torchsummary import summary

class convolution2D(nn.Module):
  def __init__(self , in_channels , out_channels , kernel_size , stride , padding , activation):
    super(convolution2D , self).__init__()
    self.conv = nn.Conv2d(in_channels , out_channels , kernel_size , stride , padding)
    self.batchNornalization = nn.BatchNorm2d(num_features=out_channels)
    self.activation = nn.ReLU()
    self.act = activation
  
  def forward(self , x):
    out = self.conv(x)
    out = self.batchNornalization(out)
    if self.act :
      out = self.activation(out)
    return out

class Conv_Block(nn.Module):
  
  def __init__(self , in_channels , filters , stride):
    super(Conv_Block , self).__init__()
    f1 , f2 , f3 = filters
    
    self.branch1 = nn.Sequential(
        convolution2D(in_channels , f1 , 1 , stride , 0 , True),
        convolution2D(f1 , f2 , 3 , 1 , 1, True),
        convolution2D(f2 , f3 , 1 , 1 , 0, False)
    )

    self.branch2 = convolution2D(in_channels , f3 , 1 , 1 , 0, False)
    self.activation = nn.ReLU()

  def forward(self,x):
    
    paths = [self.branch1(x) for i in range(32)]
    paths.append(self.branch2(x))

    out = torch.cat(paths , 1)
    return self.activation(out)  
    
class Identity_Block(nn.Module):
  
  def __init__(self , in_channels , filters):
    super(Identity_Block , self).__init__()
    f1 , f2 , f3 = filters
    
    self.branch1 = nn.Sequential(
        convolution2D(in_channels , f1 , 1 , 1 , 0 , True),
        convolution2D(f1 , f2 , 3 , 1 , 1, True),
        convolution2D(f2 , f3 , 1 , 1 , 0, False)
    )
    self.activation = nn.ReLU()
  def forward(self , x):
    paths = [self.branch1(x) for i in range(32)]
    paths.append(x)

    out = torch.cat(paths , 1)
    return self.activation(out)

class ResNext_50(nn.Module):
  
  def __init__(self):
    super(ResNext_50,self).__init__()
    self.conv1 = convolution2D(in_channels = 3 , out_channels = 64, kernel_size = 7 , stride = 2 , padding = 0 , activation = True)
    self.MaxPooling1 = nn.MaxPool2d(kernel_size=3 , stride = 2)

    self.convBlock1 = Conv_Block(64 , [128 , 128 , 256] , 1)
    self.IdentityBlock1 = Identity_Block(8448 , [128 , 128 , 256])
    self.IdentityBlock2 = Identity_Block(16640 , [128 , 128 , 256])
    self.convBlock2 = Conv_Block(16896 , [256 , 256 , 512] , 2)
    self.IdentityBlock3 = Identity_Block(33280 , [256 , 256 , 512])
    self.IdentityBlock4 = Identity_Block(49664 , [256 , 256 , 512])
    self.IdentityBlock5 = Identity_Block(66048 , [256 , 256 , 512])
    self.convBlock3 = Conv_Block(33792 , [512 , 512 , 1024] , 2)
    self.IdentityBlock6 = Identity_Block(66560 , [512 , 512 , 1024])
    self.IdentityBlock7 = Identity_Block(99328 , [512 , 512 , 1024])
    self.IdentityBlock8 = Identity_Block(132096 , [512 , 512 , 1024])
    self.IdentityBlock9 = Identity_Block(164864, [512 , 512 , 1024])
    self.IdentityBlock10 = Identity_Block(197632 , [512 , 512 , 1024])
    self.convBlock4 = Conv_Block(67584 , [1024 , 1024 , 2048] , 2)
    self.IdentityBlock11 = Identity_Block(133120, [1024 , 1024 , 2048])
    self.IdentityBlock12 = Identity_Block(192656, [1024 , 1024 , 2048])
    self.globalAvgPooling = nn.Conv2d(in_channels=8192 , out_channels=8192 , kernel_size=7)
    self.fc = nn.Linear(in_features=192656 , out_features=1000)
    self.activation = nn.Softmax()
  def forward(self , x):
    out = self.conv1(x)
    out = self.MaxPooling1(out)

    out = self.convBlock1(out)
    
    out = self.IdentityBlock1(out)
    out = self.IdentityBlock2(out)
    
    out = self.convBlock2(out)
    
    out = self.IdentityBlock3(out)
    out = self.IdentityBlock4(out)
    out = self.IdentityBlock5(out)
    
    out = self.convBlock3(out)
    
    out = self.IdentityBlock6(out)
    out = self.IdentityBlock7(out)
    out = self.IdentityBlock8(out)
    out = self.IdentityBlock9(out)
    out = self.IdentityBlock10(out)
    
    out = self.convBlock4(out)
    
    out = self.IdentityBlock11(out)
    out = self.IdentityBlock12(out)
    
    out = self.globalAvgPooling(out)

    out = out.reshape(out.shape[0] , -1)

    out = self.fc(out)
    out = self.activation(out)
    return out