前文:

预处理共轭梯度算法(Preconditioned Conjugate Gradients Method)

给出代码:

  1. import numpy as np
  2. # from rllab.misc.ext import sliced_fun
  3. EPS = np.finfo('float64').tiny
  4. def cg(f_Ax, b, cg_iters=10, callback=None, verbose=False, residual_tol=1e-10):
  5. """
  6. Demmel p 312
  7. """
  8. p = b.copy()
  9. r = b.copy()
  10. x = np.zeros_like(b)
  11. rdotr = r.dot(r)
  12. fmtstr = "%10i %10.3g %10.3g"
  13. titlestr = "%10s %10s %10s"
  14. if verbose: print(titlestr % ("iter", "residual norm", "soln norm"))
  15. for i in range(cg_iters):
  16. if callback is not None:
  17. callback(x)
  18. if verbose: print(fmtstr % (i, rdotr, np.linalg.norm(x)))
  19. z = f_Ax(p)
  20. v = rdotr / p.dot(z)
  21. x += v * p
  22. r -= v * z
  23. newrdotr = r.dot(r)
  24. mu = newrdotr / rdotr
  25. p = r + mu * p
  26. rdotr = newrdotr
  27. if rdotr < residual_tol:
  28. break
  29. if callback is not None:
  30. callback(x)
  31. if verbose: print(fmtstr % (i + 1, rdotr, np.linalg.norm(x))) # pylint: disable=W0631
  32. return x
  33. def preconditioned_cg(f_Ax, f_Minvx, b, cg_iters=10, callback=None, verbose=False, residual_tol=1e-10):
  34. """
  35. Demmel p 318
  36. """
  37. x = np.zeros_like(b)
  38. r = b.copy()
  39. p = f_Minvx(b)
  40. y = p
  41. ydotr = y.dot(r)
  42. fmtstr = "%10i %10.3g %10.3g"
  43. titlestr = "%10s %10s %10s"
  44. if verbose: print(titlestr % ("iter", "residual norm", "soln norm"))
  45. for i in range(cg_iters):
  46. if callback is not None:
  47. callback(x, f_Ax)
  48. if verbose: print(fmtstr % (i, ydotr, np.linalg.norm(x)))
  49. z = f_Ax(p)
  50. v = ydotr / p.dot(z)
  51. x += v * p
  52. r -= v * z
  53. y = f_Minvx(r)
  54. newydotr = y.dot(r)
  55. mu = newydotr / ydotr
  56. p = y + mu * p
  57. ydotr = newydotr
  58. if ydotr < residual_tol:
  59. break
  60. if verbose: print(fmtstr % (cg_iters, ydotr, np.linalg.norm(x)))
  61. return x
  62. def test_cg():
  63. A = np.random.randn(5, 5)
  64. A = A.T.dot(A)
  65. b = np.random.randn(5)
  66. x = cg(lambda x: A.dot(x), b, cg_iters=5, verbose=True) # pylint: disable=W0108
  67. assert np.allclose(A.dot(x), b)
  68. x = preconditioned_cg(lambda x: A.dot(x), lambda x: np.linalg.solve(A, x), b, cg_iters=5,
  69. verbose=True) # pylint: disable=W0108
  70. assert np.allclose(A.dot(x), b)
  71. x = preconditioned_cg(lambda x: A.dot(x), lambda x: x / np.diag(A), b, cg_iters=5,
  72. verbose=True) # pylint: disable=W0108
  73. assert np.allclose(A.dot(x), b)
  74. def lanczos(f_Ax, b, k):
  75. """
  76. Runs Lanczos algorithm to generate a orthogonal basis for the Krylov subspace
  77. b, Ab, A^2b, ...
  78. as well as the upper hessenberg matrix T = Q^T A Q
  79. from Demmel ch 6
  80. """
  81. assert k > 1
  82. alphas = []
  83. betas = []
  84. qs = []
  85. q = b / np.linalg.norm(b)
  86. beta = 0
  87. qm = np.zeros_like(b)
  88. for j in range(k):
  89. qs.append(q)
  90. z = f_Ax(q)
  91. alpha = q.dot(z)
  92. alphas.append(alpha)
  93. z -= alpha * q + beta * qm
  94. beta = np.linalg.norm(z)
  95. betas.append(beta)
  96. print("beta", beta)
  97. if beta < 1e-9:
  98. print("lanczos: early after %i/%i dimensions" % (j + 1, k))
  99. break
  100. else:
  101. qm = q
  102. q = z / beta
  103. return np.array(qs, 'float64').T, np.array(alphas, 'float64'), np.array(betas[:-1], 'float64')
  104. def lanczos2(f_Ax, b, k, residual_thresh=1e-9):
  105. """
  106. Runs Lanczos algorithm to generate a orthogonal basis for the Krylov subspace
  107. b, Ab, A^2b, ...
  108. as well as the upper hessenberg matrix T = Q^T A Q
  109. from Demmel ch 6
  110. """
  111. b = b.astype('float64')
  112. assert k > 1
  113. H = np.zeros((k, k))
  114. qs = []
  115. q = b / np.linalg.norm(b)
  116. beta = 0
  117. for j in range(k):
  118. qs.append(q)
  119. z = f_Ax(q.astype('float64')).astype('float64')
  120. for (i, q) in enumerate(qs):
  121. H[j, i] = H[i, j] = h = q.dot(z)
  122. z -= h * q
  123. beta = np.linalg.norm(z)
  124. if beta < residual_thresh:
  125. print("lanczos2: stopping early after %i/%i dimensions residual %f < %f" % (j + 1, k, beta, residual_thresh))
  126. break
  127. else:
  128. q = z / beta
  129. return np.array(qs).T, H[:len(qs), :len(qs)]
  130. def make_tridiagonal(alphas, betas):
  131. assert len(alphas) == len(betas) + 1
  132. N = alphas.size
  133. out = np.zeros((N, N), 'float64')
  134. out.flat[0:N ** 2:N + 1] = alphas
  135. out.flat[1:N ** 2 - N:N + 1] = betas
  136. out.flat[N:N ** 2 - 1:N + 1] = betas
  137. return out
  138. def tridiagonal_eigenvalues(alphas, betas):
  139. T = make_tridiagonal(alphas, betas)
  140. return np.linalg.eigvalsh(T)
  141. def test_lanczos():
  142. np.set_printoptions(precision=4)
  143. A = np.random.randn(5, 5)
  144. A = A.T.dot(A)
  145. b = np.random.randn(5)
  146. f_Ax = lambda x: A.dot(x) # pylint: disable=W0108
  147. Q, alphas, betas = lanczos(f_Ax, b, 10)
  148. H = make_tridiagonal(alphas, betas)
  149. assert np.allclose(Q.T.dot(A).dot(Q), H)
  150. assert np.allclose(Q.dot(H).dot(Q.T), A)
  151. assert np.allclose(np.linalg.eigvalsh(H), np.linalg.eigvalsh(A))
  152. Q, H1 = lanczos2(f_Ax, b, 10)
  153. assert np.allclose(H, H1, atol=1e-6)
  154. print("ritz eigvals:")
  155. for i in range(1, 6):
  156. Qi = Q[:, :i]
  157. Hi = Qi.T.dot(A).dot(Qi)
  158. print(np.linalg.eigvalsh(Hi)[::-1])
  159. print("true eigvals:")
  160. print(np.linalg.eigvalsh(A)[::-1])
  161. print("lanczos on ill-conditioned problem")
  162. A = np.diag(10 ** np.arange(5))
  163. Q, H1 = lanczos2(f_Ax, b, 10)
  164. print(np.linalg.eigvalsh(H1))
  165. print("lanczos on ill-conditioned problem with noise")
  166. def f_Ax_noisy(x):
  167. return A.dot(x) + np.random.randn(x.size) * 1e-3
  168. Q, H1 = lanczos2(f_Ax_noisy, b, 10)
  169. print(np.linalg.eigvalsh(H1))
  170. if __name__ == "__main__":
  171. test_lanczos()
  172. test_cg()

上面的cg函数是共轭梯度法,preconditioned_cg函数是预处理共轭梯度法。

可以看到,预处理的共轭梯度法和共轭梯度法是比较相似的,下面给出不同的地方:

共轭梯度法:

  1. newrdotr = r.dot(r)
  2. mu = newrdotr / rdotr
  3. p = r + mu * p
  4. rdotr = newrdotr

预处理共轭梯度法:

  1. y = f_Minvx(r)
  2. newydotr = y.dot(r)
  3. mu = newydotr / ydotr
  4. p = y + mu * p
  5. ydotr = newydotr

上面的代码中给出的对预处理共轭梯度法的两次调用:

  1. x = preconditioned_cg(lambda x: A.dot(x), lambda x: np.linalg.solve(A, x), b, cg_iters=5,
  2. verbose=True) # pylint: disable=W0108
  3. assert np.allclose(A.dot(x), b)
  4. x = preconditioned_cg(lambda x: A.dot(x), lambda x: x / np.diag(A), b, cg_iters=5,
  5. verbose=True) # pylint: disable=W0108
  6. assert np.allclose(A.dot(x), b)

运行结果:

之所以说第一个预处理共轭梯度法是一个伪的呢,是因为其预处理依旧是使用求解A矩阵的解,因此并不具备实际意义和价值。

下图来自:预处理共轭梯度法(2)

可以看到上面代码中的预处理共轭梯度法其实就是使用Jacobi方法的,主要体现:

  1. lambda x: x / np.diag(A)

由于预处理共轭梯度法比共轭梯度法的优势在于对稀疏的系数矩阵且系数矩阵的条件数(最大最小特征值之比)很大的情况,因此上面的Jacobi方法的预处理共轭梯度法并没有明显的优势。

预处理共轭梯度算法(Preconditioned Conjugate Gradients Method)的代码实现的更多相关文章

  1. 机器学习: 共轭梯度算法(PCG)

    今天介绍数值计算和优化方法中非常有效的一种数值解法,共轭梯度法.我们知道,在解大型线性方程组的时候,很少会有一步到位的精确解析解,一般都需要通过迭代来进行逼近,而 PCG 就是这样一种迭代逼近算法. ...

  2. 共轭梯度算法求最小值-scipy

    # coding=utf-8 #共轭梯度算法求最小值 import numpy as np from scipy import optimize def f(x, *args): u, v = x a ...

  3. Mahout 系列之----共轭梯度

    无预处理共轭梯度 要求解线性方程组 ,稳定双共轭梯度法从初始解 开始按以下步骤迭代: 任意选择向量 使得 ,例如, 对 若 足够精确则退出 预处理共轭梯度 预处理通常被用来加速迭代方法的收敛.要使用预 ...

  4. 3. OpenCV-Python——图像梯度算法、边缘检测、图像金字塔与轮廓检测、直方图与傅里叶变换

    一.图像梯度算法 1.图像梯度-Sobel算子 dst = cv2.Sobel(src, ddepth, dx, dy, ksize) ddepth:图像的深度 dx和dy分别表示水平和竖直方向 ks ...

  5. 近端梯度算法(Proximal Gradient Descent)

    L1正则化是一种常用的获取稀疏解的手段,同时L1范数也是L0范数的松弛范数.求解L1正则化问题最常用的手段就是通过加速近端梯度算法来实现的. 考虑一个这样的问题: minx  f(x)+λg(x) x ...

  6. 临近梯度下降算法(Proximal Gradient Method)的推导以及优势

    邻近梯度下降法 对于无约束凸优化问题,当目标函数可微时,可以采用梯度下降法求解:当目标函数不可微时,可以采用次梯度下降法求解:当目标函数中同时包含可微项与不可微项时,常采用邻近梯度下降法求解.上述三种 ...

  7. C++算法之大数加法计算的代码

    如下代码段是关于C++算法之大数加法计算的代码,希望对大家有用. { int length; int index; int smaller; int prefix = 0; if(NULL == sr ...

  8. 基本算法思想Java实现的详细代码

    基本算法思想Java实现的详细代码 算法是一个程序的灵魂,一个好的算法往往可以化繁为简,高效的求解问题.在程序设计中算法是独立于语言的,无论使用哪一种语言都可以使用这些算法,本文笔者将以Java语言为 ...

  9. 【优化算法】Greedy Randomized Adaptive Search算法 超详细解析,附代码实现TSP问题求解

    01 概述 Greedy Randomized Adaptive Search,贪婪随机自适应搜索(GRAS),是组合优化问题中的多起点元启发式算法,在算法的每次迭代中,主要由两个阶段组成:构造(co ...

  10. 《算法导论》第二章demo代码实现(Java版)

    <算法导论>第二章demo代码实现(Java版) 前言 表示晚上心里有些不宁静,所以就写一篇博客,来缓缓.囧 拜读<算法导论>这样的神作,当然要做一些练习啦.除了练习题与思考题 ...

随机推荐

  1. Spring扩展——BeanFactory和FactoryBean

    BeanFactory和FactoryBean BeanFactory和FactoryBean长得很相似,也很容易让我们产生误解,特别是对于初学者而言,搞懂他俩关系非常有必要,因为这两个接口,是Spr ...

  2. RSS 解析:全球内容分发的利器及使用技巧

    使用 RSS 可以将最新的网络内容从一个网站分发到全球数千个其他网站. RSS 允许快速浏览新闻和更新. RSS 文档示例 <?xml version="1.0" encod ...

  3. 燕千云AITSM重塑IT服务管理

    ​ IT服务经历了三个阶段,缘起于设备管理,兴起于灾难恢复,发展于IT服务管理.IT服务发展到目前的阶段,企业所使用的系统功能也由孤立的系统转变为综合的集成系统,IT服务所管理的对象也由核心业务转变为 ...

  4. Thanos解码:打造企业级云原生监控解决方案

    本文深入探讨了Thanos技术在云原生监控领域的应用,详细介绍了Thanos的基本概念.核心组件.安装配置步骤以及一个实战案例,帮助读者理解如何利用Thanos解决大规模监控数据的存储.查询和高可用性 ...

  5. 你不知道的 CSS 之包含块

    你不知道的 CSS 之包含块 一说到 CSS 盒模型,这是很多小伙伴耳熟能详的知识,甚至有的小伙伴还能说出 border-box 和 content-box 这两种盒模型的区别. 但是一说到 CSS ...

  6. 解决Vue中使用history路由模式出现404的问题

    背景 vue中默认的路由模式是hash,会出现烦人的符号#,如http://127.0.0.1/#/. 改为history模式可以解决这个问题,但是有一个坑是:强刷新.回退等操作会出现404. Vue ...

  7. 基于MCU的SD卡fat文件系统读写移植

    背景 https://blog.csdn.net/huang20083200056/article/details/78508490 SD卡(Secure Digital Memory Card)具有 ...

  8. 背包DP——完全背包

    完全背包模型与 0-1 背包类似,与 0-1 背包的区别仅在于一个物品可以选取无限次,而非仅能选取一次. 而状态转移方程于01背包区别在于可以直接从[i][j-w[i]]转移 理由是当我们这样转移时, ...

  9. 构建高可用性、高性能和可扩展的Zabbix Server架构

    简介 本教程讲解了一下如何设计构建一个高性能.高可靠.高扩展的Zabbix 监控集群. 架构图 架构图PDF下载: https://songxwn.com/file/Zabbix_HA.pdf Pig ...

  10. 使用EF 连接 数据库 SQLserver、MySql 实现 CodeFirst

    1.新建项目,下载Nuget安装包 创建项目需要注意几点,如果是基于 .net framework 的项目 需要选择 相应版本的 EF, 如果是跨平台则选择EF Core版本. 我这里选择的是 .ne ...