2017-12-21 21 views
1

Was ich versuche:
ich alle Schichten aus verschiedenen Modellen verbinden möge ein neues keras Modell zu erstellen.Keras: Verbinden von zwei Schichten aus verschiedenen Modellen zu schaffen neues Modell

Was ich bisher gefunden:
https://github.com/keras-team/keras/issues/4205: mit Hilfe des Modells Ruf Klasse, um die Eingabe eines anderen Modells zu ändern. Meine Probleme mit diesem Ansatz:

  • Kann nur den Eingang des Modells ändern, keine anderen Schichten. Also, wenn ich einige Schichten am Anfang des Encoders abschneiden möchte, ist das nicht möglich
  • Kein Fan der verschachtelten Array-Struktur beim Abrufen der Konfigurationsdatei. Möchte ein 1D-Array haben
  • Bei Verwendung von model.summary() oder plot_model() wird der Encoder nur als "Modell" angezeigt. Wenn überhaupt, würde ich sagen, beide Modelle sollten verpackt werden. So sollte die config [model_base, model_encoder] zeigt und nicht [base_input, base_conv2D, ..., encoder_model]

  • Um fair zu sein, mit diesem Ansatz: https://github.com/keras-team/keras/issues/3021, oberhalb der Punkt ist tatsächlich möglich, aber auch hier ist es sehr unflexibel. Sobald ich einige Schichten auf der Ober- oder Unterseite des Bodens oder Encoder Netzwerk abgeschnitten werden, scheitert dieser Ansatz

https://github.com/keras-team/keras/issues/3465: neue Schichten auf ein Basismodell Hinzufügen von beliebigen Ausgang des Basismodells. Probleme hier:

  • Während es möglich ist, jede Schicht aus dem Basismodell zu verwenden, was bedeutet, dass ich Schichten aus dem Basismodell abschneiden kann, kann ich den Encoder nicht als Keras-Modell laden. Die Top-Modelle müssen immer neu erstellt werden.
  • Was habe ich versucht:
    Mein Ansatz alle Schichten aus verschiedenen Modellen zu verbinden:

    1. löschen Inbound-Knoten Eingangsschicht
    2. den Anruf() -Methode der Ausgangsschicht mit dem Tensor der Ausgabeschicht
    3. Bereinigen Sie die Ausgangsknoten des Ausgangstensors, indem Sie den neu angelegten Tensor mit dem vorherigen Ausgangstensor
    4. ausschaltet

      Ich war zuerst wirklich optimistisch, als die summary() und die plot_model() mich genau bekommen haben, was ich wollte, also sollte das Node-Diagramm in Ordnung sein, oder? Aber ich habe beim Training Fehler bekommen. Während der Ansatz in dem Abschnitt "Was ich bisher gefunden habe" gut trainiert war, stieß ich bei meinem Ansatz auf einen Fehler. Dies ist die Fehlermeldung:

      Könnte eine wichtige Information sein, dass ich Tensorflow als Backend verwende. Ich konnte die Wurzel dieses Fehlers zurückverfolgen. Es scheint, als ob ein Fehler vorliegt, wenn die Gradienten berechnet werden. Normalerweise gibt es für jeden Knoten eine Gradientenberechnung, aber alle Knoten des Basisnetzwerks haben "None", wenn Sie meinen Ansatz verwenden. Also grundsätzlich in keras/optimizers.py, get_updates(), wenn die Gradienten berechnet werden (grad = self.get_gradients(loss, params)).Hier

      ist der Code (ohne Ausbildung), mit allen drei Ansätzen umgesetzt:

      def create_base(): 
          in_layer = Input(shape=(32, 32, 3), name="base_input") 
          x = Conv2D(32, (3, 3), padding='same', activation="relu", name="base_conv2d_1")(in_layer) 
          x = Conv2D(32, (3, 3), padding='same', activation="relu", name="base_conv2d_2")(x) 
          x = MaxPooling2D(pool_size=(2, 2), name="base_maxpooling_2d_1")(x) 
          x = Dropout(0.25, name="base_dropout")(x) 
      
          x = Conv2D(64, (3, 3), padding='same', activation="relu", name="base_conv2d_3")(x) 
          x = Conv2D(64, (3, 3), padding='same', activation="relu", name="base_conv2d_4")(x) 
          x = MaxPooling2D(pool_size=(2, 2), name="base_maxpooling2d_2")(x) 
          x = Dropout(0.25, name="base_dropout_2")(x) 
      
          return Model(inputs=in_layer, outputs=x, name="base_model") 
      
      def create_encoder(): 
          in_layer = Input(shape=(8, 8, 64)) 
          x = Flatten(name="encoder_flatten")(in_layer) 
          x = Dense(512, activation="relu", name="encoder_dense_1")(x) 
          x = Dropout(0.5, name="encoder_dropout_2")(x) 
          x = Dense(10, activation="softmax", name="encoder_dense_2")(x) 
          return Model(inputs=in_layer, outputs=x, name="encoder_model") 
      
      def extend_base(input_model): 
          x = Flatten(name="custom_flatten")(input_model.output) 
          x = Dense(512, activation="relu", name="custom_dense_1")(x) 
          x = Dropout(0.5, name="custom_dropout_2")(x) 
          x = Dense(10, activation="softmax", name="custom_dense_2")(x) 
          return Model(inputs=input_model.input, outputs=x, name="custom_edit") 
      
      def connect_layers(from_tensor, to_layer, clear_inbound_nodes=True): 
          try: 
           tmp_output = to_layer.output 
          except AttributeError: 
           raise ValueError("Connecting to shared layers is not supported!") 
      
          if clear_inbound_nodes: 
           to_layer.inbound_nodes = [] 
          else: 
           tensor_list = to_layer.inbound_nodes[0].input_tensors 
           tensor_list.append(from_tensor) 
           from_tensor = tensor_list 
           to_layer.inbound_nodes = [] 
          new_output = to_layer(from_tensor) 
          for out_node in to_layer.outbound_nodes: 
           for i, in_tensor in enumerate(out_node.input_tensors): 
            if in_tensor == tmp_output: 
             out_node.input_tensors[i] = new_output 
      
      
      if __name__ == "__main__": 
          base = create_base() 
          encoder = create_encoder() 
      
          #new_model_1 = Model(inputs=base.input, outputs=encoder(base.output)) 
          #plot_model(new_model_1, to_file="plots/new_model_1.png") 
      
          new_model_2 = extend_base(base) 
          plot_model(new_model_2, to_file="plots/new_model_2.png") 
          print(new_model_2.summary()) 
      
          base_layer = base.get_layer("base_dropout_2") 
          top_layer = encoder.get_layer("encoder_flatten") 
          connect_layers(base_layer.output, top_layer) 
          new_model_3 = Model(inputs=base.input, outputs=encoder.output) 
          plot_model(new_model_3, to_file="plots/new_model_3.png") 
          print(new_model_3.summary()) 
      

      Ich weiß, das viel Text ist und eine Menge Code. Aber ich glaube, dass es notwendig ist, das Problem hier zu erklären.

      EDIT: Ich habe gerade versucht thenao und ich denke, der Fehler mehr Informationen verschenkt:

      theano.gradient.DisconnectedInputError: 
      Backtrace when that variable is created: 
      

      Es scheint wie jede Schicht aus dem Encoder Modell über TensorVariables eine Verbindung mit der Encoder-Eingang Schicht aufweist.

    Antwort

    0

    So ist das, was ich mit für die connect_layer() Funktion endete:

    def connect_layers(from_tensor, to_layer, old_tensor=None): 
        # if there is any shared layer after the to_layer, it is not supported 
        try: 
         tmp_output = to_layer.output 
        except AttributeError: 
         raise ValueError("Connecting to shared layers is not supported!") 
        # check if to_layer has multiple input_tensors, and therefore some sort of merge layer 
        if len(to_layer.inbound_nodes[0].input_tensors) > 1: 
         tensor_list = to_layer.inbound_nodes[0].input_tensors 
         found_tensor = False 
         for i, tensor in enumerate(tensor_list): 
          # exchange the old tensor with the new created tensor 
          if tensor == old_tensor: 
           tensor_list[i] = from_tensor 
           found_tensor = True 
           break 
         if not found_tensor: 
          tensor_list.append(from_tensor) 
         from_tensor = tensor_list 
         to_layer.inbound_nodes = [] 
        else: 
         to_layer.inbound_nodes = [] 
    
        new_output = to_layer(from_tensor) 
    
        tmp_out_nodes = to_layer.outbound_nodes[:] 
        to_layer.outbound_nodes = [] 
        # recursively connect all layers after the current to_layer 
        for out_node in tmp_out_nodes: 
         l = out_node.outbound_layer 
         print("Connecting: " + str(to_layer) + " ----> " + str(l)) 
         connect_layers(new_output, l, tmp_output) 
    

    Da jeder Tensor hat alle Informationen über sie root Tensor ist über -> owner.inputs -> owner.inputs -> .. ., alle Tensor nach dem new_output Tensor muss aktualisiert werden.
    Es war viel einfacher, das mit theano dann mit Tensorflow Backend zu debuggen.

    Ich muss immer noch herausfinden, wie man mit geteilten Schichten umgehen. Mit der aktuellen Implementierung ist es nicht möglich, nach dem ersten to_layer weitere Modelle zu verbinden, die eine gemeinsame Schicht enthalten.

    Verwandte Themen