MCMC using Hamiltonian dynamics

Neal R. M. , MCMC Using Hamiltonian Dynamics[J]. arXiv: Computation, 2011: 139-188.

@article{neal2011mcmc,
title={MCMC Using Hamiltonian Dynamics},
author={Neal, Radford M},
journal={arXiv: Computation},
pages={139–188},
year={2011}}

Hamiltonian Monte Carlo-wiki

算法

先把算法列一下.

Input: 初始值 q q q, 步长 ϵ \epsilon ϵ与leapfrog迭代次数 L L L.

  • q ( 0 ) = q q^{(0)} = q q(0)=q;
  • 循环迭代直到停止条件满足(以下第 t t t步):
  1. 从标准正态分布中抽取 p p p, q = q ( t − 1 ) q = q^{{(t-1)}} q=q(t1), p ( t − 1 ) = p p^{(t-1)} = p p(t1)=p.
  2. p = p − ϵ ∇ q U ( q ) / 2 , (alg.1) \tag{alg.1} p = p- \epsilon \nabla_q U(q) / 2, p=pϵqU(q)/2,(alg.1)
  3. 重复 i = 1 , 2 , … , L i=1,2,\ldots, L i=1,2,,L:
    • q = q + ϵ ∇ p H ( p ) , (alg.2) \tag{alg.2} q = q + \epsilon \nabla_pH(p), q=q+ϵpH(p),(alg.2)
    • 如果 i ≠ L i \not = L i=L:
      p = p − ϵ ∇ q U ( q ) . (alg.3) \tag{alg.3} p = p- \epsilon \nabla_q U(q). p=pϵqU(q).(alg.3)
  4. p = p − ϵ ∇ q U ( q ) / 2 , p ∗ = − p , q ∗ = q . (alg.4) \tag{alg.4} p = p- \epsilon \nabla_q U(q) / 2, \quad p^* = -p, q^*=q. p=pϵqU(q)/2,p=p,q=q.(alg.4)
  5. 计算接受概率
    α = min ⁡ { 1 , exp ⁡ ( − H ( q ∗ , p ∗ ) + H ( q ∗ , p ∗ ) } . (alg.5) \tag{alg.5} \alpha = \min \{ 1, \exp(-H(q^*,p^*) + H(q^*, p^*)\}. α=min{1,exp(H(q,p)+H(q,p)}.(alg.5)
  6. 从均匀分布 U ( 0 , 1 ) U(0,1) U(0,1)中抽取 u u u, 如果 u < α u<\alpha u<α, q ( t ) = q ∗ q^{(t)}=q^* q(t)=q, 否则 q ( t ) = q ( t − 1 ) q^{(t)}=q^{(t-1)} q(t)=q(t1).

output: { p ( t ) , q ( t ) } \{p^{(t)},q^{(t)}\} {p(t),q(t)}.

注: 1中的标准正态分布不是唯一的, 但是文中选的便是这个. 4中的 p ∗ = − p p^*=-p p=p在实际编写程序的时候可以省去.

符号说明

因为作者从物理方程的角度给出几何解释,所以这里给出的符号一般有俩个含义:

符号概率物理
q q q随机变量,服从我们所在意的分布冰球的位置
p p p用以构造马氏链的额外的变量冰球的动量(mv)
U ( q ) U(q) U(q)…与我们所在意的分布有关冰球的势能
K ( p ) K(p) K(p)冰球的动能
H ( q , p ) H(q, p) H(q,p)与我们所在意的分布有关 H ( q , p ) = U ( q ) + K ( p ) H(q, p) = U(q) + K(p) H(q,p)=U(q)+K(p)

Hamilton方程

物理解释

Hamilton方程( i = 1 , 2 , … , d i=1,2,\ldots, d i=1,2,,d, d d d是维度):
d q i d t = ∂ H ∂ p i (2.1) \tag{2.1} \frac{dq_i}{dt} = \frac{\partial H}{\partial p_i} dtdqi=piH(2.1)
d p i d t = − ∂ H ∂ q i (2.2) \tag{2.2} \frac{dp_i}{dt} = -\frac{\partial H}{\partial q_i} dtdpi=qiH(2.2)

这个东西怎么来的, 大概是因为 H ( q , p ) = U ( q ) + K ( p ) H(q, p) = U(q)+K(p) H(q,p)=U(q)+K(p), 如果机械能守恒, 那么随着时间 t t t的变化 H ( q , p ) H(q, p) H(q,p)应该是一个常数, 所以其关于t的导数应该是0.
d H d t = ∑ i [ ∂ H ∂ p i d p i d t + ∂ H ∂ q i d q i d t ] = ( ∇ p H ) T p ˙ + ( ∇ q H ) T q ˙ = 0 , \frac{dH}{dt} = \sum_i [\frac{\partial H}{\partial p_i} \frac{dp_i}{dt}+\frac{\partial H}{\partial q_i}\frac{dq_i}{dt}] = (\nabla_p H)^T \dot{p}+(\nabla_qH)^T \dot{q} = 0, dtdH=i[piHdtdpi+qiHdtdqi]=(pH)Tp˙+(qH)Tq˙=0,
其中 p ˙ = ( ∂ p 1 / ∂ t , … , ∂ p d / ∂ t ) \dot{p}=(\partial{p_1}/\partial t, \ldots, \partial p_d / \partial t) p˙=(p1/t,,pd/t).
( 2.1 ) (2.1) (2.1), 左边是速度 q ˙ = v \dot{q} = v q˙=v, 右边
∇ p H = ∇ p K = ∇ p ∣ p ∣ 2 2 m = p m = v = q ˙ . \nabla_p H = \nabla_p K = \nabla_p \frac{|p|^2}{2m} = \frac{p}{m} = v=\dot{q}. pH=pK=p2mp2=mp=v=q˙.

不过,估计是先有的(2.2)再有的H吧, 就先这么理解吧. 需要一提的是, K ( p ) K(p) K(p)通常定义为
K ( p ) = p T M − 1 p / 2 , K(p)=p^TM^{-1}p/2, K(p)=pTM1p/2,
其中 M M M是对称正定的, 后面我们可以看到, 这种取法与正态分布相联系起来.
此时:
在这里插入图片描述

一些性质

可逆 Reversibility

映射 T s : ( q ( t ) , p ( t ) ) ↦ ( q ( t + s ) , p ( t + s ) ) T_s: (q(t), p(t)) \mapsto (q(t+s), p(t+s)) Ts:(q(t),p(t))(q(t+s),p(t+s))是一一的,这个我感觉只能从物理的解释上理解啊, 一个冰球从一个点到另一个点, 现在H确定, 初值确定, 不就相当于整个轨迹都确定了吗, 那从哪到哪自然是一一的, 也就存在逆 T − s T_{-s} Ts, 且只需:
d q i d t = − ∂ H ∂ p i , \frac{dq_i}{dt} = -\frac{\partial H}{\partial p_i}, dtdqi=piH,
d p i d t = − ( − ∂ H ∂ q i ) . \frac{dp_i}{dt} = -(-\frac{\partial H}{\partial q_i}). dtdpi=(qiH).

H的不变性


在这里插入图片描述
当然, 因为我们的算法是离散化的, 所以这个性质只是在 ϵ \epsilon ϵ比较小的时候近似保持.

保体积 Volume preservation

即假设区域 R = { ( q , p ) } R=\{(q,p)\} R={(q,p)}在映射 T t T_t Tt的作用下为 R t = { ( q ( t ) , p ( t ) } R_t=\{(q(t), p(t)\} Rt={(q(t),p(t)}, 则二者的体积相同, 均为 V V V.

定义
v ( t ) = ∫ R t d V = ∫ R det ⁡ ( ∂ T t ∂ z ) d V , v(t)= \int_{R_t} dV = \int_{R} \det( \frac{\partial T_t}{\partial z}) dV, v(t)=RtdV=Rdet(zTt)dV,
其中 z = ( q , p ) z = (q, p) z=(q,p). 又
z ( t ) = T t z = z + t J ∇ H ( z ) + O ( t 2 ) , z(t) = T_tz = z+t J\nabla H(z) + \mathcal{O}(t^2), z(t)=Ttz=z+tJH(z)+O(t2),
其中
f : = d z d t = J ∇ H ( z ) , J = ( 0 d × d I d × d − I d × d 0 d × d ) . f:=\frac{dz}{dt} = J\nabla H(z), \\ J = \left ( \begin{array}{ll} 0_{d \times d} & I_{d\times d} \\ -I_{d\times d} & 0_{d \times d} \end{array}\right ). f:=dtdz=JH(z),J=(0d×dId×dId×d0d×d).
所以
∂ T t ∂ z = I + ∂ f ∂ z t + O ( t 2 ) , \frac{\partial{T_t}}{\partial z} = I + \frac{\partial f}{\partial z}t + \mathcal{O}(t^2), zTt=I+zft+O(t2),
又对于任意方阵 A A A
在这里插入图片描述
所以
det ⁡ ( ∂ T t ∂ z ) = 1 + t r ( ∂ f / ∂ z ) t + O ( t 2 ) , \det (\frac{\partial{T_t}}{\partial z} ) = 1 + \mathrm{tr}(\partial f / \partial z) t + \mathcal{O}(t^2), det(zTt)=1+tr(f/z)t+O(t2),
t r ( ∂ f / ∂ z ) = d i v f \mathrm{tr}(\partial f / \partial z)=\mathrm{div} f tr(f/z)=divf, 于是
d v d t ∣ t = 0 = ∫ R d i v f   d V . \frac{d v}{ d t} |_{t=0} = \int_{R}\mathrm{div} f \: d V. dtdvt=0=RdivfdV.

d i v f = d i v J ∇ H ( z ) = J d i v ∇ H ( z ) = ∑ i = 1 d [ ∂ ∂ q ∂ H ∂ p i − ∂ ∂ p ∂ H ∂ q i ] = 0. \mathrm{div}f = \mathrm{div} J\nabla H(z) = J \mathrm{div} \nabla H(z) = \sum_{i=1}^d [\frac{\partial}{\partial q}\frac{\partial H}{\partial p_i}-\frac{\partial}{\partial p}\frac{\partial H}{\partial q_i}] = 0. divf=divJH(z)=JdivH(z)=i=1d[qpiHpqiH]=0.
对于 t = t 0 t=t_0 t=t0, 我们都可以类似的证明 d v ( t 0 ) / d t = 0 dv(t_0)/dt=0 dv(t0)/dt=0, 所以 v ( t ) v(t) v(t)是常数.

这部分的证明参考自

Here

辛 Symplecticness

在这里插入图片描述

离散化Hamilton方程 leapfrog方法

下面四幅图, 是 U ( q ) = q 2 / 2 , K ( p ) = p 2 / 2 U(q)=q^2/2, K(p)=p^2/2 U(q)=q2/2,K(p)=p2/2, 起始点为 ( q , p ) = ( 0 , 1 ) (q, p) = (0, 1) (q,p)=(0,1).
在这里插入图片描述

在这里插入图片描述

Euler’s method

如果假定 K ( p ) = ∑ i = 1 d p i 2 2 m i K(p) = \sum_{i=1}^d \frac{p_i^2}{2m_i} K(p)=i=1d2mipi2,
在这里插入图片描述

Modified Euler’s method

仅有一个小小的变动,
在这里插入图片描述

Leapfrog method

在这里插入图片描述
注意到, 在实际编写程序的时候, 除了第一步和最后一步, 我们可以将 p p p的俩个半步合并成一步.
另外从右下角的图可以发现, 因为离散化的缘故, H ( q , p ) H(q, p) H(q,p)的值是有偏差的. 但是Leapfrog 方法和 modified Euler方法都是保体积的, 因为每步更新都只改变一个量, 可以验证其雅可比行列式为1.

MCMC

概率与Hamiltonian, 正则(canonical)分布

如何将分布于Hamilton方程联系在一起? 假如, 我们关心的是 q q q的分布 P ( q ) P(q) P(q), 则我们构造一个容易采样的分布 P ( q ) P(q) P(q),
P ( q , p ) = 1 Z exp ⁡ ( − H ( q , p ) / T ) , (3.2) \tag{3.2} P(q, p) = \frac{1}{Z}\exp(-H(q,p)/T), P(q,p)=Z1exp(H(q,p)/T),(3.2)
其中 Z Z Z是规范化的常数, T T T一般取1. 从(3.2)中容易得到 H ( q , p ) H(q,p) H(q,p). 事实上此时 q , p q, p q,p是独立的(这么写是说明直接构造 P ( q , p ) P(q, p) P(q,p)也是可以的), 则可以分别
P ( q ) = 1 Z 1 exp ⁡ ( − U ( q ) / T ) , P ( p ) = 1 Z 2 exp ⁡ ( − K ( p ) / T ) . P(q) = \frac{1}{Z_1}\exp(-U(q)/T), \\ P(p) = \frac{1}{Z_2}\exp(-K(p)/T). P(q)=Z11exp(U(q)/T),P(p)=Z21exp(K(p)/T).
在贝叶斯统计中, 有
U ( q ) = − log ⁡ [ π ( q ) L ( D ∣ q ) ] , U(q) = -\log [\pi (q) L(D|q)], U(q)=log[π(q)L(Dq)],
其中 D D D为数据, L L L为似然函数, 与文章中不同, 文章中是 L ( q ∣ D ) L(q|D) L(qD), 应该是笔误.

HMC算法

就是开头提到的算法, 但是其中有一些地方值得思考. (alg.4)我们令 p ∗ = − p p^*=-p p=p, 这一步在实际中是不起作用的, 既然 K ( p ) = K ( − p ) K(p)=K(-p) K(p)=K(p)而且在下轮中我们重新采样 p p p, 我看网上的解释是为了理论, 取反这一部分使得proposal是对称的, 是建议分布 g ( p ∗ , q ∗ ∣ p , q ) = g ( p , q ∣ p ∗ , q ∗ ) g(p^*, q^*|p, q)=g(p, q| p^*, q^*) g(p,qp,q)=g(p,qp,q)? 不是很懂.

关于这个问题的讨论

有点明白了, 首先因为Leapfrog是确定的, 所以 P ( q ∗ , p ∗ ∣ q , p ) P(q^*, p^*|q, p) P(q,pq,p)非0即1:
P ( q ∗ , p ∗ ∣ q , p ) = δ ( q ∗ , p ∗ , q , p ) = { 1 , T L ϵ ( q , p ) = q ∗ , p ∗ , 0 , T L ϵ ( q , p ) ≠ q ∗ , p ∗ . P(q^*, p^*|q, p) = \delta(q^*,p^*,q,p) = \left \{ \begin{array}{ll} 1, & T_{L\epsilon} (q, p) = q^*, p^*, \\ 0, & T_{L\epsilon} (q, p) \not = q^*, p^*. \end{array} \right. P(q,pq,p)=δ(q,p,q,p)={1,0,TLϵ(q,p)=q,p,TLϵ(q,p)=q,p.
为了 P ( q ∗ , p ∗ ∣ q , p ) = P ( q , p ∣ q ∗ , p ∗ ) P(q^*, p^*|q, p)=P(q, p|q^*, p^*) P(q,pq,p)=P(q,pq,p), 如果不取反肯定不行, 因为他就会往下走, 取反的操作实际上就是在可逆性里提到的, 在同样的操作下, q ∗ , p ∗ q^*, p^* q,p会回到 q , p q, p q,p. 于是MH接受概率就退化成了M接受概率. 但是前文也提到了, 取反的操作, 只有在 K ( p ) = K ( − p ) K(p)=K(-p) K(p)=K(p)的情况下是成立的.

HMC保持正则分布不变的证明 detailed balance

假设 { A k } \{A_k\} {Ak} ( q , p ) ∈ R 2 d (q, p) \in \mathbb{R}^{2d} (q,p)R2d空间的一个分割, 其在L次leapfrog的作用, 及取反的操作下的像为 { B k } \{B_k\} {Bk}, 由于可逆性, { B k } \{B_k\} {Bk}也是一个分割, 且有相同的体积 V V V(保体积性),则
P ( A i ) T ( B j ∣ A i ) = P ( B j ) T ( A i ∣ B j ) . P(A_i) T(B_j|A_i) = P(B_j)T(A_i|B_j). P(Ai)T(BjAi)=P(Bj)T(AiBj).
实际上 i ≠ j i\not =j i=j是时候是显然的, 因为二者都是0. 因为 H H H是连续函数, 当 V V V变得很小的时候, H H H X X X区域上的值相当于常数 H X H_X HX, 于是
在这里插入图片描述

所以(3.7)成立.

Detailed balance:

在这里插入图片描述
其中 R ( X ) R(X) R(X)是当前状态属于 X X X, 拒绝提议的 ( q ∗ , p ∗ ) (q^*,p^*) (q,p)的概率. 注意 ∑ i T ( A i ∣ B k ) = T ( A k ∣ B k ) = 1 − R ( B k ) \sum_{i} T(A_i|B_k)=T(A_k|B_k)=1-R(B_k) iT(AiBk)=T(AkBk)=1R(Bk). 看上面的连等式可能会有点晕, 注意到, 左端实际上是概率 P { q ( t ) , p ( t ) ) ∈ B k } P\{q^{(t)}, p^{(t)}) \in B_k\} P{q(t),p(t))Bk}, 最右端是 P { ( q ( t − 1 ) , p ( t − 1 ) ) ∈ B k } P\{(q^{(t-1)}, p^{(t-1)}) \in B_k\} P{(q(t1),p(t1))Bk}, 这样就能明白啥意思了.

遍历性 Ergodicty

马氏链具有遍历性才会收敛到一个唯一的分布上(这部分不了解), HMC是具有这个性质的, 只要 L L L ϵ \epsilon ϵ选的足够好. 但是如果选的不过也会导致坏的结果, 比如上面的图, p 2 + q 2 = 1 p^2+q^2=1 p2+q2=1, 如果我们选择了 L ϵ ≈ 2 π L\epsilon \approx 2\pi Lϵ2π, 那么我们的Leapfrog总会带我们回到原点附近, 这就会导致比较差的结果.

HMC的一个例子及优势

下图是:
在这里插入图片描述
ϵ = 0.25 , L = 30 , q = [ − 1.5 , − 1.55 ] T , p = [ − 1 , 1 T ] \epsilon=0.25, L=30, q = [-1.5, -1.55]^T, p=[-1, 1^T] ϵ=0.25,L=30,q=[1.5,1.55]T,p=[1,1T].
在这里插入图片描述

相关系数由 0.95 0.95 0.95改为 0.98 0.98 0.98, ϵ = 0.18 , L = 20 \epsilon=0.18, L=20 ϵ=0.18,L=20, 随机游走取的协方差矩阵为对角阵, 标准差为 0.18 0.18 0.18, HMC生成 p p p的为标准正态分布.

在这里插入图片描述

文章中提到, HMC较Randomwalk的优势在于,Randomwalk对协方差很敏感, 而且太大会导致接受率很低, 太小俩俩之间的相关性又会太高.

HMC在实际中的应用和理论

线性变换

有些时候, 我们会对变量施加线性映射 q ′ = A q q'=Aq q=Aq( A A A非奇异方阵), 此时新的密度函数 P ′ ( q ′ ) = P ( A − 1 q ′ ) / ∣ det ⁡ ( A ) ∣ P'(q') = P(A^{-1}q') / |\det (A)| P(q)=P(A1q)/det(A), 其中 P ( q ) P(q) P(q) q q q的密度函数, 相应的我们需要令 U ′ ( q ′ ) = U ( A − 1 q ′ ) U'(q')=U(A^{-1}q') U(q)=U(A1q).

如果我们希望线性变化前后不会是的情况变得"更糟", 一个选择是 p ′ = ( A T ) − 1 p p'=(A^T)^{-1}p p=(AT)1p,则 K ′ ( p ′ ) = K ( A T p ′ ) K'(p')=K(A^Tp') K(p)=K(ATp), 如果 K ( p ) = p T M − 1 p / 2 K(p) = p^TM^{-1}p / 2 K(p)=pTM1p/2, 则
在这里插入图片描述
其中 M ′ = ( A M − 1 A T ) − 1 = ( A − 1 ) T M A − 1 M' = (AM^{-1}A^T)^{-1}=(A^{-1})^TMA^{-1} M=(AM1AT)1=(A1)TMA1. 此时 ( q ′ , p ′ ) (q', p') (q,p)的更新会使得原先的 ( q , p ) (q,p) (q,p)的更新保持, 即
在这里插入图片描述
所以 ( q , p ) (q, p) (q,p)本质上按照原来的轨迹发生着变化.

设想, 我们对 q q q的协方差矩阵有一个估计 Σ \Sigma Σ, 且近似服从高斯分布, 我们可以对其做Cholesky分解 Σ = L L T \Sigma=LL^T Σ=LLT, 并且令 q ′ = L − 1 q q'=L^{-1} q q=L1q, 则 q ′ q' q的各分量之间就相互独立了, 那么我们很自然的一个选择是 K ( p ) = p T p / 2 K(p)=p^Tp/2 K(p)=pTp/2, 那么 q ′ q' q的各分量的独立性能够保持.

另一个做法是, 保持 q q q不变, 但是 K ( p ) = p T Σ p / 2 K(p) = p^T \Sigma p / 2 K(p)=pTΣp/2, 此时 q ′ = L − 1 q , p ′ = ( L T ) − 1 p q'=L^{-1}q, p'=(L^{T})^{-1}p q=L1q,p=(LT)1p, 则相当于
K ( p ′ ) = ( p ′ ) T M ′ − 1 p ′ , M ′ = ( L − 1 L L T ( L − 1 ) T ) − 1 = I . K(p')=(p')^T{M'}^{-1}p', \quad M' = (L^{-1}LL^T(L^{-1})^T)^{-1}=I. K(p)=(p)TM1p,M=(L1LLT(L1)T)1=I.
所以俩个方法是等价的.

HMC的调整 ϵ , L \epsilon, L ϵ,L

HMC对 ϵ , L \epsilon, L ϵ,L的选择比较严苛.

预先的实验

我们可以对一些 ϵ , L \epsilon,L ϵ,L进行实验, 观察轨迹, 虽然这个做法可能产生误导, 另外在抽样过程中随机选择 ϵ , L \epsilon, L ϵ,L是一个不错的选择.

stepsize ϵ \epsilon ϵ

ϵ \epsilon ϵ的选择很关键, 如果太大, 会导致低的接受率, 如果太小, 不仅会造成大量的计算成本, 且如果此时 L L L也很小, 那么HMC会缺乏足够的探索.

考虑下面的例子:

在这里插入图片描述
每一次leapfrog将 ( q ( t ) , p ( t ) ) (q(t), p(t)) (q(t),p(t))映射为 ( q ( t + s ) , p ( t + s ) ) (q(t+s), p(t+s)) (q(t+s),p(t+s)), 则
在这里插入图片描述
( q , p ) (q, p) (q,p)是否稳定, 关键在于系数矩阵的特征值的模(?还是实部)是否小于1, 特征值为

在这里插入图片描述
ϵ > 2 σ \epsilon>2\sigma ϵ>2σ的时候,(4.6)有一个实的大于1的特征值, 当 ϵ < 2 σ \epsilon < 2 \sigma ϵ<2σ的时候, 特征值是复制, 且模为:
在这里插入图片描述
所以, 我们应当选择 ϵ < 2 σ \epsilon < 2\sigma ϵ<2σ.

在多维问题中, K ( p ) = p T p / 2 K(p)=p^Tp/2 K(p)=pTp/2,如果 q < 0 q<0 q<0且协方差矩阵为 Σ \Sigma Σ, 我们可以取协方差矩阵的最小特征值(非零?)作为步长. 如果 K ( p ) = p T M − 1 p / 2 K(p)=p^TM^{-1}p/2 K(p)=pTM1p/2, 我们可以通过线性变化将其转换再考虑.

tracjectory length L L L

如何选择 L L L也是一个问题, 我们需要足够大的 L L L使得每次的探索的足够的, 以便能够模拟出独立的样本, 但是正如前面所讲, 大的 L L L不仅会带来计算成本, 而且可能会导致最后结果在起点附近(由周期性带来的麻烦). 而且 L L L没法通过轨迹图正确的选择. 一个不错的想法是在一个小的区间内随机选择 L L L, 这样做可能会减少由于周期性带来的麻烦.

多尺度

我们可以利用 q q q的缩放信息, 为不同的 q i q_i qi添加给予不同的 ϵ i \epsilon_i ϵi. 比方说在 K ( p ) = p T p / 2 K(p)=p^Tp/2 K(p)=pTp/2的前提下, 应该对 q i q_i qi放大 s i s_i si倍, 即 q ′ = q / s i q'= q / s_i q=q/si( p p p不变).

等价的, 可以令 K ( p ) = p T M − 1 p / 2 , m i = 1 / s i 2 K(p) = p^TM^{-1}p / 2, m_i = 1/ s_i^2 K(p)=pTM1p/2,mi=1/si2( q q q不变), 相当于 q i ′ = q i / s i , p ′ = s i p q_i'=q_i/s_i, p'=s_ip qi=qi/si,p=sip, 则
m i ′ = s i ( 1 / s i 2 ) s i = 1 m_i' = s_i (1/ s_i^2)s_i=1 mi=si(1/si2)si=1, 所以 K ( p ′ ) = ( p ′ ) T p ′ / 2 K(p')=(p')^Tp'/2 K(p)=(p)Tp/2. 这么做就相当于一次leapfrog为:

在这里插入图片描述

结合HMC与其它MCMC

当我们所关心的变量是离散的, 或者其对数概率密度( U ( q ) U(q) U(q))的导数难以计算的时候, 结合其它MCMC是有必要的.

Scaling with dimensionality

U ( q ) = ∑ u i ( q i ) U(q) = \sum u_i(q_i) U(q)=ui(qi)的情况

如果 U ( q ) = ∑ u i ( q i ) U(q)=\sum u_i(q_i) U(q)=ui(qi), 且 u i u_i ui之间相互独立(?), 这种假设是可行的, 因为之前已经讨论过, 对于 q q q其协方差矩阵为 Σ \Sigma Σ, 我们可以通过线性变化使其对角化, 且效能保持.

Cruetz指出, 任何的Metropolis形式的算法在采样密度函数 P ( x ) = 1 Z exp ⁡ ( − E ( x ) ) P(x)=\frac{1}{Z}\exp(-E(x)) P(x)=Z1exp(E(x))的时候都满足:
在这里插入图片描述
其中 x x x表现在的状态, 而 x ∗ x^* x表提议. 则根据Jensen不等式可知:
1 = E [ exp ⁡ ( Δ ) ] ≥ exp ⁡ ( E [ − Δ ] ) , 1 = \mathbb{E}[\exp(\Delta)] \ge \exp(\mathbb{E}[-\Delta]), 1=E[exp(Δ)]exp(E[Δ]),
所以 E [ − Δ ] ≤ 0 \mathbb{E}[-\Delta]\le 0 E[Δ]0,
E [ Δ ] ≥ 0. (4.18) \tag{4.18} \mathbb{E}[\Delta] \ge 0. E[Δ]0.(4.18)

U ( q ) = ∑ u i ( q i ) U(q) = \sum u_i(q_i) U(q)=ui(qi)的情况下, 令 Δ 1 : = E ( x ∗ ) − E ( x ) \Delta_1:=E(x^*)-E(x) Δ1:=E(x)E(x), x = q i , E ( x ) = u i ( q i ) x=q_i, E(x)=u_i(q_i) x=qi,E(x)=ui(qi)或者 x = ( q i , p i ) , E ( x ) = u i ( q i ) = p i 2 / 2 x=(q_i, p_i), E(x)=u_i(q_i)=p_i^2/2 x=(qi,pi),E(x)=ui(qi)=pi2/2. 对于整个状态, 我们则用 Δ d \Delta_d Δd表示, 则 Δ d \Delta_d Δd是所有 Δ 1 \Delta_1 Δ1的和. 既然 Δ \Delta Δ的平均值均为正, 这会导致接受概率 min ⁡ ( 1 , exp ⁡ ( − Δ d ) \min (1, \exp(-\Delta_d) min(1,exp(Δd)的减小(随着维度的增加), 除非以减小步长作为代价, 或者建议分布的宽度进一步降低(即 x , x ∗ x,x^* x,x尽可能在一个区域内).

因为 exp ⁡ ( − Δ 1 ) ≈ 1 − Δ 1 + Δ 1 2 / 2 \exp(-\Delta_1) \approx 1 -\Delta_1+\Delta_1^2 / 2 exp(Δ1)1Δ1+Δ12/2, 再根据(4.17)得:
E [ Δ 1 ] ≈ E [ Δ 1 2 ] / 2. (4.19) \tag{4.19} \mathbb{E} [\Delta_1] \approx \mathbb{E} [\Delta_1^2]/2. E[Δ1]E[Δ12]/2.(4.19)

Δ 1 \Delta_1 Δ1的方差约是均值的两倍( Δ 1 \Delta_1 Δ1足够小的时候), 类似的也作用与 Δ d \Delta_d Δd. 为了有一个比较好的接受率, 我们应当控制 Δ d \Delta_d Δd的均值在1左右(小于?), 此时 exp ⁡ ( − 1 ) ≈ 0.3679 \exp(-1)\approx0.3679 exp(1)0.3679.

HMC的全局误差(标准差)在 O ( ϵ 2 ) \mathcal{O}(\epsilon^2) O(ϵ2)级别, 所以 Δ 1 2 \Delta_1^2 Δ12应当在 ϵ 4 \epsilon^4 ϵ4级别, 所以 E [ Δ 1 ] \mathbb{E}[\Delta_1] E[Δ1]也应当在 ϵ 4 \epsilon^4 ϵ4级别, 则 E [ Δ d ] \mathbb{E}[\Delta_d] E[Δd] d ϵ 4 d\epsilon^4 dϵ4级别上, 所以为了保持均值为1左右, 我们需要令 ϵ \epsilon ϵ正比于 d − 1 / 4 d^{-1/4} d1/4, 相应的 L L L d 1 / 4 d^{1/4} d1/4.

文章中还有关于Randomwalk的分析, 这里不多赘述了.

HMC的扩展和变种

这个不一一讲了, 提一下

分割

假如 H H H能够分解成:
在这里插入图片描述
那么我们可以一个一个来处理, 相当于 T 1 , ϵ ∘ T 2 , ϵ , ∘ ⋯ ∘ T k − 1 , ϵ ∘ T k , ϵ T_{1, \epsilon} \circ T_{2, \epsilon}, \circ \cdots \circ T_{k-1, \epsilon} \circ T_{k, \epsilon} T1,ϵT2,ϵ,Tk1,ϵTk,ϵ. 这个做法依旧是保体积的(既然每一个算子都是保体积的), 但是如果希望其可逆(对称), 这就要求 H i ( q , p ) = H k − i + 1 ( q , p ) . H_i(q, p)=H_{k-i+1}(q, p). Hi(q,p)=Hki+1(q,p). 这个有很多应用场景:

比如 U ( q ) = U 0 ( q ) + U 1 ( q ) U(q) = U_0(q)+U_1(q) U(q)=U0(q)+U1(q), 其中计算 U 0 U_0 U0如果是容易的, 我们可以作如下分解:
在这里插入图片描述
此时有 3 M + 2 3M+2 3M+2项, H 1 ( q , p ) = H k ( q , p ) = U 1 ( q ) / 2 H_1(q, p) = H_k(q, p)=U_1(q)/2 H1(q,p)=Hk(q,p)=U1(q)/2, H 3 i − 1 = H 3 i + 1 = U 0 ( q ) / 2 M H_{3i-1}=H_{3i+1}=U_0(q)/2M H3i1=H3i+1=U0(q)/2M, H 3 i = K ( p ) / M H_{3i}=K(p)/M H3i=K(p)/M. 此时对于中间部分, 相当于步长变小了,误差自然会小.

当处理大量数据, 并用到似然函数的时候:
在这里插入图片描述
不过文章中说这个分解是不对称的, 可明明是对称的啊.

处理约束

有些时候, 我们对 q q q有约束条件, 比方 q > v , q < w q >v, q<w q>v,q<w等等, 直接给算法:

在这里插入图片描述

Langevin method, LMC

假设我们使用 K ( p ) = ( 1 / 2 ) ∑ p i 2 K(p)=(1/2)\sum p_i^2 K(p)=(1/2)pi2, p p p从标准正态分布中采样, 每次我们只进行一次leapfrog变计算接受概率, 即
在这里插入图片描述
以及其接受概率:
在这里插入图片描述

Windows of states

这个方法试图将 H H H的曲线平滑来提高接受率.

我们可以通过任意 ( q , p ) (q, p) (q,p)构造一列 [ ( q 0 , p 0 ) , … , ( q W − 1 , p W − 1 ) ] [(q_0, p_0), \ldots, (q_{W-1}, p_{W-1})] [(q0,p0),,(qW1,pW1)]. 首先从 { 0 , 1 , … , W − 1 } \{0, 1, \ldots, W-1\} {0,1,,W1}中等概率选一个数, 这个数代表 ( q , p ) (q, p) (q,p)在序列中的位置, 记为 ( q s , p s ) (q_s, p_s) (qs,ps), 则其前面的可以通过leapfrog ( − ϵ -\epsilon ϵ)产生, 后面的通过leapfrog( + ϵ +\epsilon +ϵ)产生. 所以任意列的概率密度为:

在这里插入图片描述

然后从 ( q W − 1 , p W − 1 ) (q_{W-1}, p_{W-1}) (qW1,pW1)出发, 通过L-W+1步leapfrog( + ϵ +\epsilon +ϵ)获得 [ q W , p W , … , ( q L , p L ) ] [q_W,p_W,\ldots, (q_L, p_L)] [qW,pW,,(qL,pL)]并定义提议序列为 [ ( q L , − p L ) , … , ( q L − W + 1 , p L − W + 1 ) ] [(q_L, -p_{L}), \ldots, (q_{L-W+1}, p_{L-W+1)}] [(qL,pL),,(qLW+1,pLW+1)],计算接受概率:
在这里插入图片描述
其中 P ( q , p ) ∝ exp ⁡ ( − H ( q , p ) ) P(q, p)\propto \exp(-H(q,p)) P(q,p)exp(H(q,p)). 设拒绝或者接受后的状态为: [ ( q 0 + , p 0 + ) , … , ( q W − 1 + , p W − 1 + ) ] [(q_0^+, p_0^+), \ldots, (q_{W-1}^+, p_{W-1}^+)] [(q0+,p0+),,(qW1+,pW1+)], 依照概率
在这里插入图片描述
抽取 ( q e + , p e + ) (q_e^+, p_e^+) (qe+,pe+), 这个就是 ( q , p ) (q,p) (q,p)后的下一个状态.

文中说这么做分布不变, 因为:
在这里插入图片描述
如果没理解错, 前面的部分就是 ( q e + , p e + ) (q_e^+, p_e^+) (qe+,pe+)出现在最开始的序列中的概率, 但是中间的接受概率哪里去了? 总不能百分百接受吧…

代码

import numpy as np
from collections.abc import Iterator, Callable
from scipy import stats
class Euler:
    """
    Euler方法
    """
    def __init__(self, grad_u, grad_k, epsilon):
        self.grad_u = grad_u
        self.grad_k = grad_k
        self.epsilon = epsilon

    def start(self, p, q, steps):
        trajectory_p = [p]
        trajectory_q = [q]
        for t in range(steps):
            temp = p - self.epsilon * self.grad_u(q)  # 更新一步P
            q = q + self.epsilon * self.grad_k(p)  # 更新一步q
            p = temp
            trajectory_p.append(p)
            trajectory_q.append(q)
        return trajectory_p, trajectory_q

    def modified_start(self, p, q, steps):
        """
        启动!
        :param p:
        :param q:
        :param steps:  步数
        :return: p, q
        """
        trajectory_p = [p]
        trajectory_q = [q]
        for t in range(steps):
            p = p - self.epsilon * self.grad_u(q) #更新一步P
            q = q + self.epsilon * self.grad_k(p) #更新一步q
            trajectory_p.append(p)
            trajectory_q.append(q)
        return trajectory_p, trajectory_q
class Leapfrog:
	"""
	Leapfrog 方法
	"""
    def __init__(self, grad_u, grad_k, epsilon):
        self.grad_u = grad_u
        self.grad_k = grad_k
        self.epsilon = epsilon
        self.trajectory_q = []
        self.trajectory_p = []

    def start(self, p, q, steps):
        self.trajectory_p.append(p)
        self.trajectory_q.append(q)
        for t in range(steps):
            p = p - self.epsilon * self.grad_u(q) / 2
            q = q + self.epsilon * self.grad_k(p)
            p = p - self.epsilon * self.grad_u(q) / 2
            self.trajectory_q.append(q)
            self.trajectory_p.append(p)
        return p, q

class HMC:
	"""
	HMC方法 
	start为进行一次
	accept_prob: 计算接受概率
	hmc: 完整的过程
	acc_rate: 接受概率
	"""
    def __init__(self, grad_u, grad_k, hamiltonian, epsilon):
        assert isinstance(grad_u, Callable), "function needed..."
        assert isinstance(grad_k, Callable), "function needed..."
        assert isinstance(hamiltonian, Callable), "function needed..."
        self.grad_u = grad_u
        self.grad_k = grad_k
        self.hamiltonian = hamiltonian
        self.epsilon = epsilon
        self.trajectory_q = []
        self.trajectory_p = []

    def start(self, p, q, steps):
        self.trajectory_p.append(p)
        self.trajectory_q.append(q)
        p = p - self.epsilon * self.grad_u(q) / 2
        for t in range(steps-1):
            q = q + self.epsilon * self.grad_k(p)
            p = p - self.epsilon * self.grad_u(q)
        q = q + self.epsilon * self.grad_k(p)
        p = p - self.epsilon * self.grad_u(q) / 2
        p = -p
        return p, q

    def accept_prob(self, p1, q1, p2, q2):
        """
        :param p1: 原先的
        :param q1:
        :param p2: 建议的
        :param q2:
        :return:
        """
        p1 = np.exp(self.hamiltonian(p1, q1))
        p2 = np.exp(self.hamiltonian(p2, q2))
        alpha = min(1, p1 / p2)
        return alpha

    def hmc(self, generate_p, q, iterations, steps):
        assert isinstance(generate_p, Iterator), "Invalid generate_p"
        self.trajectory_q = [q]
        p = next(generate_p)
        self.trajectory_p = [p]
        count = 0.
        for t in range(iterations):
            tempp, tempq = self.start(p, q, steps)
            if np.random.rand() < self.accept_prob(p, q, tempp, tempq):
                p = tempp
                q = tempq
                self.trajectory_p.append(p)
                self.trajectory_q.append(q)
                count += 1
            p = next(generate_p)
        self.acc_rate = count / iterations
        return self.trajectory


    @property
    def trajectory(self):
        return np.array(self.trajectory_p), \
               np.array(self.trajectory_q)

class Randomwalk:
	"""
	walk: 完整的过程, 实际上Metropolis更新似乎就是start中steps=1, 
	一开始将文章的意思理解错了, 不过将错就错, 这样子也能增加一下灵活性.
	"""
    def __init__(self, pdf, sigma):
        assert isinstance(pdf, Callable), "function needed..."
        self.pdf = pdf
        self.sigma = sigma
        self.trajectory = []

    def start(self, q, steps=1):
        for t in range(steps):
            q = stats.multivariate_normal.rvs(mean=q,
                                              cov=self.sigma)
        return q

    def accept_prob(self, q1, q2):
        """
        :param q1: 原始
        :param q2: 建议
        :return:
        """
        p1 = self.pdf(q1)
        p2 = self.pdf(q2)
        alpha = min(1, p2 / p1)
        return alpha
    
    def walk(self, q, iterations, steps=1):
        self.trajectory = [q]
        count = 0.
        for t in range(iterations):
            temp = self.start(q, steps)
            if np.random.rand() < self.accept_prob(q, temp):
                q = temp
                count += 1
            self.trajectory.append(q)
        self.acc_rate = count / iterations
        return np.array(self.trajectory)

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值