【问题标题】:Keras - Pop and re-add layers, but layer does not disconnectKeras - 弹出并重新添加图层,但图层不会断开连接
【发布时间】:2017-07-25 11:28:39
【问题描述】:

使用 Keras (1.2.2),我正在加载一个顺序模型,其最后一层是:

model.add(Dense(512))
model.add(Activation('relu'))
model.add(Dense(nb_classes))
model.add(Activation('softmax'))

然后,我想弹出最后一层,再添加一个全连接层,重新添加分类层。

model = load_model('model1.h5')                                                                         
layer1 = model.layers.pop() # Copy activation_6 layer                                      
layer2 = model.layers.pop() # Copy classification layer (dense_2)                          

model.add(Dense(512, name='dense_3'))
model.add(Activation('softmax', name='activation_7'))

model.add(layer2)
model.add(layer1)

print(model.summary())

如您所见,我的 dense_3 和 activation_7 没有连接到网络(summary() 中的空值带有“已连接到”)。我在文档中找不到任何解释如何解决此问题的内容。有什么想法吗?

dense_1 (Dense)                  (None, 512)           131584      flatten_1[0][0]                  
____________________________________________________________________________________________________
activation_5 (Activation)        (None, 512)           0           dense_1[0][0]                    
____________________________________________________________________________________________________
dense_3 (Dense)                  (None, 512)           5632                                         
____________________________________________________________________________________________________
activation_7 (Activation)        (None, 512)           0                                            
____________________________________________________________________________________________________
dense_2 (Dense)                  (None, 10)            5130        activation_5[0][0]               
____________________________________________________________________________________________________
activation_6 (Activation)        (None, 10)            0           dense_2[0][0]                    
====================================================================================================

按照下面的答案,我在打印出model.summary()之前编译了模型,但是由于某些原因,没有正确弹出层,如摘要所示:最后一层的连接错误:

dense_1 (Dense)                  (None, 512)           131584      flatten_1[0][0]                  
____________________________________________________________________________________________________
activation_5 (Activation)        (None, 512)           0           dense_1[0][0]                    
____________________________________________________________________________________________________
dense_3 (Dense)                  (None, 512)           5632        activation_6[0][0]               
____________________________________________________________________________________________________
activation_7 (Activation)        (None, 512)           0           dense_3[0][0]                    
____________________________________________________________________________________________________
dense_2 (Dense)                  (None, 10)            5130        activation_5[0][0]               
                                                                   activation_7[0][0]               
____________________________________________________________________________________________________
activation_6 (Activation)        (None, 10)            0           dense_2[0][0]                    
                                                                   dense_2[1][0]                    
====================================================================================================

但应该是的

dense_1 (Dense)                  (None, 512)           131584      flatten_1[0][0]                  
____________________________________________________________________________________________________
activation_5 (Activation)        (None, 512)           0           dense_1[0][0]                    
____________________________________________________________________________________________________
dense_3 (Dense)                  (None, 512)           5632        activation_5[0][0]               
____________________________________________________________________________________________________
activation_7 (Activation)        (None, 512)           0           dense_3[0][0]                    
____________________________________________________________________________________________________
dense_2 (Dense)                  (None, 10)            5130                       
                                                                   activation_7[0][0]               
____________________________________________________________________________________________________
activation_6 (Activation)        (None, 10)            0           dense_2[0][0]                    

====================================================================================================

【问题讨论】:

    标签: python deep-learning keras keras-layer


    【解决方案1】:

    我正在使用以下函数,它适用于我的代码:

    for layer in model1.layers[:22]:
        model.add(layer)
    

    【讨论】:

      【解决方案2】:

      出于某种原因,我需要在添加新层之前使用模型构建带有弹出层的模型以使事情正常运行。

      conda list keras
      # Name                    Version                   Build  Channel
      keras                     2.1.5                    py36_0    conda-forge
      

      这里是代码sn-p:

      def pop_layer(model):
          if not model.outputs:
              raise Exception('Sequential model cannot be popped: model is empty.')
      
          model.layers.pop()
          if not model.layers:
              model.outputs = []
              model.inbound_nodes = []
              model.outbound_nodes = []
          else:
              model.layers[-1].outbound_nodes = []
              model.outputs = [model.layers[-1].output]
          model.built = False
      
      def get_model():
          #Fully convolutional part of VGG16
          model = VGG16(include_top=False, weights='imagenet')
      
          #Remove last max pooling layer
          pop_layer(model)
      
          #Freeze pretrained layers
          for layer in model.layers:
              layer.trainable = False
      
          model = Model(inputs=model.inputs, outputs=model.outputs)
      
          print('len(model.layers)', len(model.layers)) #
          print(model.summary()) #
      
          x = GlobalAveragePooling2D()(model.output)
          head = Dense(N_CLASS, activation='softmax')(x)
      
          model = Model(inputs=model.inputs, outputs=head)
      
          model.compile(optimizer=Adadelta(), loss='categorical_crossentropy', metrics=['accuracy'])
      
          print('len(model.layers)', len(model.layers)) #
          print(model.summary()) #
      
          return model
      

      【讨论】:

        【解决方案3】:

        当你删除层时,你需要重新编译你的模型以使其生效。

        所以用

        model.compile(loss=...,optimizer=..., ...)
        

        在打印摘要之前,它应该正确整合更改。

        编辑:

        你想要做的实际上是非常复杂的顺序模式。这是我可以为您的序列模型提出的解决方案(如果有更好的请告诉我):

        model = load_model('model1.h5')                                                                         
        layer1 = model.layers.pop() # Copy activation_6 layer                                      
        layer2 = model.layers.pop() # Copy classification layer (dense_2)                          
        
        model.add(Dense(512, name='dense_3'))
        model.add(Activation('softmax', name='activation_7'))
        
        # get layer1 config
        layer1_config = layer1.get_config()
        layer2_config = layer2.get_config()
        # change the name of the layers otherwise it complains
        layer1_config['name'] = layer1_config['name'] + '_new'
        layer2_config['name'] = layer2_config['name'] + '_new'
        
        # import the magic function
        from keras.utils.layer_utils import layer_from_config
        # re-add new layers from the config of the old ones 
        model.add(layer_from_config({'class_name':type(l2), 'config':layer2_config}))
        model.add(layer_from_config({'class_name':type(l1), 'config':layer1_config}))
        
        model.compile(...)
        
        print(model.summary())
        

        问题在于,您的图层具有我无法更改的 layer1.inputlayer1.output 属性。

        一种解决方法是使用 Functionnal API 模型。这使您可以定义层的输入和输出。

        首先你需要定义你的 pop() 函数,以便在每次弹出一个层时正确地重新链接层,该函数来自this github issue

        def pop_layer(model):
            if not model.outputs:
                raise Exception('Sequential model cannot be popped: model is empty.')
        
            popped_layer = model.layers.pop()
            if not model.layers:
                model.outputs = []
                model.inbound_nodes = []
                model.outbound_nodes = []
            else:
                model.layers[-1].outbound_nodes = []
                model.outputs = [model.layers[-1].output]
            model.built = False
            return popped_layer
        

        它只是删除最后一层的每个输出链接,并将模型的输出更改为新的最后一层。现在你可以使用它了:

        model = load_model('model1.h5')                                                                         
        layer1 = model.layers.pop() # Copy activation_6 layer                                      
        layer2 = model.layers.pop() # Copy classification layer (dense_2)     
        
        # take model.outputs and feed a Dense layer
        h = Dense(512,name='dense_3')(model.outputs)
        h = Activation('relu', name=('activation_7')(h)
        # apply
        h = layer2(h)
        output = layer1(h)
        
        model = Model(input=model.input, output=output)
        model.compile(...)
        model.summary()
        

        可能有比这更好的解决方案,但这是我会做的。

        我希望这会有所帮助。

        【讨论】:

        • 编译显示我添加了到新添加的层(dense_3 和activation_7)的连接,但是到activation_6 和dense_2 的连接似乎没有被pop() 更新。我尝试在弹出后编译并在添加下一层后再次编译,但没有效果。我在这里缺少什么?
        • 确实如此,我学到了很多,谢谢!在看到您的答案之前,我实际上所做的是弹出图层,而不是保存它们,而是重新添加了一个新的相同图层。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-07-01
        • 2019-04-07
        • 2022-01-20
        • 1970-01-01
        • 1970-01-01
        • 2017-11-26
        • 2019-03-06
        相关资源
        最近更新 更多