在 Tensor-flow 2.0 中以 eager 模式访问中间层的输出



我有我在Tensor-flow 2.0上构建的CNN。我需要访问中间层的输出。我正在讨论其他类似的堆栈溢出问题,但都有涉及 Keras 顺序模型的解决方案。

我尝试使用model.layers[index].output,但我得到

层 conv2d 没有入站节点。

我可以在这里发布我的代码(这是超长的(,但我相信即使没有它,也有人可以指出如何在渴望模式下仅使用 Tensorflow 2.0 来完成它。

我在寻找答案时偶然发现了这个问题,当我默认使用 TF 2.0 中的模型子类化 API 时,我花了一些时间才弄清楚(如这里 https://www.tensorflow.org/tutorials/quickstart/advanced(。 如果有人遇到类似情况,您需要做的就是分配所需的中间输出作为类的属性。然后保留没有 @tf.function 装饰器的test_step,并创建其修饰副本(例如val_step(,以便在训练期间有效地内部计算验证性能。 作为一个简短的例子,我相应地修改了链接中教程的一些功能。我假设我们需要在扁平化后访问输出。

def call(self, x):
x = self.conv1(x)
x = self.flatten(x)
self.intermediate=x #assign it as an object attribute for accessing later
x = self.d1(x)
return self.d2(x)
#Remove @tf.function decorator from test_step for prediction
def test_step(images, labels):
predictions = model(images, training=False)
t_loss = loss_object(labels, predictions)
test_loss(t_loss)
test_accuracy(labels, predictions)
return
#Create a decorated val_step for object's internal use during training
@tf.function
def val_step(images, labels):
return test_step(images, labels)

现在,当你在训练后运行 model.predict(( 时,使用未修饰的测试步骤,你可以使用 model.intermediate 访问中间输出,这将是一个 EagerTensor,其值只需通过 model.intermediate.numpy(( 获得。但是,如果您不从test_step中删除@tf_function装饰器,这将返回一个张量,其值不是那么容易获得。

感谢您回答我之前的问题。我写了这个简单的例子来说明如何在 TensorFlow 2.x 中完成你尝试做的事情,使用 MNIST 数据集作为示例问题。

方法的要点:

  1. 构建一个辅助模型(aux_model在下面的示例中(,这就是具有多个输出的所谓"功能模型"。第一个输出是原始模型的输出,将用于损耗计算和反向传播,而其余输出是您要访问的中间层输出。

  2. 使用tf.GradientTape()编写自定义训练循环,并在模型的每个单独变量上公开详细的梯度值。然后,您可以选择您感兴趣的渐变。这要求您知道模型变量的顺序。但对于顺序模型来说,这应该相对容易。

import tensorflow as tf
(x_train, y_train), (_, _) = tf.keras.datasets.mnist.load_data()
# This is the original model.
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=[28, 28, 1]),
tf.keras.layers.Dense(100, activation="relu"),
tf.keras.layers.Dense(10, activation="softmax")])
# Make an auxiliary model that exposes the output from the intermediate layer
# of interest, which is the first Dense layer in this case.
aux_model = tf.keras.Model(inputs=model.inputs,
outputs=model.outputs + [model.layers[1].output])
# Define a custom training loop using `tf.GradientTape()`, to make it easier
# to access gradients on specific variables (the kernel and bias of the first
# Dense layer in this case).
cce = tf.keras.losses.CategoricalCrossentropy()
optimizer = tf.optimizers.Adam()
with tf.GradientTape() as tape:
# Do a forward pass on the model, retrieving the intermediate layer's output.
y_pred, intermediate_output = aux_model(x_train)
print(intermediate_output)  # Now you can access the intermediate layer's output.
# Compute loss, to enable backprop.
loss = cce(tf.one_hot(y_train, 10), y_pred)
# Do backprop. `gradients` here are for all variables of the model.
# But we know we want the gradients on the kernel and bias of the first
# Dense layer, which happens to be the first two variables of the model.
gradients = tape.gradient(loss, aux_model.variables)
# This is the gradient on the first Dense layer's kernel.
intermediate_layer_kerenl_gradients = gradients[0]
print(intermediate_layer_kerenl_gradients)
# This is the gradient on the first Dense layer's bias.
intermediate_layer_bias_gradients = gradients[1]
print(intermediate_layer_bias_gradients)
# Update the variables of the model.
optimizer.apply_gradients(zip(gradients, aux_model.variables))

最直接的解决方案是这样的:

mid_layer = model.get_layer("layer_name")

您现在可以将"mid_layer"视为模型,例如:

mid_layer.predict(X)

哦,另外,要获取隐藏层的名称,您可以使用以下内容:

model.summary()

这也将为您提供有关图层输入/输出的一些见解。

最新更新