Python tensorflow中numpy.linalg.pinv的替代方案

Python tensorflow中numpy.linalg.pinv的替代方案,python,python-3.x,numpy,tensorflow,Python,Python 3.x,Numpy,Tensorflow,我正在寻找tensorflow中numpy.linalg.pinv的替代品。 到目前为止,我发现tensorflow只有tf.matrix_inverse(输入,伴随=None,name=None),如果矩阵不可逆,它就会抛出一个错误 我不知道tensorflow中的numpy.linalg.pinv替代方案,但正则化是矩阵不可逆时的替代方案。例如: try: result = tf.matrix_inverse(input, adjoint=None, name=None) exce

我正在寻找tensorflow中numpy.linalg.pinv的替代品。
到目前为止,我发现tensorflow只有
tf.matrix_inverse(输入,伴随=None,name=None)
,如果矩阵不可逆,它就会抛出一个错误

我不知道tensorflow中的numpy.linalg.pinv替代方案,但正则化是矩阵不可逆时的替代方案。例如:

try: 
    result = tf.matrix_inverse(input, adjoint=None, name=None)
except: 
    input += np.identity((input.shape))* c 
    result = tf.matrix_inverse(input, adjoint=None, name=None)
式中,c为常数,应非常小,如c=0.000001

然而,矩阵求逆在计算上相当昂贵,只有在必要时才能进行。有关更多信息,请参见:

您可以将
tensorflow
numpy
组合,如下所示:

return tf.py_func(np.linalg.pinv, [input], tf.float32)

TensorFlow提供了一个SVD op,因此您可以很容易地从中计算伪逆:

def pinv(A, b, reltol=1e-6):
  # Compute the SVD of the input matrix A
  s, u, v = tf.svd(A)

  # Invert s, clear entries lower than reltol*s[0].
  atol = tf.reduce_max(s) * reltol
  s = tf.boolean_mask(s, s > atol)
  s_inv = tf.diag(tf.concat([1. / s, tf.zeros([tf.size(b) - tf.size(s)])], 0))

  # Compute v * s_inv * u_t * b from the left to avoid forming large intermediate matrices.
  return tf.matmul(v, tf.matmul(s_inv, tf.matmul(u, tf.reshape(b, [-1, 1]), transpose_a=True)))

numpy实现之后的实现:

def pinv(a, rcond=1e-15):
    s, u, v = tf.svd(a)
    # Ignore singular values close to zero to prevent numerical overflow
    limit = rcond * tf.reduce_max(s)
    non_zero = tf.greater(s, limit)

    reciprocal = tf.where(non_zero, tf.reciprocal(s), tf.zeros(s.shape))
    lhs = tf.matmul(v, tf.matrix_diag(reciprocal))
    return tf.matmul(lhs, u, transpose_b=True)
这支持伪逆的单次和批量计算:

# Pseudo-inverse of one (4, 3) matrix, has shape (3, 4)
pinv(tf.random_normal((4, 3)))

# Pseudo-inverses of two (4, 3) matrices, has shape (2, 3, 4)
pinv(tf.random_normal((2, 4, 3)))

谢谢@Andy Tsai的提示

支持批处理以提高计算速度的另一种方法是将
tf.diag
替换为
tf.matrix\u diag
。大概是这样的:

def pinv(a, rcond=1e-15):
    s, u, v = tf.svd(a)
    # Ignore singular values close to zero to prevent numerical overflow
    limit = rcond * tf.reduce_max(s)
    non_zero = tf.greater(s, limit)

    reciprocal = tf.where(non_zero, tf.reciprocal(s), tf.zeros(s.shape))
    lhs = tf.matmul(v, tf.matrix_diag(reciprocal))
    return tf.matmul(lhs, u, transpose_b=True)

如果矩阵不可逆,您也可以使用正则化。@NikolasRieble,请提供一个示例
pinv()
基于SVD,Tensorflow有一个SVD函数。。。我不打算提供一个例子:)扩展你的最后一句话,如果OP必须解决
ax=b
,他们可以在
x方面找到
x
← pinv(A)@b
(OP暗示的路线)或(按照您的建议)他们可以做如下操作:
b^← A.T@b
A^← A.T@A
并使用LU分解等方法求解线性系统
A^x=b^
将永远不会调用除块之外的
。调用
tf.matrix\u inverse(输入,伴随=None,name=None)
只是将相应的操作添加到图形中。它不会检查输入是否可逆,因为输入本身只是一个没有任何值的张量。您仍然会遇到
InvalidArgumentError(回溯见上文):输入不可逆。
+1,这应该是可接受的答案。但是,是否可以将
b
设置为可选?除了计算A+*b之外,用户可能还需要伪逆函数。我认为,可以用s_inv=tf.diag(1./s)替换最后两行。返回tf.matmul(v,tf.matmul(s_inv,u,transpose_b=True))