Up

マルチプロセッシングとメッセージフォーム

 

計算量は多いが、分割できるときは、分割した計算をマルチプロセッシングで処理すると計算時間が短縮できる。各プロセスでの計算の進み具合をメッセージフォームの形で表示すると、計算処理の進み具合を知ることができる。相関係数の推定とサンプルサイズの関係を調べるシミュレーションにおいてマルチプロセッシングを用いるPythonスクリプトをリストのように作成した。リストのプログラムのファイルは、圧縮ファイルMultiProcMsgFmFile.zipとして用意している。リストでは関数inputを用いていないが、関数inputを用いるときは位置に注意する必要がある。このことは、このウェブサイトで説明している。

リストでは、相関係数がrhoである母集団からサンプルサイズsmpl_sのサンプルを、乱数を得る関数multivariate_normalを用いて以下のように作成している。

 

xy = ss.multivariate_normal([0, 0], [[1.0, rho], [rho, 1.0]]).rvs(size = smpl_s)

 

この乱数生成によって得られたデータxyに対して、ベイズ分析によってrhoの推定を行っている。

相関係数は00.52通り、サンプルサイズは10100の2通りである。この2×2=4通りのベイズ分析をStanを用いて行っているが、これをマルチプロセッシングで同時に並行して行う。このためのパラメータの設定が

 

params = [{'smpl_s':10, 'rho':0.0},

          {'smpl_s':10, 'rho':0.5},

          {'smpl_s':100, 'rho':0.0},

          {'smpl_s':100, 'rho':0.5}]

 

であり、これを用いて次の関数

 

def do_mcmc(smpl_s, rho):

 

が呼び出される。直接の呼び出しは次のコードによる。

 

def funcs(params):

    rslts = do_mcmc(params['smpl_s'], params['rho'])

    return rslts

 

上のコードに基づいて、次のPoolによるマルチプロセッシングを行っている。

 

pool = Pool()

Results = pool.map(funcs, params)

 

マルチプロセッシングの実行中は、図1のように各プロセスの処理の進行状況を示すフォームが提示される。各条件で20回のシミュレーションを行っている。

図1

 

計算が終わると、各条件での相関係数の事後分布を描いたグラフが表示される(図2)。

図2

 

各条件で20回のシミュレーションを行っているので、事後分布のグラフは各条件20本である。

サンプルサイズが10個と小さいときは、事後分布は相関係数の真の値rho=0あるいはrho=0.5を中心にかなりの変動が見られ、デーtから相関係数の推定を行うことは難しいと言える。

サンプルサイズが100個のときは、事後分布は相関係数の真の値rho=0あるいはrho=0.5を中心にまとまっており、デーtから相関係数の推定を行ってもよさそうである。

 

 

リスト1

 

from multiprocessing.pool import Pool

import numpy as np

import scipy.stats as ss

import matplotlib.pyplot as plt

import seaborn as sb

import tkinter as tk

import pystan

import pickle

import platform

 

stan_code = """

    data {

        int N;

        vector[2] xy[N];

    }

    parameters {

        real mu_x;

        real mu_y;

        real<lower = 0.0> sgm_x;

        real<lower = 0.0> sgm_y;

        real<lower = -1.0, upper = 1.0> r;

    }

    model {

        mu_x ~ normal(0.0, 1000.0);

        mu_y ~ normal(0.0, 1000.0);

        sgm_x ~ exponential(0.001);

        sgm_y ~ exponential(0.001);

        r ~ uniform(-1.0, 1.0);

        xy ~ multi_normal([mu_x, mu_y],

                          [[sgm_x*sgm_x, sgm_x*sgm_y*r],

                           [sgm_x*sgm_y*r, sgm_y*sgm_y]]); 

    }

"""

 

def do_mcmc(smpl_s, rho):

    root = tk.Tk()

    root.title(f'sample size: {smpl_s},  rho = {rho}')

    cnvs = tk.Canvas(width = 700, height = 300, background = '#00ffff')

    cnvs.pack()

    cnvs.create_text(350, 150, text = '', font = ('', 100), fill = 'blue',

                     tags = 'MyText')

   

    fit_list = []

    for t in range(20):

        cnvs.itemconfig('MyText', text = f'{t+1}/20')

        cnvs.update()

       

        xy = ss.multivariate_normal([0, 0],

                            [[1.0, rho], [rho, 1.0]]).rvs(size = smpl_s)

        with open('sm.pkl', 'rb') as f:

                sm = pickle.load(f)

 

        if platform.system() == 'Windows':

                fit = sm.sampling(data = {'N':len(xy), 'xy':xy}, n_jobs = 1)

        else:

                fit = sm.sampling(data = {'N':len(xy), 'xy':xy})

 

        fit_list.append(fit['r'])

 

    root.destroy()

    return smpl_s, rho, fit_list

 

 

params = [{'smpl_s':10, 'rho':0.0},

          {'smpl_s':10, 'rho':0.5},

          {'smpl_s':100, 'rho':0.0},

          {'smpl_s':100, 'rho':0.5}]

 

def funcs(params):

    rslts = do_mcmc(params['smpl_s'], params['rho'])

    return rslts

 

 

if __name__ == '__main__':

   

    sm = pystan.StanModel(model_code = stan_code)

 

    with open('sm.pkl', 'wb') as f:

        pickle.dump(sm, f)

           

    pool = Pool()

    Results = pool.map(funcs, params)

    pool.close()

 

    plt.figure(figsize = (8, 6))

    ip = 0

    for v in Results:

        ip += 1

        plt.subplot(2,2,ip)

        plt.title(f'Sample_size = {v[0]},  rho = {v[1]}', fontsize = 14)

        dt = v[2]

        for p in dt:

            sb.kdeplot(p, clip = [-1.0, 1.0])

        plt.xticks([-1.1, -1.0, 0, 1.0, 1.1], ['', '-1', '0', '1', ''])

 

    plt.tight_layout()

    plt.show()

 

 

Up