4

假设我想计算一个标量值函数关于某些参数 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_paramstf.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

4

1 回答 1

3

事实证明(根据 TensorFlow r1.13)如果 len(xs) > 1,则 tf.hessians(ys, xs) 返回仅对应于完整 Hessian 矩阵的块对角子矩阵的张量。本文全文和解决方案https://arxiv.org/pdf/1905.05559,代码在https://github.com/gknilsen/pyhessian

于 2018-11-20T22:30:54.990 回答