Tensorflow 在推理过程中,如何从经过训练的模型的每一层获取特征图?

Tensorflow 在推理过程中,如何从经过训练的模型的每一层获取特征图?,tensorflow,machine-learning,keras,deep-learning,keras-layer,Tensorflow,Machine Learning,Keras,Deep Learning,Keras Layer,我已经从实施和培训了该模型,并使用了作者的: 我现在正在通过经过培训的网络运行一幅图像,希望在每个阶段获得网络输出(功能图等) 我的方法 为此,我尝试从完整模型(在我的代码中称为sizedModel)的层组中创建子模型,并检查它们的输出 我在第一次L1(Conv2D) 该模型上的.predict()结果是张量形状的(1360640,12),与预期一样,图像看起来很好 我现在尝试将该张量输入到图中标记为L2的层中(sizedModel.layers[2-8])。 我知道的唯一方法是在新模型中隔离

我已经从实施和培训了该模型,并使用了作者的:

我现在正在通过经过培训的网络运行一幅图像,希望在每个阶段获得网络输出(功能图等)

我的方法 为此,我尝试从完整模型(在我的代码中称为
sizedModel
)的层组中创建子模型,并检查它们的输出

我在第一次
L1(Conv2D)

该模型上的
.predict()
结果是张量形状的
(1360640,12)
,与预期一样,图像看起来很好

我现在尝试将该张量输入到图中标记为L2的层中(sizedModel.layers[2-8])。 我知道的唯一方法是在新模型中隔离。为此,我正在做: #从L1(1360640,12)的输出中拾取输入形状 _input=tf.keras.input(shape=L1\u result.shape,name=“input\u layer”)

这导致 #ValueError:层L2-0的输入0与层不兼容:输入形状的预期轴-1 #具有值4但接收到形状输入[None,1,360,4,12]

# Build sub-model from these two layers of the large model
Layer2 = Model(_input,_conv)

# Pass first sub-model (L1) output to this model
Result_L2 = Layer2.predict(L1_result)
为什么层
L2-0
输入0
不兼容?
是否有更简单的方法来单独调试每个层的输出?

如果我正确理解了您的问题,您希望获得模型每个层的输出特征映射。通常,正如我们在评论框中提到的,一个模型具有一个(或多个)输入一个(或多个)输出。但是为了检查内部层的激活特征映射,我们可以采取一些策略。一些可能的场景:(1)。希望在运行时或训练时获得每个层的输出特征映射(2)。希望在推理时或训练后得到各层的输出特征图。正如你所说:

我现在通过训练有素的网络运行一个映像,并希望 每个阶段的网络输出(特征图等)

这将转到数字2,在推断时间内获得特征映射。下面是一个简单可行的解决方法。首先,我们建立一个模型,然后在训练之后,我们将修改训练过的模型,以获得其中每个层的特征图(技术上,通过一些修改创建相同的模型)


我使用的是你在文章中引用的模型定义

def buildModel(inputSize=(9,9), networkWidth=[48, 24], parBlockSize=12): 
    ....
    ....
    return tf.keras.models.Model(inputs=input, outputs=output)

现在,我们迭代各个层,得到每个层的输出,并构建一个新模型

model = buildModel(...)
features_list = [layer.output for layer in model.layers]
activations_model = tf.keras.Model(inputs=model.input, outputs=features_list)
现在,如果我们将一些输入传递给
activations\u model
,我们将获得多个输出,而
model
只获得最后一层输出

img = np.random.random((1, 128, 128, 1)).astype("float32")
activations = activations_model.predict(img)

for i, _ in enumerate(activations):
    print(activations[i].shape)

(1, 128, 128, 1)
(1, 124, 124, 48)
(1, 124, 124, 12)
(1, 124, 124, 12)
(1, 124, 124, 12)
(1, 124, 124, 12)
(1, 122, 122, 8)
(1, 122, 122, 8)
(1, 122, 122, 8)
(1, 122, 122, 8)
(1, 122, 122, 32)
(1, 122, 122, 24)
(1, 122, 122, 12)
(1, 122, 122, 12)
(1, 120, 120, 8)
(1, 120, 120, 8)
(1, 120, 120, 16)
(1, 120, 120, 4)
(1, 240, 240, 1)
因此,我们从单个实例中获得了总计
1+48+12*6+8*6+32+24+16+4+1=246
特征映射。现在,我们可以根据需要保存这些要素地图

layer_names = []

for layer in model.layers:
    layer_names.append(layer)

for i, (layer_name, layer_activation) in enumerate(zip(layer_names, activations)):
    n_features = layer_activation.shape[-1]
    feat_maps = tf.squeeze(layer_activation)
    print(feat_maps.shape)

    if n_features == 1:
        tf.keras.preprocessing.image.save_img(
            f'tmp/{layer_name.name}_{n_features}.png',
            tf.expand_dims(feat_maps, axis=-1))
    else:
        for n_feature in range(n_features):
            feat_map = feat_maps[:, :, n_feature]
            tf.keras.preprocessing.image.save_img(
                f'tmp/{layer_name.name}_{n_feature}.png',
                tf.expand_dims(feat_map, axis=-1))

我认为现在还不太清楚您想在这里做什么,但您是否希望从模型中获得每个层的输出特征图?@M.Innat正确。我正在尝试在经过训练的模型中获得单个正向过程的输出功能映射,以便我可以针对另一个实现进行调试。这是可以实现的,但您能否为您的问题添加更多详细信息?你到底想要什么还不清楚。通常,我们可以修改模型,给出每个层的输出特征图,而不是最后一层,但这取决于具体情况。从一个模型中获取一些输出特征映射,并将其添加到另一个模型中,这也是相互的情况。但是,如果您可以添加一些即插即用代码,这将很容易了解。@M.Innat非常感谢您抽出时间来帮助我。我真的很感激。我已经更新了问题。希望这能让事情变得更清楚。有没有更简单的方法来调试每一层的输出张量?你的意思是保存的图像文件看起来不同?好的,我看到了两种结果。但我不确定区别是否来自于我们在这里提出的方法。我使用efficientnet-b5测试了一个糖尿病视网膜病变数据集的建议方法,下面是一些激活结果-,我发现了问题。当我通过网络运行图像时,我需要使用expand_dims传递它,例如:(tf.expand_dims(tf.expand_dims(lrImage,axis=0,axis=3))我没有为您的代码版本这样做,因此功能映射不正确!我懂了。如果你想让我知道什么,请通知我。最后,这里需要考虑的是:确保在你说特征映射的方式中,它们是激活的输出(不仅仅是线性变换),其次,保存过程有时会做出很多更改。或者,您可以逐步检查中间层输出并进行类似检查:例如,
tf.keras.Model(old_Model.input,old_Model.\u一些特定的_layer_输出
),实际上,在我上面的示例代码中,我不必这样做,但您可能需要它。如果您注意到,我已经通过了
np。random.random((1128128,1))
塑造了样本,因此我不需要为模型的输入扩展任何维度。
model = buildModel(...)
features_list = [layer.output for layer in model.layers]
activations_model = tf.keras.Model(inputs=model.input, outputs=features_list)
img = np.random.random((1, 128, 128, 1)).astype("float32")
activations = activations_model.predict(img)

for i, _ in enumerate(activations):
    print(activations[i].shape)

(1, 128, 128, 1)
(1, 124, 124, 48)
(1, 124, 124, 12)
(1, 124, 124, 12)
(1, 124, 124, 12)
(1, 124, 124, 12)
(1, 122, 122, 8)
(1, 122, 122, 8)
(1, 122, 122, 8)
(1, 122, 122, 8)
(1, 122, 122, 32)
(1, 122, 122, 24)
(1, 122, 122, 12)
(1, 122, 122, 12)
(1, 120, 120, 8)
(1, 120, 120, 8)
(1, 120, 120, 16)
(1, 120, 120, 4)
(1, 240, 240, 1)
layer_names = []

for layer in model.layers:
    layer_names.append(layer)

for i, (layer_name, layer_activation) in enumerate(zip(layer_names, activations)):
    n_features = layer_activation.shape[-1]
    feat_maps = tf.squeeze(layer_activation)
    print(feat_maps.shape)

    if n_features == 1:
        tf.keras.preprocessing.image.save_img(
            f'tmp/{layer_name.name}_{n_features}.png',
            tf.expand_dims(feat_maps, axis=-1))
    else:
        for n_feature in range(n_features):
            feat_map = feat_maps[:, :, n_feature]
            tf.keras.preprocessing.image.save_img(
                f'tmp/{layer_name.name}_{n_feature}.png',
                tf.expand_dims(feat_map, axis=-1))