假设我要针对某些参数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矩阵。但是,正如Why does Tensorflow Reshape tf.reshape() break the flow of gradients?中关于tf.gradients所指出的(但对于tf.hessians也成立),张量流无法看到图中的params
和flat_params
与{{ 1}}将引发错误,因为渐变将被视为tf.hessians(loss, flat_params)
。
在https://afqueiruga.github.io/tensorflow/2017/12/28/hessian-mnist.html中,代码的编写者采用另一种方法,首先创建flat参数并将其部分重塑为None
。此技巧确实有效,并且具有 expected 形状(2x2矩阵)的粗麻布效果。但是,在我看来,当您拥有复杂的模型时,这将很麻烦,并且如果通过内置函数(例如self.params
等创建模型,则无法应用)。
当tf.layers.dense
是任意形状的张量列表时,没有直接方法可以从tf.hessians
获取Hessian矩阵(在此示例中为2x2矩阵)吗?如果没有,如何自动self.params
的输出张量重塑?
答案 0 :(得分:1)
(根据TensorFlow r1.13)证明,如果len(xs)> 1,则tf.hessians(ys,xs)返回仅与完整Hessian矩阵的块对角线子矩阵相对应的张量。本文https://arxiv.org/pdf/1905.05559的全文和解决方案,以及https://github.com/gknilsen/pyhessian的代码