我们都知道,在概率图模型的推断中,精确推断方法通常需要很大的计算开销。因此,在现实应用中近似推断方法更为常用。这类方法一般分为2类:通过使用随机化方法完成近似,比如MCMC(Markov Chain Monte Carlo);使用确定性近似完成近似推断,比如变分推断。本文主要讨论采样技术,基本思想是直接计算或逼近某个变量的期望往往比推断概率分布更加容易。西瓜书里举了一个非常直观的例子,假定我们的目标是计算函数
在概率密度函数
下的期望:
为了有效的计算期望,我们可根据
抽取一组样本
,然后计算
在这些样本上的均值
来逼近目标期望
。若样本独立,基于大数定律,这种通过大量采样的方法就能获得较高的近似精度。
讲到这里,我们对采样技术有了一个直观的理解。目前有许对的关于采样的教程,来完整的讲述MCMC(构造一条马尔科夫链,收敛至平稳分布),MH(Metropolis-Hastings, 基于拒绝采样来逼近平稳分布),吉布斯采样(Gibbs sampling, 马尔科夫链的平稳分布也是采样的目标分布)。但是这些教程大多都是介绍其理论或者简单的罗列各个采样的步骤,并没有展示如何实现它们,如何运用到概率图模型的推断中;阅读后读者然后感到困惑,不知从何入手。本文的目标就是解决这些困惑,以一个实际中的视觉问题进行展开,直观的理解整个建模过程和近似推断。
我们考虑图像去噪,假设噪声图像为
,待还原的干净图像
。那么我们的建模过程为
。也许看到这,我们都联想到了条件随机场(Conditinal random field, CRF)。CRF是给定一组随机变量条件下另一组输出随机变量的条件概率分布模型,其特点是假设输出随机变量构成马尔科夫随机场。即输出变量之间存在成对马尔科夫性,局部马尔可夫性和全局马尔可夫性。这里不做详细介绍,可参考条件随机场(Conditinal random field)。为了套用CRF,一个基本假设图像中的像素只与它的直接相邻像素有联系(即具备条件独立性质),我们就可以得到一个具备局部马尔可夫性质(Local Markov property)的图模型:
从该模型可知,图像中两两相邻像素间构成最大团。
的定义为:
为归一化因子,
为势函数或能量函数。为了定义势函数,我们一方面期望相邻像素间的值比较接近,另一方面期望还原的像素值与原噪声像素值比较接近。另外,我们考虑两种情况,当
为离散变量时,即图像为二值图像(取值0/1);当
为连续变量时,即图像为灰度图像。势函数分别定义为:
上式中,当相邻像素间的值比较接近,且还原的像素值与原噪声像素值比较接近时,势函数最小。对 的求解,我们可以采用很多算法,比如基于贪心策略的 Iterated Conditional Modes(ICM)。这里我们采用Gibbs sampling,步骤如下:
- 随机或以某个次序选取变量
- 根据 中除 外的变量的现有取值,计算条件概率
- 根据 概率分布对变量 采样,并用采样值替代原值
首先我们考虑离散值情况,根据图像的遍历顺序,依次处理变量
;计算条件概率分布:
为紧邻 的变量集合。根据得到的条件概率分布对 进行采样。由于 为离散值,则我们分别计算 取0/1的条件概率值;最终通过产生随机数选取 的值。最终的代码如下:
from random import random
def _discrete(N_i, x_i, WP, WL):
# Use the model to get the energy when the pixel takes value c.
potential = lambda c: sum([WP for z in N_i if z == c]) + \
(WL if x_i == c else 0.0)
# Now we can evaluate the Giibs distribution and find the probability that
# the pixel yi is white.
Pwhite = exp(potential(1)) / sum([exp(potential(c)) for c in [0,1]])
return 1.0 if random() < Pwhite else 0.0
我们对这个图像的所有像素值进行同样处理,采样出一个新的图像;注意,Gibbs sampling是一个不断采样的过程;最终将每次采样的图像进行平均,这样我们就近似推断出了每一个随机变量 的期望值。
我们再考虑连续变量的情况,即处理的图像是灰度图像。同样的步骤,下面我们考虑计算条件概率分布:
注意上述的概率分布,存在指数和平方,那么我们想到了正态分布;下面我们来凑成正态分布的形式
,我们发现
所有 的条件概率分布服从参数为 的正态分布;有了该分布,我们就可以采样 的值。代码如下:
from random import normalvariate as normal
clamp = lambda x, low, high: low if x < low else (high if x > high else x)
def _continuous(N_i, x_i, WP, WL):
# Calculate the parameters for our normal distribution
variance = 0.5 / (WP * len(N_i) + WL)
mean = 2*variance * (WL*x_i + sum([WP*z for z in N_i]))
stdev = variance**0.5
z = normal(mean, stdev)
return clamp(mean + z*stdev, 0.0, 1.0)
同样采样多次后取均值。
上述简单的例子只是为了阐明采样技术在概率图模型中的应用。而更复杂的模型也只是在简单的基础上进行不断扩展,希望以此文为基石,让更多人直观理解概率图模型中的采样技术。