假设我想计算一个标量值函数关于某些参数 W 的 Hessian 矩阵(例如,前馈神经网络的权重和偏差)。如果您考虑以下代码,实现一个经过训练以最小化 MSE 损失的二维线性模型:
import numpy as np
import tensorflow as tf
x = tf.placeholder(dtype=tf.float32, shape=[None, 2]) #inputs
t = tf.placeholder(dtype=tf.float32, shape=[None,]) #labels
W = tf.placeholder(np.eye(2), dtype=tf.float32) #weights
preds = tf.matmul(x, W) #linear model
loss = tf.reduce_mean(tf.square(preds-t), axis=0) #mse loss
params = tf.trainable_variables()
hessian = tf.hessians(loss, params)
您希望session.run(tf.hessian,feed_dict={})
返回一个 2x2 矩阵(等于 W)。事实证明,因为params
是一个 2x2 张量,所以输出是一个形状为 [2, 2, 2, 2] 的张量。params
虽然我可以轻松地重塑张量以获得我想要的矩阵,但当成为不同大小的张量列表时(例如,当模型是深度神经网络时),这个操作似乎非常麻烦。
似乎有两种解决方法:
展平
params
为一维张量,称为flat_params
:flat_params = tf.concat([tf.reshape(p, [-1]) for p in params])
这样
tf.hessians(loss, flat_params)
自然会返回一个 2x2 矩阵。然而,正如在为什么 Tensorflow Reshape tf.reshape() 会破坏梯度流中所指出的那样?对于 tf.gradients(但也适用于 tf.hessians),tensorflow 无法在图中看到 和 之间的符号链接,params
并且flat_params
会tf.hessians(loss, flat_params)
引发错误,因为梯度将被视为None
.在https://afqueiruga.github.io/tensorflow/2017/12/28/hessian-mnist.html中,代码作者反其道而行之,首先创建了 flat 参数并将其部分重塑为
self.params
. 这个技巧确实有效,并为您提供了具有预期形状(2x2 矩阵)的粗麻布。但是,在我看来,当你有一个复杂的模型时,这会很麻烦,如果你通过内置函数(如tf.layers.dense
,..)创建模型,则无法应用。
是否没有直接的方法可以从中获取 Hessian 矩阵(如本例中的 2x2 矩阵)tf.hessians
,何时self.params
是任意形状的张量列表?如果没有,您如何自动调整输出张量的形状tf.hessians
?