在朴素贝叶斯中如何使用log-sum-exp技巧的示例


14

我已经在很多地方(例如here和here)阅读了有关log-sum-exp技巧,但从未见过将其专门应用于Naive Bayes分类器的示例(例如,具有离散功能和两个类)

使用该技巧如何完全避免数字下溢的问题?


2
这里有几个使用它的示例,尽管对于朴素的贝叶斯不一定一定要明确使用它。但是,这并不重要,因为该技巧的思想非常简单且易于适应。
— Glen_b-恢复莫妮卡2014年

问题更可能是下溢而不是上溢。
— 亨利

我建议您尝试搜索下溢,然后更新您的问题以更具体地解决尚未涵盖的问题。
— Glen_b-恢复莫妮卡2014年

您能否也澄清一下-这是伯努利式的朴素贝叶斯吗?也许还有其他东西?
— Glen_b-恢复莫妮卡2014年

请参见此处的示例,该示例位于日志的底部(在“另请参阅”之前,它们记录日志;在对双方进行取幂但使RHS保持“原样”(作为日志总数的exp)将是日志的示例) -sum-exp技巧,这是否能为您提供有关在朴素贝叶斯中使用它的足够信息,以提出更具体的问题?
— Glen_b -Reinstate Monica 2014年

Answers:


26

在

p(Y=C|x)=p(x|Y=C)p(Y=C) ∑k=1|C|p(x|Y=Ck)p(Y=Ck)

分母和分子都可以变得非常小,通常是因为可以接近0,并且我们将它们彼此相乘。为了防止下溢,可以简单地获取分子的对数,但是需要对分母使用log-sum-exp技巧。p(xi|Ck)


更具体地说,为了防止下溢:

  • 如果我们只关心知道哪些类输入(X = X 1,... ,X ñ)最有可能属于与最大后验(MAP)决策规则,我们没有适用的对数sum-exp技巧,因为在这种情况下我们不必计算分母。对于分子,可以简单地取日志以防止下溢:l o g (p (x | Y = C )p (Y = C ))(y^)(x=x1,…,xn)log(p(x|Y=C)p(Y=C))。进一步来说:

    y^=argmaxk∈{1,…,|C|}p(Ck|x1,…,xn)=argmaxk∈{1,…,|C|} p(Ck)∏i=1np(xi|Ck)

    在获取日志后变为:

y^=argmaxk∈{1,…,|C|}log⁡(p(Ck|x1,…,xn))=argmaxk∈{1,…,|C|}log⁡( p(Ck)∏i=1np(xi|Ck))=argmaxk∈{1,…,|C|}(log⁡(p(Ck))+ ∑i=1nlog⁡(p(xi|Ck)))
  • 如果要计算类概率,则需要计算分母:p(Y=C|x)

    日志⁡(p(ÿ=C|X))=日志⁡(p(X|ÿ=C)p(ÿ=C) ∑ķ=1个|C|p(X|ÿ=Cķ)p(ÿ=Cķ))=日志⁡(p(X|ÿ=C)p(ÿ=C)⏟分子)-日志⁡( ∑ķ=1个|C|p(X|ÿ=Cķ)p(ÿ=Cķ)⏟分母)

    元素log⁡( ∑k=1|C|p(x|Y=Ck)p(Y=Ck))可能会下溢,因为可能很小:这与分子中的问题相同,但是这次我们在对数内进行求和,这使我们无法转换 p (x i | C k))(可以是接近0)转换成日志( p (X 我 | C ^ ķ))(阴性和不接近0了,因为0 ≤ p (X 我 | C ^ ķ)≤ 1p(xi|Ck)p(xi|Ck)log⁡(p(xi|Ck))0≤p(xi|Ck)≤1)。为了解决这个问题,我们可以使用的事实来获得:p(xi|Ck)=exp⁡(log⁡(p(xi|Ck)))

    log⁡( ∑k=1|C|p(x|Y=Ck)p(Y=Ck))=log⁡( ∑k=1|C|exp⁡(log⁡(p(x|Y=Ck)p(Y=Ck))))

    在这一点上,一个新的问题出现了:可能相当负面,这意味着EXP (日志( p (X | Ÿ = Ç ķ)p (Y = C k)))可能变得非常接近0,即下溢。这是我们使用log-sum-exp技巧的地方:log⁡(p(x|Y=Ck)p(Y=Ck))exp⁡(log⁡(p(x|Y=Ck)p(Y=Ck)))

    log⁡∑keak=log⁡∑keakeA−A=A+log⁡∑keak−A

    与:

    • ,ak=log⁡(p(x|Y=Ck)p(Y=Ck))
    • A=maxk∈{1,…,|C|}ak.

    我们可以看到引入变量可以避免下溢。例如k = 2 ,a 1 = − 245 ,a 2 = − 255,我们有:Ak=2,a1=−245,a2=−255

    • exp⁡(a1)=exp⁡(−245)=3.96143×10−107
    • exp⁡(a2)=exp⁡(−255)=1.798486×10−111

    使用对数和-EXP特技我们避免了下溢,与: 日志Σ ķ Ë 一个ķA=max(−245,−255)=−245log⁡∑keak=log⁡∑keakeA−A=A+log⁡∑keak−A=−245+log⁡∑keak+245=−245+log⁡(e−245+245+e−255+245)=−245+log⁡(e0+e−10)

    我们避免了下溢,因为 为0比要远得多3.96143 × 10 - 107或1.798486 × 10 - 111。e−103.96143×10−1071.798486×10−111


2

假设我们要确定两个数据库中哪个更可能产生了一个短语(例如,这个短语更可能来自哪个小说)。我们可以假设条件词在数据库中的独立性(朴素贝叶斯假设)。

aebŤ


1

从这个答案中我们可以看到,Python中最小的数字(例如,以它为例)是5e-324由于IEEE754引起的,硬件原因也适用于其他语言。

In [2]: np.nextafter(0, 1)
Out[2]: 5e-324

任何小于该值的浮点数都将导致0。

In [3]: np.nextafter(0, 1)/2
Out[3]: 0.0

让我们with discrete features and two classes根据需要查看Naive Bayes的功能:

p(小号=1个|w1个,。。。wñ)=p(小号=1个)∏一世=1个ñp(w一世|小号=1个) ∑s={0,1个}p(小号=s)∏一世=1个ñp(w一世|小号=s)

让我通过下面的简单NLP任务实例化该函数。

小号=1个小号=0ñ=5,000w一世p(w一世|小号=1个)1个-p(w一世|小号=1个)

In [1]: import numpy as np
In [2]: from sklearn.naive_bayes import BernoulliNB
# let's train our model with 200 samples
In [3]: X = np.random.randint(2, size=(200, 5000))
In [4]: y = np.random.randint(2, size=(200, 1)).ravel()
In [5]: clf = BernoulliNB()
In [6]: model = clf.fit(X, y)

p(小号=s)∏一世=1个ñp(w一世|小号=s)p(w一世|小号=1个)1个-p(w一世|小号=1个)∏一世50005Ë-3240/0

In [7]: (np.nextafter(0, 1)*2) / (np.nextafter(0, 1)*2)
Out[7]: 1.0

In [8]: (np.nextafter(0, 1)/2) / (np.nextafter(0, 1)/2)
/home/lerner/anaconda3/bin/ipython3:1: RuntimeWarning: invalid value encountered in double_scalars
  #!/home/lerner/anaconda3/bin/python
Out[8]: nan
In [9]: l_cpt = model.feature_log_prob_
In [10]: x = np.random.randint(2, size=(1, 5000))
In [11]: cls_lp = model.class_log_prior_
In [12]: probs = np.where(x, np.exp(l_cpt[1]), 1-np.exp(l_cpt[1]))
In [13]: np.exp(cls_lp[1]) * np.prod(probs)
Out[14]: 0.0

p(小号=1个|w1个,。。。wñ)

我们可以在sklearn中看到官方实现:

jll = self._joint_log_likelihood(X)
# normalize by P(x) = P(f_1, ..., f_n)
log_prob_x = logsumexp(jll, axis=1)
return jll - np.atleast_2d(log_prob_x).T

对于分子,它将概率的乘积转换为对数似然之和;对于分母,它使用scipy中的logumexp:

out = log(sum(exp(a - a_max), axis=0))
out += a_max

∑s={0,1个}ËĴ升升s-米一种X_Ĵ升升日志⁡∑s={0,1个}ËĴ升升s-米一种X_Ĵ升升米一种X_Ĵ升升+日志⁡∑s={0,1个}ËĴ升升s-米一种X_Ĵ升升max_jll

这是推导:

log⁡∑s={0,1}ejlls=log⁡∑s={0,1}ejllsemax_jll−max_jll=log⁡emax_jll+log⁡∑s={0,1}ejlls−max_jll=max_jll+log⁡∑s={0,1}ejlls−max_jll

max_jlla_max

log⁡p(S=1|w1,...wn)

return jll - np.atleast_2d(log_prob_x).T

希望能有所帮助。

参考:
1. Bernoulli朴素贝叶斯分类器
2. 朴素贝叶斯的垃圾邮件过滤–哪些朴素贝叶斯?

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.