Python Pyro 베이지안 추정

최근 확률적 모델 [Pyro (https://pyro.ai/)를 알고 재미있을 것 같다고 생각해서 시험으로 만져 보았습니다. 소스 코드는 Jupyter Notebook에서 쓰고 있습니다.

환경 Python : 3.7.7 Jupyter Notebook : 1.0.0 PyTorch : 1.5.1 Pyro : 1.4.0 scipy : 1.5.2 numpy : 1.19.1 matplotlib : 3.3.0

Pyro이란?

Pyro은 Pytorch를 백엔드로 한 확률적 모델을 처리하는 라이브러리입니다. pip에서 설치할 수 있습니다.

pip install pyro-ppl

그러나 사전에 Pytorch 설치가 필요합니다. 자세한 내용은 공식 페이지를 참조하세요.

튜토리얼을 따라해 보자.

이번에는 베르누이 분포 Ber ( p ) 에 따라 데이터에서 해당 매개 변수 p를 추정하는 것을 생각합니다. 먼저 필요한 모듈을 가져옵니다.

from collections import Counter

import numpy as np
import scipy.stats as stats
import matplotlib.pyplot as plt

import torch
import torch.distributions.constraints as constraints
import pyro
import pyro.distributions as dist
from pyro.optim import SGD, Adam
from pyro.infer import SVI, Trace_ELBO

% matplotlib inline

pyro.set_rng_seed (0)
pyro.enable_validation (True)

데이터 생성

난수 데이터를 생성합니다. 이때 형태를 Pytorch의 tensor 할 필요가 있습니다.

obs = stats.bernoulli.rvs (0.7, size = 30, random_state = 1)
obs = torch.tensor (obs, dtype = torch.float32)
obs
> tensor (1., 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1., 0. 1. 1 . 1. 1.,
          1. 1., 0.5, 0. 1. 1., 0.5, 0. 1. 1. 1., 0.)

데이터 중의 1의 개수를 확인합니다.

Counter (obs.numpy ())
> Counter ({1.0 : 23, 0.0 : 7})

따라서 매개 변수 p 의 최대 가능성 추정 금액은 * 23 / 30 \ fallingdotseq 0.77 *입니다. [^ 2] 이후 p를 베이지안 추정하고 있습니다.

사전 분포의 설정

베이 즈 추론은 매개 변수의 사전 분포를 가정하여 관측 한 데이터를 맞게 사후 분포를 구합니다.

베르누이 분포 Ber ( p ) 매개 변수 p 내용은 사전 분포를 베타 분포를 가정하는 것이 일반적입니다 [^ 1] Pyro에서는model 방법으로 사전 분포와 데이터 모델을 작성합니다.

def model (data) :
    # 사전 분포를 가정
    prior = dist.Beta (1, 1)

    # 데이터 모델링
    p = pyro.sample ( 'p', prior)
    for i in range (len (data)) :
        pyro.sample (f'obs {i} ', dist.Bernoulli (p), obs = data [i])

이번에는 *Beta ( 1, 1 )*를 가정하고 있지만, 실은 이것은 균일 한 분포와 일치합니다.

사후 분포의 설정

guide 방법으로 사후 분포를 설명합니다. 사후 분포도 사전 분포와 마찬가지로 베타 분포합니다. 이 때, 사후 분포의 매개 변수로 적절한 초기 값을 제공합니다.

def guide (data) :
    # 사후 분포의 정의
    alpha_q = pyro.param ( 'alpha_q', torch.tensor (15), constraint = constraints.positive)
    beta_q = pyro.param ( 'beta_q', torch.tensor (15), constraint = constraints.positive)
    posterior = dist.Beta (alpha_q, beta_q)

    pyro.sample ( 'p', posterior)

이 사후 분포의 매개 변수 * \ alpha, \ beta *를 요구하게됩니다.

사후 분포 피팅

사후 분포의 매개 변수 추정 방법을 이번에는 확률 적 변분 추정을 채용합니다. Pyro에서는이 방법을 사용하는 것이 기본 인 것 같습니다. 이번 베르누이 분포의 예에서는 분석으로 사후 분포를 구할 수 있기 때문에 변분 추정과 같은 근사 방법을 사용하는 것은 넌센스이지만 연습하는 것으로이 방법을 사용해 봅니다. (본래는 해석 적 분포를 구할 수없는 경우에 사용하는 수법 이군요.)

NUM_STEPS = 2000

optimizer = SGD (dict (lr = 0.0001, momentum = 0.9))
svi = SVI (model, guide, optimizer, loss = Trace_ELBO ())
pyro.clear_param_store ()

history = {
    'loss': []
    'alpha': []
    'beta': []
}

for step in range (1, NUM_STEPS + 1) :
    loss = svi.step (obs)
    
    history [ 'loss']. append (loss)
    history [ 'alpha']. append (pyro.param ( 'alpha_q'). item ())
    history [ 'beta']. append (pyro.param ( 'beta_q'). item ())
    
    if step % 100 == 0 :
        print (f'STEP : {step} LOSS : {loss} ')

>
STEP : 100 LOSS : 17.461310371756554
STEP : 200 LOSS : 18.102468490600586
(중략)
STEP : 1900 LOSS : 17.97793820500374
STEP : 2000 LOSS : 17.95139753818512

여기서history 피팅중인 Loss 사후 분포의 매개 변수 $ \ alpha, \ beta $를 기록하고 있습니다. 단계별 이러한 수치를 플롯하면 다음과 같이됩니다. (소스 코드는 생략합니다.)

! [다운로드 .png (https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558932/bd2e9763-bba9-9ce3-4730-9a6a8cdc4d80.png)!

마지막으로 얻은 $ \ alpha, \ beta $를 확인하고 사후 분포의 기대 값, 분산을 확인합니다.

infered_alpha = pyro.param ( 'alpha_q'). item ()
infered_beta = pyro.param ( 'beta_q'). item ()
posterior = stats.beta (infered_alpha_beta, infered_beta_beta)

print (f'alpha : {infered_alpha} ')
print (f'beta : {infered_beta} ')
print (f'Expected : {posterior.expect ()} ')
print (f'Variance : {posterior.var ()} ')
>
alpha : 25.764650344848633
beta : 7.556574821472168
Expected : 0.7732203787899605
Variance : 0.005109101547631603

사전 분포와 사후 분포를 플롯 봅니다. (소스 코드는 생략합니다.)

! [다운로드 .png (https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558932/63517b79-10fd-9256-7d7e-996320d7ce83.png)

잘 추정 할 수있을 것 같습니다.

정리

Pyro를 사용하여 간단한 베이지안 추정을 실행 해 보았습니다. 이번에는 간단한 베이지안 추정했지만 복잡한 모델을 유연하게하고 간단하게 기술 할 수있는 것이 Pyro의 강점 아닐까 생각합니다. 공식 문서에는 많은 확률 적 방법의 예가 실려 있고, 이들을 바라보고있는 것만으로도 공부가 될 것입니다.

[^ 2 : $ p $의 최대 가능성 추정량은 표본 평균과 일치합니다. [^ 1] : $ p $의 사전 분포를 베타 분포하는 것으로, 사후 분포도 베타 분포를 따르는 것으로 알려져 있습니다. 이러한 분포를 공액 사전 분포라고합니다.