예제 #1
0
	def __init__(self):

		self.config_file = None
		self.io = EmbeddingIO(None)
		self.init = False
		self.cfgs = None
		self.loss_functions = ObjectiveFunctions()
예제 #2
0
class InceptionV3_finetune():
    def __init__(self):

        self.layer_list = []
        self.config_file = None
        self.io = EmbeddingIO(None)
        self.init = False
        self.cfgs = None
        self.loss_functions = ObjectiveFunctions()

    #def

    def configure(self, config_file):

        self.config_file = config_file
        self.init = False

        if not os.path.exists(self.config_file):
            self.io.print_error(
                'Could not find config file for InceptionV3 {0}'.format(
                    self.config_file))
            self.init = False
            return
        #if

        pfile = open(self.config_file, 'r')
        self.cfgs = yaml.load(pfile)
        self.betas = random_float(0, 20,
                                  self.cfgs['n_channels_partClassifiers'])
        pfile.close()
        #Tracer()()
        self.init = True

    #def

    def add_to_graph(self, *args, **kwargs):

        self.model.add_node(*args, **kwargs)
        self.last_added_node = kwargs['name']

        self.layer_list.append(kwargs['name'])

        return kwargs['name']

    #def

    def add_bn_conv_layer(self, *args, **kwargs):

        layer_name = kwargs['name']
        input_layer = kwargs['input']

        del kwargs['name']
        del kwargs['input']

        if 'padding' in kwargs:
            layer_name = layer_name + '_pad'
            self.add_to_graph(ZeroPadding2D(padding=kwargs['padding']),
                              name=layer_name,
                              input=input_layer)
            input_layer = layer_name
            del kwargs['padding']
        #if

        # CONV with linear activation by default
        layer_name = layer_name + '_conv'
        self.add_to_graph(Convolution2D(*args, border_mode='valid', **kwargs),
                          name=layer_name,
                          input=input_layer)

        # Batch normalization added directly on output of a linear layer
        input_layer = layer_name
        layer_name = layer_name + '_bn'
        _ = self.add_to_graph(BatchNormalization(mode=0,
                                                 epsilon=0.0001,
                                                 axis=1),
                              name=layer_name,
                              input=input_layer)

        # Standard normalization
        input_layer = layer_name
        layer_name = layer_name + '_nonlin'
        _ = self.add_to_graph(Activation('relu'),
                              name=layer_name,
                              input=input_layer)

        return layer_name

    #def

    def add_inceptionA(self, input_layer, list_nb_filter, base_name):

        l1_1 = self.add_bn_conv_layer(name=base_name + '_l1_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[0][0],
                                      nb_row=1,
                                      nb_col=1)

        l2_1 = self.add_bn_conv_layer(name=base_name + '_l2_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[1][0],
                                      nb_row=1,
                                      nb_col=1)
        l2_2 = self.add_bn_conv_layer(name=base_name + '_l2_2',
                                      input=l2_1,
                                      nb_filter=list_nb_filter[1][1],
                                      nb_row=5,
                                      nb_col=5,
                                      padding=(2, 2))

        l3_1 = self.add_bn_conv_layer(name=base_name + '_l3_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[2][0],
                                      nb_row=1,
                                      nb_col=1)
        l3_2 = self.add_bn_conv_layer(name=base_name + '_l3_2',
                                      input=l3_1,
                                      nb_filter=list_nb_filter[2][1],
                                      nb_row=3,
                                      nb_col=3,
                                      padding=(1, 1))
        l3_3 = self.add_bn_conv_layer(name=base_name + '_l3_3',
                                      input=l3_2,
                                      nb_filter=list_nb_filter[2][2],
                                      nb_row=3,
                                      nb_col=3,
                                      padding=(1, 1))

        l4_1 = self.add_to_graph(ZeroPadding2D(padding=(1, 1)),
                                 name=base_name + '_14_1',
                                 input=input_layer)
        l4_2 = self.add_to_graph(AveragePooling2D(pool_size=(3, 3),
                                                  strides=(1, 1)),
                                 name=base_name + '_14_2',
                                 input=l4_1)
        l4_3 = self.add_bn_conv_layer(name=base_name + '_l4_3',
                                      input=l4_2,
                                      nb_filter=list_nb_filter[3][0],
                                      nb_row=1,
                                      nb_col=1)

        self.add_to_graph(Activation("linear"),
                          name=base_name,
                          inputs=[l1_1, l2_2, l3_3, l4_3],
                          merge_mode="concat",
                          concat_axis=1)

        self.io.print_info('Added Inception-A {0}'.format(base_name))
        # https://github.com/fchollet/keras/issues/391

    def add_inceptionB(self, input_layer, list_nb_filter, base_name):

        l1_1 = self.add_bn_conv_layer(name=base_name + '_l1_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[0][0],
                                      nb_row=3,
                                      nb_col=3,
                                      subsample=(2, 2))

        l2_1 = self.add_bn_conv_layer(name=base_name + '_l2_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[1][0],
                                      nb_row=1,
                                      nb_col=1)
        l2_2 = self.add_bn_conv_layer(name=base_name + '_l2_2',
                                      input=l2_1,
                                      nb_filter=list_nb_filter[1][1],
                                      nb_row=3,
                                      nb_col=3,
                                      padding=(1, 1))
        l2_3 = self.add_bn_conv_layer(name=base_name + '_l2_3',
                                      input=l2_2,
                                      nb_filter=list_nb_filter[1][2],
                                      nb_row=3,
                                      nb_col=3,
                                      subsample=(2, 2))

        l3_1 = self.add_to_graph(MaxPooling2D(pool_size=(3, 3),
                                              strides=(2, 2)),
                                 name=base_name + '_13_1',
                                 input=input_layer)

        self.add_to_graph(Activation("linear"),
                          name=base_name,
                          inputs=[l1_1, l2_3, l3_1],
                          merge_mode="concat",
                          concat_axis=1)

        self.io.print_info('Added Inception-B {0}'.format(base_name))
        # https://github.com/fchollet/keras/issues/391

    def add_inceptionC(self, input_layer, list_nb_filter, base_name):

        l1_1 = self.add_bn_conv_layer(name=base_name + '_l1_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[0][0],
                                      nb_row=1,
                                      nb_col=1)

        l2_1 = self.add_bn_conv_layer(name=base_name + '_l2_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[1][0],
                                      nb_row=1,
                                      nb_col=1)
        l2_2 = self.add_bn_conv_layer(name=base_name + '_l2_2',
                                      input=l2_1,
                                      nb_filter=list_nb_filter[1][1],
                                      nb_row=1,
                                      nb_col=7,
                                      padding=(0, 3))
        l2_3 = self.add_bn_conv_layer(name=base_name + '_l2_3',
                                      input=l2_2,
                                      nb_filter=list_nb_filter[1][2],
                                      nb_row=7,
                                      nb_col=1,
                                      padding=(3, 0))
        ## padding and nb_row might not match with the lasagne weights

        l3_1 = self.add_bn_conv_layer(name=base_name + '_l3_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[2][0],
                                      nb_row=1,
                                      nb_col=1)
        l3_2 = self.add_bn_conv_layer(name=base_name + '_l3_2',
                                      input=l3_1,
                                      nb_filter=list_nb_filter[2][1],
                                      nb_row=7,
                                      nb_col=1,
                                      padding=(3, 0))
        l3_3 = self.add_bn_conv_layer(name=base_name + '_l3_3',
                                      input=l3_2,
                                      nb_filter=list_nb_filter[2][2],
                                      nb_row=1,
                                      nb_col=7,
                                      padding=(0, 3))
        l3_4 = self.add_bn_conv_layer(name=base_name + '_l3_4',
                                      input=l3_3,
                                      nb_filter=list_nb_filter[2][3],
                                      nb_row=7,
                                      nb_col=1,
                                      padding=(3, 0))
        l3_5 = self.add_bn_conv_layer(name=base_name + '_l3_5',
                                      input=l3_4,
                                      nb_filter=list_nb_filter[2][4],
                                      nb_row=1,
                                      nb_col=7,
                                      padding=(0, 3))

        l4_1 = self.add_to_graph(ZeroPadding2D(padding=(1, 1)),
                                 name=base_name + '_14_1',
                                 input=input_layer)
        l4_2 = self.add_to_graph(AveragePooling2D(pool_size=(3, 3),
                                                  strides=(1, 1)),
                                 name=base_name + '_14_2',
                                 input=l4_1)
        l4_3 = self.add_bn_conv_layer(name=base_name + '_l4_3',
                                      input=l4_2,
                                      nb_filter=list_nb_filter[3][0],
                                      nb_row=1,
                                      nb_col=1)

        self.add_to_graph(Activation("linear"),
                          name=base_name,
                          inputs=[l1_1, l2_3, l3_5, l4_3],
                          merge_mode="concat",
                          concat_axis=1)

        self.io.print_info('Added Inception-C {0}'.format(base_name))
        # https://github.com/fchollet/keras/issues/391

    def add_inceptionD(self, input_layer, list_nb_filter, base_name):

        l1_1 = self.add_bn_conv_layer(name=base_name + '_l1_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[0][0],
                                      nb_row=1,
                                      nb_col=1)
        l1_2 = self.add_bn_conv_layer(name=base_name + '_l1_2',
                                      input=l1_1,
                                      nb_filter=list_nb_filter[0][1],
                                      nb_row=3,
                                      nb_col=3,
                                      subsample=(2, 2))

        l2_1 = self.add_bn_conv_layer(name=base_name + '_l2_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[1][0],
                                      nb_row=1,
                                      nb_col=1)
        l2_2 = self.add_bn_conv_layer(name=base_name + '_l2_2',
                                      input=l2_1,
                                      nb_filter=list_nb_filter[1][1],
                                      nb_row=1,
                                      nb_col=7,
                                      padding=(0, 3))
        l2_3 = self.add_bn_conv_layer(name=base_name + '_l2_3',
                                      input=l2_2,
                                      nb_filter=list_nb_filter[1][2],
                                      nb_row=7,
                                      nb_col=1,
                                      padding=(3, 0))
        l2_4 = self.add_bn_conv_layer(name=base_name + '_l2_4',
                                      input=l2_3,
                                      nb_filter=list_nb_filter[1][2],
                                      nb_row=3,
                                      nb_col=3,
                                      subsample=(2, 2))

        l3_1 = self.add_to_graph(MaxPooling2D(pool_size=(3, 3),
                                              strides=(2, 2)),
                                 name=base_name + '_13_1',
                                 input=input_layer)

        self.add_to_graph(Activation("linear"),
                          name=base_name,
                          inputs=[l1_2, l2_4, l3_1],
                          merge_mode="concat",
                          concat_axis=1)

        self.io.print_info('Added Inception-D {0}'.format(base_name))
        # https://github.com/fchollet/keras/issues/391

    def add_inceptionE(self, input_layer, list_nb_filter, base_name,
                       pool_mode):

        l1_1 = self.add_bn_conv_layer(name=base_name + '_l1_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[0][0],
                                      nb_row=1,
                                      nb_col=1)

        l2_1 = self.add_bn_conv_layer(name=base_name + '_l2_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[1][0],
                                      nb_row=1,
                                      nb_col=1)
        l2_2a = self.add_bn_conv_layer(name=base_name + '_l2_2a',
                                       input=l2_1,
                                       nb_filter=list_nb_filter[1][1],
                                       nb_row=1,
                                       nb_col=3,
                                       padding=(0, 1))
        l2_2b = self.add_bn_conv_layer(name=base_name + '_l2_2b',
                                       input=l2_1,
                                       nb_filter=list_nb_filter[1][1],
                                       nb_row=3,
                                       nb_col=1,
                                       padding=(1, 0))

        l3_1 = self.add_bn_conv_layer(name=base_name + '_l3_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[2][0],
                                      nb_row=1,
                                      nb_col=1)
        l3_2 = self.add_bn_conv_layer(name=base_name + '_l3_2',
                                      input=l3_1,
                                      nb_filter=list_nb_filter[2][1],
                                      nb_row=3,
                                      nb_col=3,
                                      padding=(1, 1))
        l3_3a = self.add_bn_conv_layer(name=base_name + '_l3_3a',
                                       input=l3_2,
                                       nb_filter=list_nb_filter[2][2],
                                       nb_row=1,
                                       nb_col=3,
                                       padding=(0, 1))
        l3_3b = self.add_bn_conv_layer(name=base_name + '_l3_3b',
                                       input=l3_2,
                                       nb_filter=list_nb_filter[2][3],
                                       nb_row=3,
                                       nb_col=1,
                                       padding=(1, 0))

        l4_1 = self.add_to_graph(ZeroPadding2D(padding=(1, 1)),
                                 name=base_name + '_14_1',
                                 input=input_layer)
        l4_2 = self.add_to_graph(pooling_dict[pool_mode](pool_size=(3, 3),
                                                         strides=(1, 1)),
                                 name=base_name + '_14_2',
                                 input=l4_1)
        l4_3 = self.add_bn_conv_layer(name=base_name + '_l4_3',
                                      input=l4_2,
                                      nb_filter=list_nb_filter[3][0],
                                      nb_row=1,
                                      nb_col=1)

        self.add_to_graph(Activation("linear"),
                          name=base_name,
                          inputs=[l1_1, l2_2a, l2_2b, l3_3a, l3_3b, l4_3],
                          merge_mode="concat",
                          concat_axis=1)

        self.io.print_info('Added Inception-E {0}'.format(base_name))
        # https://github.com/fchollet/keras/issues/391

    def define(self):

        try:

            self.model = Graph()
            #self.model.add_input(name='input',  input_shape=(self.cfgs['n_channels'], self.cfgs['image_height'], self.cfgs['image_width']))
            self.model.add_input(name='input',
                                 input_shape=(self.cfgs['n_channels'], None,
                                              None))

            #
            # Part of the network which is defined in the config file should move here
            #

            cgfs_nodes = self.cfgs['nodes']

            for node in cgfs_nodes:

                if not node['type'] == 'Activation':
                    self.add_to_graph(
                        layer_dict[node['type']](**node['parameter']),
                        name=node['name'],
                        input=node['input'])
                else:
                    self.add_to_graph(layer_dict[node['type']](
                        node['parameter']['mode']),
                                      name=node['name'],
                                      input=node['input'])
                #if

                self.io.print_info('Added {1}:{0}'.format(
                    node['type'], node['name']))

            #for

            self.add_inceptionA(input_layer=self.last_added_node,
                                list_nb_filter=((64, ), (48, 64), (64, 96, 96),
                                                (32, )),
                                base_name='mixed')
            self.add_inceptionA(input_layer=self.last_added_node,
                                list_nb_filter=((64, ), (48, 64), (64, 96, 96),
                                                (64, )),
                                base_name='mixed_1')
            self.add_inceptionA(input_layer=self.last_added_node,
                                list_nb_filter=((64, ), (48, 64), (64, 96, 96),
                                                (64, )),
                                base_name='mixed_2')

            self.add_inceptionB(input_layer=self.last_added_node,
                                list_nb_filter=((384, ), (64, 96, 96)),
                                base_name='mixed_3')

            self.add_inceptionC(input_layer=self.last_added_node,
                                list_nb_filter=((192, ), (128, 128, 192),
                                                (128, 128, 128, 128,
                                                 192), (192, )),
                                base_name='mixed_4')
            self.add_inceptionC(input_layer=self.last_added_node,
                                list_nb_filter=((192, ), (160, 160, 192),
                                                (160, 160, 160, 160,
                                                 192), (192, )),
                                base_name='mixed_5')
            self.add_inceptionC(input_layer=self.last_added_node,
                                list_nb_filter=((192, ), (160, 160, 192),
                                                (160, 160, 160, 160,
                                                 192), (192, )),
                                base_name='mixed_6')
            self.add_inceptionC(input_layer=self.last_added_node,
                                list_nb_filter=((192, ), (192, 192, 192),
                                                (192, 192, 192, 192,
                                                 192), (192, )),
                                base_name='mixed_7')

            self.add_inceptionD(input_layer=self.last_added_node,
                                list_nb_filter=((192, 320), (192, 192, 192,
                                                             192)),
                                base_name='mixed_8')

            self.add_inceptionE(input_layer=self.last_added_node,
                                list_nb_filter=((320, ), (384, 384, 384),
                                                (448, 384, 384, 384), (192, )),
                                pool_mode='average',
                                base_name='mixed_9')
            self.add_inceptionE(input_layer=self.last_added_node,
                                list_nb_filter=((320, ), (384, 384, 384),
                                                (448, 384, 384, 384), (192, )),
                                pool_mode='max',
                                base_name='mixed_10')

            #self.add_to_graph(AveragePooling2D(pool_size=(5,5)), name='pool3', input=self.last_added_node)
            #self.io.print_info('Added {1}:{0}'.format('AveragePooling',self.last_added_node))
            """
			self.add_to_graph(Flatten(), name='flatten', input='pool3')
			self.io.print_info('Added {1}:{0}'.format('Flatten',self.last_added_node))

			self.add_to_graph(Dense(self.cfgs['nb_classes']), name='softmax', input='flatten')
			self.io.print_info('Added {1}:{0}'.format('Dense',self.last_added_node))
			"""
            #print 'Adding finetuning layers'---------------------------------------------------------------------------------------

            self.add_to_graph(BatchNormalization(mode=0,
                                                 epsilon=0.0001,
                                                 axis=1),
                              name='batchnorm',
                              input=self.last_added_node)
            self.io.print_info('Added {1}:{0}'.format(
                'BatchNormalization before finetuning', self.last_added_node))

            self.add_to_graph(Convolution2D(
                self.cfgs['n_channels_partClassifiers'], 1, 1),
                              name='partClassifiers',
                              input=self.last_added_node)
            self.io.print_info('Added {1}:{0}'.format('partClassifiers',
                                                      self.last_added_node))

            self.add_to_graph(Activation('relu'),
                              name='relu_on_partClassifiers',
                              input=self.last_added_node)
            self.io.print_info('Added {1}:{0}'.format(
                'ReLu on partClassifiers', self.last_added_node))

            if self.cfgs['pooling_AtfineTuning'] == 'avg':
                self.add_to_graph(global_Average_Pooling(),
                                  name='custom_pool',
                                  input=self.last_added_node)
                self.io.print_info('Added {1}:{0}'.format(
                    'Custom Pooling Layer:' +
                    self.cfgs['pooling_AtfineTuning'], self.last_added_node))
            elif self.cfgs['pooling_AtfineTuning'] == 'softpool':
                self.add_to_graph(power_mean_Layer(self.betas),
                                  name='custom_pool',
                                  input=self.last_added_node)  # Learnable
                self.io.print_info('Added {1}:{0}'.format(
                    'Custom Pooling Layer:' +
                    self.cfgs['pooling_AtfineTuning'], self.last_added_node))

            self.add_to_graph(Flatten(),
                              name='flatten',
                              input=self.last_added_node)
            self.io.print_info('Added {1}:{0}'.format('Flatten',
                                                      self.last_added_node))

            self.add_to_graph(Dense(self.cfgs['nb_classes']),
                              name='softmax',
                              input=self.last_added_node)  #Learnable
            self.io.print_info('Added {1}:{0}'.format('Softmax-dense weights',
                                                      self.last_added_node))

            self.add_to_graph(Activation(self.cfgs['activation']),
                              name='prob',
                              input=self.last_added_node)
            self.io.print_info('Added {1}:{0}'.format('Activation',
                                                      self.last_added_node))

            #Harsimrat original architecture ---------------------------------------------------------------------------------------

            # self.add_to_graph(AveragePooling2D(pool_size=(5,5)), name='pool3', input=self.last_added_node)
            # self.io.print_info('Added {1}:{0}'.format('AveragePooling',self.last_added_node))

            # """
            # self.add_to_graph(Flatten(), name='flatten', input='pool3')
            # self.io.print_info('Added {1}:{0}'.format('Flatten',self.last_added_node))
            # self.add_to_graph(Dense(self.cfgs['nb_classes']), name='softmax', input='flatten')
            # self.io.print_info('Added {1}:{0}'.format('Dense',self.last_added_node))
            # """

            # self.add_to_graph(Convolution2D(self.cfgs['nb_classes'],1,1),name='softmax',input='pool3')

            # self.add_to_graph(Activation(self.cfgs['activation']), name='prob', input='softmax')

            #Adding dense finetunning layers
            #Re
            # Output to the Graph
            self.model.add_output(name='output', input='prob')
            #Tracer()()
            if not self.cfgs['model_weights_file'] == 'None':
                #import ipdb; ipdb.set_trace()
                self.init_from_this()
                #import ipdb; ipdb.set_trace()
            #if

        except Exception as err:

            self.io.print_error('Error configuring the model, {0}'.format(err))
            self.init = False
            return

        #try

        self.init = True

    #def

    def init_from_this(self):

        weights_file = self.cfgs['model_weights_file']
        #Tracer()()
        if not weights_file == 'None':
            self.load_weights(weights_file)
            self.io.print_info(
                'Weights Initalized from {0}'.format(weights_file))
        #if

    #def

    def load_weights(self, filepath):

        #Tracer()()
        if filepath.endswith('.npz'):
            pfile = open(filepath, 'r')
            graph = np.load(pfile)['graph'].item()

            for node_name, weights in graph.items():

                if node_name in self.cfgs['ignore_while_loading']:
                    self.io.print_warning(
                        'Ignoring weights from {0}'.format(node_name))
                    continue
                #if

                self.io.print_info(
                    'Transfering parameters from {0}'.format(node_name))
                self.model.nodes[node_name].set_weights(weights)

            #for

            pfile.close()
        elif filepath.endswith('.npy'):
            pfile = open(filepath, 'r')
            graph = np.load(pfile).item()

            for node_name, weights in graph.items():

                if node_name in self.cfgs['ignore_while_loading']:
                    self.io.print_warning(
                        'Ignoring weights from {0}'.format(node_name))
                    continue
                #if

                self.io.print_info(
                    'Transfering parameters from {0}'.format(node_name))
                self.model.nodes[node_name].set_weights(weights)

            #for

            pfile.close()
        elif filepath.endswith('.hdf5'):

            self.model.load_weights(filepath)
        else:
            self.io.print_error(
                'Unknown model weights file {}'.format(filepath))
        #if

        self.io.print_info(self.model.nodes['softmax'].get_config())

    #def

    def setup_loss_function(self, w):

        self.loss_functions.set_weights(w)

    #def

    def compile(self, compile_cfgs):

        try:

            #opt = optimizer_dict[compile_cfgs['optimizer']](lr=compile_cfgs['lr'], epsilon=compile_cfgs['epsilon'])
            opt = SGD(lr=compile_cfgs['lr'])
            #model_layer = dict([(ler.name, layer) for layer in self.model.layesrs])

            for layer_name, model_layer in self.model.nodes.items():
                if layer_name not in self.cfgs['trainable_layers']:
                    model_layer.trainable = False
                else:
                    self.io.print_info(
                        'Trainable Layer: {0}'.format(layer_name))

            self.model.compile(loss={
                'output':
                self.loss_functions.dict[compile_cfgs['loss']]
            },
                               optimizer=opt)

        except Exception as e:
            self.io.print_error('Error configuring the model, {0}'.format(e))
            self.init = False
            return
        #try

        self.init = True

    def get_model(self):
        return self.model
예제 #3
0
class GoogleNet():

	def __init__(self):

		self.layer_list = []
		self.config_file = None
		self.io = EmbeddingIO(None)
		self.init = False
		self.cfgs = None
		self.loss_functions = ObjectiveFunctions()

	#def

	def configure(self,config_file):

		self.config_file = config_file
		self.init = False

		if not os.path.exists(self.config_file):
			self.io.print_error('Could not find config file for GoogLeNet {0}'.format(self.config_file))
			self.init = False
			return
		#if

		pfile = open(self.config_file,'r')
		self.cfgs = yaml.load(pfile)
		pfile.close()

		self.init = True

	#def

	def add_to_graph(self, *args, **kwargs):

		self.model.add_node(*args, **kwargs)
		self.last_added_node = kwargs['name']

		self.layer_list.append(kwargs['name'])

		return kwargs['name']

	#def

	def add_bn_conv_layer(self, *args, **kwargs):

		layer_name = kwargs['name']
		input_layer = kwargs['input']

		del kwargs['name']
		del kwargs['input']

		kwargs['border_mode'] = 'same'

		if 'padding' in kwargs:
			layer_name = layer_name + '_pad'
			self.add_to_graph(ZeroPadding2D(padding=kwargs['padding']), name=layer_name, input=input_layer)
			input_layer = layer_name
			del kwargs['padding']
		#if

		# CONV with linear activation by default
		layer_name = layer_name + '_conv'
		self.add_to_graph(Convolution2D(*args, **kwargs), name=layer_name, input=input_layer)

		# Batch normalization added directly on output of a linear layer
		input_layer = layer_name
		layer_name = layer_name + '_bn'
		_ = self.add_to_graph(BatchNormalization(mode=0, epsilon=0.0001, axis=1), name=layer_name, input=input_layer)

		# Standard normalization
		input_layer = layer_name
		layer_name = layer_name + '_nonlin'
		_ = self.add_to_graph(Activation('relu'), name=layer_name, input=input_layer)

		return layer_name

	#def

	def add_inception(self, input_layer, list_nb_filter, base_name):

		tower_1_1 = self.add_bn_conv_layer(name=base_name+'tower_1_1', input=input_layer, nb_filter=list_nb_filter[0], nb_row=1, nb_col=1)

		tower_2_1 = self.add_bn_conv_layer(name=base_name+'tower_2_1', input=input_layer, nb_filter=list_nb_filter[1], nb_row=1, nb_col=1)
		tower_2_2 = self.add_bn_conv_layer(name=base_name+'tower_2_2', input=tower_2_1, nb_filter=list_nb_filter[2], nb_row=3, nb_col=3)

		tower_3_1 = self.add_bn_conv_layer(name=base_name+'tower_3_1', input=input_layer, nb_filter=list_nb_filter[3], nb_row=1, nb_col=1)
		tower_3_2 = self.add_bn_conv_layer(name=base_name+'tower_3_2', input=tower_3_1, nb_filter=list_nb_filter[4], nb_row=5, nb_col=5)

		tower_4_1 = self.add_to_graph(MaxPooling2D((3, 3), strides=(1, 1), border_mode='same'), name=base_name+'tower_4_1', input=input_layer)
		tower_4_2 = self.add_bn_conv_layer(name=base_name+'tower_4_2', input=tower_4_1, nb_filter=list_nb_filter[5], nb_row=1, nb_col=1)

		self.add_to_graph(Activation("linear"), name=base_name, inputs=[tower_1_1,tower_2_2,tower_3_2,tower_4_2], merge_mode="concat", concat_axis=1)

		self.io.print_info('Added Inception {0}'.format(base_name))

	def define(self):

		try:

			self.model = Graph()
			self.model.add_input(name='input', input_shape=(self.cfgs['n_channels'], self.cfgs['image_height'], self.cfgs['image_width']))

			pad_1 = self.add_to_graph(ZeroPadding2D((3,3)), name='pad_1',input='input')
			conv_1 = self.add_bn_conv_layer(name='conv_1', input=self.last_added_node, nb_filter=64, nb_row=7, nb_col=7,subsample=(2,2))

			pad_2 = self.add_to_graph(ZeroPadding2D((1,1)), name='pad_2',input=self.last_added_node)
			max_1 = self.add_to_graph(MaxPooling2D(pool_size=(3,3), strides=(2,2)), name='max_1', input=self.last_added_node)

			pad_3 = self.add_to_graph(ZeroPadding2D((1,1)), name='pad_3', input=self.last_added_node)
			conv_2 = self.add_bn_conv_layer( name='conv_2', input=self.last_added_node, nb_filter=192, nb_row=3, nb_col=3 )

			pad_4 = self.add_to_graph(ZeroPadding2D((1,1)), name='pad_4', input=self.last_added_node)
			max_2 = self.add_to_graph(MaxPooling2D(pool_size=(3,3), strides=(2,2)), name='max_2', input=self.last_added_node)

			#Inception_layer 1
			nb_kernel_inception_1=[64,96,128,16,32,32]
			self.add_inception(self.last_added_node,nb_kernel_inception_1,'inception_1')

			#Inception_layer 2
			nb_kernel_inception_2=[128,128,192,32,96,64]
			self.add_inception(self.last_added_node,nb_kernel_inception_2,'inception_2')

			pad_5 = self.add_to_graph(ZeroPadding2D((1,1)), name='pad_5', input=self.last_added_node)
			max_3 = self.add_to_graph(MaxPooling2D(pool_size=(3,3), strides=(2,2)), name='max_3', input=self.last_added_node)

			#Inception_layer 3
			nb_kernel_inception_3=[192,96,208,16,48,64]
			self.add_inception(self.last_added_node,nb_kernel_inception_3,'inception_3')

			#Inception_layer 4
			nb_kernel_inception_4=[160,112,224,24,64,64]
			self.add_inception(self.last_added_node,nb_kernel_inception_4,'inception_4')

			#Inception_layer 5
			nb_kernel_inception_5=[128,128,256,24,64,64]
			self.add_inception(self.last_added_node,nb_kernel_inception_5,'inception_5')

			#Inception_layer 6
			nb_kernel_inception_6=[112,144,288,32,64,64]
			self.add_inception(self.last_added_node,nb_kernel_inception_6,'inception_6')

			#Inception_layer 7
			nb_kernel_inception_7=[256,160,320,32,128,128]
			self.add_inception(self.last_added_node,nb_kernel_inception_7,'inception_7')

			pad_6 = self.add_to_graph(ZeroPadding2D((1,1)), name='pad_6', input=self.last_added_node)
			max_4 = self.add_to_graph(MaxPooling2D(pool_size=(3,3), strides=(2,2)), name='max_4', input=self.last_added_node)

			#Inception_layer 8
			nb_kernel_inception_8=[256,160,320,32,128,128]
			self.add_inception(self.last_added_node,nb_kernel_inception_8,'inception_8')

			#Inception_layer 9
			nb_kernel_inception_9=[384,192,384,48,128,128]
			self.add_inception(self.last_added_node,nb_kernel_inception_9,'inception_9')

			self.add_to_graph(AveragePooling2D((7,7)), name='pool_1', input=self.last_added_node)

			self.add_to_graph(Flatten(), name='flatten', input='pool_1')

			self.add_to_graph(Dense(self.cfgs['nb_classes']), name='logits', input='flatten')
			self.add_to_graph(Activation(self.cfgs['activation']), name='prob', input='logits')

			# Output to the Graph
			self.model.add_output(name='output', input='prob')

			self.init_from_this()

		except Exception as err:

			self.io.print_error('Error configuring the model, {0}'.format(err))
			self.init = False
			return

		#try

		self.init = True

	#def

	def init_from_this(self):

		weights_file = self.cfgs['model_weights_file']

		if not weights_file == 'None':
			self.load_weights(weights_file)
			self.io.print_info('Weights Initalized from {0}'.format(weights_file))
		#if

	#def

	def load_weights(self, filepath):

		if filepath.endswith('.npz'):
			pfile = open(filepath,'r')
			graph = np.load(pfile)['graph'].item()

			for node_name,weights in graph.items():

				if node_name in self.cfgs['ignore_while_loading']:
					self.io.print_warning('Ignoring weights from {0}'.format(node_name))
					continue
				#if

				self.io.print_info('Transfering parameters from {0}'.format(node_name))
				self.model.nodes[node_name].set_weights(weights)

			#for

			pfile.close()

		elif filepath.endswith('.hdf5'):
			self.model.load_weights(filepath)
		else:
			self.io.print_error('Unknown model weights file {}'.format(filepath))
		#if

		self.io.print_info(self.model.nodes['prob'].get_config())

	def setup_loss_function(self,w):

		self.loss_functions.set_weights(w)

	#def

	def compile(self,compile_cfgs):

		try:
			opt = optimizer_dict[compile_cfgs['optimizer']](lr=compile_cfgs['lr'], epsilon=compile_cfgs['epsilon'])
			self.model.compile(loss={'output':self.loss_functions.dict[compile_cfgs['loss']]}, optimizer=opt)
		except Exception as e:
			self.io.print_error('Error configuring the model, {0}'.format(e))
			self.init = False
			return
		#try

		self.init = True
예제 #4
0
class VGG19():

	def __init__(self):

		self.config_file = None
		self.io = EmbeddingIO(None)
		self.init = False
		self.cfgs = None
		self.loss_functions = ObjectiveFunctions()

	#def

	def configure(self,config_file):

		self.config_file = config_file
		self.init = False

		if not os.path.exists(self.config_file):
			self.io.print_error('Could not find config file for VGG-19 {0}'.format(self.config_file))
			self.init = False
			return
		#if

		pfile = open(self.config_file,'r')
		self.cfgs = yaml.load(pfile)
		pfile.close()

		self.init = True

	#def

	def define(self):

		#
		# TODO : get the filter size, number of filters, reception field size from yaml file
		#

		try:

			self.model = Sequential()

			# C1

			self.model.add(ZeroPadding2D((1,1),input_shape=(self.cfgs['n_channels'], self.cfgs['image_height'], self.cfgs['image_width'])))
			self.model.add(Convolution2D(64, 3, 3, init=self.cfgs['conv_init']))
			self.model.add(Activation(self.cfgs['conv_non_linearity']))

			self.model.add(ZeroPadding2D((1,1)))
			self.model.add(Convolution2D(64, 3, 3,init=self.cfgs['conv_init']))
			self.model.add(Activation(self.cfgs['conv_non_linearity']))

			self.model.add(MaxPooling2D(pool_size=(2, 2),strides=(2,2)))
			# C1

			# C2
			self.model.add(ZeroPadding2D((1,1)))
			self.model.add(Convolution2D(128, 3, 3,init=self.cfgs['conv_init']))
			self.model.add(Activation(self.cfgs['conv_non_linearity']))

			self.model.add(ZeroPadding2D((1,1)))
			self.model.add(Convolution2D(128, 3, 3,init=self.cfgs['conv_init']))
			self.model.add(Activation(self.cfgs['conv_non_linearity']))

			self.model.add(MaxPooling2D(pool_size=(2, 2),strides=(2,2)))
			# C2

			# C3
			self.model.add(ZeroPadding2D((1,1)))
			self.model.add(Convolution2D(256, 3, 3,init=self.cfgs['conv_init']))
			self.model.add(Activation(self.cfgs['conv_non_linearity']))

			self.model.add(ZeroPadding2D((1,1)))
			self.model.add(Convolution2D(256, 3, 3,init=self.cfgs['conv_init']))
			self.model.add(Activation(self.cfgs['conv_non_linearity']))

			self.model.add(ZeroPadding2D((1,1)))
			self.model.add(Convolution2D(256, 3, 3,init=self.cfgs['conv_init']))
			self.model.add(Activation(self.cfgs['conv_non_linearity']))

			self.model.add(ZeroPadding2D((1,1)))
			self.model.add(Convolution2D(256, 3, 3,init=self.cfgs['conv_init']))
			self.model.add(Activation(self.cfgs['conv_non_linearity']))

			self.model.add(MaxPooling2D(pool_size=(2, 2),strides=(2,2)))
			# C3

			# C4
			self.model.add(ZeroPadding2D((1,1)))
			self.model.add(Convolution2D(512, 3, 3,init=self.cfgs['conv_init']))
			self.model.add(Activation(self.cfgs['conv_non_linearity']))

			self.model.add(ZeroPadding2D((1,1)))
			self.model.add(Convolution2D(512, 3, 3,init=self.cfgs['conv_init']))
			self.model.add(Activation(self.cfgs['conv_non_linearity']))

			self.model.add(ZeroPadding2D((1,1)))
			self.model.add(Convolution2D(512, 3, 3,init=self.cfgs['conv_init']))
			self.model.add(Activation(self.cfgs['conv_non_linearity']))

			self.model.add(ZeroPadding2D((1,1)))
			self.model.add(Convolution2D(512, 3, 3,init=self.cfgs['conv_init']))
			self.model.add(Activation(self.cfgs['conv_non_linearity']))

			self.model.add(MaxPooling2D(pool_size=(2, 2),strides=(2,2)))
			# C4

			# C5
			self.model.add(ZeroPadding2D((1,1)))
			self.model.add(Convolution2D(512, 3, 3,init=self.cfgs['conv_init']))
			self.model.add(Activation(self.cfgs['conv_non_linearity']))

			self.model.add(ZeroPadding2D((1,1)))
			self.model.add(Convolution2D(512, 3, 3,init=self.cfgs['conv_init']))
			self.model.add(Activation(self.cfgs['conv_non_linearity']))

			self.model.add(ZeroPadding2D((1,1)))
			self.model.add(Convolution2D(512, 3, 3,init=self.cfgs['conv_init']))
			self.model.add(Activation(self.cfgs['conv_non_linearity']))

			self.model.add(ZeroPadding2D((1,1)))
			self.model.add(Convolution2D(512, 3, 3,init=self.cfgs['conv_init']))
			self.model.add(Activation(self.cfgs['conv_non_linearity']))

			self.model.add(MaxPooling2D(pool_size=(2, 2),strides=(2,2)))
			# C5

			# FC6
			self.model.add(Flatten())
			self.model.add(Dense(4096,init=self.cfgs['fc_init']))
			#self.model.add(BatchNormalization(mode=0, epsilon=0.0001, axis=1))
			self.model.add(Activation(self.cfgs['fc_non_linearity']))

			# FC6

			# FC7
			self.model.add(Dropout(self.cfgs['drop_out']))
			self.model.add(Dense(4096,init=self.cfgs['fc_init']))
			#self.model.add(BatchNormalization(mode=0, epsilon=0.0001, axis=1))
			self.model.add(Activation(self.cfgs['fc_non_linearity']))
			# Fc7

			# FC8
			self.model.add(Dropout(self.cfgs['drop_out']))
			self.model.add(Dense(self.cfgs['nb_classes'],init=self.cfgs['fc_init']))
			#self.model.add(BatchNormalization(mode=0, epsilon=0.0001, axis=1))
			self.model.add(Activation(self.cfgs['activation']))

			# FC8

			if not self.cfgs['model_weights_file'] == None:
				self.init_from_this()
			#if

		except Exception as e:

			self.io.print_error('Error configuring the model, {0}'.format(e))
			self.init = False
			return

		#try

		self.init = True

	#def

	def init_from_this(self):

		weights_file = self.cfgs['model_weights_file']

		if weights_file.endswith('.hdf5'):
			self.load_weights(weights_file)
			self.io.print_info('Initalized from {0}'.format(weights_file))
		#if

		if weights_file.endswith('.caffemodel'):
			self.io.print_warning('Loading from caffe model not implemented starting with random weights')
		#if

	#def

	def load_weights(self, filepath):

		'''
			This method does not make use of Sequential.set_weights()
			for backwards compatibility.
		'''

		# Loads weights from HDF5 file

		import h5py

		f = h5py.File(filepath)

		for k in range(f.attrs['nb_layers']):

			layer_type = self.model.layers[k].get_config()['name']
			layer_name_string = '{0}_layer_{1}'.format(layer_type,k)

			if layer_name_string in self.cfgs['ignore_while_loading']:
				self.io.print_warning('Ignoring weights from {0}'.format(layer_name_string))
				continue
			#if

			layer_name = 'layer_{}'.format(k)
			g = f[layer_name]
			self.io.print_info('Transfering parameters from {0}'.format(layer_name_string))

			weights = [g['param_{}'.format(p)] for p in range(g.attrs['nb_params'])]
			self.model.layers[k].set_weights(weights)

		#for

		f.close()

		self.io.print_info(self.model.layers[-1].get_config().values())

	#def

	def setup_loss_function(self,w):

		self.loss_functions.set_weights(w)

	#def

	def compile(self,compile_cfgs):

		try:
			opt = optimizer_dict[compile_cfgs['optimizer']](lr=compile_cfgs['lr'], epsilon=compile_cfgs['epsilon'])
			self.model.compile(loss=self.loss_functions.dict[compile_cfgs['loss']], optimizer=opt)
		except Exception as e:
			self.io.print_error('Error configuring the model, {0}'.format(e))
			self.init = False
			return
		#try

		self.init = True
class InceptionV3InfoLayer():
    def __init__(self):

        self.layer_list = []
        self.config_file = None
        self.io = EmbeddingIO(None)
        self.init = False
        self.cfgs = None
        self.loss_functions = ObjectiveFunctions()

    def configure(self, config_file):

        self.config_file = config_file
        self.init = False

        if not os.path.exists(self.config_file):
            self.io.print_error(
                'Could not find config file for InceptionV3 {0}'.format(
                    self.config_file))
            self.init = False
            return

        pfile = open(self.config_file, 'r')
        self.cfgs = yaml.load(pfile)
        pfile.close()

        self.init = True

    def add_to_graph(self, *args, **kwargs):

        self.model.add_node(*args, **kwargs)
        self.last_added_node = kwargs['name']

        self.layer_list.append(kwargs['name'])

        return kwargs['name']

    def add_bn_conv_layer(self, *args, **kwargs):

        layer_name = kwargs['name']
        input_layer = kwargs['input']

        del kwargs['name']
        del kwargs['input']

        if 'padding' in kwargs:
            layer_name = layer_name + '_pad'
            self.add_to_graph(ZeroPadding2D(padding=kwargs['padding']),
                              name=layer_name,
                              input=input_layer)
            input_layer = layer_name
            del kwargs['padding']

        # CONV with linear activation by default
        layer_name = layer_name + '_conv'
        self.add_to_graph(Convolution2D(*args, **kwargs),
                          name=layer_name,
                          input=input_layer)

        # Batch normalization added directly on output of a linear layer
        input_layer = layer_name
        layer_name = layer_name + '_bn'

        _ = self.add_to_graph(BatchNormalization(mode=0,
                                                 epsilon=0.0001,
                                                 axis=1),
                              name=layer_name,
                              input=input_layer)

        # Standard normalization
        input_layer = layer_name
        layer_name = layer_name + '_nonlin'
        _ = self.add_to_graph(Activation('relu'),
                              name=layer_name,
                              input=input_layer)

        return layer_name

    def add_inceptionA(self, input_layer, list_nb_filter, base_name):

        l1_1 = self.add_bn_conv_layer(name=base_name + '_l1_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[0][0],
                                      nb_row=1,
                                      nb_col=1)

        l2_1 = self.add_bn_conv_layer(name=base_name + '_l2_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[1][0],
                                      nb_row=1,
                                      nb_col=1)
        l2_2 = self.add_bn_conv_layer(name=base_name + '_l2_2',
                                      input=l2_1,
                                      nb_filter=list_nb_filter[1][1],
                                      nb_row=5,
                                      nb_col=5,
                                      padding=(2, 2))

        l3_1 = self.add_bn_conv_layer(name=base_name + '_l3_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[2][0],
                                      nb_row=1,
                                      nb_col=1)
        l3_2 = self.add_bn_conv_layer(name=base_name + '_l3_2',
                                      input=l3_1,
                                      nb_filter=list_nb_filter[2][1],
                                      nb_row=3,
                                      nb_col=3,
                                      padding=(1, 1))
        l3_3 = self.add_bn_conv_layer(name=base_name + '_l3_3',
                                      input=l3_2,
                                      nb_filter=list_nb_filter[2][2],
                                      nb_row=3,
                                      nb_col=3,
                                      padding=(1, 1))

        l4_1 = self.add_to_graph(ZeroPadding2D(padding=(1, 1)),
                                 name=base_name + '_14_1',
                                 input=input_layer)
        l4_2 = self.add_to_graph(AveragePooling2D(pool_size=(3, 3),
                                                  strides=(1, 1)),
                                 name=base_name + '_14_2',
                                 input=l4_1)
        l4_3 = self.add_bn_conv_layer(name=base_name + '_l4_3',
                                      input=l4_2,
                                      nb_filter=list_nb_filter[3][0],
                                      nb_row=1,
                                      nb_col=1)

        self.add_to_graph(Activation("linear"),
                          name=base_name,
                          inputs=[l1_1, l2_2, l3_3, l4_3],
                          merge_mode="concat",
                          concat_axis=1)

        self.io.print_info('Added Inception-A {0}'.format(base_name))
        # https://github.com/fchollet/keras/issues/391

    def add_inceptionB(self, input_layer, list_nb_filter, base_name):

        l1_1 = self.add_bn_conv_layer(name=base_name + '_l1_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[0][0],
                                      nb_row=3,
                                      nb_col=3,
                                      subsample=(2, 2))

        l2_1 = self.add_bn_conv_layer(name=base_name + '_l2_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[1][0],
                                      nb_row=1,
                                      nb_col=1)
        l2_2 = self.add_bn_conv_layer(name=base_name + '_l2_2',
                                      input=l2_1,
                                      nb_filter=list_nb_filter[1][1],
                                      nb_row=3,
                                      nb_col=3,
                                      padding=(1, 1))
        l2_3 = self.add_bn_conv_layer(name=base_name + '_l2_3',
                                      input=l2_2,
                                      nb_filter=list_nb_filter[1][2],
                                      nb_row=3,
                                      nb_col=3,
                                      subsample=(2, 2))

        l3_1 = self.add_to_graph(MaxPooling2D(pool_size=(3, 3),
                                              strides=(2, 2)),
                                 name=base_name + '_13_1',
                                 input=input_layer)

        self.add_to_graph(Activation("linear"),
                          name=base_name,
                          inputs=[l1_1, l2_3, l3_1],
                          merge_mode="concat",
                          concat_axis=1)

        self.io.print_info('Added Inception-B {0}'.format(base_name))
        # https://github.com/fchollet/keras/issues/391

    def add_inceptionC(self, input_layer, list_nb_filter, base_name):

        l1_1 = self.add_bn_conv_layer(name=base_name + '_l1_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[0][0],
                                      nb_row=1,
                                      nb_col=1)

        l2_1 = self.add_bn_conv_layer(name=base_name + '_l2_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[1][0],
                                      nb_row=1,
                                      nb_col=1)
        l2_2 = self.add_bn_conv_layer(name=base_name + '_l2_2',
                                      input=l2_1,
                                      nb_filter=list_nb_filter[1][1],
                                      nb_row=1,
                                      nb_col=7,
                                      padding=(0, 3))
        l2_3 = self.add_bn_conv_layer(name=base_name + '_l2_3',
                                      input=l2_2,
                                      nb_filter=list_nb_filter[1][2],
                                      nb_row=7,
                                      nb_col=1,
                                      padding=(3, 0))

        l3_1 = self.add_bn_conv_layer(name=base_name + '_l3_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[2][0],
                                      nb_row=1,
                                      nb_col=1)
        l3_2 = self.add_bn_conv_layer(name=base_name + '_l3_2',
                                      input=l3_1,
                                      nb_filter=list_nb_filter[2][1],
                                      nb_row=7,
                                      nb_col=1,
                                      padding=(3, 0))
        l3_3 = self.add_bn_conv_layer(name=base_name + '_l3_3',
                                      input=l3_2,
                                      nb_filter=list_nb_filter[2][2],
                                      nb_row=1,
                                      nb_col=7,
                                      padding=(0, 3))
        l3_4 = self.add_bn_conv_layer(name=base_name + '_l3_4',
                                      input=l3_3,
                                      nb_filter=list_nb_filter[2][3],
                                      nb_row=7,
                                      nb_col=1,
                                      padding=(3, 0))
        l3_5 = self.add_bn_conv_layer(name=base_name + '_l3_5',
                                      input=l3_4,
                                      nb_filter=list_nb_filter[2][4],
                                      nb_row=1,
                                      nb_col=7,
                                      padding=(0, 3))

        l4_1 = self.add_to_graph(ZeroPadding2D(padding=(1, 1)),
                                 name=base_name + '_14_1',
                                 input=input_layer)
        l4_2 = self.add_to_graph(AveragePooling2D(pool_size=(3, 3),
                                                  strides=(1, 1)),
                                 name=base_name + '_14_2',
                                 input=l4_1)
        l4_3 = self.add_bn_conv_layer(name=base_name + '_l4_3',
                                      input=l4_2,
                                      nb_filter=list_nb_filter[3][0],
                                      nb_row=1,
                                      nb_col=1)

        self.add_to_graph(Activation("linear"),
                          name=base_name,
                          inputs=[l1_1, l2_3, l3_5, l4_3],
                          merge_mode="concat",
                          concat_axis=1)

        self.io.print_info('Added Inception-C {0}'.format(base_name))
        # https://github.com/fchollet/keras/issues/391

    def add_inceptionD(self, input_layer, list_nb_filter, base_name):

        l1_1 = self.add_bn_conv_layer(name=base_name + '_l1_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[0][0],
                                      nb_row=1,
                                      nb_col=1)
        l1_2 = self.add_bn_conv_layer(name=base_name + '_l1_2',
                                      input=l1_1,
                                      nb_filter=list_nb_filter[0][1],
                                      nb_row=3,
                                      nb_col=3,
                                      subsample=(2, 2))

        l2_1 = self.add_bn_conv_layer(name=base_name + '_l2_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[1][0],
                                      nb_row=1,
                                      nb_col=1)
        l2_2 = self.add_bn_conv_layer(name=base_name + '_l2_2',
                                      input=l2_1,
                                      nb_filter=list_nb_filter[1][1],
                                      nb_row=1,
                                      nb_col=7,
                                      padding=(0, 3))
        l2_3 = self.add_bn_conv_layer(name=base_name + '_l2_3',
                                      input=l2_2,
                                      nb_filter=list_nb_filter[1][2],
                                      nb_row=7,
                                      nb_col=1,
                                      padding=(3, 0))
        l2_4 = self.add_bn_conv_layer(name=base_name + '_l2_4',
                                      input=l2_3,
                                      nb_filter=list_nb_filter[1][2],
                                      nb_row=3,
                                      nb_col=3,
                                      subsample=(2, 2))

        l3_1 = self.add_to_graph(MaxPooling2D(pool_size=(3, 3),
                                              strides=(2, 2)),
                                 name=base_name + '_13_1',
                                 input=input_layer)

        self.add_to_graph(Activation("linear"),
                          name=base_name,
                          inputs=[l1_2, l2_4, l3_1],
                          merge_mode="concat",
                          concat_axis=1)

        self.io.print_info('Added Inception-D {0}'.format(base_name))
        # https://github.com/fchollet/keras/issues/391

    def add_inceptionE(self, input_layer, list_nb_filter, base_name,
                       pool_mode):

        l1_1 = self.add_bn_conv_layer(name=base_name + '_l1_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[0][0],
                                      nb_row=1,
                                      nb_col=1)

        l2_1 = self.add_bn_conv_layer(name=base_name + '_l2_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[1][0],
                                      nb_row=1,
                                      nb_col=1)
        l2_2a = self.add_bn_conv_layer(name=base_name + '_l2_2a',
                                       input=l2_1,
                                       nb_filter=list_nb_filter[1][1],
                                       nb_row=1,
                                       nb_col=3,
                                       padding=(0, 1))
        l2_2b = self.add_bn_conv_layer(name=base_name + '_l2_2b',
                                       input=l2_1,
                                       nb_filter=list_nb_filter[1][1],
                                       nb_row=3,
                                       nb_col=1,
                                       padding=(1, 0))

        l3_1 = self.add_bn_conv_layer(name=base_name + '_l3_1',
                                      input=input_layer,
                                      nb_filter=list_nb_filter[2][0],
                                      nb_row=1,
                                      nb_col=1)
        l3_2 = self.add_bn_conv_layer(name=base_name + '_l3_2',
                                      input=l3_1,
                                      nb_filter=list_nb_filter[2][1],
                                      nb_row=3,
                                      nb_col=3,
                                      padding=(1, 1))
        l3_3a = self.add_bn_conv_layer(name=base_name + '_l3_3a',
                                       input=l3_2,
                                       nb_filter=list_nb_filter[2][2],
                                       nb_row=1,
                                       nb_col=3,
                                       padding=(0, 1))
        l3_3b = self.add_bn_conv_layer(name=base_name + '_l3_3b',
                                       input=l3_2,
                                       nb_filter=list_nb_filter[2][3],
                                       nb_row=3,
                                       nb_col=1,
                                       padding=(1, 0))

        l4_1 = self.add_to_graph(ZeroPadding2D(padding=(1, 1)),
                                 name=base_name + '_14_1',
                                 input=input_layer)
        l4_2 = self.add_to_graph(pooling_dict[pool_mode](pool_size=(3, 3),
                                                         strides=(1, 1)),
                                 name=base_name + '_14_2',
                                 input=l4_1)
        l4_3 = self.add_bn_conv_layer(name=base_name + '_l4_3',
                                      input=l4_2,
                                      nb_filter=list_nb_filter[3][0],
                                      nb_row=1,
                                      nb_col=1)

        self.add_to_graph(Activation("linear"),
                          name=base_name,
                          inputs=[l1_1, l2_2a, l2_2b, l3_3a, l3_3b, l4_3],
                          merge_mode="concat",
                          concat_axis=1)

        self.io.print_info('Added Inception-E {0}'.format(base_name))
        # https://github.com/fchollet/keras/issues/391

    def define(self):

        try:

            self.model = Graph()
            self.model.add_input(name='input',
                                 input_shape=(self.cfgs['n_channels'],
                                              self.cfgs['image_height'],
                                              self.cfgs['image_width']))

            #
            # Part of the network which is defined in the config file should move here
            #

            cgfs_nodes = self.cfgs['nodes']

            for node in cgfs_nodes:

                if not node['type'] == 'Activation':
                    self.add_to_graph(
                        layer_dict[node['type']](**node['parameter']),
                        name=node['name'],
                        input=node['input'])
                else:
                    self.add_to_graph(layer_dict[node['type']](
                        node['parameter']['mode']),
                                      name=node['name'],
                                      input=node['input'])

                self.io.print_info('Added {1}:{0}'.format(
                    node['type'], node['name']))

            self.add_inceptionA(input_layer=self.last_added_node,
                                list_nb_filter=((64, ), (48, 64), (64, 96, 96),
                                                (32, )),
                                base_name='mixed')
            self.add_inceptionA(input_layer=self.last_added_node,
                                list_nb_filter=((64, ), (48, 64), (64, 96, 96),
                                                (64, )),
                                base_name='mixed_1')
            self.add_inceptionA(input_layer=self.last_added_node,
                                list_nb_filter=((64, ), (48, 64), (64, 96, 96),
                                                (64, )),
                                base_name='mixed_2')

            self.add_inceptionB(input_layer=self.last_added_node,
                                list_nb_filter=((384, ), (64, 96, 96)),
                                base_name='mixed_3')

            self.add_inceptionC(input_layer=self.last_added_node,
                                list_nb_filter=((192, ), (128, 128, 192),
                                                (128, 128, 128, 128,
                                                 192), (192, )),
                                base_name='mixed_4')
            self.add_inceptionC(input_layer=self.last_added_node,
                                list_nb_filter=((192, ), (160, 160, 192),
                                                (160, 160, 160, 160,
                                                 192), (192, )),
                                base_name='mixed_5')
            self.add_inceptionC(input_layer=self.last_added_node,
                                list_nb_filter=((192, ), (160, 160, 192),
                                                (160, 160, 160, 160,
                                                 192), (192, )),
                                base_name='mixed_6')
            self.add_inceptionC(input_layer=self.last_added_node,
                                list_nb_filter=((192, ), (192, 192, 192),
                                                (192, 192, 192, 192,
                                                 192), (192, )),
                                base_name='mixed_7')

            self.add_inceptionD(input_layer=self.last_added_node,
                                list_nb_filter=((192, 320), (192, 192, 192,
                                                             192)),
                                base_name='mixed_8')

            self.add_inceptionE(input_layer=self.last_added_node,
                                list_nb_filter=((320, ), (384, 384, 384),
                                                (448, 384, 384, 384), (192, )),
                                pool_mode='average',
                                base_name='mixed_9')
            self.add_inceptionE(input_layer=self.last_added_node,
                                list_nb_filter=((320, ), (384, 384, 384),
                                                (448, 384, 384, 384), (192, )),
                                pool_mode='max',
                                base_name='mixed_10')

            self.add_to_graph(AveragePooling2D(pool_size=(5, 5)),
                              name='pool3',
                              input=self.last_added_node)
            self.io.print_info('Added {1}:{0}'.format('AveragePooling',
                                                      self.last_added_node))

            self.add_to_graph(Flatten(), name='flatten', input='pool3')
            self.io.print_info('Added {1}:{0}'.format('Flatten',
                                                      self.last_added_node))

            # Feature embedding FC layer
            self.add_to_graph(Dense(
                self.cfgs['mutual_information_layer_size']),
                              name='softmax',
                              input='flatten')
            self.io.print_info('Added {1}:{0}'.format('Dense',
                                                      self.last_added_node))

            # L2 normalization of softmax layer
            # self.add_to_graph(Lambda(lambda x: K.l2_normalize(x, axis=-1)), name='softmax_norm', input='softmax')

            self.model.add_output(name='output', input='softmax')

            if self.cfgs['model_weights_file'] is not None:
                self.init_from_this()

        except Exception as err:

            self.io.print_error('Error configuring the model, {0}'.format(err))
            self.init = False
            return

        self.init = True

    def init_from_this(self):

        weights_file = self.cfgs['model_weights_file']

        if not weights_file == 'None':

            self.load_weights(weights_file)
            self.io.print_info(
                'Weights Initalized from {0}'.format(weights_file))

    def load_weights(self, filepath):

        if filepath.endswith('.npz'):
            pfile = open(filepath, 'r')
            graph = np.load(pfile)['graph'].item()

            for node_name, weights in graph.items():

                if node_name in self.cfgs['ignore_while_loading']:
                    self.io.print_warning(
                        'Ignoring weights from {0}'.format(node_name))
                    continue

                self.io.print_info(
                    'Transfering parameters from {0}'.format(node_name))
                self.model.nodes[node_name].set_weights(weights)

            pfile.close()

        elif filepath.endswith('.hdf5'):
            self.model.load_weights(filepath)
        else:
            self.io.print_error(
                'Unknown model weights file {}'.format(filepath))

        self.io.print_info(self.model.nodes['softmax'].get_config())

    def setup_loss_function(self, w):

        self.loss_functions.set_weights(w)

    def update_optimizer(self, decay_rate=0.95):

        lr = self.opt.get_config()['lr']

        self.opt.lr = K.variable(lr * np.exp(-decay_rate))

        lr = self.opt.get_config()['lr']

        return lr

    def compile(self, compile_cfgs):

        try:
            self.opt = optimizer_dict[compile_cfgs['optimizer']](
                lr=compile_cfgs['lr'], epsilon=compile_cfgs['epsilon'])
            self.model.compile(loss={
                'output':
                self.loss_functions.dict[compile_cfgs['loss']]
            },
                               optimizer=self.opt)
        except Exception as e:
            self.io.print_error('Error configuring the model, {0}'.format(e))
            self.init = False
            return

        self.init = True