Naive Bayesでlog-sum-expトリックがどのように機能するかの例


14

log-sum-expトリックについて多くの場所(例:ここここ)で読みましたが、それがNaive Bayes分類器(例:離散機能と2つのクラス)に具体的に適用される例を見たことがありません。

このトリックを使用して数値のアンダーフローの問題をどの程度正確に回避できますか?


2
ここではいくつかの使用例がありますが、ナイーブベイズでは必ずしも明示的には使用されていません。ただし、トリックのアイデアは非常に単純で、すぐに適用できるため、問題はほとんどありません。
Glen_b-モニカを復活させる14

問題はオーバーフローよりもアンダーフローである可能性が高いです。
ヘンリー

アンダーフローで検索してから、質問を更新して、まだカバーされていないものを具体的に取り上げることをお勧めします。
Glen_b-モニカを復活させる'07 / 07/03

明確にしてもらえますか-これはベルヌーイモデルの素朴なベイズですか?おそらく何か他に?
Glen_b-モニカを復活させる14

ここの例をご覧ください。右下( 'See Also'の直前でログを取得します。両側を累乗しますが、RHSを(ログの合計のexpとして)そのままにしておきます)がログの例です。 -sum-expトリック。これにより、Naive Bayesでの使用に関連して、より具体的な質問をするのに十分な情報が得られますか?
Glen_b -Reinstate Monica

回答:


26

In

pY=C|バツ=pバツ|Y=CpY=C Σk=1|C|pバツ|Y=CkpY=Ck

分母と分子の両方が非常に小さくなる可能性があります。これは、通常、が0に近くなる可能性があり、それらの多くを互いに乗算するためです。アンダーフローを防ぐために、分子のログを取得することができますが、分母にはlog-sum-expトリックを使用する必要があります。pバツ|Ck


より具体的には、アンダーフローを防ぐために:

  • 私たちはどのクラスを知ることを気にしている場合入力がX = X 1... xはn個、最も可能性の高い最大事後(MAP)決定ルールとに属し、我々は対数を適用する必要はありませんsum-expトリック。その場合、分母を計算する必要がないため。分子の場合、ログを取得してアンダーフローを防ぐことができます:l o g p x | Y = C p Y = C y^バツ=バツ1バツlogpバツ|Y=CpY=C。すなわち:

    y^=argmaxk{1|C|}pCk|バツ1バツ=argmaxk{1|C|} pCkΠ=1pバツ|Ck

    これはログを取った後になります:

y^=argmaxk{1|C|}ログpCk|バツ1バツ=argmaxk{1|C|}ログ pCkΠ=1pバツ|Ck=argmaxk{1|C|}ログpCk+ Σ=1ログpバツ|Ck
  • クラス確率を計算する場合、分母を計算する必要があります。pY=C|バツ

    ログpY=C|バツ=ログpバツ|Y=CpY=C Σk=1|C|pバツ|Y=CkpY=Ck=ログpバツ|Y=CpY=C分子ログ Σk=1|C|pバツ|Y=CkpY=Ck分母

    要素ログ Σk=1|C|pバツ|Y=CkpY=Ckは非常に小さくなる可能性があるためアンダーフローする可能性があります。これは分子と同じ問題ですが、今回は対数内に合計があり、p x i | C kを変換できません) (に)0に近いことができるログ P X I | CのK(以降、もはや負なく0に近い0 P X I | C K1pバツ|Ckpバツ|Ckログpバツ|Ck0pバツ|Ck1)。この問題を回避するために、という事実を使用して、以下を取得できます。pバツ|Ck=expログpバツ|Ck

    ログ Σk=1|C|pバツ|Y=CkpY=Ck=ログ Σk=1|C|expログpバツ|Y=CkpY=Ck

    その時点で、新しい問題が発生しlog p x | Y = C kp Y = C kは非常に負の値になる可能性があります。これは、exp log p x | Y = C kp Y = C kは、0に非常に近くなる可能性があります(アンダーフロー)。これがlog-sum-expトリックを使用する場所です:ログpバツ|Y=CkpY=Ckexpログpバツ|Y=CkpY=Ck

    ログΣkeak=ログΣkeake=+ログΣkeak

    と:

    • ak=ログpバツ|Y=CkpY=Ck
    • =最高k{1|C|}ak

    変数を導入することでアンダーフローを回避できることがわかります。たとえば、k = 2 a 1 = 245 a 2 = 255の場合、次のようになります。k=2a1=245a2=255

    • expa1=exp245=3.96143×10107
    • expa2=exp255=1.798486×10111

    log-sum-expトリックを使用して、アンダーフローを回避しますlog k e a k=最高245255=245ログΣkeak=ログΣkeake=+ログΣkeak=245+ログΣkeak+245=245+ログe245+245+e255+245=245+ログe0+e10

    3.96143 × 10 107または1.798486 × 10 111よりも0からはるかに離れているため、アンダーフローを回避し ました。e103.96143×101071.798486×10111


2

2つのデータベースのどちらがフレーズを生成した可能性が高いかを特定したいとします(たとえば、このフレーズはどの小説から来た可能性が高いですか)。データベースを条件として、単語の独立性を仮定することができます(単純ベイズ仮定)。

次に、投稿した2番目のリンクを調べます。そこデータベース所与の文を観察する同時確率を表すであろうとのE bはT Sは文章中の単語の各々を観測する確率を表すことになります。aebt


1

この回答から、Pythonの最小数(たとえば、それを取り上げる)はIEEE7545e-324によるものであり、ハードウェアの原因は他の言語にも当てはまることがわかります。

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の機能を見てみましょう。

pS=1|w1w=pS=1Π=1pw|S=1 Σs={01}pS=sΠ=1pw|S=s

以下の簡単なNLPタスクでその機能をインスタンス化しましょう。

S=1S=0=5000wpw|S=11pw|S=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)

pS=sΠ=1pw|S=spw|S=11pw|S=1Π50005e3240/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

pS=1|w1w

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

分子の場合、確率の積を対数尤度の合計に変換し、分母の場合、scipylogsumexpを使用しました

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

Σs={01}ejllsメートルaバツ_jlllogs={0,1}ejllsmax_jllmax_jll+logs={0,1}ejllsmax_jllメートルaバツ_jll

そしてここに派生があります:

ログΣs={01}ejlls=ログΣs={01}ejllseメートルaバツ_jllメートルaバツ_jll=ログeメートルaバツ_jll+ログΣs={01}ejllsメートルaバツ_jll=メートルaバツ_jll+ログΣs={01}ejllsメートルaバツ_jll

メートルaバツ_jlla_メートルaバツ

ログpS=1|w1w

return jll - np.atleast_2d(log_prob_x).T

お役に立てば幸いです。

参照:
1. ベルヌーイ単純ベイズ分類器
2. 単純ベイズによるスパムフィルタリング–単純ベイズはどれですか?

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.