ベイズ勉強会資料は『ベイズ推論による機械学習入門』1を元に、途中式計算をできるだけ省略せずに行ったものです。

ベルヌーイ分布

ベルヌーイ分布は次の確率質量関数で表される確率分布である。

この確率質量関数は確率μで1、1μで0を出力する。

Important: ベルヌーイ分布の確率質量関数Bern(xμ)=μx(1μ)1x (x{0,1},μ(0,1))

問題

今N個のデータ点D={x1,x2,,xN} (x1,,xN{0,1})が得られたとする。未知のデータ点xを予測するためにベイズ推測を行いたい。

この問題が解ければ、コインを投げた時表が出る確率はどの程度かをベイズ推測で評価できるようになる。

モデル構築

D,x,μで同時分布を構築する。データ点のとりうる値が2値なので、D,xμをパラメータに持つベルヌーイ分布から生成されているとする。D,x,μの関係をDAGで描くと以下のようになる。

よって同時分布は

p(D,x,μ)=p(Dμ)p(xμ)p(μ)

という尤度関数×事前分布の形で書ける。

尤度関数

データ点はベルヌーイ分布から独立に生成されるとしているので

p(Dμ)=ΠNn=1Bern(xnμ)p(xμ)=Bern(xμ)

と書ける。

事前分布

事前分布p(μ)μ(0,1)を満たすような確率分布である必要がある。これを満たす確率分布に、ベータ分布がある。

Important: ベータ分布の確率密度関数
Beta(μa,b)=CB(a,b)μa1(1μ)b1ただし,CB(a,b)=Γ(a+b)Γ(a)Γ(b),μ(0,1),{a,b}R+を満たす.

a,bがベータ分布のパラメータである。

Note: ベータ分布の係数とガンマ関数

CB(a,b)は正規化されることを保証する係数である。CB(a,b)中のΓ()はガンマ関数である。ガンマ関数は自然数に定義される階乗を一般化したものであり、正の実数xR+に対して、

Γ(x)=tx1etdt

と定義される。重要な性質として

Γ(x+1)=xΓ(x)Γ(1)=1

を満たし、自然数nに対しては

Γ(n+1)=n!

が成り立つ。

ベータ分布を用いることで事前分布p(μ)

p(μ)=Beta(μa,b)

と定義できる。a,bも加えてDAGを描き直すと次のように描ける。

更にa,bを出力する確率分布を考えることもできるが、モデルを複雑化すると計算も煩雑になるのでここまでにしておく。ではa,bの値はどうするのかというと、事前に決めておくことになる。このような変数を、パラメータのためのパラメータということで、超パラメータ(ハイパーパラメータ)と呼ぶ。

まとめ

まとめると、推論のためのモデルは次のように書ける。

p(D,x,μ)=p(D|μ)p(x|μ)p(μ)p(D|μ)=ΠNn=1Bern(xn|μ)p(x|μ)=Bern(x|μ)p(μ)=Beta(μ|a,b)

事後分布の推論

実際にDを観測した後の事後分布p(μD)を求める。

Note: モデルの事後分布はp(x,μD)=p(xμ)p(μD)だがデータからの学習に関わるのはp(μD)の部分のみ。学習のみに推論を絞ってこちらを事後分布と呼ぶ場合も多い。本節でもp(μD)を事後分布と呼ぶ。

ベイズの定理を用いて、

p(μ|D)=p(D|μ)p(μ)p(D)={ΠNn=1p(xn|μ)}p(μ)p(D){ΠNn=1p(xn|μ)}p(μ)

である。分母は正規化されていることを保証する項であり、分布形状を決めるのは分子の部分であるため3行目では省略している。ベルヌーイ分布もベータ分布も指数部分があり、対数をとると計算が楽になる。

lnp(μ|D)=ΣNn=1lnp(xn|μ)+lnp(μ)+const. ()=ΣNn=1ln(μxn(1μ)1xn)+ln(CB(a,b)μa1(1μ)b1)+const. (,)=ΣNn=1xnlnμ+ΣNn=1(1xn)ln(1μ)+(a1)lnμ+(b1)ln(1μ)+const. (CB(a,b)const.)=(ΣNn=1xn+a1)lnμ+(NΣNn=1xn+b1)ln(1μ)+const.

対数を元に戻すと

p(μD)μ(ΣNn=1xn+a1)(1μ)NΣNn=1xn+b1

でありこれはベータ分布の形である。なお定数項は正規化されることを保証する係数となっている。つまり

p(μ|D)=Beta(μ|ˆa,ˆb) ˆa=ΣNn=1xn+aˆb=NΣNn=1xn+b

となる。

Note: このように、特定の確率分布のパラメータの事前分布とすることで、事後分布が事前分布と同じ形になる確率分布を共役事前分布という。ベルヌーイ分布の共役事前分布はベータ分布である。

Note: ベルヌーイ分布の場合は、成功確率パラメータであるμをベータ分布で幅を持たせて推定できることがベイズ推論の意義となる。

Note: Nはデータ点の個数、ΣNn=1xnは値が1だったデータ点の個数である。ハイパーパラメータa,bをデータの情報で更新しているという見方ができる。また、Nが大きくなると、a,bが無視できる、すなわちハイパーパラメータが結果に影響しなくなることがわかる。

予測分布の算出

未知のデータ点xの予測分布p(xD)p(x,μD)=p(xμ)p(μD)をパラメータμについて周辺化することで求まる。

p(x|D)=p(x|μ)p(μ|D)dμ=Bern(x|μ)Beta(μ|ˆa,ˆb)dμ=CB(ˆa,ˆb)μx(1μ)1xμˆa1(1μ)ˆb1dμ=CB(ˆa,ˆb)μx+ˆa1(1μ)1x+ˆb1dμ

ここでベータ分布の定義式から

μx+ˆa1(1μ)1x+ˆb1dμ=1CB(x+ˆa,1x+ˆb)

となる。

Note: ベータ分布は確率分布なので積分した時1になる。つまり係数CB以外の部分を積分した時の値は係数CBの逆数である。μx+ˆa1(1μ)1x+ˆb1dμはベータ分布の積分から係数CBの部分を除いた形になっている。

したがって、

p(x|D)=CB(ˆa,ˆb)CB(x+ˆa,1x+ˆb)=Γ(ˆa+ˆb)Γ(x+ˆa)Γ(1x+ˆb)Γ(ˆa)Γ(ˆb)Γ(ˆa+ˆb+1)

複雑な式になっているがxは0か1しかとり得ないことを利用するともっと単純に書ける。

p(x=1|D)=Γ(ˆa+ˆb)Γ(1+ˆa)Γ(ˆb)Γ(ˆa)Γ(ˆb)Γ(ˆa+ˆb+1)=Γ(ˆa+ˆb)ˆaΓ(ˆa)Γ(ˆb)Γ(ˆa)Γ(ˆb)(ˆa+ˆb)Γ(ˆa+ˆb)=ˆaˆa+ˆbp(x=0|D)=Γ(ˆa+ˆb)Γ(ˆa)Γ(1+ˆb)Γ(ˆa)Γ(ˆb)Γ(ˆa+ˆb+1)=ˆbˆa+ˆb

より

p(x|D)=(ˆaˆa+ˆb)x(ˆbˆa+ˆb)1x=(ˆaˆa+ˆb)x(1ˆaˆa+ˆb)1x=Bern(x|ˆaˆa+ˆb)=Bern(x|ΣNn=1xn+aN+a+b)

と予測分布はベルヌーイ分布の形で書ける。

Note: 予測分布についても、Nが大きくなると、a,bが無視できる、すなわちハイパーパラメータが結果に影響しなくなることがわかる。また予測分布の形状が尤度関数と変わっておらず、μの点推定を行った場合の予測と結局同じことをやっているように見える(特にNが大きければ最尤推定と同じである)が、尤度関数の種類によっては予測分布の形と異なる場合がある。ポアソン分布→負の二項分布、精度未知の1次元ガウス分布→Studentのt分布などの例がある。また、事後分布としてμの分布が得られていて、幅のある推定ができている。

Juliaによる実装

Turing.jlのTutorialより。

素朴に

# パッケージのimport

# 乱数生成のためのパッケージ
using Random

# グラフ描画用のパッケージ
using Plots

# 確率分布の関数を呼び出すパッケージ
using Distributions
# 真の成功確率を0.5と置く
p_true = 0.5

# 0~100までの数列
Ns = 0:100;
# 100回ベルヌーイ試行を行う
Random.seed!(12)
data = rand(Bernoulli(p_true), last(Ns))

# 最初の5回
data[1:5]
5-element Array{Bool,1}:
 1
 0
 1
 1
 0
# 事前分布をベータ分布で置く。ハイパーパラメータはa=1,b=1とする
prior_belief = Beta(1, 1);
#hide_output
# アニメーションをつけるためにStatsPlotsパッケージをimport
using StatsPlots

# ベイズ推論の進行過程をアニメーションに
animation = @gif for (i, N) in enumerate(Ns)

    # 表がでた回数(heads)と裏が出た回数(tails)を計算
    heads = sum(data[1:i-1])
    tails = N - heads
    
    # 事後確率分布
    updated_belief = Beta(prior_belief.α + heads, prior_belief.β + tails)

    # 描画用の関数
    plot(updated_belief, 
        size = (500, 250), 
        title = "Updated belief after $N observations",
        xlabel = "probability of heads", 
        ylabel = "", 
        legend = nothing,
        xlim = (0,1),
        fill=0, α=0.3, w=3)
    vline!([p_true])
end;

Turing.jlを使ったハミルトニアン・モンテカルロによる近似計算

# パッケージのimport

# Load Turing and MCMCChains.
using Turing, MCMCChains

# Load the distributions library.
using Distributions

# Load StatsPlots for density plots.
using StatsPlots
# モデル設定
@model coinflip(y) = begin
    
    # 事前分布
    p ~ Beta(1, 1)
    
    # 試行回数N
    N = length(y)
    for n in 1:N
        # 各試行の結果はベルヌーイ分布で決定する
        y[n] ~ Bernoulli(p)
    end
end;
# HMCの設定
iterations = 1000
ϵ = 0.05
τ = 10

# HMCの実行
chain = sample(coinflip(data), HMC(ϵ, τ), iterations, progress=false);
# 結果のサマリ
p_summary = chain[:p]
plot(p_summary, seriestype = :histogram)
# 解析的に解いた事後分布
N = length(data)
heads = sum(data)
updated_belief = Beta(prior_belief.α + heads, prior_belief.β + N - heads)

# HMCによる事後分布の近似を青で描画
p = plot(p_summary, seriestype = :density, xlim = (0,1), legend = :best, w = 2, c = :blue)

# 解析的に解いた事後分布を緑で描画
plot!(p, range(0, stop = 1, length = 100), pdf.(Ref(updated_belief), range(0, stop = 1, length = 100)), 
        xlabel = "probability of heads", ylabel = "", title = "", xlim = (0,1), label = "Closed-form",
        fill=0, α=0.3, w=3, c = :lightgreen)

# 真の成功確率を赤で描画
vline!(p, [p_true], label = "True probability", c = :red)