├── .idea ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml └── vcs.xml ├── Architectures ├── Inception ResNet-v1.png ├── Inception ResNet-v2.png └── Inception-v4.png ├── LICENSE ├── README.md ├── inception_resnet_v1.py ├── inception_resnet_v2.py ├── inception_v4.py └── weights └── ADD_WEIGHT_FILES_HERE.txt /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Architectures/Inception ResNet-v1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/titu1994/Inception-v4/52417ac0e878d9e67031fda1323a73760ec08049/Architectures/Inception ResNet-v1.png -------------------------------------------------------------------------------- /Architectures/Inception ResNet-v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/titu1994/Inception-v4/52417ac0e878d9e67031fda1323a73760ec08049/Architectures/Inception ResNet-v2.png -------------------------------------------------------------------------------- /Architectures/Inception-v4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/titu1994/Inception-v4/52417ac0e878d9e67031fda1323a73760ec08049/Architectures/Inception-v4.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Somshubra Majumdar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Inception v4 in Keras 2 | Implementations of the Inception-v4, Inception - Resnet-v1 and v2 Architectures in Keras using the Functional API. The paper on these architectures is available at "Inception-v4, Inception-ResNet and the Impact of Residual Connections on Learning". 3 | 4 | The models are plotted and shown in the architecture sub folder. Due to lack of suitable training data (ILSVR 2015 dataset) and limited GPU processing power, the weights are not provided. 5 | 6 | ## Inception v4 7 | The python script 'inception_v4.py' contains the methods necessary to create the Inception v4 network. 8 | 9 | Usage: 10 | ``` 11 | from inception_v4 import create_inception_v4 12 | 13 | model = create_inception_v4() 14 | 15 | ``` 16 | 17 | ## Inception ResNet v1 18 | The python script 'inception_resnet_v1.py' contains the methods necessary to create the Inception ResNet v1 network. 19 | It is to be noted that scaling of the residuals is turned OFF by default. This can be rectified by supplying 'scale=True' in the create method. 20 | 21 | Usage: 22 | ``` 23 | from inception_resnet_v1 import create_inception_resnet_v1 24 | 25 | model = create_inception_resnet_v1() 26 | 27 | ``` 28 | 29 | ## Inception ResNet v2 30 | The python script 'inception_resnet_v2.py' contains the methods necessary to create the Inception ResNet v2 network. 31 | It is to be noted that scaling of the residuals is turned ON by default. 32 | 33 | There are a few differences in the v2 network from the original paper:
34 | [1] In the B blocks: 'ir_conv' nb of filters is given as 1154 in the paper, however input size is 1152.
35 | This causes inconsistencies in the merge-sum mode, therefore the 'ir_conv' filter size 36 | is reduced to 1152 to match input size. 37 |
38 | [2] In the C blocks: 'ir_conv' nb of filter is given as 2048 in the paper, however input size is 2144.
39 | This causes inconsistencies in the merge-sum mode, therefore the 'ir_conv' filter size 40 | is increased to 2144 to match input size. 41 | 42 | Usage: 43 | ``` 44 | from inception_resnet_v2 import create_inception_resnet_v2 45 | 46 | model = create_inception_resnet_v2(scale=True) 47 | ``` 48 | 49 | # Architectures 50 | ## Inception v4 51 | 52 | 53 | 54 | ## Inception ResNet v1 55 | 56 | 57 | 58 | ## Inception ResNet v2 59 | 60 | 61 | -------------------------------------------------------------------------------- /inception_resnet_v1.py: -------------------------------------------------------------------------------- 1 | from keras.layers import Input, merge, Dropout, Dense, Lambda, Flatten, Activation 2 | from keras.layers.normalization import BatchNormalization 3 | from keras.layers.convolutional import MaxPooling2D, Convolution2D, AveragePooling2D 4 | from keras.models import Model 5 | 6 | from keras import backend as K 7 | 8 | import warnings 9 | warnings.filterwarnings('ignore') 10 | 11 | """ 12 | Implementation of Inception-Residual Network v1 [Inception Network v4 Paper](http://arxiv.org/pdf/1602.07261v1.pdf) in Keras. 13 | 14 | Some additional details: 15 | [1] Each of the A, B and C blocks have a 'scale_residual' parameter. 16 | The scale residual parameter is according to the paper. It is however turned OFF by default. 17 | 18 | Simply setting 'scale=True' in the create_inception_resnet_v1() method will add scaling. 19 | """ 20 | 21 | 22 | def inception_resnet_stem(input): 23 | if K.image_dim_ordering() == "th": 24 | channel_axis = 1 25 | else: 26 | channel_axis = -1 27 | 28 | # Input Shape is 299 x 299 x 3 (tf) or 3 x 299 x 299 (th) 29 | c = Convolution2D(32, 3, 3, activation='relu', subsample=(2, 2))(input) 30 | c = Convolution2D(32, 3, 3, activation='relu', )(c) 31 | c = Convolution2D(64, 3, 3, activation='relu', )(c) 32 | c = MaxPooling2D((3, 3), strides=(2, 2))(c) 33 | c = Convolution2D(80, 1, 1, activation='relu', border_mode='same')(c) 34 | c = Convolution2D(192, 3, 3, activation='relu')(c) 35 | c = Convolution2D(256, 3, 3, activation='relu', subsample=(2,2), border_mode='same')(c) 36 | b = BatchNormalization(axis=channel_axis)(c) 37 | b = Activation('relu')(b) 38 | return b 39 | 40 | def inception_resnet_A(input, scale_residual=True): 41 | if K.image_dim_ordering() == "th": 42 | channel_axis = 1 43 | else: 44 | channel_axis = -1 45 | 46 | # Input is relu activation 47 | init = input 48 | 49 | ir1 = Convolution2D(32, 1, 1, activation='relu', border_mode='same')(input) 50 | 51 | ir2 = Convolution2D(32, 1, 1, activation='relu', border_mode='same')(input) 52 | ir2 = Convolution2D(32, 3, 3, activation='relu', border_mode='same')(ir2) 53 | 54 | ir3 = Convolution2D(32, 1, 1, activation='relu', border_mode='same')(input) 55 | ir3 = Convolution2D(32, 3, 3, activation='relu', border_mode='same')(ir3) 56 | ir3 = Convolution2D(32, 3, 3, activation='relu', border_mode='same')(ir3) 57 | 58 | ir_merge = merge([ir1, ir2, ir3], concat_axis=channel_axis, mode='concat') 59 | 60 | ir_conv = Convolution2D(256, 1, 1, activation='linear', border_mode='same')(ir_merge) 61 | if scale_residual: ir_conv = Lambda(lambda x: x * 0.1)(ir_conv) 62 | 63 | out = merge([init, ir_conv], mode='sum') 64 | out = BatchNormalization(axis=channel_axis)(out) 65 | out = Activation("relu")(out) 66 | return out 67 | 68 | def inception_resnet_B(input, scale_residual=True): 69 | if K.image_dim_ordering() == "th": 70 | channel_axis = 1 71 | else: 72 | channel_axis = -1 73 | 74 | # Input is relu activation 75 | init = input 76 | 77 | ir1 = Convolution2D(128, 1, 1, activation='relu', border_mode='same')(input) 78 | 79 | ir2 = Convolution2D(128, 1, 1, activation='relu', border_mode='same')(input) 80 | ir2 = Convolution2D(128, 1, 7, activation='relu', border_mode='same')(ir2) 81 | ir2 = Convolution2D(128, 7, 1, activation='relu', border_mode='same')(ir2) 82 | 83 | ir_merge = merge([ir1, ir2], mode='concat', concat_axis=channel_axis) 84 | 85 | ir_conv = Convolution2D(896, 1, 1, activation='linear', border_mode='same')(ir_merge) 86 | if scale_residual: ir_conv = Lambda(lambda x: x * 0.1)(ir_conv) 87 | 88 | out = merge([init, ir_conv], mode='sum') 89 | out = BatchNormalization(axis=channel_axis)(out) 90 | out = Activation("relu")(out) 91 | return out 92 | 93 | def inception_resnet_C(input, scale_residual=True): 94 | if K.image_dim_ordering() == "th": 95 | channel_axis = 1 96 | else: 97 | channel_axis = -1 98 | 99 | # Input is relu activation 100 | init = input 101 | 102 | ir1 = Convolution2D(128, 1, 1, activation='relu', border_mode='same')(input) 103 | 104 | ir2 = Convolution2D(192, 1, 1, activation='relu', border_mode='same')(input) 105 | ir2 = Convolution2D(192, 1, 3, activation='relu', border_mode='same')(ir2) 106 | ir2 = Convolution2D(192, 3, 1, activation='relu', border_mode='same')(ir2) 107 | 108 | ir_merge = merge([ir1, ir2], mode='concat', concat_axis=channel_axis) 109 | 110 | ir_conv = Convolution2D(1792, 1, 1, activation='linear', border_mode='same')(ir_merge) 111 | if scale_residual: ir_conv = Lambda(lambda x: x * 0.1)(ir_conv) 112 | 113 | out = merge([init, ir_conv], mode='sum') 114 | out = BatchNormalization(axis=channel_axis)(out) 115 | out = Activation("relu")(out) 116 | return out 117 | 118 | def reduction_A(input, k=192, l=224, m=256, n=384): 119 | if K.image_dim_ordering() == "th": 120 | channel_axis = 1 121 | else: 122 | channel_axis = -1 123 | 124 | r1 = MaxPooling2D((3,3), strides=(2,2))(input) 125 | 126 | r2 = Convolution2D(n, 3, 3, activation='relu', subsample=(2,2))(input) 127 | 128 | r3 = Convolution2D(k, 1, 1, activation='relu', border_mode='same')(input) 129 | r3 = Convolution2D(l, 3, 3, activation='relu', border_mode='same')(r3) 130 | r3 = Convolution2D(m, 3, 3, activation='relu', subsample=(2,2))(r3) 131 | 132 | m = merge([r1, r2, r3], mode='concat', concat_axis=channel_axis) 133 | m = BatchNormalization(axis=channel_axis)(m) 134 | m = Activation('relu')(m) 135 | return m 136 | 137 | 138 | def reduction_resnet_B(input): 139 | if K.image_dim_ordering() == "th": 140 | channel_axis = 1 141 | else: 142 | channel_axis = -1 143 | 144 | r1 = MaxPooling2D((3,3), strides=(2,2), border_mode='valid')(input) 145 | 146 | r2 = Convolution2D(256, 1, 1, activation='relu', border_mode='same')(input) 147 | r2 = Convolution2D(384, 3, 3, activation='relu', subsample=(2,2))(r2) 148 | 149 | r3 = Convolution2D(256, 1, 1, activation='relu', border_mode='same')(input) 150 | r3 = Convolution2D(256, 3, 3, activation='relu', subsample=(2, 2))(r3) 151 | 152 | r4 = Convolution2D(256, 1, 1, activation='relu', border_mode='same')(input) 153 | r4 = Convolution2D(256, 3, 3, activation='relu', border_mode='same')(r4) 154 | r4 = Convolution2D(256, 3, 3, activation='relu', subsample=(2, 2))(r4) 155 | 156 | m = merge([r1, r2, r3, r4], concat_axis=channel_axis, mode='concat') 157 | m = BatchNormalization(axis=channel_axis)(m) 158 | m = Activation('relu')(m) 159 | return m 160 | 161 | def create_inception_resnet_v1(nb_classes=1001, scale=True): 162 | ''' 163 | Creates a inception resnet v1 network 164 | 165 | :param nb_classes: number of classes.txt 166 | :param scale: flag to add scaling of activations 167 | :return: Keras Model with 1 input (299x299x3) input shape and 2 outputs (final_output, auxiliary_output) 168 | ''' 169 | 170 | if K.image_dim_ordering() == 'th': 171 | init = Input((3, 299, 299)) 172 | else: 173 | init = Input((299, 299, 3)) 174 | 175 | # Input Shape is 299 x 299 x 3 (tf) or 3 x 299 x 299 (th) 176 | x = inception_resnet_stem(init) 177 | 178 | # 5 x Inception Resnet A 179 | for i in range(5): 180 | x = inception_resnet_A(x, scale_residual=scale) 181 | 182 | # Reduction A - From Inception v4 183 | x = reduction_A(x, k=192, l=192, m=256, n=384) 184 | 185 | # 10 x Inception Resnet B 186 | for i in range(10): 187 | x = inception_resnet_B(x, scale_residual=scale) 188 | 189 | # Auxiliary tower 190 | aux_out = AveragePooling2D((5, 5), strides=(3, 3))(x) 191 | aux_out = Convolution2D(128, 1, 1, border_mode='same', activation='relu')(aux_out) 192 | aux_out = Convolution2D(768, 5, 5, activation='relu')(aux_out) 193 | aux_out = Flatten()(aux_out) 194 | aux_out = Dense(nb_classes, activation='softmax')(aux_out) 195 | 196 | # Reduction Resnet B 197 | x = reduction_resnet_B(x) 198 | 199 | # 5 x Inception Resnet C 200 | for i in range(5): 201 | x = inception_resnet_C(x, scale_residual=scale) 202 | 203 | # Average Pooling 204 | x = AveragePooling2D((8,8))(x) 205 | 206 | # Dropout 207 | x = Dropout(0.8)(x) 208 | x = Flatten()(x) 209 | 210 | # Output 211 | out = Dense(output_dim=nb_classes, activation='softmax')(x) 212 | 213 | model = Model(init, output=[out, aux_out], name='Inception-Resnet-v1') 214 | 215 | return model 216 | 217 | if __name__ == "__main__": 218 | from keras.utils.visualize_util import plot 219 | 220 | inception_resnet_v1 = create_inception_resnet_v1() 221 | 222 | plot(inception_resnet_v1, to_file="Inception ResNet-v1.png", show_shapes=True) -------------------------------------------------------------------------------- /inception_resnet_v2.py: -------------------------------------------------------------------------------- 1 | from keras.layers import Input, merge, Dropout, Dense, Lambda, Flatten, Activation 2 | from keras.layers.convolutional import MaxPooling2D, Convolution2D, AveragePooling2D 3 | from keras.layers.normalization import BatchNormalization 4 | from keras.models import Model 5 | 6 | from keras import backend as K 7 | 8 | import warnings 9 | warnings.filterwarnings('ignore') 10 | 11 | """ 12 | Implementation of Inception-Residual Network v1 [Inception Network v4 Paper](http://arxiv.org/pdf/1602.07261v1.pdf) in Keras. 13 | 14 | Some additional details: 15 | [1] Each of the A, B and C blocks have a 'scale_residual' parameter. 16 | The scale residual parameter is according to the paper. It is however turned OFF by default. 17 | 18 | Simply setting 'scale=True' in the create_inception_resnet_v2() method will add scaling. 19 | 20 | [2] There were minor inconsistencies with filter size in both B and C blocks. 21 | 22 | In the B blocks: 'ir_conv' nb of filters is given as 1154, however input size is 1152. 23 | This causes inconsistencies in the merge-add mode, therefore the 'ir_conv' filter size 24 | is reduced to 1152 to match input size. 25 | 26 | In the C blocks: 'ir_conv' nb of filter is given as 2048, however input size is 2144. 27 | This causes inconsistencies in the merge-add mode, therefore the 'ir_conv' filter size 28 | is increased to 2144 to match input size. 29 | 30 | Currently trying to find a proper solution with original nb of filters. 31 | 32 | [3] In the stem function, the last Convolutional2D layer has 384 filters instead of the original 256. 33 | This is to correctly match the nb of filters in 'ir_conv' of the next A blocks. 34 | """ 35 | 36 | def inception_resnet_stem(input): 37 | if K.image_dim_ordering() == "th": 38 | channel_axis = 1 39 | else: 40 | channel_axis = -1 41 | 42 | # Input Shape is 299 x 299 x 3 (th) or 3 x 299 x 299 (th) 43 | c = Convolution2D(32, 3, 3, activation='relu', subsample=(2, 2))(input) 44 | c = Convolution2D(32, 3, 3, activation='relu', )(c) 45 | c = Convolution2D(64, 3, 3, activation='relu', border_mode='same')(c) 46 | 47 | c1 = MaxPooling2D((3, 3), strides=(2, 2))(c) 48 | c2 = Convolution2D(96, 3, 3, activation='relu', subsample=(2, 2))(c) 49 | 50 | m = merge([c1, c2], mode='concat', concat_axis=channel_axis) 51 | 52 | c1 = Convolution2D(64, 1, 1, activation='relu', border_mode='same')(m) 53 | c1 = Convolution2D(96, 3, 3, activation='relu', )(c1) 54 | 55 | c2 = Convolution2D(64, 1, 1, activation='relu', border_mode='same')(m) 56 | c2 = Convolution2D(64, 7, 1, activation='relu', border_mode='same')(c2) 57 | c2 = Convolution2D(64, 1, 7, activation='relu', border_mode='same')(c2) 58 | c2 = Convolution2D(96, 3, 3, activation='relu', border_mode='valid')(c2) 59 | 60 | m2 = merge([c1, c2], mode='concat', concat_axis=channel_axis) 61 | 62 | p1 = MaxPooling2D((3, 3), strides=(2, 2), )(m2) 63 | p2 = Convolution2D(192, 3, 3, activation='relu', subsample=(2, 2))(m2) 64 | 65 | m3 = merge([p1, p2], mode='concat', concat_axis=channel_axis) 66 | m3 = BatchNormalization(axis=channel_axis)(m3) 67 | m3 = Activation('relu')(m3) 68 | return m3 69 | 70 | def inception_resnet_v2_A(input, scale_residual=True): 71 | if K.image_dim_ordering() == "th": 72 | channel_axis = 1 73 | else: 74 | channel_axis = -1 75 | 76 | # Input is relu activation 77 | init = input 78 | 79 | ir1 = Convolution2D(32, 1, 1, activation='relu', border_mode='same')(input) 80 | 81 | ir2 = Convolution2D(32, 1, 1, activation='relu', border_mode='same')(input) 82 | ir2 = Convolution2D(32, 3, 3, activation='relu', border_mode='same')(ir2) 83 | 84 | ir3 = Convolution2D(32, 1, 1, activation='relu', border_mode='same')(input) 85 | ir3 = Convolution2D(48, 3, 3, activation='relu', border_mode='same')(ir3) 86 | ir3 = Convolution2D(64, 3, 3, activation='relu', border_mode='same')(ir3) 87 | 88 | ir_merge = merge([ir1, ir2, ir3], concat_axis=channel_axis, mode='concat') 89 | 90 | ir_conv = Convolution2D(384, 1, 1, activation='linear', border_mode='same')(ir_merge) 91 | if scale_residual: ir_conv = Lambda(lambda x: x * 0.1)(ir_conv) 92 | 93 | out = merge([init, ir_conv], mode='sum') 94 | out = BatchNormalization(axis=channel_axis)(out) 95 | out = Activation("relu")(out) 96 | return out 97 | 98 | def inception_resnet_v2_B(input, scale_residual=True): 99 | if K.image_dim_ordering() == "th": 100 | channel_axis = 1 101 | else: 102 | channel_axis = -1 103 | 104 | # Input is relu activation 105 | init = input 106 | 107 | ir1 = Convolution2D(192, 1, 1, activation='relu', border_mode='same')(input) 108 | 109 | ir2 = Convolution2D(128, 1, 1, activation='relu', border_mode='same')(input) 110 | ir2 = Convolution2D(160, 1, 7, activation='relu', border_mode='same')(ir2) 111 | ir2 = Convolution2D(192, 7, 1, activation='relu', border_mode='same')(ir2) 112 | 113 | ir_merge = merge([ir1, ir2], mode='concat', concat_axis=channel_axis) 114 | 115 | ir_conv = Convolution2D(1152, 1, 1, activation='linear', border_mode='same')(ir_merge) 116 | if scale_residual: ir_conv = Lambda(lambda x: x * 0.1)(ir_conv) 117 | 118 | out = merge([init, ir_conv], mode='sum') 119 | out = BatchNormalization(axis=channel_axis)(out) 120 | out = Activation("relu")(out) 121 | return out 122 | 123 | def inception_resnet_v2_C(input, scale_residual=True): 124 | if K.image_dim_ordering() == "th": 125 | channel_axis = 1 126 | else: 127 | channel_axis = -1 128 | 129 | # Input is relu activation 130 | init = input 131 | 132 | ir1 = Convolution2D(192, 1, 1, activation='relu', border_mode='same')(input) 133 | 134 | ir2 = Convolution2D(192, 1, 1, activation='relu', border_mode='same')(input) 135 | ir2 = Convolution2D(224, 1, 3, activation='relu', border_mode='same')(ir2) 136 | ir2 = Convolution2D(256, 3, 1, activation='relu', border_mode='same')(ir2) 137 | 138 | ir_merge = merge([ir1, ir2], mode='concat', concat_axis=channel_axis) 139 | 140 | ir_conv = Convolution2D(2144, 1, 1, activation='linear', border_mode='same')(ir_merge) 141 | if scale_residual: ir_conv = Lambda(lambda x: x * 0.1)(ir_conv) 142 | 143 | out = merge([init, ir_conv], mode='sum') 144 | out = BatchNormalization(axis=channel_axis)(out) 145 | out = Activation("relu")(out) 146 | return out 147 | 148 | 149 | def reduction_A(input, k=192, l=224, m=256, n=384): 150 | if K.image_dim_ordering() == "th": 151 | channel_axis = 1 152 | else: 153 | channel_axis = -1 154 | 155 | r1 = MaxPooling2D((3,3), strides=(2,2))(input) 156 | 157 | r2 = Convolution2D(n, 3, 3, activation='relu', subsample=(2,2))(input) 158 | 159 | r3 = Convolution2D(k, 1, 1, activation='relu', border_mode='same')(input) 160 | r3 = Convolution2D(l, 3, 3, activation='relu', border_mode='same')(r3) 161 | r3 = Convolution2D(m, 3, 3, activation='relu', subsample=(2,2))(r3) 162 | 163 | m = merge([r1, r2, r3], mode='concat', concat_axis=channel_axis) 164 | m = BatchNormalization(axis=1)(m) 165 | m = Activation('relu')(m) 166 | return m 167 | 168 | 169 | def reduction_resnet_v2_B(input): 170 | if K.image_dim_ordering() == "th": 171 | channel_axis = 1 172 | else: 173 | channel_axis = -1 174 | 175 | r1 = MaxPooling2D((3,3), strides=(2,2), border_mode='valid')(input) 176 | 177 | r2 = Convolution2D(256, 1, 1, activation='relu', border_mode='same')(input) 178 | r2 = Convolution2D(384, 3, 3, activation='relu', subsample=(2,2))(r2) 179 | 180 | r3 = Convolution2D(256, 1, 1, activation='relu', border_mode='same')(input) 181 | r3 = Convolution2D(288, 3, 3, activation='relu', subsample=(2, 2))(r3) 182 | 183 | r4 = Convolution2D(256, 1, 1, activation='relu', border_mode='same')(input) 184 | r4 = Convolution2D(288, 3, 3, activation='relu', border_mode='same')(r4) 185 | r4 = Convolution2D(320, 3, 3, activation='relu', subsample=(2, 2))(r4) 186 | 187 | m = merge([r1, r2, r3, r4], concat_axis=channel_axis, mode='concat') 188 | m = BatchNormalization(axis=channel_axis)(m) 189 | m = Activation('relu')(m) 190 | return m 191 | 192 | def create_inception_resnet_v2(nb_classes=1001, scale=True): 193 | ''' 194 | Creates a inception resnet v2 network 195 | 196 | :param nb_classes: number of classes.txt 197 | :param scale: flag to add scaling of activations 198 | :return: Keras Model with 1 input (299x299x3) input shape and 2 outputs (final_output, auxiliary_output) 199 | ''' 200 | 201 | if K.image_dim_ordering() == 'th': 202 | init = Input((3, 299, 299)) 203 | else: 204 | init = Input((299, 299, 3)) 205 | 206 | # Input Shape is 299 x 299 x 3 (tf) or 3 x 299 x 299 (th) 207 | x = inception_resnet_stem(init) 208 | 209 | # 10 x Inception Resnet A 210 | for i in range(10): 211 | x = inception_resnet_v2_A(x, scale_residual=scale) 212 | 213 | # Reduction A 214 | x = reduction_A(x, k=256, l=256, m=384, n=384) 215 | 216 | # 20 x Inception Resnet B 217 | for i in range(20): 218 | x = inception_resnet_v2_B(x, scale_residual=scale) 219 | 220 | # Auxiliary tower 221 | aux_out = AveragePooling2D((5, 5), strides=(3, 3))(x) 222 | aux_out = Convolution2D(128, 1, 1, border_mode='same', activation='relu')(aux_out) 223 | aux_out = Convolution2D(768, 5, 5, activation='relu')(aux_out) 224 | aux_out = Flatten()(aux_out) 225 | aux_out = Dense(nb_classes, activation='softmax')(aux_out) 226 | 227 | # Reduction Resnet B 228 | x = reduction_resnet_v2_B(x) 229 | 230 | # 10 x Inception Resnet C 231 | for i in range(10): 232 | x = inception_resnet_v2_C(x, scale_residual=scale) 233 | 234 | # Average Pooling 235 | x = AveragePooling2D((8,8))(x) 236 | 237 | # Dropout 238 | x = Dropout(0.8)(x) 239 | x = Flatten()(x) 240 | 241 | # Output 242 | out = Dense(output_dim=nb_classes, activation='softmax')(x) 243 | 244 | model = Model(init, output=[out, aux_out], name='Inception-Resnet-v2') 245 | return model 246 | 247 | if __name__ == "__main__": 248 | from keras.utils.visualize_util import plot 249 | 250 | inception_resnet_v2 = create_inception_resnet_v2() 251 | #inception_resnet_v2.summary() 252 | 253 | plot(inception_resnet_v2, to_file="Inception ResNet-v2.png", show_shapes=True) -------------------------------------------------------------------------------- /inception_v4.py: -------------------------------------------------------------------------------- 1 | from keras.layers import Input, merge, Dropout, Dense, Flatten, Activation 2 | from keras.layers.convolutional import MaxPooling2D, Convolution2D, AveragePooling2D 3 | from keras.layers.normalization import BatchNormalization 4 | from keras.models import Model 5 | 6 | from keras import backend as K 7 | from keras.utils.data_utils import get_file 8 | 9 | """ 10 | Implementation of Inception Network v4 [Inception Network v4 Paper](http://arxiv.org/pdf/1602.07261v1.pdf) in Keras. 11 | """ 12 | 13 | TH_BACKEND_TH_DIM_ORDERING = "https://github.com/titu1994/Inception-v4/releases/download/v1.2/inception_v4_weights_th_dim_ordering_th_kernels.h5" 14 | TH_BACKEND_TF_DIM_ORDERING = "https://github.com/titu1994/Inception-v4/releases/download/v1.2/inception_v4_weights_tf_dim_ordering_th_kernels.h5" 15 | TF_BACKEND_TF_DIM_ORDERING = "https://github.com/titu1994/Inception-v4/releases/download/v1.2/inception_v4_weights_tf_dim_ordering_tf_kernels.h5" 16 | TF_BACKEND_TH_DIM_ORDERING = "https://github.com/titu1994/Inception-v4/releases/download/v1.2/inception_v4_weights_th_dim_ordering_tf_kernels.h5" 17 | 18 | 19 | def conv_block(x, nb_filter, nb_row, nb_col, border_mode='same', subsample=(1, 1), bias=False): 20 | if K.image_dim_ordering() == "th": 21 | channel_axis = 1 22 | else: 23 | channel_axis = -1 24 | 25 | x = Convolution2D(nb_filter, nb_row, nb_col, subsample=subsample, border_mode=border_mode, bias=bias)(x) 26 | x = BatchNormalization(axis=channel_axis)(x) 27 | x = Activation('relu')(x) 28 | return x 29 | 30 | 31 | def inception_stem(input): 32 | if K.image_dim_ordering() == "th": 33 | channel_axis = 1 34 | else: 35 | channel_axis = -1 36 | 37 | # Input Shape is 299 x 299 x 3 (th) or 3 x 299 x 299 (th) 38 | x = conv_block(input, 32, 3, 3, subsample=(2, 2), border_mode='valid') 39 | x = conv_block(x, 32, 3, 3, border_mode='valid') 40 | x = conv_block(x, 64, 3, 3) 41 | 42 | x1 = MaxPooling2D((3, 3), strides=(2, 2), border_mode='valid')(x) 43 | x2 = conv_block(x, 96, 3, 3, subsample=(2, 2), border_mode='valid') 44 | 45 | x = merge([x1, x2], mode='concat', concat_axis=channel_axis) 46 | 47 | x1 = conv_block(x, 64, 1, 1) 48 | x1 = conv_block(x1, 96, 3, 3, border_mode='valid') 49 | 50 | x2 = conv_block(x, 64, 1, 1) 51 | x2 = conv_block(x2, 64, 1, 7) 52 | x2 = conv_block(x2, 64, 7, 1) 53 | x2 = conv_block(x2, 96, 3, 3, border_mode='valid') 54 | 55 | x = merge([x1, x2], mode='concat', concat_axis=channel_axis) 56 | 57 | x1 = conv_block(x, 192, 3, 3, subsample=(2, 2), border_mode='valid') 58 | x2 = MaxPooling2D((3, 3), strides=(2, 2), border_mode='valid')(x) 59 | 60 | x = merge([x1, x2], mode='concat', concat_axis=channel_axis) 61 | return x 62 | 63 | 64 | def inception_A(input): 65 | if K.image_dim_ordering() == "th": 66 | channel_axis = 1 67 | else: 68 | channel_axis = -1 69 | 70 | a1 = conv_block(input, 96, 1, 1) 71 | 72 | a2 = conv_block(input, 64, 1, 1) 73 | a2 = conv_block(a2, 96, 3, 3) 74 | 75 | a3 = conv_block(input, 64, 1, 1) 76 | a3 = conv_block(a3, 96, 3, 3) 77 | a3 = conv_block(a3, 96, 3, 3) 78 | 79 | a4 = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same')(input) 80 | a4 = conv_block(a4, 96, 1, 1) 81 | 82 | m = merge([a1, a2, a3, a4], mode='concat', concat_axis=channel_axis) 83 | return m 84 | 85 | 86 | def inception_B(input): 87 | if K.image_dim_ordering() == "th": 88 | channel_axis = 1 89 | else: 90 | channel_axis = -1 91 | 92 | b1 = conv_block(input, 384, 1, 1) 93 | 94 | b2 = conv_block(input, 192, 1, 1) 95 | b2 = conv_block(b2, 224, 1, 7) 96 | b2 = conv_block(b2, 256, 7, 1) 97 | 98 | b3 = conv_block(input, 192, 1, 1) 99 | b3 = conv_block(b3, 192, 7, 1) 100 | b3 = conv_block(b3, 224, 1, 7) 101 | b3 = conv_block(b3, 224, 7, 1) 102 | b3 = conv_block(b3, 256, 1, 7) 103 | 104 | b4 = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same')(input) 105 | b4 = conv_block(b4, 128, 1, 1) 106 | 107 | m = merge([b1, b2, b3, b4], mode='concat', concat_axis=channel_axis) 108 | return m 109 | 110 | 111 | def inception_C(input): 112 | if K.image_dim_ordering() == "th": 113 | channel_axis = 1 114 | else: 115 | channel_axis = -1 116 | 117 | c1 = conv_block(input, 256, 1, 1) 118 | 119 | c2 = conv_block(input, 384, 1, 1) 120 | c2_1 = conv_block(c2, 256, 1, 3) 121 | c2_2 = conv_block(c2, 256, 3, 1) 122 | c2 = merge([c2_1, c2_2], mode='concat', concat_axis=channel_axis) 123 | 124 | c3 = conv_block(input, 384, 1, 1) 125 | c3 = conv_block(c3, 448, 3, 1) 126 | c3 = conv_block(c3, 512, 1, 3) 127 | c3_1 = conv_block(c3, 256, 1, 3) 128 | c3_2 = conv_block(c3, 256, 3, 1) 129 | c3 = merge([c3_1, c3_2], mode='concat', concat_axis=channel_axis) 130 | 131 | c4 = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same')(input) 132 | c4 = conv_block(c4, 256, 1, 1) 133 | 134 | m = merge([c1, c2, c3, c4], mode='concat', concat_axis=channel_axis) 135 | return m 136 | 137 | 138 | def reduction_A(input): 139 | if K.image_dim_ordering() == "th": 140 | channel_axis = 1 141 | else: 142 | channel_axis = -1 143 | 144 | r1 = conv_block(input, 384, 3, 3, subsample=(2, 2), border_mode='valid') 145 | 146 | r2 = conv_block(input, 192, 1, 1) 147 | r2 = conv_block(r2, 224, 3, 3) 148 | r2 = conv_block(r2, 256, 3, 3, subsample=(2, 2), border_mode='valid') 149 | 150 | r3 = MaxPooling2D((3, 3), strides=(2, 2), border_mode='valid')(input) 151 | 152 | m = merge([r1, r2, r3], mode='concat', concat_axis=channel_axis) 153 | return m 154 | 155 | 156 | def reduction_B(input): 157 | if K.image_dim_ordering() == "th": 158 | channel_axis = 1 159 | else: 160 | channel_axis = -1 161 | 162 | r1 = conv_block(input, 192, 1, 1) 163 | r1 = conv_block(r1, 192, 3, 3, subsample=(2, 2), border_mode='valid') 164 | 165 | r2 = conv_block(input, 256, 1, 1) 166 | r2 = conv_block(r2, 256, 1, 7) 167 | r2 = conv_block(r2, 320, 7, 1) 168 | r2 = conv_block(r2, 320, 3, 3, subsample=(2, 2), border_mode='valid') 169 | 170 | r3 = MaxPooling2D((3, 3), strides=(2, 2), border_mode='valid')(input) 171 | 172 | m = merge([r1, r2, r3], mode='concat', concat_axis=channel_axis) 173 | return m 174 | 175 | 176 | def create_inception_v4(nb_classes=1001, load_weights=True): 177 | ''' 178 | Creates a inception v4 network 179 | 180 | :param nb_classes: number of classes.txt 181 | :return: Keras Model with 1 input and 1 output 182 | ''' 183 | 184 | if K.image_dim_ordering() == 'th': 185 | init = Input((3, 299, 299)) 186 | else: 187 | init = Input((299, 299, 3)) 188 | 189 | # Input Shape is 299 x 299 x 3 (tf) or 3 x 299 x 299 (th) 190 | x = inception_stem(init) 191 | 192 | # 4 x Inception A 193 | for i in range(4): 194 | x = inception_A(x) 195 | 196 | # Reduction A 197 | x = reduction_A(x) 198 | 199 | # 7 x Inception B 200 | for i in range(7): 201 | x = inception_B(x) 202 | 203 | # Reduction B 204 | x = reduction_B(x) 205 | 206 | # 3 x Inception C 207 | for i in range(3): 208 | x = inception_C(x) 209 | 210 | # Average Pooling 211 | x = AveragePooling2D((8, 8))(x) 212 | 213 | # Dropout 214 | x = Dropout(0.8)(x) 215 | x = Flatten()(x) 216 | 217 | # Output 218 | out = Dense(output_dim=nb_classes, activation='softmax')(x) 219 | 220 | model = Model(init, out, name='Inception-v4') 221 | 222 | if load_weights: 223 | if K.backend() == "theano": 224 | if K.image_dim_ordering() == "th": 225 | weights = get_file('inception_v4_weights_th_dim_ordering_th_kernels.h5', TH_BACKEND_TH_DIM_ORDERING, 226 | cache_subdir='models') 227 | else: 228 | weights = get_file('inception_v4_weights_tf_dim_ordering_th_kernels.h5', TH_BACKEND_TF_DIM_ORDERING, 229 | cache_subdir='models') 230 | else: 231 | if K.image_dim_ordering() == "th": 232 | weights = get_file('inception_v4_weights_th_dim_ordering_tf_kernels.h5', TF_BACKEND_TH_DIM_ORDERING, 233 | cache_subdir='models') 234 | else: 235 | weights = get_file('inception_v4_weights_tf_dim_ordering_tf_kernels.h5', TH_BACKEND_TF_DIM_ORDERING, 236 | cache_subdir='models') 237 | 238 | model.load_weights(weights) 239 | print("Model weights loaded.") 240 | 241 | return model 242 | 243 | 244 | if __name__ == "__main__": 245 | # from keras.utils.visualize_util import plot 246 | 247 | inception_v4 = create_inception_v4(load_weights=True) 248 | # inception_v4.summary() 249 | 250 | # plot(inception_v4, to_file="Inception-v4.png", show_shapes=True) 251 | -------------------------------------------------------------------------------- /weights/ADD_WEIGHT_FILES_HERE.txt: -------------------------------------------------------------------------------- 1 | Download the appropriate weight file from Release tab (https://github.com/titu1994/Inception-v4/releases/tag/v1.0) 2 | 3 | Acknowledgements : Weight for Inception V4 (Tensorflow backend, Tensorflow dim ordering) is provided by 4 | Kent Sommer (@kentsommer) in his repository - https://github.com/kentsommer/keras-inceptionV4 5 | 6 | --------------------------------------------------------------------------------