我现在正在将图像输入到训练好的网络中,并希望在每个阶段获取网络输出(如特征图等)。
我的方法
为此,我尝试从完整模型(在我的代码中称为sizedModel
)中创建由多个层组成的子模型,并检查它们的输出。
我已经对第一个L1(Conv2D)
完成了这个操作
L1_inp = sizedModel.layers[1].inputL1_out = sizedModel.layers[1].outputLayer1 = Model(L1_inp,L1_out)L1_result = Layer1.predict( tf.expand_dims(tf.expand_dims(lrImage, axis=0), axis=3))# 将特征图保存为灰度图像Xresult = tf.squeeze(L1_result)for i in range(Xresult.shape[2]): data = (Xresult[:,:,i].numpy() * 255).astype(np.uint8) filename = 'tmp_test/result'+str(i).zfill(2)+'.png' Image.fromarray(data).save(filename)`
对该模型使用.predict()
得到的张量形状为(1,360,640,12)
,这与预期相符,图像看起来也很好。
我现在正试图将该张量输入到图中标记为L2的层中(sizedModel.layers[2-8])。我唯一知道的方法是在一个新的模型中进行隔离。为此,我正在做:# 从L1的输出中获取输入形状(1,360,640,12)_input = tf.keras.Input(shape=L1_result.shape, name=”input_layer”)
# 从大模型中获取第一个"tf_op_layer_strided_slice"split = largeModel.layers[2](_input)# 从大模型中获取第一个"L2-0 (Conv 3x3)"conv = largeModel.layers[5](_split)
这会导致# ValueError: 层L2-0的输入0与层不兼容:预期输入形状的轴-1值为4,但接收到的输入形状为[None, 1, 360, 4, 12]
# 从大模型的这两个层构建子模型Layer2 = Model(_input,_conv)# 将第一个子模型(L1)的输出传递给这个模型Result_L2 = Layer2.predict(L1_result)
为什么层L2-0
的Input 0
不兼容?有没有更简单的方法来调试每个层的输出?
回答:
如果我正确理解了您的问题,您想要获取模型每个层的输出特征图。通常,如我们在评论框中提到的,一个模型有一个(或多个)输入和一个(或多个)输出。但是,为了检查内部层的激活特征图,我们可以采取一些策略。一些可能的情景:(1)。希望在运行时或训练时获取每个层的输出特征图。(2)。希望在推理时或训练后获取每个层的输出特征图。就像您引用的:
我现在正在将图像输入到训练好的网络中,并希望在每个阶段获取网络输出(特征图等)。
这属于第2种情况,即在推理时获取特征图。下面是一个简单可行的解决方案。首先,我们构建一个模型,然后在训练后,我们将修改训练好的模型以获取其中每个层的特征图(技术上是创建一个具有某些修改的相同模型)。
# 我们训练的模型 input|conv1|conv2|conv3|output|# 我们用于推理的修改后的模型 input|conv1 --> outputA [获取特征图]|conv2 --> outputB [获取特征图]|conv3 --> outputC [获取特征图]|output|
我正在使用您在帖子中引用的这里的模型定义。
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_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))