MCMC_calibration

源文件

1.导入已知的包:

# Packages import
# Required packages
import numpy as np
import scipy as sp
import pandas as pd
import matplotlib.pyplot as plt
import pyDOE as doe
import sklearn.gaussian_process.kernels as skl
import pymc3 as pm
import theano.tensor as tt
import theano
import time
import seaborn as sns
from tqdm import tqdm
import sys
import psutil
import os
import shutil
import copy
from matplotlib import gridspec
from scipy.stats import multivariate_normal
from mpl_toolkits.mplot3d import Axes3D

import pickle as pkl
import tensorflow as tf
import tensorflow_probability as tfp

2.函数定义

下面的函数是直接从 Variational Calibration 复制而来的
在进行仿真之前运行3、4章的函数:

1. 模拟输入函数

该函数根据给定输入范围和维度内的拉丁超立方体设计或统一设计生成模型/观察的输入。

参数:

  • d_input:要生成的输入的维度
  • n_input:输入的数量
  • lims:Ndarray,每个变量的输入范围,每一行是每个变量的限制
  • criterion:“m”,“c”表示超立方体,“uniform”表示均匀设计

返回值:
inpues:n_input * d_input Ndarray 个生成的输入点。

"""产生模拟输入"""
def input_locations(d_input, n_input, lims, criterion = "c"): 
    """Simulation inputs generator
    The function generates inputs for model/observations according to latin hypercube design or uniform design within given range and dimension of inputs
    Args:
        d_input: The dimension of inputs to be generated
        n_input: The number of inputs
        lims: Ndarray with the range of inputs for each variable , each row is limits for each var
        criterion: "m", "c" for lating hypercube, "uniform" for uniform design
        
    Returns:
        inputs: n_input * d_input Ndarray with generated input points.
    """
    if criterion == "uniform":
        inputs = []
        for i in range(d_input):
            inputs = inputs + [np.linspace(lims[i, 0], lims[i, 1], int(n_input ** (1 / d_input)))]
        grid_list = np.meshgrid(*inputs)
        inputs = np.zeros((n_input, d_input))
        for i in range(d_input):
            inputs[:,i] = grid_list[i].flatten()        
        
    else:
        # Data generation
        inputs = doe.lhs(d_input, samples = n_input, criterion = criterion)
        # Transformation for the interval
        for i in range(d_input):
            inputs[:,i] = inputs[:,i] * (lims[i,1] - lims[i, 0]) + lims[i, 0]

    return inputs

2. 生成先验GP的均值和协方差

根据 KOH 校准框架对观测 Y 和模型评估 Z 的数据生成进行训练。

参数:

  • input_obs:- 观察输入(Ndarray)
  • input_m:- 模型输入的 Ndarray
  • d_input:模型输入的维度
  • theta:校准参数的真实值
  • kernels:包含 3 项的字典:f、delta 和noise kernels
  • means:包含 2 个项目的字典:f、delta

返回:

  • M:MVN分布的平均向量
  • K:MVN分布的协方差矩阵
def gp_mean_cov(input_obs, input_m, d_input, theta, kernels, means):
    """The function generates the mean and convariance function of the prior GP that is 
    to be used for triaining data generation of observations Y and model evaluations Z according to
    Kennedy & O'Hagan (2001) framework to calibration.
    
    Args:
        input_obs: Ndarray with observation inputs.
        input_m: Ndarray with model inputs.
        d_input: The dimension of model inputs.
        theta: True value of calibration parameter
        kernels: A dictionary containing 3 items: f, delta, and noise kernels
        means: A dictionary containing 2 items: f, delta
                
    Returns:
        M: Mean vector of MVN distribution
        K: Covariance matrix of MVN distribution
    """
    
    ##### 方差部分
    """核input"""
    theta_stack = np.repeat(theta, len(input_obs))
    theta_stack = theta_stack.reshape((len(input_obs), input_m.shape[1] - d_input), order='F')
    kernel_input = np.concatenate((np.concatenate([input_obs, theta_stack], axis = 1), input_m), axis = 0)
    
    # 模型 GP 的无噪声基础内核
    kernel_base = kernels["f"]
    K_base = kernel_base(kernel_input)
    
    # Model discrepancy kernel
    #模型差异核
    if kernels["delta"] != 0:
        
        zeros = np.zeros((input_m.shape[0], input_obs.shape[1]))
        delta_input = np.concatenate([input_obs, zeros])
        K_delta = kernels["delta"](delta_input)
        # Need to set the non-obs parts of the kernel to be zero
        #需要将内核的非观察部分设置为零
        K_delta[:, input_obs.shape[0]:] = 0
        K_delta[input_obs.shape[0]:, :] = 0
        K_base = K_base + K_delta
        
    # Add noise to the observations
    #为观察添加噪音
    K = K_base + np.diag([kernels["sigma"] ** 2] * input_obs.shape[0] + [0] * input_m.shape[0])
    
    ##### Means part  均值部分

    # Obs mean观测均值
    obs_mean = np.array([])
    input_obs_theta = np.concatenate([input_obs, theta_stack], axis = 1)
    for elem in input_obs_theta:
        # First input to mean is x, second input is theta
        obs_mean = np.append(obs_mean, means["f"](elem[:d_input], elem[d_input:]) + means["delta"](elem[:d_input]))
    
    # Model mean模型均值
    m_mean = np.array([])
    for elem in input_m:
        # First input to mean is x, second input is theta
        m_mean = np.append(m_mean, means["f"](elem[:d_input], elem[d_input:]))

    M = np.concatenate((obs_mean, m_mean))
    
    return M, K

3. 分布的类族

关于分布的类,用作 1) 变分族,2) 过度分散的族,3) 先验
每个类都包含以下方法:

  • __init__(self, param, init)
  • sample(self, n_size)
  • log_pdf(self, theta)
  • log_grad_pdf(self, theta)

3.1 任意维度的平均场高斯族的类

高斯平均场族的参数作为字典传递
参数

  • param: 一个字典,包含两个维度为 (dim,) 的数组条目
    • param[“mu”] 是具有独立高斯分布均值的一维 Ndarray
    • param[“sigma”] 是一个具有独立高斯分布的 np.log(SDs) 的一维 Ndarray
  • dim:族的维度
class gaussian_mean_field_family:
    """Class for a mean field gaussian family of arbitrary dimension"""
    
    def __init__(self, param, dim):
        """The parameters for the Gaussian mean field family are passed as a dictionary
        
        Args:
            param: A dictionaray containing two entries with arrays of dimension (dim,)
                 - param["mu"] is a 1-dim Ndarray with the means of independent Gaussian distributions
                 - param["sigma"] is a 1-dim Ndarray with the np.log(SDs) of independent Gaussian distributions
            dim: dimension of the family
        """
        
        self.mu = param["mu"]
        self.sigma = param["sigma"]
        self.dim = dim
        
    def sample(self, n_size):
        """Samples from the gaussian mean_field variational family
        
        Args:
            n_size: the number of samples to be generated
        Returns:
            samle: 2 dimensional NDarray where each row is a single sample from the variational family
        """
        """高斯均值场变分族的样本
         参数:
             n_size:要生成的样本数
         返回值:
             sample:二维 NDarray,其中每一行是来自变分族的单个样本
         """
        sample = np.zeros((n_size, self.dim))
        for i in range(self.dim):
            sample[:, i] = np.random.normal(loc = self.mu[i], scale = self.sigma[i], size = n_size)     
        return sample
    
    def log_pdf(self, theta):
        """Calculates the value of log density of the mean field gaussian family at theta
        计算平均场高斯族在 theta 处的log密度值
        
        Args:
            theta: 1-dim Ndarray of theta values at which the log density will be evaluated
            theta:将评估对数密度的 theta 值的 1-dim Ndarray
        Returns:
            log_dens: The value of log density at theta
        """
        
        log_dens = 0
        for i in range(self.dim):
            density = sp.stats.norm(loc = self.mu[i], scale = self.sigma[i])
            log_dens = log_dens + np.log(density.pdf(theta[i]))       
        return log_dens
    
    def grad_log_pdf(self, theta):
        """Calculates the value of score function at theta
        在 theta 处计算得分函数的值
        
        Args:
            theta: 1-dim Ndarray of theta values at which the log gradient will be evaluated
        Returns:
            gradient: 1-dim Ndarray of len(2 * dim) where gradient[:dim] are the values of score function
                    w.r.t mu and gradient[dim:] are the values of score function w.r.t sigma
        """
        
        gradient = np.zeros(self.dim * 2)
        for i in range(self.dim):
            # score function w.r.t. mean
            gradient[i] = (theta[i] - self.mu[i]) / (self.sigma[i] ** 2)
            # score function w.r.t. SD
            gradient[i + self.dim] = - 1 / self.sigma[i] + ((theta[i] - self.mu[i]) ** 2) / (self.sigma[i] ** 3)
        return gradient

3.2 具有 np.log(param) 参数化的任意维度的平均场 γ \gamma γ 系列的类

f ( x ∣ α , β ) = β α Γ ( α ) ∗ x α − 1 ∗ exp ⁡ ( − β ∗ x ) f(x|\alpha, \beta) = \frac{\beta ^ \alpha}{\Gamma(\alpha)} * x ^{\alpha - 1} * \exp({- \beta * x}) f(xα,β)=Γ(α)βαxα1exp(βx)
E ( X ) = α / β E(X) = \alpha / \beta E(X)=α/β
V a r ( X ) = α / ( β 2 ) Var(X) = \alpha / (\beta^2) Var(X)=α/(β2)
伽马平均场族的参数作为字典传递
参数

  • param: 一个字典,包含两个维度为 (dim,) 的数组条目
    • param[“alpha”] 是一个 一维 Ndarray,具有独立 Gamma 分布的 np.log(alpha) 参数
    • param[“beta”]是一个 一维 Ndarray,具有独立 Gamma 分布的 np.log(beta) 参数
  • dim:族的维度
class gamma_mean_field_family:
    """Class for a mean field gamma family of arbitrary dimension with np.log(param) parametrization
      
      Gamma parametrization:
      Gamma 参数
          
          $f(x|alpha, beta) = \frac{beta ^ alpha}{Gamma(alpha)} * x ^{alpha - 1} * \exp{- beta * x}$
          
          E(X) = alpha / beta
          Var(X) = alpha / (beta^2)
          
    """
    
    def __init__(self, param, dim):
        """The parameters for the gamma mean field family are passed as a dictionary
        
        Args:
            param: A dictionaray containing two entries with arrays of dimension (dim,)
                 - param["alpha"] is a 1-dim Ndarray with the np.log(alpha) parameters of independent Gamma distributions
                 - param["beta"] is a 1-dim Ndarray with the np.log(beta) parameters of independent Gamma distributions
            dim: Dimension of the family
        """
        
        self.alpha = param["alpha"]
        self.beta = param["beta"]
        self.dim = dim
        
    def sample(self, n_size):
        """Samples from the gamma mean field variational family
        
        Note: np.random.gamma has parametrization with shape = alpha, scale = 1 / beta
        
        Args:
            n_size: the number of samples to be generated
        Returns:
            samle: 2 dimensional NDarray where each row is a single sample from the variational family
        """
        
        sample = np.zeros((n_size, self.dim))
        for i in range(self.dim):
            sample[:, i] = np.random.gamma(shape = self.alpha[i], scale = self.beta[i], size = n_size)
        return sample
    
    def log_pdf(self, theta):
        """Calculates the value of log density of the mean field gamma family at theta
        
        Args:
            theta: 1-dim Ndarray of theta values at which the log density will be evaluated
        Returns:
            log_dens: The value of log density at theta
        """
        
        log_dens = 0
        for i in range(self.dim):
            log_dens = log_dens + (self.alpha[i] - 1) * np.log(theta[i]) - theta[i] / 
            self.beta[i] - self.alpha[i] * np.log(self.beta[i]) - np.log(sp.special.gamma(self.alpha[i]))
    
        return log_dens
    
    def grad_log_pdf(self, theta):
        """Calculates the value of score function at theta
        
        Args:
            theta: 1-dim Ndarray of theta values at which the log gradient will be evaluated
        Returns:
            gradient: 1-dim Ndarray of len(2 * dim) where gradient[:dim] are the values of score function
                    w.r.t alpha and gradient[dim:] are the values of score function w.r.t beta
        """
        
        gradient = np.zeros(self.dim * 2)
        for i in range(self.dim):    
            # score function w.r.t. alpha
            gradient[i] = np.log(theta[i]) - np.log(self.beta[i]) - sp.special.digamma(self.alpha[i])
            # score function w.r.t. beta
            gradient[i + self.dim] = theta[i] / (self.beta[i] ** 2) - self.alpha[i] / self.beta[i]
        return gradient

3.3 具有尺度参数化的任意维度的平均场高斯族的类

λ = l o g ( e x p ( σ ) − a ) \lambda = log(exp(\sigma) - a) λ=log(exp(σ)a)
参数

  • param: 一个字典,包含两个维度为 (dim,) 的数组条目
    • param[“mu”] 是具有独立高斯分布均值的一维 Ndarray
    • param[“sigma”] 是一个一维 Ndarray,具有独立高斯分布的变换 sd
    • param[“a”] 见参数化
  • dim:族的维度
class gaussian_mean_field_family_lambda_param:
    """Class for a mean field gaussian family of arbitrary dimension with scale parametrization 
    
    lambda = log(exp(sigma) - a)
    
    """
    def __init__(self, param, dim):
        """The parameters for the Gaussian mean field family aare passed as a dictionary
        
        Args:
            param: A dictionaray containing two entries with arrays of dimension (dim,)
                 - param["mu"] is a 1-dim Ndarray with the means of independent Gaussian distributions
                 - param["sigma"] is a 1-dim Ndarray with the transformed sd of independent Gaussian distributions
                 - param["a"] see parametrization
            dim: Dimension of the family
        """
        
        self.mu = param["mu"]
        self.sigma = param["sigma"]
        self.a = param["a"]
        self.dim = dim
        
    def sample(self, n_size):
        """Samples from the gaussian mean_field variational family
        
        Args:
            n_size: the number of samples to be generated
        Returns:
            samle: 2 dimensional NDarray where each row is a single sample from the variational family
        """
        
        sample = np.zeros((n_size, self.dim))
        for i in range(self.dim):
            sd = np.log(np.exp(self.sigma[i]) + self.a)
            sample[:, i] = np.random.normal(loc = self.mu[i], scale = sd, size = n_size)     
        return sample
    
    def log_pdf(self, theta):
        """Calculates the value of log density of the mean field gaussian family at theta
        
        Args:
            theta: 1-dim Ndarray of theta values at which the log density will be evaluated
        Returns:
            log_dens: The value of log density at theta
        """
        
        log_dens = 0
        for i in range(self.dim):
            sd = np.log(np.exp(self.sigma[i]) + self.a)
            density = sp.stats.norm(loc = self.mu[i], scale = sd)
            log_dens = log_dens + np.log(density.pdf(theta[i]))       
        return log_dens
    
    def grad_log_pdf(self, theta):
        """Calculates the value of score function at theta
        
        Args:
            theta: 1-dim Ndarray of theta values at which the log gradient will be evaluated
        Returns:
            gradient: 1-dim Ndarray of len(2 * dim) where gradient[:dim] are the values of score function
                    w.r.t mu and gradient[dim:] are the values of score function w.r.t sigma
        """
        
        gradient = np.zeros(self.dim * 2)
        for i in range(self.dim):
            # score function w.r.t. mean
            gradient[i] = - (self.mu[i] - theta[i]) / (np.log(np.exp(self.sigma[i]) + self.a) ** 2)
            # score function w.r.t. lambda
            gradient[i + self.dim] = np.exp(self.sigma[i]) * (- 1 / (np.log(self.a + np.exp(self.sigma[i])) * (self.a + np.exp(self.sigma[i]))) + \
              ((self.mu[i] - theta[i]) ** 2) /
              ((self.a + np.exp(self.sigma[i])) * np.log(self.a + np.exp(self.sigma[i])) ** 3))
        return gradient

3.4 任意平均场伽马族的类,参数化均值和标准差

此处直接参数化无变换
伽玛参数化:

f ( x ∣ α , β ) = β α Γ ( α ) ∗ x α − 1 ∗ exp ⁡ ( − β ∗ x ) f(x|\alpha, \beta) = \frac{\beta ^ \alpha}{\Gamma(\alpha)} * x ^{\alpha - 1} * \exp({- \beta * x}) f(xα,β)=Γ(α)βαxα1exp(βx)

E ( X ) = α / β E(X) = \alpha / \beta E(X)=α/β
V a r ( X ) = α / ( β 2 ) Var(X) = \alpha / (\beta^2) Var(X)=α/(β2)
参数

  • param: 一个字典,包含两个维度为 (dim,) 的数组条目
    • param[“alpha”]是具有独立 Gamma 分布的 np.log(alpha) 参数的 1-dim Ndarray
    • param[“beta”] 是具有独立 Gamma 分布的 np.log(beta) 参数的 1-dim Ndarray
    • param[“a”] 见参数化
  • dim:族的维度
class gamma_mean_field_family_ms:
    """Class for a mean field gamma family of arbitrary, parametrized with mean and standard deviation
    
    Directly parametrized no transformation here
      
      Gamma parametrization:
          
          f(x|alpha, beta) = \frac{beta ^ alpha}{Gamma(alpha)} * x ^{alpha - 1} * \exp{- beta * x}
          
          E(X) = alpha / beta
          Var(X) = alpha / (beta^2)
          
    """
    
    def __init__(self, param, dim):
        """The parameters for the gamma mean field family are passed as a dictionary
        
        Args:
            param: A dictionaray containing two entries with arrays of dimension (dim,)
                 - param["alpha"] is a 1-dim Ndarray with the np.log(alpha) parameters of independent Gamma distributions
                 - param["beta"] is a 1-dim Ndarray with the np.log(beta) parameters of independent Gamma distributions
                 - param["a"] see parametrization
            dim: Dimension of the family
        """
        
        self.alpha = param["alpha"]
        self.beta = param["beta"]
        self.a = param["a"]
        self.dim = dim
        
    def sample(self, n_size):
        """Samples from the gamma mean field variational family
        
        Note: np.random.gamma has parametrization with shape = alpha, scale = 1 / beta
        
        Args:
            n_size: the number of samples to be generated
        Returns:
            samle: 2 dimensional NDarray where each row is a single sample from the variational family
        """
        
        
        sample = np.zeros((n_size, self.dim))
        for i in range(self.dim):
            mu = self.alpha[i]
            sigma = self.beta[i]
            alpha = float(mu/sigma) ** 2
            beta = float(mu/ (sigma**2))
            tfd = tfp.distributions
            tfdGamma = tfd.Gamma(concentration=alpha, rate=beta)
            samples = tfdGamma.sample(n_size)
            sample[:, i] = samples.numpy()
        return sample
    
    def log_pdf(self, theta):
        """Calculates the value of log density of the mean field gamma family at theta
        
        Args:
            theta: 1-dim Ndarray of theta values at which the log density will be evaluated
        Returns:
            log_dens: The value of log density at theta
        """
        
        log_dens = 0
        for i in range(self.dim):
            
            mu = self.alpha[i]
            sigma = self.beta[i]
            alpha = float(mu/sigma) ** 2
            beta = float(mu/ (sigma**2))
            tfd = tfp.distributions
            tfdGamma = tfd.Gamma(concentration=alpha, rate=beta)
            log_dens = log_dens + float(tfdGamma.log_prob(theta[i]))
        return log_dens
    
    def grad_log_pdf(self, theta):
        """Calculates the value of score function at theta
        
        Args:
            theta: 1-dim Ndarray of theta values at which the log density will be evaluated
        Returns:
            gradient: 1-dim Ndarray of len(2 * dim) where gradient[:dim] are the values of score function
                    w.r.t alpha and gradient[dim:] are the values of score function w.r.t beta
        """
        
        gradient = np.zeros(self.dim * 2)
        for i in range(self.dim):    
            # score function w.r.t. np.log(alpha)
            l_m = self.alpha[i]
            l_s = self.beta[i]
            
            gradient[i] = (l_m - theta[i] + 2 * l_m * np.log(theta[i]) + 2 * l_m * np.log(l_m / (l_s ** 2)) - 2 * l_m * sp.special.digamma((l_m/l_s) ** 2)) / (l_s ** 2)
    
            gradient[i + self.dim] = 2 * (l_m * theta[i] - l_m ** 2 + sp.special.digamma((l_m/l_s)** 2) * l_m ** 2 - np.log(theta[i]) * l_m ** 2 - np.log(l_m / (l_s ** 2)) * l_m **2) / (l_s ** 3)
        return gradient
    

3.5 任意平均场伽马族的类,参数化均值和标准差

f ( x ∣ α , β ) = β α Γ ( α ) ∗ x α − 1 ∗ exp ⁡ ( − b e t a ∗ x ) s f(x|\alpha, \beta) = \frac{\beta ^ \alpha}{\Gamma(\alpha)} * x ^{\alpha - 1} * \exp({- beta * x})s f(xα,β)=Γ(α)βαxα1exp(betax)s

E ( X ) = α / β E(X) = \alpha / \beta E(X)=α/β
V a r ( X ) = α / ( β 2 ) Var(X) = \alpha / (\beta^2) Var(X)=α/(β2)
参数

  • param: 一个字典,包含两个维度为 (dim,) 的数组条目
    • param[“alpha”]是具有独立 Gamma 分布的 np.log(alpha) 参数的 1-dim Ndarray
    • param[“beta”] 是具有独立 Gamma 分布的 np.log(beta) 参数的 1-dim Ndarray
    • param[“a”] 见参数化
  • dim:族的维度
  • tau: 色散系数 >= 1
class gamma_mean_field_family_ms_overdisp:
    """Class for a mean field gamma family of arbitrary, parametrized with mean and standard deviation
    directly
      
      Gamma parametrization:
          
          f(x|alpha, beta) = \frac{beta ^ alpha}{Gamma(alpha)} * x ^{alpha - 1} * \exp{- beta * x}
          
          E(X) = alpha / beta
          Var(X) = alpha / (beta^2)
          
    """
    
    def __init__(self, param, dim, tau):
        """The parameters for the gamma mean field family are passed as a dictionary
        
        Args:
            param: A dictionaray containing two entries with arrays of dimension (dim,)
                 - param["alpha"] is a 1-dim Ndarray with the np.log(alpha) parameters of independent Gamma distributions
                 - param["beta"] is a 1-dim Ndarray with the np.log(beta) parameters of independent Gamma distributions
                 - param["a"] see parametrization
            dim: Dimension of the family
            tau: Dispersion coefficient >= 1
        """
        
        self.alpha = param["alpha"]
        self.beta = param["beta"]
        self.a = param["a"]
        self.tau = tau
        self.dim = dim
        
    def sample(self, n_size):
        """Samples from the gamma mean field variational family
        
        Note: np.random.gamma has parametrization with shape = alpha, scale = 1 / beta
        
        Args:
            n_size: the number of samples to be generated
        Returns:
            samle: 2 dimensional NDarray where each row is a single sample from the variational family
        """
        
        
        sample = np.zeros((n_size, self.dim))
        for i in range(self.dim):
            mu = self.alpha[i]
            sigma = self.beta[i]
            alpha = (float(mu/sigma) ** 2 + self.tau[i] - 1) / self.tau[i]
            beta = float(mu/ (sigma**2)) / self.tau[i]
            tfd = tfp.distributions
            tfdGamma = tfd.Gamma(concentration=alpha, rate=beta)
            samples = tfdGamma.sample(n_size)
            sample[:, i] = samples.numpy()
        return sample
    
    def log_pdf(self, theta):
        """Calculates the value of log density of the mean field gamma family at theta
        
        Args:
            theta: 1-dim Ndarray of theta values at which the log density will be evaluated
        Returns:
            log_dens: The value of log density at theta
        """
        
        log_dens = 0
        for i in range(self.dim):
            
            mu = self.alpha[i]
            sigma = self.beta[i]
            alpha = (float(mu/sigma) ** 2 + self.tau[i] - 1) / self.tau[i]
            beta = float(mu/ (sigma**2)) / self.tau[i]
            tfd = tfp.distributions
            tfdGamma = tfd.Gamma(concentration=alpha, rate=beta)
            log_dens = log_dens + float(tfdGamma.log_prob(theta[i]))
        return log_dens
    
    def grad_log_pdf_tau(self, theta):
        """Calculate the value of score function at theta w.r.t dispersion coefficient tau
        
        Args:
            theta: 1-dim Ndarray of theta values at which the log gradient will be evaluated
        Returns:
            gradient: 1-dim Ndarray of len(dim) with the values of score function
                    w.r.t tau
        """
        gradient = np.zeros(self.dim)
        for i in range(self.dim):    
            mu = self.alpha[i]
            sigma = self.beta[i]
            alpha = float(mu/sigma) ** 2
            beta = float(mu/ (sigma**2))
            
            gradient[i] = (self.tau[i] * np.log(beta / self.tau[i]) - (alpha + self.tau[i] - 1) + beta * theta[i] - \
                          np.log(beta / self.tau[i]) * (alpha + self.tau[i] - 1) + sp.special.digamma((alpha + self.tau[i] - 1) /self.tau[i]) * (alpha - 1) - \
                          np.log(theta[i]) * (alpha - 1)) / self.tau[i]      
        return gradient
   
    

3.6 具有尺度参数化的任意维度的平均场过分散高斯族的类

class gaussian_mean_field_family_lambda_param_overdisp:
    """Class for a mean field overdispersed gaussian family of arbitrary dimension with scale parametrization 
    
    lambda = log(exp(sigma) - a)
    
    """
    def __init__(self, param, dim, tau):
        """The parameters for the Gaussian mean field family aare passed as a dictionary
        
        Args:
            param: A dictionaray containing two entries with arrays of dimension (dim,)
                 - param["mu"] is a 1-dim Ndarray with the means of independent Gaussian distributions
                 - param["sigma"] is a 1-dim Ndarray with the np.log(SDs) of independent Gaussian distributions
                 - param["a"] see parametrization 
            dim: Dimension of the family
            tau: Dispersion coefficient >= 1
        """
        
        self.mu = param["mu"]
        self.sigma = param["sigma"]
        self.a = param["a"]
        self.tau = tau
        self.dim = dim
        
    def sample(self, n_size):
        """Samples from the gaussian mean_field variational family
        
        Args:
            n_size: the number of samples to be generated
        Returns:
            samle: 2 dimensional NDarray where each row is a single sample from the variational family
        """
        
        sample = np.zeros((n_size, self.dim))
        for i in range(self.dim):
            sd = np.log(np.exp(self.sigma[i]) + self.a) * np.sqrt(self.tau[i])
            sample[:, i] = np.random.normal(loc = self.mu[i], scale = sd , size = n_size)     
        return sample
    
    def log_pdf(self, theta):
        """Calculates the value of log density of the mean field gaussian family at theta
        
        Args:
            theta: 1-dim Ndarray of theta values at which the log density will be evaluated
        Returns:
            log_dens: The value of log density at theta
        """
        
        log_dens = 0
        for i in range(self.dim):
            sd = np.log(np.exp(self.sigma[i]) + self.a) * np.sqrt(self.tau[i])
            density = sp.stats.norm(loc = self.mu[i], scale = sd)
            log_dens = log_dens + np.log(density.pdf(theta[i]))       
        return log_dens
    
    def grad_log_pdf_tau(self, theta):
        """"Calculate the value of score function at theta w.r.t dispersion coefficient tau
        
        Args:
            theta: 1-dim Ndarray of theta values at which the log gradient will be evaluated
        Returns:
            gradient: 1-dim Ndarray of len(dim) with the values of score function
                    w.r.t tau
        """
        gradient = np.zeros(self.dim)
        for i in range(self.dim):
            sd = np.log(np.exp(self.sigma[i]) + self.a)
            gradient[i] = - 1/(2 * self.tau[i]) + (((theta[i] - self.mu[i]) / (self.tau[i] * sd)) ** 2) / 2
            
        return gradient

3.7平均场过度分散的任意伽马族的类,参数化均值和标准差

class gamma_mean_field_family_lambda_param_overdisp:
    """Class for a mean field overdispersed gamma family of arbitrary, parametrized with mean and standard deviation
    
        lambda_alfa = log(exp(alfa) - a)
        lambda_beta = log(exp(alfa) - a)
    
        where alpha corresponds to the mean of the gamma distribution and beta corresponds to the std of the gamma dist
      
      Gamma parametrization:
          
          f(x|alpha, beta) = \frac{beta ^ alpha}{Gamma(alpha)} * x ^{alpha - 1} * \exp{- beta * x}
          
          E(X) = alpha / beta
          Var(X) = alpha / (beta^2)
          
    """
    
    def __init__(self, param, dim, tau):
        """The parameters for the gamma mean field family are passed as a dictionary
        
        Args:
            param: A dictionaray containing two entries with arrays of dimension (dim,)
                 - param["alpha"] is a 1-dim Ndarray with the np.log(alpha) parameters of independent Gamma distributions
                 - param["beta"] is a 1-dim Ndarray with the np.log(beta) parameters of independent Gamma distributions
                 - param["a"] see above
            tau: Overdispersion parameter value
        """
        
        self.alpha = param["alpha"]
        self.beta = param["beta"]
        self.a = param["a"]
        self.tau = tau
        self.dim = dim
        
    def sample(self, n_size):
        """Samples from the gamma mean field variational family
        
        Note: np.random.gamma has parametrization with shape = alpha, scale = 1 / beta
        
        Args:
            n_size: the number of samples to be generated
        Returns:
            samle: 2 dimensional NDarray where each row is a single sample from the variational family
        """
        
        
        sample = np.zeros((n_size, self.dim))
        for i in range(self.dim):
            mu = np.log(np.exp(self.alpha[i]) + self.a)
            sigma = np.log(np.exp(self.beta[i]) + self.a)
            alpha = (float(mu/sigma) ** 2 + self.tau[i] - 1) / self.tau[i]
            beta = float(mu/ (sigma**2)) / self.tau[i]
            tfd = tfp.distributions
            tfdGamma = tfd.Gamma(concentration=alpha, rate=beta)
            samples = tfdGamma.sample(n_size)
            sample[:, i] = samples.numpy()
        return sample
    
    def log_pdf(self, theta):
        """Calculates the value of log density of the mean field gamma family at theta
        
        Args:
            theta: 1-dim Ndarray of theta values at which the log density will be evaluated
        Returns:
            log_dens: The value of log density at theta
        """
        
        log_dens = 0
        for i in range(self.dim):
            
            mu = np.log(np.exp(self.alpha[i]) + self.a)
            sigma = np.log(np.exp(self.beta[i]) + self.a)
            alpha = (float(mu/sigma) ** 2 + self.tau[i] - 1) / self.tau[i]
            beta = float(mu/ (sigma**2)) / self.tau[i]
            tfd = tfp.distributions
            tfdGamma = tfd.Gamma(concentration=alpha, rate=beta)
            log_dens = log_dens + float(tfdGamma.log_prob(theta[i]))
        return log_dens
    
    
    def grad_log_pdf_tau(self, theta):
        """"Calculate the value of score function at theta w.r.t dispersion coefficient tau
        
        Args:
            theta: 1-dim Ndarray of theta values at which the log gradient will be evaluated
        Returns:
            gradient: 1-dim Ndarray of len(dim) with the values of score function
                    w.r.t tau
        """
        
        gradient = np.zeros(self.dim)
        for i in range(self.dim):    
            mu = np.log(np.exp(self.alpha[i]) + self.a)
            sigma = np.log(np.exp(self.beta[i]) + self.a)
            alpha = (float(mu/sigma) ** 2)
            beta = float(mu/ (sigma**2))
            
            gradient[i] = (self.tau[i] * np.log(beta / self.tau[i]) - (alpha + self.tau[i] - 1) + beta * theta[i] - \
                          np.log(beta / self.tau[i]) * (alpha + self.tau[i] - 1) + sp.special.digamma((alpha + self.tau[i] - 1) /self.tau[i]) * (alpha - 1) - \
                          np.log(theta[i]) * (alpha - 1)) / self.tau[i]      
        return gradient

4.GP模型均值类定义

4.1模型差异 GP 的均值函数

表示模型差异 GP 的均值函数的通用类

参数

  • 超参数:均值的超参数字典

方法

  • Zero mean: m ( x ) = 0 m(x) = 0 m(x)=0
  • Constant mean: m ( x ) = β m(x) = \beta m(x)=β
  • Linear mean: m ( x ) = I n t e r c e p t + β ∗ x T m(x) =Intercept + \beta * x^T m(x)=Intercept+βxT
class delta_mean:
    def __init__(self, hyperparametrs):
        """General class representing the mean function of model discrepancy GP
        
        Args:
            hyperparameters: A dictionary of hyperparameters for the mean
        """
        self.hyperparameters = hyperparametrs
        
    def zero(self, x):
        """Zero mean: m(x) = 0
        
        Args:
            x: 1-dim Ndarray of model imputs (or scalar)
        Returns: 0
        """
        return 0
    
    def constant(self, x):
        """Constant mean: m(x) = \Beta
        
        Args:
            x: 1-dim Ndarray of model imputs (or scalar)
            self.hyperparameters: A scalar with dictionary key "Beta"
        Returns: self.hyperparameters["Beta"]
        """
        return self.hyperparameters["Beta"]
    
    def linear(self, x):
        """Linear mean: m(x) =Intercept + \Beta * x^T
        
        Args:
            x: 1-dim Ndarray of model imputs (or scalar)
            self.hyperparameters: A scalar with dictionary key "Intercept" and a vector of parameters
                                  with dictionary key "Beta" of the same length as lengt(x)
        Returns:
            mean: Intercept + \Beta * (x, theta)^T
        """
        mean = self.hyperparameters["Intercept"] + np.dot(self.hyperparameters["Beta"], x)
        return mean

4.2 计算机模型 GP 的均值函数

表示计算机模型 GP 的均值函数的通用类

参数

  • 超参数:均值的超参数字典

方法

  1. Zero mean: m ( x ) = 0 m(x) = 0 m(x)=0
  2. Constant mean: m ( x ) = β m(x) = \beta m(x)=β
  3. dot_product: m ( x , θ ) = β ∗ ( θ 1 ∗ c o s ( x 1 ) + θ 2 ∗ c o s ( x 2 ) ) m(x,\theta) = \beta * (\theta_1 * cos(x_1) + \theta_2 * cos(x_2)) m(x,θ)=β(θ1cos(x1)+θ2cos(x2))
```python
class model_mean:
    def __init__(self, hyperparametrs):
        """General class representing the mean function of computer model GP
        
        Args:
            hyperparameters: A dictionary of hyperparameters for the mean
        """
        self.hyperparameters = hyperparametrs
        
    def zero(self, x, theta):
        """Zero mean: m(x,theta) = 0
        
        Args:
            x: 1-dim Ndarray of model imputs (or scalar)
            theta: 1-dim Ndarray (or scalar) of calibration parameters  
        Returns: 0
        """
        return 0
    
    def constant(self, x, theta):
        """Constant mean: m(x,theta) = \Beta
        
        Args:
            x: 1-dim Ndarray of model imputs (or scalar)
            theta: 1-dim Ndarray (or scalar) of calibration parameters
            self.hyperparameters: A scalar with dictionary key "Beta"
        Returns: self.hyperparameters["Beta"]
        """
        return self.hyperparameters["Beta"]
    
    def dot_product(self, x, theta):
        """Dot product mean, for two dimensional model input x as defined in the 
           simulation setup in Kejzlar and Maiti (2020): 
           
           m(x,theta) = \Beta * (\theta_1 * cos(x_1) + \theta_2 * cos(x_2))
        
        Args:
            x: 1-dim Ndarray of model imputs (or scalar)
            theta: 1-dim Ndarray (or scalar) of calibration parameter
            self.hyperparameters: A scalar with dictionary key "Beta"
        Returns: self.hyperparameters["Beta"] * np.dot(x, theta)
        """
        if x.ndim == 1:
            return self.hyperparameters["Beta"] * np.dot(np.array([np.cos(x[0]), np.sin(x[1])]), theta)
        else:
            return self.hyperparameters["Beta"] * np.dot(np.array([np.cos(x[:,0]), np.sin(x[:,1])]), theta)

3.MCMC 贝叶斯校准 - 模拟

此块包含对模拟研究执行 MCMC 校准的代码,
变分方法的代码在 Variational_calibration.ipynb notebook 中

1. 生成训练数据并定义先验分布

准备

priors_dictionary = {}
theta_dim = 2
ns = 30 #Numerators for eta_f and eta_delta
tf.random.set_seed(123)
np.random.seed(123)
  1. 定义先验分布
  • 设置 θ \theta θ 先验
### Theta prior
mean_theta = np.array([0.5,0.5])
cov_theta = np.array([1/10,1/10])
dim = theta_dim
theta_prior = gaussian_mean_field_family(param = {"mu": mean_theta, "sigma": cov_theta}, dim = dim)
"""作为先验分布样本的真实 theta 值"""
theta = theta_prior.sample(1).flatten() # The true theta value as a sample from prior distribution
priors_dictionary["theta"] = theta_prior
  • 设置噪声先验
### Noise prior
alpha = np.array([1])
beta = np.array([1/80])
dim = 1
noise_prior = gamma_mean_field_family(param = {"alpha": alpha, "beta": beta}, dim = dim)
noise = np.array([0.01]) # Noise value for simulation
priors_dictionary["sigma"] = noise_prior
  • f f f 的核超参数先验

-------- 长度刻度 f l f_l fl 先验

## length scales
alpha = np.array([1])
beta = np.array([20])
beta = np.array([1/4])
dim = 1
kernel_f_l_prior = gamma_mean_field_family(param = {"alpha": alpha, "beta": beta}, dim = dim)
kernel_f_l = 1 # true value of length scale
priors_dictionary["kernel_f_l"] = kernel_f_l_prior

-------- f η f_\eta fη 先验

## eta
alpha = np.array([1])
beta = np.array([1/40])
dim = 1
kernel_f_eta_prior = gamma_mean_field_family(param = {"alpha": alpha, "beta": beta}, dim = dim)
kernel_f_eta = 1/ns # true value of eta_f
priors_dictionary["kernel_f_eta"] = kernel_f_eta_prior
  • δ \delta δ 的核超参数先验

-------- 长度刻度 δ l \delta_l δl 先验

## length scales
alpha = np.array([1])
beta = np.array([1/4])
dim = 1
kernel_delta_l_prior = gamma_mean_field_family(param = {"alpha": alpha, "beta": beta}, dim = dim)
kernel_delta_l = 1/2 # true vaule of lenght scale
priors_dictionary["kernel_delta_l"] = kernel_delta_l_prior

-------- δ η \delta_\eta δη 先验

alpha = np.array([1])
beta = np.array([1/40])
dim = 1
kernel_delta_eta_prior = gamma_mean_field_family(param = {"alpha": alpha, "beta": beta}, dim = dim)
kernel_delta_eta = 1/ns # true value of delta_eta
priors_dictionary["kernel_delta_eta"] = kernel_delta_eta_prior
  • f f f的均值超参数
f_beta = 1
  • δ \delta δ 的均值超参数
### Mean delta hyperparameters
mean_beta = np.array([0])
cov_beta = np.array([1/4])
dim = 1
mean_delta_prior = gaussian_mean_field_family(param = {"mu": mean_beta, "sigma": cov_beta}, dim = dim)
delta_beta = 0.15 # true value of beta
priors_dictionary["mean_delta"] = mean_delta_prior
  • 核定义

-------- f f f

# f kernel
kernel = {"sq_quad": [kernel_f_eta, kernel_f_l]}
kernel_type = list(kernel)[0]
if kernel_type == "sq_quad":
    kernel_f = float(kernel[kernel_type][0]) ** 2 * skl.RBF(length_scale = kernel[kernel_type][1])       
    
if kernel_type == "matern": # option for mattern kernel
    kernel_f = float(kernel[kernel_type][0]) ** 2 * skl.Matern(length_scale = kernel[kernel_type][1],
                                                               nu = kernel[kernel_type][2])

-------- δ \delta δ

# delta kernel
kernel = {"sq_quad": [kernel_delta_eta, kernel_delta_l]} # sigma, l_scale
kernel_type = list(kernel)[0]
if kernel_type == "sq_quad":
    kernel_delta = float(kernel[kernel_type][0]) ** 2 * skl.RBF(length_scale = kernel[kernel_type][1])       
    
if kernel_type == "matern":
    kernel_delta = float(kernel[kernel_type][0]) ** 2 * skl.Matern(length_scale = kernel[kernel_type][1],
                                                               nu = kernel[kernel_type][2])
if kernel_type == "zero":
    kernel_delta = 0

--------- 各种核的输入

kernels_input = {"f":kernel_f, "delta": kernel_delta, "sigma": float(noise)}
kernels = {"f": "sq_quad", "delta": "sq_quad"}
  • 均值定义
model_hyperparameters = {"Beta": float(f_beta)}
delta_hyperparameters = {"Beta": float(delta_beta)}

f_mean_init = model_mean(model_hyperparameters)
delta_mean_init = delta_mean(delta_hyperparameters)

means_input = {"f": f_mean_init.dot_product, "delta": delta_mean_init.constant}
means = {"f": f_mean_init.dot_product, "delta": "constant" }
  1. 数据生成部分
n_obs = 144 # set to 2500, 5000, 10000 for the scalability simulation
n_m = 81 # set to 2500, 5000, 10000 for the scalability simulation
n_average = 1
d_input = 2 # dimension of the variable input
tf.random.set_seed(123)
np.random.seed(123)
# For scalability simulation switch criterion = "c" for numerical stability
lims = np.array([[0, 3], [0, 3]])
input_obs = input_locations(d_input, n_obs, lims=lims, criterion = "uniform")
d_input = 2
lims = np.array([[0, 3], [0,3], [0, 1], [0, 1]])
input_m = input_locations(theta_dim + d_input, n_m, lims=lims, criterion = "uniform")
print(theta)
  • 训练数据的均值和协方差函数
tf.random.set_seed(123)
np.random.seed(123)
# Mean and covariance functions for the training data
M, K = gp_mean_cov(input_obs, input_m, d_input, theta, kernels_input, means_input)
tfd = tfp.distributions
mvn = tfd.MultivariateNormalFullCovariance(loc=M, covariance_matrix=K)
Y_Z_tensor = mvn.sample(1)

Y_Z = Y_Z_tensor.numpy().flatten()
Y = Y_Z[:n_obs][:,None]
Z = Y_Z[n_obs:][:,None]
  1. 将数据格式化为用于 VC_calibration_hyper 函数的 data_input 字典格式
    这与任何 GP 规范或使用的方差减少类型无关
# index generating
Y_index = np.array([i + 1 for i in range(len(Y))])[:,None]
Z_index = np.array([i + 1 + len(Y) for i in range(len(Z))])[:,None]

# Response conc. index
Y_input = np.concatenate((Y_index, np.array([1] * len(Y))[:,None], Y), axis = 1)
Z_input = np.concatenate((Z_index, np.array([0] * len(Z))[:, None], Z), axis = 1)
Response_input = np.concatenate((Y_input, Z_input), axis = 0)

# Input values X
Y_X = np.concatenate((Y_index, input_obs), axis = 1)
Z_X = np.concatenate((Z_index, input_m[:,:d_input]), axis = 1)
X_input = np.concatenate((Y_X, Z_X))

########### This will be done in each stap of the sampling
########### procedure but needs to be initialized to something
# 这将在采样过程的每个步骤中完成,但需要初始化为
# Input values theta
theta_variational = theta
theta_variational = np.repeat(theta_variational, len(Y))
theta_variational = theta_variational.reshape((len(Y),theta_dim), order='F')

Y_theta = np.concatenate((Y_index, theta_variational), axis = 1)
Z_theta = np.concatenate((Z_index, input_m[:,d_input:]), axis = 1)
Theta_input = np.concatenate((Y_theta, Z_theta))

# Data input for 
data_input = {"Response": Response_input, "X": X_input, "Theta": Theta_input}

# Bijection
n = n_m + n_obs

### Save the data_input dictionary as .pickle file
#with open(str(n_obs) + '_' + str(n_m) + '.pickle', 'wb') as handle:
#    pkl.dump(data_input, handle, protocol=pkl.HIGHEST_PROTOCOL)
###

### Load the data_input dictionary from .pickle file
#with open(str(n_obs) + '_' + str(n_m) + "_" + str(lims[0][1]) + '.pickle', 'rb') as handle:
#    data_input = pkl.load(handle)
###

可选 - 绘制生成的模型运行图

plt.rcParams.update({'font.size': 15})
fig = plt.figure(figsize=(18, 4)) 
gs = gridspec.GridSpec(1, 3, width_ratios=[1, 1, 1])
ax1 = plt.subplot(gs[0], projection='3d')
ax1.scatter(input_obs[:,0],input_obs[:,1], Y, c = 'firebrick')
ax1.set_xlabel(r'$x_1$', labelpad=10)
ax1.set_ylabel(r'$x_2$', labelpad=10)
ax1.set_zlabel(r'z')

ax2 = plt.subplot(gs[1])
ax2.scatter(input_obs[:,0], Y, c = 'firebrick')
ax2.set_xlabel(r'$x_1$')
ax2.yaxis.tick_right()
ax2.set_ylabel(r'$z$')
ax2.yaxis.set_label_position("right")

ax3 = plt.subplot(gs[2])
ax3.scatter(input_obs[:,1], Y, c = 'firebrick')
ax3.set_xlabel(r'$x_2$')
ax3.yaxis.tick_right()
ax3.set_ylabel(r'$z$')
ax3.yaxis.set_label_position("right")

plt.show()
plt.show()

在这里插入图片描述

2.使用 PyMC3 进行贝叶斯校准

x_dim = 2
theta_dim = 2
np.random.seed(0)
# Preprocessing input
def observations_scale(x):
    return x[:, -1]

  1. 预处理所有共享数据
obs_indicator = data_input["Response"][:,1][:,None]
X_obs_indicator = np.concatenate([data_input["X"][:,1:], obs_indicator], axis = 1)
X_shared = theano.shared(data_input["X"][:,1:])
theta_model_shared = theano.shared(input_m[:,x_dim:])
sampler_type = "MH" # "MH" or "NUTS"
n_tune = 1000 # Number of tuning samples
n_sample = 10000 # Number of effective samples

time_counter = np.array(time.monotonic())

with pm.Model() as full_bayes:
    
    ## Priors definition
    ## 定义先验
    
    # Theta prior 
    theta_random = pm.Normal("theta", mu = priors_dictionary["theta"].mu,
                        sd = priors_dictionary["theta"].sigma,
                        shape = priors_dictionary["theta"].dim)
    
    ## Noise Prior
    noise = pm.Gamma("sigma", alpha = float(priors_dictionary["sigma"].alpha),
                     beta = float(1/priors_dictionary["sigma"].beta))
    
    ### Kernel f hyperparameters priors
    ## length scales
    if priors_dictionary["kernel_f_l"].dim > 1:
        kernel_f_l = pm.Gamma("kernel_f_l", alpha = float(priors_dictionary["kernel_f_l"].alpha),
                              beta = float(1/ priors_dictionary["kernel_f_l"].beta),
                              shape = priors_dictionary["kernel_f_l"].dim)
    else:
        kernel_f_l = pm.Gamma("kernel_f_l", alpha = float(priors_dictionary["kernel_f_l"].alpha),
                          beta = float(1 / priors_dictionary["kernel_f_l"].beta))
    ## eta
    kernel_f_eta = pm.Gamma("kernel_f_eta", alpha = float(priors_dictionary["kernel_f_eta"].alpha),
                            beta = float(1 / priors_dictionary["kernel_f_eta"].beta))
    
    ### Kernel delta hyperparameters priors
    ## length scales
    if priors_dictionary["kernel_delta_l"].dim > 1:
        kernel_delta_l = pm.Gamma("kernel_delta_l", alpha = priors_dictionary["kernel_delta_l"].alpha,
                                  beta = 1/ priors_dictionary["kernel_delta_l"].beta,
                                  shape = priors_dictionary["kernel_delta_l"].dim)
    else:
        kernel_delta_l = pm.Gamma("kernel_delta_l", alpha = np.float(priors_dictionary["kernel_delta_l"].alpha),
                              beta = np.float(1 / priors_dictionary["kernel_delta_l"].beta))
    ## eta
    kernel_delta_eta = pm.Gamma("kernel_delta_eta", alpha = float(priors_dictionary["kernel_delta_eta"].alpha),
                                beta = float(1 / priors_dictionary["kernel_delta_eta"].beta))
    ## Means priors
    if "mean_f" in priors_dictionary:
        if priors_dictionary["mean_f"].dim > 1:
            mean_f = pm.Normal("mean_f", mu = priors_dictionary["mean_f"].mu,
                               sd = priors_dictionary["mean_f"].sigma,
                               shape = priors_dictionary["mean_f"].dim)
        else:
            mean_f = pm.Normal("mean_f", mu = float(priors_dictionary["mean_f"].mu),
                               sd = float(priors_dictionary["mean_f"].sigma))
            
        
    if "mean_delta" in priors_dictionary:
        if priors_dictionary["mean_delta"].dim > 1:
            mean_delta = pm.Normal("mean_delta", mu = priors_dictionary["mean_delta"].mu,
                                   sd = priors_dictionary["mean_delta"].sigma,
                                   shape = priors_dictionary["mean_delta"].dim)
        else:
            mean_delta = pm.Normal("mean_delta", mu = float(priors_dictionary["mean_delta"].mu),
                                   sd = float(priors_dictionary["mean_delta"].sigma))
        
    # Noise covariance
    cov_noise_base = pm.gp.cov.WhiteNoise(noise)
    cov_noise = pm.gp.cov.ScaledCov(1, cov_func = cov_noise_base, scaling_func = observations_scale)
    
    # Systematic discrepancy covariance
    # 系统差异协方差
    if kernels["delta"] == "sq_quad":
        cov_delta_base = kernel_delta_eta ** 2 * pm.gp.cov.ExpQuad(x_dim + 1, ls = kernel_delta_l,
                                                                   active_dims = [i for i in range(x_dim)])
    elif kernels["delta"] == "matern":
        print("matern kernel")
        
    cov_delta = pm.gp.cov.ScaledCov(x_dim + 1, cov_func = cov_delta_base, scaling_func = observations_scale)
    
    #Preprocessing theta
    # 预处理θ
    thetas_variable = tt.concatenate([tt.tile(theta_random, (int(np.sum(obs_indicator)), 1)), theta_model_shared], axis = 0)
    X_thetas_variable = tt.concatenate([X_shared, thetas_variable], axis = 1)
    
    # Model covariance
    if kernels["f"] == "sq_quad":
        cov_f = kernel_f_eta ** 2 * pm.gp.cov.ExpQuad(x_dim + theta_dim, ls = kernel_f_l)
    elif kernels["f"] == "matern":
        print("matern kernel")
        
    # Complete covariance specification
    # 完整的协方差规范
    K = cov_f(X_thetas_variable) + cov_delta(X_obs_indicator) + cov_noise(obs_indicator)
    # Mean definition
    # Mean f
    if "mean_f" in priors_dictionary:
        if means["f"] == "constant":
            mu_f = mean_f * np.ones(len(data_input["Response"]))
        elif means["f"] == "dot_product":
            mu_f = mean_f * tt.diag(tt.dot(data_input["X"][:,1:], thetas_variable.T))
        elif means["f"] == "linear":
            ones_array = theano.shared(np.ones(len(data_input["Response"]))[:, None])
            ones_X_thetas_variable = tt.concatenate([ones_array, X_thetas_variable], axis = 1)
            mu_f = tt.dot(mean_f, ones_X_thetas_variable.T)          
    else:
        if means["f"].__name__ == "zero":
            mu_f = 0 * obs_indicator.flatten()
        elif means["f"].__name__ == "constant":
            mu_f = f_mean_init.hyperparameters["Beta"] * np.ones(len(data_input["Response"]))
        elif means["f"].__name__ == "dot_product":
            mu_f = f_mean_init.hyperparameters["Beta"] * tt.diag(tt.dot(np.concatenate([np.cos(data_input["X"][:,1])[:,None], np.sin(data_input["X"][:,2])[:,None]], axis = 1), thetas_variable.T))
        elif means["f"].__name__ == "linear":
            ones_array = theano.shared(np.ones(len(data_input["Response"]))[:, None])
            ones_X_thetas_variable = tt.concatenate([ones_array, X_thetas_variable], axis = 1)
            mu_f = tt.dot(np.array([f_mean_init.hyperparameters["Intercept"],f_mean_init.hyperparameters["Beta"]]).flatten(),
                          ones_X_thetas_variable.T)  
            
    # Mean delta
    if "mean_delta" in priors_dictionary:
        if means["delta"] == "constant":
            mu_delta = mean_delta * obs_indicator.flatten()
        elif means["delta"] == "linear":
            ones_array = theano.shared(obs_indicator)
            ones_X = tt.concatenate([ones_array, X_shared], axis = 1)
            mu_delta = tt.dot(mean_delta, ones_X.T)  
    else:
        if means["delta"].__name__ == "zero":
            mu_delta = 0 * obs_indicator.flatten()
        elif means["delta"].__name__ == "constant":
            mu_delta = delta_mean_init.hyperparameters["Beta"] * obs_indicator.flatten()
        elif means["delta"].__name__ == "linear":
            ones_array = theano.shared(obs_indicator)
            ones_X = tt.concatenate([ones_array, X_shared], axis = 1)
            mu_delta = tt.dot(np.array([delta_mean_init.hyperparameters["Intercept"],delta_mean_init.hyperparameters["Beta"]]).flatten(),
                              ones_X.T)  
        
            
    mu = mu_f + mu_delta    
    obs = pm.MvNormal('obs', mu = mu, cov = K, observed = data_input["Response"][:,-1])
    if sampler_type == "MH":
        step = pm.Metropolis()
        trace = pm.sample(n_sample, tune= n_tune, chains = 1, step = step, discard_tuned_samples = False)
    elif sampler_type == "NUTS":
        trace = pm.sample(n_sample, tune= n_tune, chains = 1, discard_tuned_samples = False)
    # Saves trace    
    pm.backends.ndarray.save_trace(trace, "trace_" + str(n_obs) + "_" + str(n_m) + "_nsample_" 
                                   + str(n_sample) + "_sampler_" + sampler_type, overwrite=True)

3. 加载预计算结果

# Simulation - calibration
with full_bayes:
    trace = pm.backends.ndarray.load_trace("Simulation_results/Calibration/trace_144_81_nsample_25000_sampler_MH")
    trace_NUTS = pm.backends.ndarray.load_trace("Simulation_results/Calibration/trace_144_81_nsample_25000_sampler_NUTS")
# Simulation - scalability 5K
#with full_bayes:
#    trace = pm.backends.ndarray.load_trace("Simulation_results/Calibration/trace_2500_2500_nsample_2000_sampler_MH")
#    trace_NUTS = pm.backends.ndarray.load_trace("Simulation_results/Calibration/trace_2500_2500_nsample_1000_sampler_NUTS")
# Simulation - scalability 10K
#with full_bayes:
#    trace = pm.backends.ndarray.load_trace("Simulation_results/Calibration/trace_5000_5000_nsample_500_sampler_MH")
#    trace_NUTS = pm.backends.ndarray.load_trace("Simulation_results/Calibration/trace_5000_5000_nsample_150_sampler_NUTS")
# Simulation - scalability 20K
#with full_bayes:
#    trace = pm.backends.ndarray.load_trace("Simulation_results/Calibration/trace_10000_10000_nsample_80_sampler_MH")
#    trace_NUTS = pm.backends.ndarray.load_trace("Simulation_results/Calibration/trace_10000_10000_nsample_80_sampler_NUTS")
pm.stats.summary(trace)

求得:
在这里插入图片描述

在这里插入图片描述

4.校准结果

#### Loading the 
n_obs = 144
#n_vc = 22798
n_vc = 23000
n_steps = 150000
S = 50
l =3
#l = 
vine_type = "D"
learning_rate = "AdaGrad"
eta = 0.07
decay = 1.0
folder = str(n_obs) + "_S_" + str(S) + "_l_" + str(l) + "_vine_" + vine_type + "_learning_" + learning_rate + \
                                    "_eta_" + str(eta) + "_decay_" + str(decay)
var_lambda_array = np.load("Simulation_results/Calibration/OBB_"  + folder + "/" + "param_nobs_" + str(n_obs) + "_S_" + str(S) + "_l_" + str(l) +  "_vine_" + vine_type + "_step_" + str(n_steps) +".npy")
tau_array = np.load("Simulation_results/Calibration/OBB_"  + folder + "/" + "tau_nobs_" + str(n_obs) + "_S_" + str(S) + "_l_" + str(l) +  "_vine_" + vine_type + "_step_" + str(n_steps) +".npy")
time_array = np.load("Simulation_results/Calibration/OBB_"  + folder + "/" + "time_nobs_" + str(n_obs) + "_S_" + str(S) + "_l_" + str(l) +  "_vine_" + vine_type + "_step_" + str(n_steps) +".npy")
mean_theta = var_lambda_array[-1,:2] # First two elements are the mean
cov_theta = np.log(np.exp(var_lambda_array[-1,2:4]) + 1) # 3-4 are the transformed standard deviations
dim = 2
theta_variational = theta_prior = gaussian_mean_field_family(param = {"mu": mean_theta, "sigma": cov_theta}, dim = dim)

fig = plt.figure(figsize=(11, 3.5))
plt.rcParams.update({'font.size': 15})
gs = gridspec.GridSpec(1, 3)
n_levels = 20
bw = 0.030
bins = 50
alpha = 0.8
shade = False

ax = []
ax = ax + [plt.subplot(gs[0])]
ax = ax + [plt.subplot(gs[1])]
ax = ax + [plt.subplot(gs[2])]
plt.subplots_adjust(wspace = 0.15)

sns.distplot(trace_NUTS['theta'][25000:,0], bins = bins, ax = ax[0], label = 'NUTS', hist =False, color = "darkgreen", kde_kws={'linestyle':'--'})
sns.distplot(trace['theta'][25000:,0], bins = bins, ax = ax[0], label = 'MH', hist = False, color = "darkorange", kde_kws={'linestyle':'-.'})
sns.distplot(theta_variational.sample(25000)[:,0], bins = bins, ax = ax[0], label = 'VC', hist = False, color = "red", kde_kws={'linestyle':'-'})
ax[0].legend(frameon=False, bbox_to_anchor=(-0.05,1.05),loc = "upper left")
ax[0].title.set_text(r'$\theta_1$')

sns.distplot(trace_NUTS['theta'][25000:,1], bins = bins, ax = ax[1], hist =False, color = "darkgreen", kde_kws={'linestyle':'--'})
sns.distplot(trace['theta'][25000:,1], bins = bins, ax = ax[1],  hist = False, color = "darkorange", kde_kws={'linestyle':'-.'})
sns.distplot(theta_variational.sample(25000)[:,1], bins = bins, ax = ax[1], hist = False, color = "red", kde_kws={'linestyle':'-'})
ax[1].title.set_text(r'$\theta_2$')

sns.kdeplot(trace_NUTS['theta'][25000:,0], trace_NUTS['theta'][25000:,1], ax=ax[2], n_levels=n_levels, shade=shade, shade_lowest=shade, alpha = alpha, bw = bw, color = "darkgreen", label = 'NUTS', linestyles = '--')
sns.kdeplot(theta_variational.sample(25000)[:,0], theta_variational.sample(25000)[:,1], ax=ax[2], n_levels=n_levels,shade=True, shade_lowest=False, alpha = alpha, bw = bw, color = "red", label = 'VC')
sns.kdeplot(trace['theta'][25000:,0], trace['theta'][25000:,1], ax=ax[2], n_levels=n_levels, shade=shade, shade_lowest=shade, alpha = alpha, bw = bw, color = "darkorange", label = 'MH', linestyles = '-.')
ax[2].set_xlabel(r'$\theta_1$')
ax[2].set_ylabel(r'$\theta_2$')
ax[2].yaxis.tick_right()
ax[2].yaxis.set_label_position("right")
#ax[2].legend(frameon=False)

#AX lims
ax[2].set_xlim([0.28, 0.51])
ax[2].set_ylim([0.5, 0.73])

ax[0].set_xlim([0.28, 0.51])
ax[1].set_xlim([0.5, 0.73])

plt.gcf().subplots_adjust(bottom=0.2)
plt.savefig("calibration_quality" + '.pdf', dpi=600)
plt.show()

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风尘23187

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值