TensorFlow 中的特征值问题

Eigenvalue problems in TensorFlow

我想使用 TensorFlow 解决特征值问题。 特别是,我有

e, v = tf.self_adjoint_eig(laplacian, name="eigendata")
eigenmap = v[:,1:4]

所以我不想计算所有特征向量。

在 Matlab 中,我会使用 eigs(laplacian,4,'sm')

正在查看 https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/ops/linalg_ops.py, 我看到 tf.self_adjoint_eig 调用了 gen_linalg_ops._self_adjoint_eig_v2。 但是,我在 Github 或其他地方找不到 gen_linalg_ops

关于在 TensorFlow 中进行此类线性代数的任何建议,还是最好与 Python 中的其他库一起使用?

我想 Matlab 也计算了所有的特征向量,但随后过滤了 no。需要的载体。

Numpy 线性代数库的文档非常丰富。 请参考下面的link https://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.eig.html

您可能会在本地 python 安装中找到 gen_linalg_ops.py 文件,也许在 ~/.local/lib/ 或类似的地方。您可以在那里查找目录 site-packages,它应该包含一个目录 tensorflowgen_linalg_ops.py 文件位于 python/ops。我电脑上的完整路径是 ~/.local/lib/python3.5/site-packages/tensorflow/python/ops/gen_linalg_ops.py,你的机器上可能有类似的东西。

您是想将其作为某个更大的 TF 项目的一部分来解决,还是只是为了好玩而解决它。在第二种情况下,我只使用 numpy.linalg.eig.

我相信matlab的指定特征值数量的参数在找到所有特征值后会过滤掉不需要的特征值。所以它不会改善计算时间。

在这种情况下,您可以只使用 TF 程序中的 tf.self_adjoint_eig

当前的 TensorFlow linalg 实现是单核的,似乎是从头开始编写的,因此可能需要一些时间来匹配旧库(如 Intel 的 Matrix Kernel Library)的功能。

您可以在 MKL 中进行计算(可用于 scipy 的 conda 版本)并将值数据作为 numpy 数组在 MKL 和 TensorFlow 之间传递。由于对于足够大的矩阵,计算规模为 O(n^3),因此与计算相比,数据传输的额外成本可以忽略不计。

例如在 MKL 中计算全 SVD(与直觉相反,faster 比自伴随 eig),我使用以下包装器,它保存在 tf.Variable 个对象中,让我切换MKL 和 TensorFlow 实现之间

default_dtype = tf.float32
USE_MKL_SVD=True                   # Tensorflow vs MKL SVD

if USE_MKL_SVD:
  assert np.__config__.get_info("lapack_mkl_info"), "No MKL detected :("


class SvdWrapper:
  """Encapsulates variables needed to perform SVD of a TensorFlow target.
  Initialize: wrapper = SvdWrapper(tensorflow_var)
  Trigger SVD: wrapper.update_tf() or wrapper.update_scipy()
  Access result as TF vars: wrapper.s, wrapper.u, wrapper.v
  """

  def __init__(self, target, name):
    self.name = name
    self.target = target
    self.tf_svd = SvdTuple(tf.svd(target))

    self.init = SvdTuple(
      ones(target.shape[0], name=name+"_s_init"),
      Identity(target.shape[0], name=name+"_u_init"),
      Identity(target.shape[0], name=name+"_v_init")
    )

    assert self.tf_svd.s.shape == self.init.s.shape
    assert self.tf_svd.u.shape == self.init.u.shape
    assert self.tf_svd.v.shape == self.init.v.shape

    self.cached = SvdTuple(
      tf.Variable(self.init.s, name=name+"_s"),
      tf.Variable(self.init.u, name=name+"_u"),
      tf.Variable(self.init.v, name=name+"_v")
    )

    self.s = self.cached.s
    self.u = self.cached.u
    self.v = self.cached.v

    self.holder = SvdTuple(
      tf.placeholder(default_dtype, shape=self.cached.s.shape, name=name+"_s_holder"),
      tf.placeholder(default_dtype, shape=self.cached.u.shape, name=name+"_u_holder"),
      tf.placeholder(default_dtype, shape=self.cached.v.shape, name=name+"_v_holder")
    )

    self.update_tf_op = tf.group(
      self.cached.s.assign(self.tf_svd.s),
      self.cached.u.assign(self.tf_svd.u),
      self.cached.v.assign(self.tf_svd.v)
    )

    self.update_external_op = tf.group(
      self.cached.s.assign(self.holder.s),
      self.cached.u.assign(self.holder.u),
      self.cached.v.assign(self.holder.v)
    )

    self.init_ops = (self.s.initializer, self.u.initializer, self.v.initializer)


  def update(self):
    if USE_MKL_SVD:
      self.update_scipy()
    else:
      self.update_tf()

  def update_tf(self):
    sess = tf.get_default_session()
    sess.run(self.update_tf_op)

  def update_scipy(self):
    sess = tf.get_default_session()
    target0 = self.target.eval()
    # A=u.diag(s).v', singular vectors are columns
    # TODO: catch "ValueError: array must not contain infs or NaNs"
    u0, s0, vt0 = linalg.svd(target0)
    v0 = vt0.T
    #    v0 = vt0 # bug, makes loss increase, use for sanity checks
    feed_dict = {self.holder.u: u0,
                 self.holder.v: v0,
                 self.holder.s: s0}
    sess.run(self.update_external_op, feed_dict=feed_dict)

并使用

covariance = data @ t(data)
svd = u.SvdWrapper(target=covariance)
sess.run(svd.init_ops)   # initialize to identity matrices
svd.update()             # update using latest value of covariance 
sess.run([svd.s, svd.u, svd.v])  # get values of factors

我找到了一个使用 tensorflow here 的 Lanczos 算法实现。

希望对您有所帮助。

MATLAB 函数EIG 计算所有特征向量。 MATLAB function EIGS only calculates a selected number of the eigenvectors using precompiled https://en.wikipedia.org/wiki/ARPACK which implements https://en.wikipedia.org/wiki/Lanczos_algorithm MATLAB 中没有本地 MATLAB Lanczos 代码,很可能是因为 Lanczos 算法在舍入误差方面不可避免地不稳定,尤其是在单精度方面,使更稳定的实现变得棘手 and/or 昂贵。

EIGS 函数的替代方法是 https://www.mathworks.com/matlabcentral/fileexchange/48-lobpcg-m that implements https://en.wikipedia.org/wiki/LOBPCG MATLAB 中的原生函数。

SciPy 有一个到 ARPACK 的接口以及 Python 本机实现 https://docs.scipy.org/doc/scipy-1.1.0/reference/generated/scipy.sparse.linalg.lobpcg.html

Scikit 使用 ARPACK 或 LOBPCG 进行流形谱嵌入 http://scikit-learn.org/stable/modules/generated/sklearn.manifold.spectral_embedding.html and for spectral clustering http://scikit-learn.org/stable/modules/generated/sklearn.cluster.SpectralClustering.html

TensorFlow 现在有 Lanczos 的本机实现 https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/solvers/python/ops/lanczos.py