Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/tensorflow/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Numpy 当行列式溢出/下溢时,计算TensorFlow中行列式的对数_Numpy_Tensorflow_Gradient_Linear Algebra_Determinants - Fatal编程技术网

Numpy 当行列式溢出/下溢时,计算TensorFlow中行列式的对数

Numpy 当行列式溢出/下溢时,计算TensorFlow中行列式的对数,numpy,tensorflow,gradient,linear-algebra,determinants,Numpy,Tensorflow,Gradient,Linear Algebra,Determinants,我的代价函数涉及log(det(A))的计算(假设det(A)为正,因此log有意义,但A不是厄米特函数,因此Cholesky分解在这里不适用)。当det(A)非常大/小时,直接调用det(A)将溢出/下溢。为了避免这种情况,我们可以利用数学事实 log(det(A))=Tr(log(A)) 后者可以使用LU分解(比特征值/SVD更有效)进行评估。该算法已在numpy as中实现,因此问题在于如何从TensorFlow调用numpy 这是我试过的 import numpy as np impo

我的代价函数涉及log(det(A))的计算(假设det(A)为正,因此log有意义,但A不是厄米特函数,因此Cholesky分解在这里不适用)。当det(A)非常大/小时,直接调用det(A)将溢出/下溢。为了避免这种情况,我们可以利用数学事实

log(det(A))=Tr(log(A))

后者可以使用LU分解(比特征值/SVD更有效)进行评估。该算法已在numpy as中实现,因此问题在于如何从TensorFlow调用numpy


这是我试过的

import numpy as np
import tensorflow as tf
from tensorflow.python.framework import function

def logdet_np(a):
    _, l = np.linalg.slogdet(a)
    return l

def logdet1(a):
    return tf.py_func(logdet_np, [a], tf.float64)

@function.Defun(tf.float64, func_name='LogDet')
def logdet2(a):
    return tf.py_func(logdet_np, [a], tf.float64)

with tf.Session() as sess:
    a = tf.constant(np.eye(500)*10.)
    #print(sess.run(logdet1(a)))
    print(sess.run(logdet2(a)))
我首先定义一个python函数来传递numpy结果。然后我使用
tf.py_func
定义了两个
logdet
函数。第二个函数由
function.Defun
修饰,该函数用于定义TensorFlow函数及其以后的梯度。当我测试它们时,我发现第一个函数
logdet1
起作用并给出正确的结果。但是第二个函数
logdet2
返回一个KeyError

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-
packages/tensorflow/python/ops/script_ops.py in __call__(self, token, args)
     77   def __call__(self, token, args):
     78     """Calls the registered function for `token` with args."""
---> 79     func = self._funcs[token]
     80     if func is None:
     81       raise ValueError("callback %s is not found" % token)

KeyError: 'pyfunc_0'
我的问题是
Defun
decorator有什么问题?为什么它与py_func冲突?如何在TensorFlor中正确包装numpy函数


定义
logdet
梯度的剩余部分与问题相关。根据这个问题的答案,一个人试图写作

@function.Defun(tf.float64, tf.float64, func_name='LogDet_Gradient')
def logdet_grad(a, grad):
    a_adj_inv = tf.matrix_inverse(a, adjoint=True)
    out_shape = tf.concat([tf.shape(a)[:-2], [1, 1]], axis=0)
    return tf.reshape(grad, out_shape) * a_adj_inv
@function.Defun(tf.float64, func_name='LogDet', grad_func=logdet_grad)
def logdet(a):
    return tf.py_func(logdet_np, [a], tf.float64, stateful=False, name='LogDet')

如果你能解决
Defun
py_func
之间的冲突,上面的代码就行了,这是我在上面提出的关键问题。

如果你的问题是溢出,你可以用简单的数学来解决它。


因此,您只需要获得特征值,记录它们并将它们相加。

您可以使用SVD分解
A

A = U S V'
因为乘积的行列式是行列式的乘积,
U
V'
的行列式是1或-1,而
S
的行列式是非负的

abs(det(A)) = det(S)
因此,(正)行列式的对数可以计算为

tf.reduce_sum(tf.log(svd(A, compute_uv=False)))


从TF1.1开始,
tf.svd
缺乏梯度(未来版本可能会有梯度),因此我建议采用kofd代码的实现:


在@MaxB的帮助下,我在这里发布代码来定义log(abs(det(A))及其梯度的函数
logdet

  • logdet
    调用numpy函数,使用log(det(A))=Tr(log(A))的思想来计算行列式的log,这对行列式的溢出/下溢是鲁棒的。它基于LU分解,与基于特征值/SVD的方法相比效率更高

  • numpy函数
    slogdet
    返回一个包含行列式符号和log(abs(det(a))的元组。符号将被忽略,因为它在优化过程中不会对梯度信号做出贡献

  • 根据梯度log(det(A))=inv(A)^T,通过矩阵求逆计算
    logdet
    的梯度。它基于TensorFlow的代码,稍作修改


我们可以测试
logdet
对非常大/很小的行列式有效,并且它的梯度也是正确的

i = tf.constant(np.eye(500))
x = tf.Variable(np.array([10.]))
y = logdet(x*i)
dy = tf.gradients(y, [x])
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print(sess.run([y, dy]))

结果:
[1151.2925464970251,[array([50.])]]

您可以使用奇异值分解(SVD)并从奇异值中获取行列式是一种特殊的(如正定)?@dmuir det(A)为正,但特征值并非全部为正(意味着成对出现负特征值).@YaroslavBulatov但你知道SVD实施梯度的状态吗?将矩阵除以其最大绝对值。TF没有一般特征值op(也不是真的)。使用奇异值分解是正确的方法(如建议的)。@MaxB特征值可以是虚值这一事实并没有破坏数学。你仍然可以记录虚数,显然你可以把几个虚数相加。关于没有特征值,我不知道这一点,但是什么阻止一个人实现自己的C++函数来实现这个?现在我看到了关于SVD的评论,如果您认为该评论足以理解该怎么做-请向我们解释SVD和行列式之间的联系。写下来作为回答,因为您坚持。@Salvadodali谢谢。我知道你提到的数学。我发现特征值分解比LU分解慢得多。事实上,numpy中已经有了这种Tr(log(A))方法的实现。问题是如何在TensorFlow中调用numpy。如果你能看看我更新的问题,我将不胜感激。对数梯度(det(a))是inv(a)的转置,这一事实可以避免SVD缺乏梯度。实际上,我已经测试了您的代码,由于SVD,它非常慢,比
tf.log(tf.matrix\u determinate(A))
慢得多。我还发现numpy为我的目的提供了一个函数
slogdet
,它基于更高效的LU分解。现在我想知道如何调用numpy形式的TensorFlow。请看一下我的最新问题。我将非常感谢您的患者。@EverettYou您可以从TF致电NP:参见例如@EverettYou,或者更确切地说,最后的评论。感谢您指出这些参考资料。它们非常有用。在你的问题中,你从来没有说过CPU是可以的(否则调用NP可能是不好的)。您也从未说过此特定op的性能至关重要(否则,最简单的解决方案是最好的)。
i = tf.constant(np.eye(500))
x = tf.Variable(np.array([10.]))
y = logdet(x*i)
dy = tf.gradients(y, [x])
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print(sess.run([y, dy]))