├── config ├── default.yml ├── model_config.yml └── test_params.yml ├── _config.yml ├── img ├── posterior.png ├── rbf_kernel.png ├── linear_kernel.png ├── periodic_kernel.png ├── prior_vs_posterior.png └── gaussian_process_samples.png ├── .gitignore ├── mod ├── __init__.py └── config │ ├── __init__.py │ └── config_loader.py ├── core ├── __init__.py ├── gaussian_process │ ├── __init__.py │ ├── kernels.py │ └── sampling.py └── gaussian_distribution │ ├── __init__.py │ └── prob_dist_func.py ├── src ├── settings.py └── gpr_modeling.py └── README.md /config/default.yml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /config/model_config.yml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /config/test_params.yml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-minimal 2 | markdown: kramdown 3 | -------------------------------------------------------------------------------- /img/posterior.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ulti-Dreisteine/gaussian-process-regression/HEAD/img/posterior.png -------------------------------------------------------------------------------- /img/rbf_kernel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ulti-Dreisteine/gaussian-process-regression/HEAD/img/rbf_kernel.png -------------------------------------------------------------------------------- /img/linear_kernel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ulti-Dreisteine/gaussian-process-regression/HEAD/img/linear_kernel.png -------------------------------------------------------------------------------- /img/periodic_kernel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ulti-Dreisteine/gaussian-process-regression/HEAD/img/periodic_kernel.png -------------------------------------------------------------------------------- /img/prior_vs_posterior.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ulti-Dreisteine/gaussian-process-regression/HEAD/img/prior_vs_posterior.png -------------------------------------------------------------------------------- /img/gaussian_process_samples.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ulti-Dreisteine/gaussian-process-regression/HEAD/img/gaussian_process_samples.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | tmp/ 3 | trash/ 4 | .DS_Store/ 5 | *.xml 6 | *.iml 7 | *.pyc 8 | 9 | .git/ 10 | .vscode/ 11 | __pycache__/ 12 | cache/ 13 | mod/logs/ 14 | pkg/ 15 | trash/ -------------------------------------------------------------------------------- /mod/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on 2021/09/01 09:49:06 4 | 5 | @File -> __init__.py 6 | 7 | @Author: luolei 8 | 9 | @Email: dreisteine262@163.com 10 | 11 | @Describe: 初始化 12 | """ 13 | 14 | __all__ = [] -------------------------------------------------------------------------------- /core/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on 2021/09/01 10:08:25 4 | 5 | @File -> __init__.py 6 | 7 | @Author: luolei 8 | 9 | @Email: dreisteine262@163.com 10 | 11 | @Describe: 初始化 12 | """ 13 | 14 | __all__ = [] -------------------------------------------------------------------------------- /mod/config/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on 2021/02/27 21:14:34 4 | 5 | @File -> __init__.py 6 | 7 | @Author: luolei 8 | 9 | @Email: dreisteine262@163.com 10 | 11 | @Describe: 初始化 12 | """ 13 | 14 | __all__ = [] -------------------------------------------------------------------------------- /core/gaussian_process/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on 2021/09/01 10:17:50 4 | 5 | @File -> __init__.py 6 | 7 | @Author: luolei 8 | 9 | @Email: dreisteine262@163.com 10 | 11 | @Describe: 初始化 12 | """ 13 | 14 | from .kernels import calKernelFunc 15 | 16 | __all__ = ['calKernelFunc'] -------------------------------------------------------------------------------- /core/gaussian_distribution/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on 2021/09/01 10:15:27 4 | 5 | @File -> __init__.py 6 | 7 | @Author: luolei 8 | 9 | @Email: dreisteine262@163.com 10 | 11 | @Describe: 初始化 12 | """ 13 | 14 | from .prob_dist_func import univar_gaussian, multivar_gaussian 15 | 16 | __all__ = ['univar_gaussian', 'multivar_gaussian'] -------------------------------------------------------------------------------- /src/settings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on 2020/1/21 下午3:01 4 | 5 | @Project -> File: pollution-forecast-offline-training-version-2 -> settings.py 6 | 7 | @Author: luolei 8 | 9 | @Email: dreisteine262@163.com 10 | 11 | @Describe: 默认设置 12 | """ 13 | 14 | import sys 15 | import os 16 | 17 | BASE_DIR = os.path.abspath(os.path.join(os.path.abspath(__file__), '../' * 2)) 18 | sys.path.append(BASE_DIR) 19 | 20 | from mod.config.config_loader import config_loader 21 | 22 | PROJ_DIR, PROJ_CMAP = config_loader.proj_dir, config_loader.proj_cmap 23 | plt = config_loader.proj_plt 24 | 25 | # 载入项目变量配置. 26 | ENC_CONFIG = config_loader.environ_config 27 | MODEL_CONFIG = config_loader.model_config 28 | TEST_PARAMS = config_loader.test_params 29 | 30 | # ---- 定义环境变量 --------------------------------------------------------------------------------- 31 | 32 | # ---- 定义模型参数 --------------------------------------------------------------------------------- 33 | 34 | # ---- 定义测试参数 --------------------------------------------------------------------------------- 35 | 36 | # ---- 定义通用函数 --------------------------------------------------------------------------------- 37 | -------------------------------------------------------------------------------- /core/gaussian_process/kernels.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on 2020/1/30 18:04 4 | 5 | @Project -> File: gaussian-process-regression -> kernels.py 6 | 7 | @Author: luolei 8 | 9 | @Email: dreisteine262@163.com 10 | 11 | @Describe: 高斯过程核函数 12 | """ 13 | 14 | import numpy as np 15 | 16 | 17 | def _rbf_kernel(x_a, x_b, sigma: float = 0.8, l: float = 0.5): 18 | """ 19 | RBF高斯核函数, 又名Exponetiated Quadratic, 公式为: 20 | k = sigma^2 * exp(-norm(x_a - x_b)^2 / (2 * l^2)) 21 | :param x_a: float, 样本值位置a 22 | :param x_b: float, 样本值位置b 23 | :param sigma: float, 方差参数 24 | :param l: float, 长度参数length 25 | """ 26 | n = np.linalg.norm(x_a - x_b) 27 | k = pow(sigma, 2) * np.exp(- pow(n, 2) / (2 * pow(l, 2))) 28 | return k 29 | 30 | 31 | def _periodic_kernel(x_a, x_b, sigma: float = 0.8, l: float = 0.5, p: float = 0.5): 32 | """ 33 | 周期性核函数, 公式为: 34 | k = sigma^2 * np.exp(-(2 / l^2) * sin(pi / p * |x_a - x_b|)^2) 35 | :param x_a: float, 样本值位置a 36 | :param x_b: float, 样本值位置b 37 | :param sigma: float, 方差参数 38 | :param l: float > 0.0, 长度参数length 39 | :param p: flaot > 0.0, 周期参数 40 | """ 41 | assert (l > 0.0) & (p > 0.0) 42 | sin = np.sin(np.pi / p * np.abs(x_a - x_b)) 43 | k = pow(sigma, 2) * np.exp(-2 / pow(l, 2) * pow(sin, 2)) 44 | return k 45 | 46 | 47 | def _linear_kernel(x_a, x_b, sigma: float = 0.8, sigma_b: float = 0.5, c: float = 0.5): 48 | """ 49 | 线性核函数, 公式为: 50 | k = sigma_b^2 + sigma^2 * (x_a - c)(x_b - c) 51 | :param x_a: float, 样本值位置a 52 | :param x_b: float, 样本值位置b 53 | :param sigma: float, 方差参数 54 | :param sigma_b: float, 方差参数b 55 | :param c: float, offset参数 56 | """ 57 | k = pow(sigma_b, 2) + pow(sigma, 2) * (x_a - c) * (x_b - c) 58 | return k 59 | 60 | 61 | def calKernelFunc(x_a, x_b, kernel_name, **kwargs): 62 | """核函数计算""" 63 | 64 | if kernel_name == 'RBF': 65 | k = _rbf_kernel(x_a, x_b, **kwargs) 66 | return k 67 | elif kernel_name == 'linear': 68 | k = _linear_kernel(x_a, x_b, **kwargs) 69 | return k 70 | elif kernel_name == 'periodic': 71 | k = _periodic_kernel(x_a, x_b, **kwargs) 72 | return k 73 | else: 74 | raise ValueError('Unknown kernel func name "{}".'.format(kernel_name)) 75 | -------------------------------------------------------------------------------- /core/gaussian_distribution/prob_dist_func.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on 2020/2/20 21:07 4 | 5 | @Project -> File: gaussian-process-regression -> prob_dist_func.py 6 | 7 | @Author: luolei 8 | 9 | @Email: dreisteine262@163.com 10 | 11 | @Describe: 概率密度函数 12 | """ 13 | 14 | import numpy as np 15 | 16 | 17 | def univar_gaussian(x, mu, sigma): 18 | """ 19 | 一维高斯分布概率密度函数 20 | :param x: float or array like, x值或向量 21 | :param mu: float, 均值 22 | :param sigma: float, 标准差 23 | """ 24 | expo = np.exp(-np.power(x - mu, 2) / (2 * np.power(sigma, 2))) 25 | f = 1 / (sigma * np.sqrt(2 * np.pi)) * expo 26 | return f 27 | 28 | 29 | def multivar_gaussian(x, mu, Sigma): 30 | """ 31 | 多维高斯分布概率密度函数 32 | :param x: array like, x向量 33 | :param mu: array like, 均值向量 34 | :param Sigma: np.array, 协方差矩阵 35 | :return: 36 | """ 37 | x = np.array(x).reshape(-1, 1) 38 | mu = np.array(mu).reshape(-1, 1) 39 | dim_x = x.shape[0] 40 | 41 | try: 42 | assert mu.shape[0] == dim_x 43 | assert Sigma.shape[0] == Sigma.shape[1] == dim_x 44 | except: 45 | raise ValueError('The shape of mu or Sigma does not correspond to the dimension of x') 46 | 47 | expo = np.exp(-0.5 * np.dot(np.dot((x - mu).T, np.linalg.inv(Sigma)), x - mu)) 48 | f = 1 / (np.power(2 * np.pi, dim_x / 2) * np.power(np.linalg.det(Sigma), 0.5)) * expo 49 | return f[0] 50 | 51 | 52 | if __name__ == '__main__': 53 | import sys 54 | import os 55 | 56 | BASE_DIR = os.path.abspath(os.path.join(os.path.abspath(__file__), '../' * 3)) 57 | sys.path.append(BASE_DIR) 58 | 59 | from src.settings import plt 60 | 61 | # ---- 一维高斯分布 ----------------------------------------------------------------------------- 62 | 63 | mu = 0.0 64 | sigma = 1.0 65 | x = np.arange(-10.0, 10.0 + 0.1, 0.1).reshape(-1, 1) 66 | y = univar_gaussian(x, mu, sigma) 67 | 68 | plt.figure('One Dimensional PDF') 69 | plt.plot(x, y) 70 | 71 | # ---- 二维高斯分布 ----------------------------------------------------------------------------- 72 | 73 | from mod.gaussian_process.sampling import cal_covariance_matrix 74 | 75 | mu = [3.0, 1.0] 76 | idx = [0.0, 1.0] 77 | kernel_name = 'RBF' 78 | kernel_params = {'sigma': 2.0, 'l': 1.0} 79 | Sigma = cal_covariance_matrix(idx, kernel_name = kernel_name, kernel_params = kernel_params) 80 | 81 | x = np.arange(-10.0, 10.0 + 0.2, 0.2).reshape(-1, 1) 82 | y = np.arange(-10.0, 10.0 + 0.2, 0.2).reshape(-1, 1) 83 | mesh_x, mesh_y = np.meshgrid(x, y) 84 | coords = np.dstack((mesh_x, mesh_y)) 85 | pdf = np.apply_along_axis(lambda x: multivar_gaussian(x, mu, Sigma), 2, coords) 86 | pdf = pdf.reshape(len(x), len(y)) 87 | 88 | plt.figure('Two Dimensional PDF') 89 | plt.contourf(mesh_x, mesh_y, pdf, cmap = 'Blues') 90 | -------------------------------------------------------------------------------- /src/gpr_modeling.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on 2021/09/01 10:33:40 4 | 5 | @File -> gpr_modeling.py 6 | 7 | @Author: luolei 8 | 9 | @Email: dreisteine262@163.com 10 | 11 | @Describe: 高斯过程回归建模 12 | """ 13 | 14 | import numpy as np 15 | import sys 16 | import os 17 | 18 | BASE_DIR = os.path.abspath(os.path.join(os.path.abspath(__file__), '../' * 2)) 19 | sys.path.append(BASE_DIR) 20 | 21 | from src.settings import PROJ_DIR, plt 22 | from core.gaussian_process.sampling import calCovMatrix, genGaussianProcessSamples 23 | 24 | if __name__ == '__main__': 25 | t_series = np.arange(0, 10, 0.1) 26 | 27 | fig, axs = plt.subplots(2, 1, figsize=(8, 6)) 28 | 29 | # ---- 先验分布 --------------------------------------------------------------------------------- 30 | 31 | mu = np.zeros([t_series.shape[0], 1]) 32 | C = calCovMatrix(t_series, kernel_name='RBF') 33 | 34 | samples_prior = genGaussianProcessSamples(t_series, mu, C, samples_n=500) 35 | 36 | # 画图. 37 | ax = axs[0] 38 | for i in range(samples_prior.shape[1]): 39 | ax.plot(t_series, samples_prior[:, i], c='grey', alpha=0.1) 40 | ax.plot(t_series, np.mean(samples_prior, axis=1), c='b') 41 | ax.set_ylabel('$y$') 42 | ax.set_title('Prior Distribution', fontsize = 15) 43 | 44 | # ---- 采集后验样本 ----------------------------------------------------------------------------- 45 | 46 | # 采集后验样本. 47 | t_obs = np.array([1.1, 1.0, 4.0, 6.0, 7.0, 7.5]) 48 | x_obs = np.array([1.0, 1.0, 0.5, 1.0, 2.0, 2.0]) 49 | N_obs = x_obs.shape[0] 50 | 51 | # 计算先验分布参数. 52 | t_total = np.hstack((t_obs, t_series)) 53 | mu_prioir = np.zeros_like(t_total) 54 | C_prior = calCovMatrix(t_total, kernel_name='RBF') 55 | 56 | # 更新后验分布参数, 1代表观测值, 2代表未知值. 57 | mu_1, mu_2 = mu_prioir[:N_obs].reshape(-1, 1), mu_prioir[N_obs:].reshape(-1, 1) 58 | C_11 = C_prior[:N_obs, :N_obs] 59 | C_12 = C_prior[:N_obs, N_obs:] 60 | C_21 = C_prior[N_obs:, :N_obs] 61 | C_22 = C_prior[N_obs:, N_obs:] 62 | mu_post = mu_2 + np.dot(np.dot(C_21, np.linalg.inv(C_11)), x_obs.reshape(-1, 1) - mu_1) 63 | sigma_post = C_22 - np.dot(np.dot(C_21, np.linalg.inv(C_11)), C_12) 64 | 65 | samples_post = genGaussianProcessSamples(t_series, mu_post, sigma_post, samples_n=500) 66 | 67 | # 画图. 68 | ax = axs[1] 69 | for i in range(samples_post.shape[1]): 70 | ax.plot(t_series, samples_post[:, i], c='grey', alpha=0.1, zorder = -i) 71 | for i in range(N_obs): 72 | ax.scatter(t_obs[i], x_obs[i], s = 60, c = 'k') 73 | ax.plot(t_series, np.mean(samples_post, axis=1), c='b', zorder=0) 74 | ax.set_xlabel('$t$') 75 | ax.set_ylabel('$y$') 76 | ax.set_title('Posterior Distribution', fontsize = 15) 77 | 78 | fig.tight_layout() 79 | fig.savefig(os.path.join(PROJ_DIR, 'img/prior_vs_posterior.png'), dpi = 450) 80 | -------------------------------------------------------------------------------- /core/gaussian_process/sampling.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on 2021/09/01 10:37:22 4 | 5 | @File -> sampling.py 6 | 7 | @Author: luolei 8 | 9 | @Email: dreisteine262@163.com 10 | 11 | @Describe: 12 | """ 13 | 14 | import numpy as np 15 | import sys 16 | import os 17 | 18 | BASE_DIR = os.path.abspath(os.path.join(os.path.abspath(__file__), '../' * 3)) 19 | sys.path.append(BASE_DIR) 20 | 21 | from core.gaussian_process.kernels import calKernelFunc 22 | 23 | __doc__ = """ 24 | 参考文献: 25 | https://www.jgoertler.com/visual-exploration-gaussian-processes/#GaussianProcesses 26 | https://blog.csdn.net/shenxiaolu1984/article/details/50386518 27 | """ 28 | 29 | def calCovMatrix(t_series: np.ndarray, kernel_name: str, **kernel_params): 30 | """计算协方差矩阵C""" 31 | # 生成采样点序列x. 32 | N = len(t_series) 33 | 34 | # 通过高斯核函数计算采样点之间的相关函数矩阵C. 35 | C = np.zeros([N, N]) 36 | for i in range(N): 37 | for j in range(i, N): 38 | t_i, t_j = t_series[i], t_series[j] 39 | C[i, j] = calKernelFunc(t_i, t_j, kernel_name, **kernel_params) 40 | C = C + np.tril(C.T, -1) # **高斯核函数具有对称性质, 所以此处为矩阵与转置矩阵下三角之和 41 | return C 42 | 43 | 44 | def _execGPRSampling(t_series, mu, C) -> np.ndarray: 45 | """ 46 | 根据给定的时间, 各时间步之间计算所得均值和协方差矩阵进行'单次'高斯过程采样 47 | 这部分过程和原理可以参考以下介绍高斯过程采样算法的材料: 48 | :param t_series: 时间值序列 49 | :param mu: 均值向量 50 | :param C: 协方差矩阵 51 | 52 | Example: 53 | ------ 54 | t_series = np.arange(0, 10, 0.1) 55 | x_series = gpr_sampling(t_series, mu, C) 56 | """ 57 | t_series = t_series.flatten() 58 | 59 | # 对C进行SVD分解. 60 | U, sigmas, _ = np.linalg.svd(C) 61 | S = np.diag(sigmas) # 向量转为对角矩阵 62 | 63 | # 生成N个独立同分布高斯随机变量. 64 | y_series = np.random.normal(loc = 0.0, scale = 1.0, size = (len(t_series),)) 65 | x_series = np.dot(np.dot(U, np.sqrt(S)), y_series.reshape(-1, 1)) 66 | 67 | # 加上均值, 得到样本向量. 68 | x_series += mu 69 | 70 | return x_series 71 | 72 | 73 | def genGaussianProcessSamples(t_series: np.ndarray, mu: np.ndarray, C: np.ndarray, samples_n): 74 | """ 75 | 生成高斯过程样本集 76 | :param t_series: 时刻series, shape = (Nt, 1) 77 | :param mu: np.array, 均值向量, shape = (Nt, 1) 78 | :param C: np.array, 协方差矩阵, shape = (Nt, N) 79 | :param sample_n: int, 采样数 80 | :return samples, shape = (Nt, Ns) 81 | 82 | Example: 83 | ------ 84 | t_series = np.array([0.0, 1.0, 3.0, 4.0, 7.0]) 85 | mu = np.zeros_like(t_series) 86 | C = np.random.random((t_series.shape[0], t_series.shape[0])) 87 | samples = genGaussianProcessSamples(t_series, mu, C, samples_n = 10) 88 | """ 89 | t_series = t_series.reshape(-1, 1) 90 | mu = mu.reshape(-1, 1) 91 | 92 | # 维数检查. 93 | dims = [t_series.shape[0], mu.shape[0], C.shape[0], C.shape[1]] 94 | assert len(set(dims)) == 1 95 | 96 | samples = None 97 | for i in range(samples_n): 98 | x = _execGPRSampling(t_series, mu, C) 99 | if i == 0: 100 | samples = x 101 | else: 102 | samples = np.hstack((samples, x)) 103 | return samples 104 | 105 | 106 | if __name__ == '__main__': 107 | ... 108 | 109 | 110 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | ![封面](img/prior_vs_posterior.png) 13 | 14 | # 高斯过程回归 15 | ## Gaussian Process Regression 16 | 17 | 18 | *** 19 | ## 一、高斯分布 20 | 21 | 高斯过程(Gaussian Process, GP)是随机过程之一,是一系列符合正态分布的随机变量在一指数集(index set)内的集合。该解释中的“指数”可以理解为“维度“,按照机器学习的角度,各个指数上的随机变量可以对应地理解为各个维度上的特征。 22 | 23 | ***1.1 一元高斯分布*** 24 | 25 | $$ 26 | X \sim N(\mu, \sigma^2) 27 | $$ 28 | 29 | 其概率密度函数为: 30 | 31 | $$ 32 | f(x) = \frac{1}{\sigma \sqrt{2 \pi}} \exp({-(x - \mu)^2} / ({2 \sigma^2})) 33 | $$ 34 | 35 | 标准正态分布: 36 | 37 | $$ 38 | \mu = 0, \sigma = 1 39 | $$ 40 | 41 | 正态分布具有如下性质: 42 | 43 | 1. 如果$X \sim N(\mu, \sigma^2)$,且$a$、$b$均为实数,则$aX + b \sim N(a \mu + b, (a \sigma)^2)$; 44 | 45 | 2. 如果$X \sim N(\mu_x, \sigma_x^2)$与$Y \sim N(\mu_y, \sigma_y^2)$独立,则: 46 | 47 | 1. $U = X + Y \sim N(\mu_x + \mu_y, \sigma_x^2 + \sigma_y^2)$; 48 | 2. $V = X - Y \sim N(\mu_x - \mu_y, \sigma_x^2 + \sigma_y^2)$; 49 | 50 | 3. 若以上$X$与$Y$相互独立,则: 51 | 52 | 1. $XY$符合以下概率密度分布: 53 | 54 | $$ 55 | p(z)=\frac{1}{\pi \sigma_x \sigma_y}K_0(\frac{|z|}{\sigma_x \sigma_y}) 56 | $$ 57 | 58 | 其中$K_0$为修正贝塞尔函数; 59 | 60 | 2. $X/Y$符合柯西分布: 61 | 62 | $$ 63 | X/Y \sim {\rm Cauchy}(0, \sigma_x / \sigma_y) 64 | $$ 65 | 66 | 4. 若$X_1, ..., X_n$各自独立,符合正态分布,则$X_1^2 + X_2^2 + ... + X_n^2$符合自由度为$n$的卡方分布; 67 | 68 | 69 | ***1.2 二元高斯分布*** 70 | 71 | $$ 72 | f(x,y) = A \exp (-(\frac{(x - x_0)^2}{2\sigma_x^2} + \frac{(y - y_0)^2}{2\sigma_y^2})) 73 | $$ 74 | 75 | ***1.3 多元高斯分布*** 76 | 77 | $$ 78 | p(x) = \frac{1}{(2\pi)^{n/2} |\Sigma|^{1/2}} \ \exp(-\frac{1}{2} (x - \mu)^T \Sigma^{-1} (x - \mu)) 79 | $$ 80 | 81 | 其中,$\mu$为各随机变量的均值组成的$n \times 1$向量,$\Sigma$表示随机变量间的$n \times n$协方差矩阵,正定。 82 | 83 | 84 | *** 85 | ## 二、多元高斯分布的条件概率密度 86 | 87 | 令随机向量$X = [x_1, x_2, ..., x_n]$服从多元高斯分布$X \sim N(\mu, \Sigma)$,令$X_1 = [x_1, ..., x_m]$为已经观测变量,$X_2 = [x_{m+1}, ..., x_n]$为未知变量,则: 88 | 89 | $$ 90 | \begin{aligned} 91 | X = \left( 92 | \begin{array}{c} 93 | X_1 \\ 94 | X_2 95 | \end{array} 96 | \right) 97 | \end{aligned} 98 | $$ 99 | 100 | 从而有: 101 | 102 | $$ 103 | \begin{aligned} 104 | \mu = \left( 105 | \begin{array}{c} 106 | \mu_1 \\ 107 | \mu_2 108 | \end{array} 109 | \right) 110 | \end{aligned} 111 | $$ 112 | 113 | $$ 114 | \begin{aligned} 115 | \Sigma = \left[ 116 | \begin{aligned}{} 117 | \Sigma_{11}, &\Sigma_{12} \\ 118 | \Sigma_{21}, &\Sigma_{22} 119 | \end{aligned} 120 | \right] 121 | \end{aligned} 122 | $$ 123 | 124 | 给定$X_1$求$X_2$的后验分布(这部分推导可以从相关文献中查到,此处略): 125 | 126 | $$ 127 | \mu_{2|1} = \mu_2 + \Sigma_{21} \Sigma_{11}^{-1}(X_1 - \mu_1) 128 | $$ 129 | 130 | $$ 131 | \Sigma_{2|1} = \Sigma_{22} - \Sigma_{21} \Sigma_{11}^{-1} \Sigma_{12} 132 | $$ 133 | 134 | 135 | *** 136 | ## 三、高斯过程回归 137 | 138 | 设随机变量$X = [x_1, x_2, x_3, ..., x_n]^T$,其服从正态分布: 139 | $$ 140 | X \sim N(\mu, \Sigma) 141 | $$ 142 | 其中$\mu = [\mu_0, \mu_1, ..., \mu_n]^T$为均值向量,$\Sigma$是这$n$个特征之间的协方差矩阵,将$\Sigma$展开有: 143 | 144 | $$ 145 | \Sigma = 146 | \left[ 147 | \begin{matrix} 148 | & cov_{1, 1}, & cov_{1, 2}, ..., & cov_{1, n} \\ 149 | & cov_{2, 1}, & cov_{2, 2}, ..., & cov_{2, n} \\ 150 | & ..., & ..., &... \\ 151 | & cov_{n, 1}, & cov_{n, 2}, ..., & cov_{n, n} \\ 152 | \end{matrix} 153 | \right] 154 | $$ 155 | 156 | 其中$cov_{i,j}$表示特征$i$和特征$j$之间的协方差(covariance)。 157 | 158 | 高斯过程样本与一般机器学习的样本区别在于,高斯过程中样本各特征之间存在相关关系,这种相关关系是通过协方差矩阵$\Sigma$来体现的。比如在一些时间序列模型里面,各个变量输出的时间序列在时间前后都会体现出一种相关性(比如平滑过渡等),这种模型输出就很适合使用高斯过程来模拟。 159 | 160 | 161 | ***3.1 协方差矩阵计算*** 162 | $\Sigma$可以通过高斯过程核进行求解,常见的高斯过程核有: 163 | 164 | *RBF kernel:* 165 | 166 | $$ 167 | k = \sigma^2 \exp(-\frac{||t_a - t_b||^2}{2l^2}) 168 | $$ 169 | 170 | ![RBF核](img/rbf_kernel.png) 171 | 172 | *periodic kernel:* 173 | 174 | $$ 175 | k = \sigma^2 \exp(-\frac{2}{l^2} \sin(\frac{\pi}{p})|t_a - t_b|) 176 | $$ 177 | 178 | ![periodicF核](img/periodic_kernel.png) 179 | 180 | *linear_kernel:* 181 | 182 | $$ 183 | k = \sigma_b^2 + \sigma^2 * (t_a - c)(t_b - c) 184 | $$ 185 | 186 | ![linear核](img/linear_kernel.png) 187 | 188 | 这样当知道两个随机变量指数$t_a$和$t_b$后,便可通过核函数计算两个变量间的协方差。如果对所有随机变量均进行上述计算便可获得协方差矩阵$\Sigma$。有了协方差矩阵$\Sigma$后便可对高斯过程进行采样(一般认为高斯过程先验分布均值$\mu$应无偏为0)。 189 | 190 | 191 | 192 | ***3.2 高斯过程采样*** 193 | 获得了各随机变量$x$的均值信息$\mu$和联合分布的协方差矩阵$\Sigma$后,便可对该高斯过程进行随机采样。采样步骤如下: 194 | 195 | 1. 首先对协方差矩阵$\Sigma$进行SVD分解,获得矩阵$\rm U$、$\rm S$和$\rm V$; 196 | 197 | 2. 生成$N$个独立同分布的高斯随机变量(均值为0,标准差为1),组成向量$y$; 198 | 199 | 3. 按照如下公式获得高斯过程样本: 200 | 201 | $$ 202 | x = \mu + {\rm U} \sqrt{\rm S}y 203 | $$ 204 | 205 | 采样结果如下图所示,图中每条灰色曲线便对应一条高斯过程样本($n=100$),蓝色曲线表示样本均值,因为我们设定先验分布各维度上均值$\mu_i=0$,所以蓝色曲线在0附近波动。 206 | 207 | ![高斯过程采样](img/gaussian_process_samples.png) 208 | 209 | 210 | ***3.3 后验分布和采样*** 211 | 3.2中获得的高斯过程样本为先验样本。但是当我们在某些指数$t$上获得了一批观测样本后,这批观测样本将有助于我们对其他指数集上的样本分布进行估计(后验)。我们将这批已观测指数集设为$X_1$,未观测到的指数集设为$X_2$。接下来便可使用第二节中的方法获得在$X_2$上样本分布后验概率参数$\mu_{2|1}$和$\Sigma_{2|1}$,最后重新对$X_2$上的随机变量进行采样。下图显示了后验分布样本: 212 | 213 | ![](img/posterior.png) 214 | -------------------------------------------------------------------------------- /mod/config/config_loader.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on 2021/02/27 21:13:39 4 | 5 | @File -> config_loader.py 6 | 7 | @Author: luolei 8 | 9 | @Email: dreisteine262@163.com 10 | 11 | @Describe: 项目配置工具 12 | """ 13 | 14 | import logging 15 | 16 | logging.basicConfig(level=logging.INFO) 17 | 18 | import matplotlib.pyplot as plt 19 | import logging.config 20 | import logging 21 | import yaml 22 | import sys 23 | import os 24 | 25 | sys.path.append(os.path.join(os.path.dirname(__file__), '../')) 26 | 27 | SMALL_SIZE = 6 28 | MEDIUM_SIZE = 8 29 | BIGGER_SIZE = 10 30 | 31 | plt.rc('font', size=BIGGER_SIZE, family='Times New Roman') 32 | plt.rc('axes', titlesize=BIGGER_SIZE) 33 | plt.rc('axes', labelsize=BIGGER_SIZE) 34 | plt.rc('xtick', labelsize=BIGGER_SIZE) 35 | plt.rc('ytick', labelsize=BIGGER_SIZE) 36 | plt.rc('legend', fontsize=BIGGER_SIZE) 37 | plt.rc('figure', titlesize=20) 38 | plt.rc('mathtext', fontset = 'cm') 39 | 40 | _color_map = { 41 | 'blue': '#1f77b4', # 蓝色 42 | 'orange': '#ff7f0e', # 黄橙色 43 | 'green': '#2ca02c', # 绿色 44 | 'red': '#d62728', # 红色 45 | 'purple': '#9467bd', # 紫色 46 | 'cyan': '#17becf', # 青色 47 | 'grey': '#7f7f7f', # 灰色 48 | 'black': 'k', # 黑色 49 | 'white': 'w', 50 | 51 | # 类似色搭配互补色, 同一色系list中颜色由亮到暗排列. 52 | 'similar-complement-cmap': { 53 | 'greens': ['#5ED1BA', '#34D1B2', '#00A383', '#1F7A68', '#006A55'], 54 | 'reds': ['#F97083', '#F93E58', '#F30021', '#B62E40s', '#9E0016'], 55 | 'yellows': ['#FFCB73', '#FFB840', '#FFA100', '#BF8A30', '#A66900'], 56 | 'oranges': ['#FFAA73', '#FF8B40', '#FF6400', '#BF6830', '#A64100'], 57 | } 58 | } 59 | 60 | 61 | def _load_yml(fp: str) -> dict: 62 | with open(fp, 'r', encoding='utf-8') as f: 63 | conf = yaml.load(f, Loader=yaml.Loader) # yaml.FullLoader 64 | 65 | if conf is None: 66 | conf = {} 67 | 68 | return conf 69 | 70 | 71 | class ConfigLoader(object): 72 | """项目配置装载器""" 73 | 74 | def __init__(self): 75 | self._get_proj_root_dir() 76 | self._config_path = os.path.join(self.proj_dir, 'config/') 77 | self._set_proj_cmap() 78 | self._load_model_config() 79 | self._load_environ_config() 80 | self._load_test_params() 81 | 82 | def _get_proj_root_dir(self): 83 | """获取项目根目录""" 84 | self._proj_dir = os.path.abspath( 85 | os.path.join(os.path.dirname(__file__), '../../')) 86 | 87 | @property 88 | def proj_dir(self): 89 | return self._proj_dir 90 | 91 | def _set_proj_cmap(self): 92 | """设置项目颜色方案""" 93 | self._proj_cmap = _color_map 94 | 95 | @property 96 | def proj_cmap(self): 97 | return self._proj_cmap 98 | 99 | def _load_model_config(self): 100 | """载入模型参数配置文件""" 101 | self._model_config_path = os.path.join( 102 | self._config_path, 'model_config.yml') 103 | self._model_config = _load_yml(self._model_config_path) 104 | 105 | @property 106 | def proj_plt(self): 107 | return plt 108 | 109 | @property 110 | def model_config(self): 111 | return self._model_config 112 | 113 | def _load_environ_config(self): 114 | """载入环境变量配置""" 115 | # 读取本地文件中的环境变量设置. 116 | # 如果本地config中有master.yml则优先使用, 否则使用default.yml, 否则为空字典. 117 | _environ_config_path_ = None 118 | for _file_name in ['master.yml', 'default.yml']: 119 | if _file_name in os.listdir(self._config_path): 120 | print('Use environmental variables in {}'.format(_file_name)) 121 | _environ_config_path_ = os.path.join( 122 | self._config_path, _file_name) 123 | break 124 | 125 | if _environ_config_path_ is None: 126 | self._local_environ_config = {} 127 | else: 128 | self._local_environ_config = _load_yml(_environ_config_path_) 129 | 130 | # 线上环境变量注入. 131 | # 如果存在可注入环境变量, 则采用注入值, 否则采用环境变量配置文件中的值. 132 | self._environ_config = self._local_environ_config 133 | for key in self._local_environ_config.keys(): 134 | if key in os.environ.keys(): 135 | self._environ_config.update({key: os.environ[key]}) 136 | 137 | @property 138 | def environ_config(self): 139 | return self._environ_config 140 | 141 | def _load_test_params(self): 142 | _test_params_path = os.path.join(self._config_path, 'test_params.yml') 143 | self._test_params = _load_yml(_test_params_path) 144 | 145 | @property 146 | def test_params(self): 147 | return self._test_params 148 | 149 | def set_logging(self): 150 | """日志配置""" 151 | # 检查本地是否有日志目录, 若没有则创建. 152 | if 'logs' not in os.listdir(self.proj_dir): 153 | os.mkdir(os.path.join(self.proj_dir, 'logs/')) 154 | 155 | # 配置日志. 156 | try: 157 | _log_config = self._model_config['logging'] 158 | except Exception as e: 159 | raise RuntimeError( 160 | 'Cannot load logging params in model_config.yml, {}'.format(e)) 161 | 162 | logging.config.dictConfig(_log_config) 163 | 164 | 165 | config_loader = ConfigLoader() 166 | --------------------------------------------------------------------------------