Keras将输入提供给中间层并获取最终输出。

9

我的模型是一个像这样的简单全连接网络:

inp=Input(shape=(10,))
d=Dense(64, activation='relu')(inp)
d=Dense(128,activation='relu')(d)
d=Dense(256,activation='relu')(d)     #want to give input here, layer3
d=Dense(512,activation='relu')(d)
d=Dense(1024,activation='relu')(d)
d=Dense(128,activation='linear')(d)

保存模型后,我想要将输入传递给第三层。目前我的做法是这样的:

model=load_model('blah.h5')    #above described network
print(temp_input.shape)        #(16,256), which is equal to what I want to give

index=3
intermediate_layer_model = Model(inputs=temp_input,
                                 outputs=model.output)

End_output = intermediate_layer_model.predict(temp_input)

但是它不起作用,也就是说我收到了一些错误信息,比如输入不兼容,输入应为元组等等。错误信息如下:
raise TypeError('`inputs` should be a list or tuple.') 
TypeError: `inputs` should be a list or tuple.

我能否在网络中间传递我的自定义输入并获得输出,而不是从开头给出输入并从末尾获取输出?任何帮助将不胜感激。


请包含有关不兼容输入的错误消息。 - Dr. Snoopy
我现在已经编辑了问题,请告诉我解决这个问题的方法。 - Asim
@Asim 问题标题和描述是两回事:您在标题中提到要将输入传递给中间层并获取模型的输出,而在问题描述中,您正在尝试获取模型的中间层输出。请决定您想要哪一个,然后相应地编辑您的问题。 - today
我之前做错了,我已经编辑了问题。我想要将输入传递给中间层,并从末端获取输出。 - Asim
4个回答

13

首先你需要学会,在Keras中当你在输入上应用一个层时,这个层内部创建了一个新的节点,该节点连接输入和输出张量。每个层可能有多个节点,将不同的输入张量连接到其相应的输出张量上。要构建一个模型,需要遍历这些节点,并创建一个新的模型图,其中包含从输入张量到达输出张量所需的所有节点(即在创建模型时指定的内容:model = Model(inputs=[...], outputs=[...]))。

现在,您想要提供模型的中间层并获取模型的输出。由于这是一条新的数据流路径,我们需要为该新计算图中的每个层创建新的节点。我们可以按照以下方式实现:

idx = 3  # index of desired layer
input_shape = model.layers[idx].get_input_shape_at(0) # get the input shape of desired layer
layer_input = Input(shape=input_shape) # a new input tensor to be able to feed the desired layer

# create the new nodes for each layer in the path
x = layer_input
for layer in model.layers[idx:]:
    x = layer(x)

# create the model
new_model = Model(layer_input, x)

幸运的是,你的模型只有一个分支,我们可以简单地使用 for 循环来构建新模型。然而,对于更复杂的模型,这可能不容易实现,你可能需要编写更多代码来构建新模型。


5

这里有另一种实现相同结果的方法。首先创建一个新的输入层,然后将其与较低的层(带有权重)连接。

为此,首先重新初始化这些层(使用相同的名称),然后使用以下方法从父模型重新加载对应的权重

new_model.load_weights("parent_model.hdf5", by_name=True)

这将从父模型中加载所需的权重。只要事先确保恰当地命名您的层即可。

idx = 3  
input_shape = model.layers[idx].get_input_shape_at(0) layer

new_input = Input(shape=input_shape)

d=Dense(256,activation='relu', name='layer_3')(new_input)
d=Dense(512,activation='relu', name='layer_4'))(d)
d=Dense(1024,activation='relu', name='layer_5'))(d)
d=Dense(128,activation='linear', name='layer_6'))(d)

new_model = Model(new_input, d)
new_model.load_weights("parent_model.hdf5", by_name=True)

这种方法适用于具有多个输入或分支的复杂模型。您只需要复制所需层的相同代码,连接新的输入,最后加载相应的权重即可。


0

我曾经遇到过同样的问题,尝试了建议的解决方案并且对我很有帮助,但我还是希望有更明确的解决方法。为了以后参考,我在这里提供了详细的解决方案:

d1 = Dense(64, activation='relu')
d2 = Dense(128,activation='relu')
d3 = Dense(256,activation='relu')
d4 = Dense(512,activation='relu')
d5 = Dense(1024,activation='relu')
d6 = Dense(128,activation='linear')

inp = Input(shape=(10,))

x = d1(inp)
x = d2(x)
x = d3(x)
x = d4(x)
x = d5(x)
x = d6(x)

full_model = tf.keras.Model(inp, x)
full_model.summary()

intermediate_input = Input(shape=d3.get_input_shape_at(0)) # get shape at node 0
x = d3(intermediate_input)
x = d4(x)
x = d5(x)
x = d6(x)
partial_model = tf.keras.Model(intermediate_input, x)
partial_model.summary()

Reference: https://keras.io/guides/functional_api/#shared-layers


0

你可以轻松地使用 keras.backend.function 来实现这个目的:

import numpy as np
from tensorflow.keras.layers import Input, Dense
from tensorflow.keras.models import Model
from tensorflow.keras import backend as K

inp=Input(shape=(10,))
d=Dense(64, activation='relu')(inp)
d=Dense(128,activation='relu')(d)
d=Dense(256,activation='relu')(d)     #want to give input here, layer3
d=Dense(512,activation='relu')(d)
d=Dense(1024,activation='relu')(d)
d=Dense(128,activation='linear')(d)

model = Model(inp, d)


foo1 = K.function(
    [inp],
    model.layers[2].output
)

foo2 = K.function(
    [model.layers[2].output],
    model.output
)


X = np.random.rand(1, 10)
X_intermediate = foo1([X])
print(np.allclose(foo2([X_intermediate]), model.predict(X)))

对于函数命名不太美观,非常抱歉 - 尽力而为吧)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接