【问题标题】:How to pass multiple values to keras joined model如何将多个值传递给 keras 连接模型
【发布时间】:2020-09-02 01:42:44
【问题描述】:

我有两个预训练模型。假设它们是model_A 和model_B。这里,model_A 是 CNN + LSTM 网络,model_B 是 GCN。

模型_A:

Model_A 需要 1 个输入,如下所示。 X_in = Input(shape=(None, 150), name='X_in', dtype=int32)

模型_B:

Model_B 需要 3 个输入,如下所示。 X_in = Input(shape=(X_train_B[0].shape[-1], ), name='X_in', dtype=tf.float64) A_in = Input(shape=(None,), sparse=True, dtype=tf.float64) I_in = Input(shape=(), name='segment_ids_in', dtype=tf.int32)

我需要通过在最后一层之前获取该层的输出来合并这两个模型。以下是我如何定义新模型。

model_A = load_model('model_A.h5')
model_A = Model(inputs=model_A.inputs, outputs=model_A.layers[-2].output)

model_B = load_model('model_B.h5', custom_objects={'GraphConvSkip': GraphConvSkip, 'MinCutPool': MinCutPool,
                                                'GlobalAvgPool': GlobalAvgPool})
model_B = Model(inputs=model_B.inputs, outputs=model_B.layers[-2].output) 

def final_model():  
    X_in = Input(shape=(X_train_B[0].shape[-1] ), name='X_in', dtype=tf.float64)
    A_in = Input(shape=(None,), sparse=True, dtype=tf.float64)
    I_in = Input(shape=(), name='segment_ids_in', dtype=tf.int32)
    merged = Concatenate(axis=1)([X_in, A_in, I_in])

    concat = concatenate([model_A.output, model_B.output], axis=-1)
    concat = Dense(1, activation='sigmoid')(concat)

    model = Model(inputs=[model_A.input, merged], outputs=concat)
    adam = tf.keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-08, decay=0.0)
    model.compile(optimizer=adam, loss='binary_crossentropy', metrics=['acc'])
    return model

model = final_model()
model.fit([X_train_A,[X_train_B, A_train_B, I_]], [y_train_A], verbose=1)

执行此代码后,出现以下错误。

---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-54-8c7e818acc11> in <module>
----> 1 model = final_model()
      2 
      3 print('Fitting model')
      4 batches = batch_iterator([A_train_B, X_train_B, y_train_B, X_train_A, y_train_A], batch_size=1, epochs=2)
      5 for b in batches:

<ipython-input-53-5c9278e5efb8> in final_model()
      3     A_in = Input(shape=(None,), sparse=True, dtype=tf.float64)
      4     I_in = Input(shape=(), name='segment_ids_in', dtype=tf.int32)
----> 5     merged = Concatenate(axis=1)([X_in, A_in, I_in])
      6 
      7     concat = concatenate([model_A.output, model_B.output], axis=-1)

~/anaconda3/lib/python3.7/site-packages/tensorflow_core/python/keras/engine/base_layer.py in __call__(self, inputs, *args, **kwargs)
    746           # Build layer if applicable (if the `build` method has been
    747           # overridden).
--> 748           self._maybe_build(inputs)
    749           cast_inputs = self._maybe_cast_inputs(inputs)
    750 

~/anaconda3/lib/python3.7/site-packages/tensorflow_core/python/keras/engine/base_layer.py in _maybe_build(self, inputs)
   2114         # operations.
   2115         with tf_utils.maybe_init_scope(self):
-> 2116           self.build(input_shapes)
   2117       # We must set self.built since user defined build functions are not
   2118       # constrained to set self.built.

~/anaconda3/lib/python3.7/site-packages/tensorflow_core/python/keras/utils/tf_utils.py in wrapper(instance, input_shape)
    304     if input_shape is not None:
    305       input_shape = convert_shapes(input_shape, to_tuples=True)
--> 306     output_shape = fn(instance, input_shape)
    307     # Return shapes from `fn` as TensorShapes.
    308     if output_shape is not None:

~/anaconda3/lib/python3.7/site-packages/tensorflow_core/python/keras/layers/merge.py in build(self, input_shape)
    380     shape_set = set()
    381     for i in range(len(reduced_inputs_shapes)):
--> 382       del reduced_inputs_shapes[i][self.axis]
    383       shape_set.add(tuple(reduced_inputs_shapes[i]))
    384 

IndexError: list assignment index out of range


有人可以帮我解决如何将这些输入值传递给两个不同的模型吗?

----编辑01----

根据 Andrea 的建议修改代码后,出现以下错误。我也尝试使用 np.array() 传递输入,但仍然遇到相同的错误。你能检查一下我在哪里做错了吗?

另外,这里是我传递给模型 B 的值。因为它是一个图,X_ 是一个 N*d 特征向量,A_ 是一个 N*N 邻接矩阵,I_ 是通过调用 @ 得到的 segment_ids 987654331@.

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-71-22f819a7a9cd> in <module>
     18     return model
     19 
---> 20 model = final_model()
     21 print('Fitting model')
     22 batches = batch_iterator([A_train_B, X_train_B, y_train_B, X_train_A, y_train_A], batch_size=1, epochs=2)

<ipython-input-71-22f819a7a9cd> in final_model()
      7 
      8 def final_model():
----> 9     concat = Concatenate(-1)([model_A.outputs, model_B.outputs]) # merge outputs
     10     concat = Dense(1, activation='sigmoid')(concat)
     11 

~/anaconda3/lib/python3.7/site-packages/tensorflow_core/python/keras/engine/base_layer.py in __call__(self, inputs, *args, **kwargs)
    771                     not base_layer_utils.is_in_eager_or_tf_function()):
    772                   with auto_control_deps.AutomaticControlDependencies() as acd:
--> 773                     outputs = call_fn(cast_inputs, *args, **kwargs)
    774                     # Wrap Tensors in `outputs` in `tf.identity` to avoid
    775                     # circular dependencies.

~/anaconda3/lib/python3.7/site-packages/tensorflow_core/python/keras/layers/merge.py in call(self, inputs)
    179         return y
    180     else:
--> 181       return self._merge_function(inputs)
    182 
    183   @tf_utils.shape_type_conversion

~/anaconda3/lib/python3.7/site-packages/tensorflow_core/python/keras/layers/merge.py in _merge_function(self, inputs)
    402 
    403   def _merge_function(self, inputs):
--> 404     return K.concatenate(inputs, axis=self.axis)
    405 
    406   @tf_utils.shape_type_conversion

~/anaconda3/lib/python3.7/site-packages/tensorflow_core/python/keras/backend.py in concatenate(tensors, axis)
   2671   """
   2672   if axis < 0:
-> 2673     rank = ndim(tensors[0])
   2674     if rank:
   2675       axis %= rank

~/anaconda3/lib/python3.7/site-packages/tensorflow_core/python/keras/backend.py in ndim(x)
   1200 
   1201   """
-> 1202   dims = x.shape._dims
   1203   if dims is not None:
   1204     return len(dims)

AttributeError: 'list' object has no attribute 'shape'


【问题讨论】:

    标签: python python-3.x tensorflow keras deep-learning


    【解决方案1】:

    问题在于您的I_in = Input(shape=(), name='segment_ids_in', dtype=tf.int32),此输入层的形状为(None,)(等级为一),而其他输入的等级为二,转换为(None, 2) 之类的形状。您可以在模型摘要中看到这一点。您正在尝试通过第二维度 (axis=1) 进行连接,这是无法完成的,因为 I_in 没有第二维度,只有批处理维度。

    尝试扩展您的I_in 以获得第二个维度,例如:

    def final_model():  
        X_in = Input(shape=(X_train_B[0].shape[-1] ), name='X_in', dtype=tf.float64)
        A_in = Input(shape=(None,), sparse=True, dtype=tf.float64)
        I_in = Input(shape=(), name='segment_ids_in', dtype=tf.int32)
        I_in = Lambda(lambda x: tf.expand_dims(x, -1))(I_in) 
        merged = Concatenate(axis=1)([X_in, A_in, I_in])
    
        concat = concatenate([model_A.output, model_B.output], axis=-1)
        concat = Dense(1, activation='sigmoid')(concat)
    
        model = Model(inputs=[model_A.input, merged], outputs=concat)
        adam = tf.keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-08, decay=0.0)
        model.compile(optimizer=adam, loss='binary_crossentropy', metrics=['acc'])
        return model
    

    在 OP 澄清后编辑

    您没有通过代码中的模型传递输入。如果我理解正确,您有 4 个输入,希望通过 model_A 传递第一个,其余通过 model_B。最后,您要输出连接的倒数第二层输出。为此,您不需要连接 model_B 的输入。 由于我没有您的完整代码,我无法尝试,但我认为这应该可行:

    model_A = load_model('model_A.h5')
    
    model_B = load_model('model_B.h5', custom_objects={'GraphConvSkip': GraphConvSkip, 'MinCutPool': MinCutPool,
                                                    'GlobalAvgPool': GlobalAvgPool})
    
    def final_model():
        concat = Concatenate(-1)([model_A.get_layer(-2).output, model_B.get_layer(-2).output]) # merge outputs
        concat = Dense(1, activation='sigmoid')(concat)
    
        model = Model(inputs=[model_A.inputs, model_B.inputs], # the inputs do not change!
                      outputs=concat)
        adam = tf.keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, 
                                        epsilon=1e-08, decay=0.0)
        model.compile(optimizer=adam, loss='binary_crossentropy', metrics= 
                     ['acc'])
        return model
    
    model = final_model()
    model.fit([X_train_A, X_train_B, A_train_B, I_], # notice how the inner list disappeared!
              [y_train_A], verbose=1) 
    

    确保您的 y_train_A 的形状为 (BATCH_NUM, 64),因为您通过最后一个轴(倒数第二层输出)连接两个 (BATCH_NUM, 32) 张量。

    【讨论】:

    • 谢谢安德里亚。我试过你在这里建议的。但是,不幸的是,这次我遇到了以下错误。是因为改变了 I_ 的输入形状吗?是否有任何不同的方法可以将输入传递给这个级联模型?类型错误:传递给“ConcatV2”操作的“值”的列表中的张量具有不完全匹配的类型 [float32, float32, int32]。
    • 我发现上述问题是由于三个输入值的dtype。因为 tf.concat() 需要相同的 dtype 并且 I_in 输入具有 int32 作为 dtype。我无法更改该输入的 dtype,因为“segment_ids”只有 DataType int32 或 int64。那么,有没有其他方法可以将这些输入传递给两个模型?
    • 澄清一下:model_A 有 1 个输入,模型 B 有 3 个输入。您想要一个新模型,基本上有 4 个输入,通过模型传递这些,然后将单个第二个连接到最后一层输出?
    • 根据您的建议修改代码后,我遇到了另一个错误。我修改了问题,在 EDIT 01 下,您将看到我现在遇到的错误。我也尝试使用 np.array() 传递输入,但仍然遇到相同的错误。你能检查我在哪里做错了吗?在这里快速了解我的输入; X_是特征向量,A_是邻接矩阵,I_是segment_ids。
    • 如果无法运行代码,这将是一个漫长的调试会话。如果你可以分享一个 github repo,那将是最好的。无论如何,我稍微修改了第二个代码,试一试。其中一个模型(A 或 B)输出导致 Concatenate 层错误的列表。
    【解决方案2】:

    我找到了以下解决我的问题的方法。

    # Constructing the model
    concat = Concatenate(-1)([model_A.output, model_B.output]) # merge outputs
    concat = Dense(2, activation='sigmoid', name='output')(concat)
    
    model = Model(inputs=[model_A.inputs, model_B.inputs], outputs=concat)
    model.compile(optimizer='adam',  
                  loss='binary_crossentropy')
    
    # Training setup
    opt = tf.keras.optimizers.Adam(learning_rate=learning_rate)
    loss_fn = model.loss_functions[0]
    acc_fn = lambda x, y: K.mean(tf.keras.metrics.categorical_accuracy(x, y))
    
    # Training function
    @tf.function(experimental_relax_shapes=True)
    def train_step(inputs, targets):
        with tf.GradientTape() as tape:
            predictions = model(inputs, training=True)
            loss = loss_fn(targets, predictions)
        gradients = tape.gradient(loss, model.trainable_variables)
        opt.apply_gradients(zip(gradients, model.trainable_variables))
        return loss, acc_fn(targets, predictions)
    
    # Training the model
    batches = batch_iterator([A_train_B, X_train_B, y_train_B, X_train_A], batch_size=batch_size, epochs=epochs)
    for b in batches:
        X_, A_, I_ = Batch(b[0], b[1]).get('XAI')
        A_ = sp_matrix_to_sp_tensor(A_)
        y_ = b[2]
        X_A_ = b[3]
        outs = train_step([X_A_, X_, A_, I_], y_)
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-10
      • 2016-11-17
      • 2020-08-10
      • 2011-12-21
      • 2017-03-16
      相关资源
      最近更新 更多