[研究ノート]ギブスサンプリング

ギブスサンプリング

イントロ

ランダムサンプルの先頭からサンプリングし、反復的なサンプリングを、エントリの状態、条件付き確率サンプリング、毎回のように、このサンプル:私は最近、関連書類を見ていたギブスサンプリング法は、確率的グラフィカルモデルは、方法は、大きくしているとして、次のサンプリング、会いましたすべての寸法は次の反復を開始、サンプリングを終了し、一次元のみ、から。

無作為抽出

我々は常に、どのように我々はサンプルそれの標本分布に従うのですか確率変数の確率密度関数と仮定しますか?

私は、先生はそれゆえ、我々はまた、分布のサンプルを生成するために、逆関数法を使用することができ、ランダムな数字に任意の確率分布を生成するために逆関数を使用するように教えてくれた、行列理論を研究しました。{ - 1}(\ XI)確率密度関数$ pに$被験者(X)$すなわち、$ \ $ XI $を仮定すると、[0、1]の間隔$均一に分布し、その逆関数$ CDF ^上のランダムな変数であります配布。

1つの問題は、$ P(x)は$正確な値は、どのようにそれをサンプリングする際に$ P(x)の逆関数のその累積分布関数に$複雑さが計算できない場合、または知らないのでしょうか?

今回は、そのようなので、上のごみサンプリング、重点サンプリング、ギブスサンプリングとなど、いくつかのサンプリングの戦略を、使用する必要があります。ここでは、様々なサンプリング戦略についての心です。

拒絶サンプリング

知られている提案分布q(しばしば単純な分布)、及び元の分布pを拒絶原理をサンプリングし、サンプリング分布からサンプルが提案\(\ハット{X} \)次に、計算受信率\((\帽子{X})= \ FRAC {P(\ハット{X}} {KQ(\帽子{X})は} \) 次いで、zの値で一様分布から生成Zは以下に等しい未満である場合、それは、試料を受け入れている、又は私たちは、サンプルを受け入れ、十分なサンプルを知るためにサンプリングし、サンプリングを続行しないでください。

この図は、青い線が、提案分布上にある、それは元の分布を含んでいなければならない、およびZ0での受入率を計算するために、説明されるべきです。

しかし、それはこのサンプリング方法を使用して、多くの場合、実用的ではない、そうでない場合は、サンプリング方法は非効率的である、提案分布とサンプリングレートが比較的高くなりますので、近いオリジナルの配布に要件をサンプリングを拒否しました。同様に、重要度サンプリング法は、比較的非効率的な方法です。(中略)

MCMC

MCMCは、マルコフ連鎖モンテカルロ法は、高次元の変数をサンプリングする方法です。

核となるアイデアは、マルコフ連鎖としてMCMCサンプリングプロセスであり、そのT + 1つの最初のサンプルを採取t番目のサンプルに依存している\(X_T \)と状態遷移分布(| X_T)Q(X \ \) 。マルコフ連鎖の収束特性によると、我々は、我々は収束がある分布と仮定以上の十分な固定状態に収束する最終状態の後、この転送のために知っている(P-(X-)が\)\その後、定常状態では、とき、サンプリングにより得られた試料だろう確実に守り、\(P(X)\)分布。

この方法は、一般的なアプリケーションMCMCメトロポリス・ヘイスティングス法とギブスサンプラーのアルゴリズムを持っています。ギブスサンプリングの導入を急いでするためには、前者は省略します。

ギブスサンプリング

ランダムベクトルと仮定\(X-は=(X_1、X_2、...、x_dを)\)、dは次元d彼であり、各次元はランダム変数であり、かつ互いに我々の共通の前提に独立していません。我々はランダムベクトルの確率分布を知っているのであれば、どのように我々はこの分布から、それをサンプリングしましたか?

もちろん、我々は多変量分布の同時確率分布から直接サンプリングしたい、非常に困難であり、ギブスサンプリングは、サンプリングのシンプルで効果的な方法です。以下の手順をサンプリングギブス:

ランダム初期状態から\(X ^ {(0) } = [X_1 | X_2 ^ {(0)}、X_3 ^ {(0)}、\ cdots、x_dは^ {(0)}] \) 、始まります別々にサンプリングされた各次元のため、以下のように、サンプリングシーケンスである:
\ [X_1 ^ {(1)} \ thicksim P(X_1 | X_2 ^ {(0)}、{^ X_3(0)}、\ cdots、x_d ^ {(0)})\\ X_2 ^ {(1)} \ thicksim P(X_2 | X_1 ^ {(0)}、X_3 ^ {(0)}、\ cdots、x_d ^ {(0)})\\ \ vdots \\ x_d ^ {(1 )} \ thicksim P(x_d | X_1 ^ {(0)}、X_2 ^ {(0)}、\ cdots、X_ {D-1} ^ {(0)})\ \\ vdots \\ X_1 ^ {(T )} \ thicksim P(X_1 | X_2 ^ {(T-1)}、X_3 ^ {(T-1)}、\ cdots、x_d ^ {(T-1)} )\\\ vdots \\ X_ {D} ^ {(T)} \ thicksim P(x_M | X_1 ^ {(T-1)}、X_2 ^ {(T-1)}、\ cdots、x_d ^ {( T-1)})\\ \
] ステップサンプリングの上方に、我々は最終的に、サンプルが必要とされる高次元分布をサンプリングすることができ得るに準拠します。サンプルのサンプリング分布の開始は、一般的に均一に分布し、分散する提案し、ギブスサンプリング処理は、より単一のようであるので、反復開始サンプリング試料サンプル分布が完全に、要求を満足しないことに留意すべきです最後の反復の結果に到達するためにEMアルゴリズム、ステップによって、すべて同じ、ステップのことを思い出した、反復プロセスステップ。

私は絵がオンラインこのプロセスを記述することができますが見つかりました:

上記のように、右は左の私たちが必要とする分布は、反復プロセス、0と1が均一な分布をサンプリングすることによって得られるサンプリング点の始まりですが、より多くのバックに、より多くのサンプリングポイントは、私たちの権利を満たすために配布されますしたがって、このプロセスは、サンプリング処理をサンプリングギブスを説明できることを実現可能です。

ほとんど、この図の下にあります。

コーディング

Gibbs Sampling我是从一篇图像合成的论文中看到并有所了解的,文章基于MRF,使用神经网络去拟合条件分布\(p(x_i|x_{-i})\),其中\(x_{-i}\)表示除了第i个属性的其他属性。

具体到图像中来,\(x_i\)就是第i个位置的像素点的像素值,而\(x_{-i}\)描述的就是除了这个点以外的其他所有点,因此上式的概率分布就是一个条件分布。

使用神经网络可以拟合出这个分布来,那么如何去生成图片又是一个问题。

文章给出的解决方案就是Gibbs Sampling,先从随机噪声开始,逐像素进行生成,第一次迭代完成将生成一张图片,那么第二次第三次依次可以使用上一次迭代完前生成的图片进行迭代生成下一次,当迭代次数足够多的时候,即我们认为达到了平稳分布,这个时候生成的图片就是服从该分布的图片了。

原文参见:

原文链接

具体的,我给出下面的代码:

import numpy as np
import torch
import torch.nn.functional as F
from torch import nn, optim
from torch.utils import data
from torchvision import datasets, transforms, utils
from tqdm import tqdm
from PIL import Image
import glob
import random
import cv2 as cv
class MaskedConv2d(nn.Conv2d):
    '''
    mask_type A or B
    A : the center is zero
    B : the center is not zero
    '''
    def __init__(self,mask_type,*args,**kwargs):
        super(MaskedConv2d,self).__init__(*args,**kwargs)
        assert mask_type in ["A","B"]
        self.mask_type = mask_type
        self.register_buffer('mask', self.weight.data.clone())
        _,_,h,w = self.weight.size()
        self.mask.fill_(1)
        self.mask[:,:,h//2,w//2 + (mask_type == 'B'):] = 0
        self.mask[:,:,h//2+1:,:] = 0
        
    def forward(self,x):
        self.weight.data *= self.mask
        return super(MaskedConv2d,self).forward(x)
    
    
class DoublePixelCNN(nn.Module):
    def __init__(self,fm,kernel_size = 7,padding = 3):
        super(DoublePixelCNN, self).__init__()
        self.net1 = nn.Sequential(
                MConv('A', 1,  64, 17, 1,8, bias=False), nn.BatchNorm2d(64), nn.ReLU(True),
                MConv('B', 64, fm, kernel_size, 1, padding, bias=False), nn.BatchNorm2d(fm), nn.ReLU(True),
                MConv('B', fm, fm, kernel_size, 1, padding, bias=False), nn.BatchNorm2d(fm), nn.ReLU(True),
                MConv('B', fm, fm, kernel_size, 1, padding, bias=False), nn.BatchNorm2d(fm), nn.ReLU(True),
                MConv('B', fm, fm, kernel_size, 1, padding, bias=False), nn.BatchNorm2d(fm), nn.ReLU(True),
                MConv('B', fm, fm, kernel_size, 1, padding, bias=False), nn.BatchNorm2d(fm), nn.ReLU(True),
                #nn.Conv2d(fm, 256, 1)
        ) 
        self.net2 = nn.Sequential(
                MConv('A', 1,  64, 17, 1,8, bias=False), nn.BatchNorm2d(64), nn.ReLU(True),
                MConv('B', 64, fm, kernel_size, 1, padding, bias=False), nn.BatchNorm2d(fm), nn.ReLU(True),
                MConv('B', fm, fm, kernel_size, 1, padding, bias=False), nn.BatchNorm2d(fm), nn.ReLU(True),
                MConv('B', fm, fm, kernel_size, 1, padding, bias=False), nn.BatchNorm2d(fm), nn.ReLU(True),
                MConv('B', fm, fm, kernel_size, 1, padding, bias=False), nn.BatchNorm2d(fm), nn.ReLU(True),
                MConv('B', fm, fm, kernel_size, 1, padding, bias=False), nn.BatchNorm2d(fm), nn.ReLU(True),
                #nn.Conv2d(fm, 256, 1)
        ) 
        
        self.conv1x1 = nn.Conv2d(fm*2, 256, 1)
    def forward(self,x):
        x1 = self.net1(x)
        x2 = self.net2(x.flip(dims = [-1,-2]))
        x = torch.cat([x1,x2.flip(dims = [-1,-2])],dim = 1)
        x = self.conv1x1(x)
        return x

if __name__ == "__main__":
    tr =       data.DataLoader(datasets.MNIST(root="/media/xueaoru/Ubuntu/dataset/data",transform=transforms.ToTensor(),),
                     batch_size=64, shuffle=True, num_workers=12, pin_memory=True)
    net = DoublePixelCNN(128)
    net.cuda()
    sample = torch.rand(64,1,k,k).cuda()
    optimizer = optim.Adam(net.parameters(),lr = 0.0001)
    for epoch in range(1000):
        net.train()
        running_loss = 0.
        for input,_ in tqdm(tr):
            #print(input.size())
            input = input.cuda()
            #target = target.cuda()
            target = (input.data[:,:] * 255).long() # (b,3,h,w)
            # net(input) (b,256,3,h,w)
            loss = F.cross_entropy(net(input), target) # 计算的是每个像素的二分类交叉熵
            running_loss += loss.item()
            
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
        print("training loss: {:.8f}".format(running_loss / len(tr)))
        if epoch % 5 == 0:
            torch.save(net.state_dict(),open("./{}.pth".format(epoch),"wb"))
            #sample.fill_(0)
            net.eval()
            with torch.no_grad():
                for t in tqdm(range(300)):
                    for i in range(k):
                        for j in range(k):
                            out = net(sample) # (b,256)
                            probs = F.softmax(out[:, :, i ,j],dim = 1).data # (b,c) = (16,256)
                            sample[:, :, i, j] = torch.multinomial(probs, 1).float() / 255.
                
                utils.save_image(sample, 'sample_{:02d}.png'.format(epoch), nrow=12, padding=0)
                sample = torch.rand(64,1,k,k).cuda()

由于这个方法采样时间极其缓慢,所以我生成的图片尺度比较小,训练周期也比较短,只是做个demo使用。

おすすめ

転載: www.cnblogs.com/aoru45/p/12092453.html