Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.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 创建形式为a.T*diag(b)*a+的稀疏矩阵的最快方法;C_Numpy_Scipy_Linear Algebra_Sparse Matrix_Hessian Matrix - Fatal编程技术网

Numpy 创建形式为a.T*diag(b)*a+的稀疏矩阵的最快方法;C

Numpy 创建形式为a.T*diag(b)*a+的稀疏矩阵的最快方法;C,numpy,scipy,linear-algebra,sparse-matrix,hessian-matrix,Numpy,Scipy,Linear Algebra,Sparse Matrix,Hessian Matrix,我试图优化一段代码,用内点法求解一个大型稀疏非线性系统。在更新步骤中,这涉及到计算海森矩阵H、梯度g,然后在H*d=-g中求解d,以获得新的搜索方向 Hessian矩阵具有以下形式的对称三对角结构: A.T*diag(b)*A+C 我已经运行了有关的特定函数: Line # Hits Time Per Hit % Time Line Contents ================================================== 386

我试图优化一段代码,用内点法求解一个大型稀疏非线性系统。在更新步骤中,这涉及到计算海森矩阵
H
、梯度
g
,然后在
H*d=-g
中求解
d
,以获得新的搜索方向

Hessian矩阵具有以下形式的对称三对角结构:

A.T*diag(b)*A+C

我已经运行了有关的特定函数:

Line # Hits     Time  Per Hit % Time Line Contents
==================================================
   386                               def _direction(n, res, M, Hsig, scale_var, grad_lnprior, z, fac):
   387                               
   388                                   # gradient
   389   44  1241715  28220.8    3.7     g = 2 * scale_var * res - grad_lnprior + z * np.dot(M.T, 1. / n)
   390                               
   391                                   # hessian
   392   44  3103117  70525.4    9.3     N = sparse.diags(1. / n ** 2, 0, format=FMT, dtype=DTYPE)
   393   44 18814307 427597.9   56.2     H = - Hsig - z * np.dot(M.T, np.dot(N, M))    # slow!
   394                                   
   395                                   # update direction
   396   44 10329556 234762.6   30.8     d, fac = my_solver(H, -g, fac)
   397                                   
   398   44      111      2.5    0.0     return d, fac
从输出来看,很明显,构建
H
是迄今为止成本最高的一步——它比实际解决新方向所需的时间要长得多

Hsig
M
都是CSC稀疏矩阵,
n
是密集向量,
z
是标量。我使用的解算器要求
H
为CSC或CSR稀疏矩阵

这里有一个函数,它可以生成一些与我的真实矩阵具有相同格式、维度和稀疏性的玩具数据:

import numpy as np
from scipy import sparse

def make_toy_data(nt=200000, nc=10):

    d0 = np.random.randn(nc * (nt - 1))
    d1 = np.random.randn(nc * (nt - 1))
    M = sparse.diags((d0, d1), (0, nc), shape=(nc * (nt - 1), nc * nt),
                     format='csc', dtype=np.float64)

    d0 = np.random.randn(nc * nt)
    Hsig = sparse.diags(d0, 0, shape=(nc * nt, nc * nt), format='csc',
                        dtype=np.float64)

    n = np.random.randn(nc * (nt - 1))
    z = np.random.randn()

    return Hsig, M, n, z
下面是我构建
H
的原始方法:

def original(Hsig, M, n, z):
    N = sparse.diags(1. / n ** 2, 0, format='csc')
    H = - Hsig - z * np.dot(M.T, np.dot(N, M))    # slow!
    return H
时间:

%timeit original(Hsig, M, n, z)
# 1 loops, best of 3: 483 ms per loop

有没有更快的方法来构造这个矩阵?

我试着运行您的测试用例,但在
np.dot(N,M)
中遇到了问题。我没有深入研究它,但我认为我的numpy/sparse组合(都是非常新的)在稀疏数组上使用
np.dot
时遇到了问题

但是
H=-Hsig-z*M.T.dot(N.dot(M))
运行得很好。这将使用
稀疏点

我还没有运行配置文件,但以下是几个部分的Ipython计时。生成数据所需的时间比生成双点所需的时间更长

In [37]: timeit Hsig,M,n,z=make_toy_data()
1 loops, best of 3: 2 s per loop

In [38]: timeit N = sparse.diags(1. / n ** 2, 0, format='csc')
1 loops, best of 3: 377 ms per loop

In [39]: timeit H = -Hsig - z*M.T.dot(N.dot(M))
1 loops, best of 3: 1.55 s per loop
H
是一个

<2000000x2000000 sparse matrix of type '<type 'numpy.float64'>'
    with 5999980 stored elements in Compressed Sparse Column format>

在计算三个对角数组中的乘积
M.T*D*M
时,我的速度几乎提高了4倍。如果
d0
d1
M
的主对角线和上对角线,
d
d
的主对角线,则以下代码直接创建
M.T*d*M

def make_tridi_bis(d0, d1, d, nc=10):
    d00 = d0*d0*d
    d11 = d1*d1*d
    d01 = d0*d1*d
    len_ = d0.size
    data = np.empty((3*len_ + nc,))
    indices = np.empty((3*len_ + nc,), dtype=np.int)
    # Fill main diagonal
    data[:2*nc:2] = d00[:nc]
    indices[:2*nc:2] = np.arange(nc)
    data[2*nc+1:-2*nc:3] = d00[nc:] + d11[:-nc]
    indices[2*nc+1:-2*nc:3] = np.arange(nc, len_)
    data[-2*nc+1::2] = d11[-nc:]
    indices[-2*nc+1::2] = np.arange(len_, len_ + nc)
    # Fill top diagonal
    data[1:2*nc:2] = d01[:nc]
    indices[1:2*nc:2] = np.arange(nc, 2*nc)
    data[2*nc+2:-2*nc:3] = d01[nc:]
    indices[2*nc+2:-2*nc:3] = np.arange(2*nc, len_+nc)
    # Fill bottom diagonal
    data[2*nc:-2*nc:3] = d01[:-nc]
    indices[2*nc:-2*nc:3] = np.arange(len_ - nc)
    data[-2*nc::2] = d01[-nc:]
    indices[-2*nc::2] = np.arange(len_ - nc ,len_)

    indptr = np.empty((len_ + nc + 1,), dtype=np.int)
    indptr[0] = 0
    indptr[1:nc+1] = 2
    indptr[nc+1:len_+1] = 3
    indptr[-nc:] = 2
    np.cumsum(indptr, out=indptr)

    return sparse.csr_matrix((data, indices, indptr), shape=(len_+nc, len_+nc))
如果您的矩阵
M
是CSR格式,您可以将
d0
d1
提取为
d0=M.data[::2]
d1=M.data[1::2]
,我修改了您的玩具数据生成例程以返回这些数组,我得到的结果如下:

In [90]: np.allclose((M.T * sparse.diags(d, 0) * M).A, make_tridi_bis(d0, d1, d).A)
Out[90]: True

In [92]: %timeit make_tridi_bis(d0, d1, d)
10 loops, best of 3: 124 ms per loop

In [93]: %timeit M.T * sparse.diags(d, 0) * M
1 loops, best of 3: 501 ms per loop

上述代码的全部目的是利用非零项的结构。如果你画了一张相乘矩阵的图表,你就可以相对容易地确信得到的三对角矩阵的主(
d_0
)和上下(
d_1
)对角线是:

d_0 = np.zeros((len_ + nc,))
d_0[:len_] = d00
d_0[-len_:] += d11

d_1 = d01

该函数中的其余代码只是直接构建三对角矩阵,因为使用上述数据调用
sparse.diags
要慢好几倍。

我的NumPy不允许我做
np.dot(M.t,np.dot(N,M))
。它肯定在你的机器上运行吗?你想做
N.dot(M)
?@MrE我怀疑这可能是版本问题-
numpy.dot()
在8个月前就被稀疏矩阵覆盖了。你不需要
dot
,只要
Hsig-z*M.t*(N*M)
,但我不知道它是否更快。@HYRY是的,我知道-我几乎总是使用ndarray而不是矩阵,因此
np.dot()
语法对我来说比
*
更自然。没有真正的性能差异,因为两者都只调用稀疏矩阵的
。\uu mul\uu()
方法。如上所述,
np.dot(N,M)
的问题与版本相关-在scipy的最新版本中,稀疏数组的
.dot()
方法覆盖了
np.dot()
,因此,在我的例子中,这两种语法是等价的(出于某种原因,
np.dot(A,B)
语法让我感觉更舒服:-)。关于计时,我只构造了
Hsig
M
一次,但是
\u direction()
函数被调用了1000次,因此我非常关心构造
H
所涉及的开销。稀疏点只是矩阵乘法,因此您可以编写
M.T*(N*M)
甚至
M.T*N*M
。并不是说没有速度差。sparsetools.csr.h文件引用了这篇SMMP论文:速度惊人。我还在想它是怎么工作的。如果我只想把
M.T*D*M
的主对角线和上下对角线构造成稠密向量,我该如何得到它们呢?太棒了,这非常有用!