Coverage for mlair/model_modules/inception_model.py: 100%

82 statements  

« prev     ^ index     » next       coverage.py v6.4.2, created at 2023-06-30 10:22 +0000

1__author__ = 'Felix Kleinert, Lukas Leufen' 

2__date__ = '2019-10-22' 

3 

4import logging 

5 

6import tensorflow.keras as keras 

7import tensorflow.keras.layers as layers 

8 

9from mlair.model_modules.advanced_paddings import PadUtils, ReflectionPadding2D, Padding2D 

10 

11 

12class InceptionModelBase: 

13 """ 

14 This class contains all necessary construction blocks 

15 """ 

16 

17 def __init__(self): 

18 self.number_of_blocks = 0 

19 self.part_of_block = 0 

20 self.act_number = 0 

21 self.ord_base = 96 # set to 96 as always add +1 for new part of block, chr(97)='a' 

22 

23 def block_part_name(self): 

24 """ 

25 Use unicode due to some issues of keras with normal strings 

26 

27 :return: 

28 """ 

29 return chr(self.ord_base + self.part_of_block) 

30 

31 def batch_normalisation(self, input_x, **kwargs): 

32 block_name = f"Block_{self.number_of_blocks}{self.block_part_name()}_BN" 

33 return layers.BatchNormalization(name=block_name, **kwargs)(input_x) 

34 

35 def create_conv_tower(self, 

36 input_x, 

37 reduction_filter, 

38 tower_filter, 

39 tower_kernel, 

40 activation='relu', 

41 batch_normalisation=False, 

42 **kwargs): 

43 """ 

44 This function creates a "convolution tower block" containing a 1x1 convolution to reduce filter size followed by 

45 convolution with given filter and kernel size 

46 

47 :param input_x: Input to network part 

48 :param reduction_filter: Number of filters used in 1x1 convolution to reduce overall filter size before conv. 

49 :param tower_filter: Number of filters for n x m convolution 

50 :param tower_kernel: kernel size for convolution (n,m) 

51 :param activation: activation function for convolution 

52 :param batch_normalisation: 

53 :return: 

54 """ 

55 self.part_of_block += 1 

56 self.act_number = 1 

57 regularizer = kwargs.get('regularizer', keras.regularizers.l2(0.01)) 

58 bn_settings = kwargs.get('bn_settings', {}) 

59 act_settings = kwargs.get('act_settings', {}) 

60 padding = kwargs.get('padding', 'ZeroPad2D') 

61 logging.debug(f'Inception Block with activation: {activation}') 

62 

63 block_name = f'Block_{self.number_of_blocks}{self.block_part_name()}_{tower_kernel[0]}x{tower_kernel[1]}' 

64 padding_size = PadUtils.get_padding_for_same(tower_kernel) 

65 

66 if tower_kernel == (1, 1): 

67 tower = layers.Conv2D(tower_filter, 

68 tower_kernel, 

69 padding='valid', 

70 kernel_regularizer=regularizer, 

71 name=block_name)(input_x) 

72 # tower = self.act(tower, activation, **act_settings) 

73 else: 

74 tower = layers.Conv2D(reduction_filter, 

75 (1, 1), 

76 padding='valid', 

77 kernel_regularizer=regularizer, 

78 name=f'Block_{self.number_of_blocks}{self.block_part_name()}_1x1')(input_x) 

79 tower = self.act(tower, activation, **act_settings) 

80 

81 tower = Padding2D(padding)(padding=padding_size, 

82 name=f'Block_{self.number_of_blocks}{self.block_part_name()}_Pad' 

83 )(tower) 

84 

85 tower = layers.Conv2D(tower_filter, 

86 tower_kernel, 

87 padding='valid', 

88 kernel_regularizer=regularizer, 

89 name=block_name)(tower) 

90 if batch_normalisation: 

91 tower = self.batch_normalisation(tower, **bn_settings) 

92 tower = self.act(tower, activation, **act_settings) 

93 

94 return tower 

95 

96 def act(self, input_x, activation, **act_settings): 

97 block_name = f"Block_{self.number_of_blocks}{self.block_part_name()}_act_{self.act_number}" 

98 try: 

99 out = getattr(layers, self._get_act_name(activation))(**act_settings, name=block_name)(input_x) 

100 except AttributeError: 

101 block_name += f"_{activation.lower()}" 

102 out = layers.Activation(activation.lower(), name=block_name)(input_x) 

103 self.act_number += 1 

104 return out 

105 

106 @staticmethod 

107 def _get_act_name(act_name): 

108 if isinstance(act_name, str): 

109 mapping = {'relu': 'ReLU', 'prelu': 'PReLU', 'elu': 'ELU'} 

110 return mapping.get(act_name.lower(), act_name) 

111 else: 

112 return act_name.__name__ 

113 

114 def create_pool_tower(self, input_x, pool_kernel, tower_filter, activation='relu', max_pooling=True, **kwargs): 

115 """ 

116 This function creates a "MaxPooling tower block" 

117 

118 :param input_x: Input to network part 

119 :param pool_kernel: size of pooling kernel 

120 :param tower_filter: Number of filters used in 1x1 convolution to reduce filter size 

121 :param activation: 

122 :param max_pooling: 

123 :return: 

124 """ 

125 self.part_of_block += 1 

126 self.act_number = 1 

127 act_settings = kwargs.get('act_settings', {}) 

128 padding = kwargs.get('padding', 'ZeroPad2D') 

129 padding_size = PadUtils.get_padding_for_same(kernel_size=pool_kernel) 

130 

131 # pooling block 

132 block_name = f"Block_{self.number_of_blocks}{self.block_part_name()}_" 

133 if max_pooling: 

134 block_type = "MaxPool" 

135 pooling = layers.MaxPooling2D 

136 else: 

137 block_type = "AvgPool" 

138 pooling = layers.AveragePooling2D 

139 

140 tower = Padding2D(padding)(padding=padding_size, name=block_name + 'Pad')(input_x) 

141 tower = pooling(pool_kernel, strides=(1, 1), padding='valid', name=block_name + block_type)(tower) 

142 

143 # convolution block 

144 tower = layers.Conv2D(tower_filter, (1, 1), padding='valid', name=block_name + "1x1")(tower) 

145 tower = self.act(tower, activation, **act_settings) 

146 

147 return tower 

148 

149 def inception_block(self, input_x, tower_conv_parts, tower_pool_parts, **kwargs): 

150 """ 

151 Crate a inception block 

152 

153 :param input_x: Input to block 

154 :param tower_conv_parts: dict containing settings for parts of inception block; Example: 

155 tower_conv_parts = {'tower_1': {'reduction_filter': 32, 

156 'tower_filter': 64, 

157 'tower_kernel': (3, 1), 

158 'activation' : 'relu', 

159 'padding' : 'SymPad2D'} 

160 'tower_2': {'reduction_filter': 32, 

161 'tower_filter': 64, 

162 'tower_kernel': (5, 1), 

163 'activation' : LeakyReLU, 

164 'padding' : keras.layers.ZeroPadding2D} 

165 'tower_3': {'reduction_filter': 32, 

166 'tower_filter': 64, 

167 'tower_kernel': (1, 1), 

168 'activation' : ELU, 

169 'padding' : src.model_modules.advanced_paddings.ReflectionPadding2D} 

170 } 

171 :param tower_pool_parts: dict containing settings for pool part of inception block; Example: 

172 tower_pool_parts = {'pool_kernel': (3, 1), 'tower_filter': 64, 'padding': 'RefPad2D'} 

173 :return: 

174 """ 

175 self.number_of_blocks += 1 

176 self.part_of_block = 0 

177 tower_build = {} 

178 block_name = f"Block_{self.number_of_blocks}" 

179 for part, part_settings in tower_conv_parts.items(): 

180 tower_build[part] = self.create_conv_tower(input_x, **part_settings, **kwargs) 

181 if 'max_pooling' in tower_pool_parts.keys(): 

182 max_pooling = tower_pool_parts.get('max_pooling') 

183 if not isinstance(max_pooling, bool): 

184 raise AttributeError(f"max_pooling has to be either a bool or empty. Given was: {max_pooling}") 

185 pool_name = '{}pool'.format('max' if max_pooling else 'avg') 

186 tower_build[pool_name] = self.create_pool_tower(input_x, **tower_pool_parts, **kwargs) 

187 else: 

188 tower_build['maxpool'] = self.create_pool_tower(input_x, **tower_pool_parts, **kwargs) 

189 tower_build['avgpool'] = self.create_pool_tower(input_x, **tower_pool_parts, **kwargs, max_pooling=False) 

190 

191 block = keras.layers.concatenate(list(tower_build.values()), axis=3, 

192 name=block_name + "_Co") 

193 return block 

194 

195 

196if __name__ == '__main__': 

197 print(__name__) 

198 from keras.datasets import cifar10 

199 from keras.utils import np_utils 

200 from keras.layers import Input 

201 from keras.layers.advanced_activations import LeakyReLU, ELU 

202 from keras.optimizers import SGD 

203 from keras.layers import Dense, Flatten, Conv2D, MaxPooling2D 

204 from keras.models import Model 

205 

206 # network settings 

207 conv_settings_dict = {'tower_1': {'reduction_filter': 64, 

208 'tower_filter': 64, 

209 'tower_kernel': (3, 3), 

210 'activation': LeakyReLU, }, 

211 'tower_2': {'reduction_filter': 64, 

212 'tower_filter': 64, 

213 'tower_kernel': (5, 5), 

214 'activation': 'relu', 

215 'padding': 'SymPad2D'}, 

216 'tower_3': {'reduction_filter': 64, 

217 'tower_filter': 64, 

218 'tower_kernel': (7, 7), 

219 'activation': ELU, 

220 'padding': ReflectionPadding2D} 

221 } 

222 pool_settings_dict = {'pool_kernel': (3, 3), 

223 'tower_filter': 64, 

224 'activation': 'relu'} 

225 

226 # load data 

227 (X_train, y_train), (X_test, y_test) = cifar10.load_data() 

228 X_train = X_train.astype('float32') 

229 X_test = X_test.astype('float32') 

230 X_train = X_train / 255.0 

231 X_test = X_test / 255.0 

232 y_train = np_utils.to_categorical(y_train) 

233 y_test = np_utils.to_categorical(y_test) 

234 input_img = Input(shape=(32, 32, 3)) 

235 

236 # create inception net 

237 inception_net = InceptionModelBase() 

238 output = inception_net.inception_block(input_img, conv_settings_dict, pool_settings_dict, batch_normalisation=True) 

239 output = Flatten()(output) 

240 output = Dense(10, activation='softmax')(output) 

241 model = Model(inputs=input_img, outputs=output) 

242 print(model.summary()) 

243 

244 # compile 

245 epochs = 1 

246 lrate = 0.01 

247 decay = lrate / epochs 

248 sgd = SGD(lr=lrate, momentum=0.9, decay=decay, nesterov=False) 

249 model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy']) 

250 print(X_train.shape) 

251 keras.utils.plot_model(model, to_file='model.pdf', show_shapes=True, show_layer_names=True) 

252 # model.fit(X_train, y_train, epochs=epochs, validation_data=(X_test, y_test)) 

253 print('test')