示例代码:
library('MCMChybridGP')
mu1 <- c(-1, -1)
mu2 <- c(+1, +1)
sigma.sq <- 0.1225
ub <- c(1.5, 3)
X0 <- generateX0(lb=c(-2,-2), ub=ub)
f <- function(x) {
px <- 1/4/pi/sqrt(sigma.sq) * exp(-1/2/sigma.sq *
sum((x - mu1)^2)) + 1/4/pi/sqrt(sigma.sq) *
exp(-1/2/sigma.sq * sum((x - mu2)^2))
return(log(px))
}
explore.out <- hybrid.explore(f, X0, ub=ub, n=150, graph=TRUE)
sample.out <- hybrid.sample(explore.out, n=500, graph=TRUE)
opar <- par(mfrow=c(2,1))
plot(density(sample.out$SAMP[,1]), xlab="x1", ylab="f(x)")
plot(density(sample.out$SAMP[,2]), xlab="x2", ylab="f(x)")
par(opar)
注:在运行之前,需要安装MCMChybridGP库,但是我在windows操作系统上装不了,在ubuntu上能装。
链接:https://pan.baidu.com/s/1wDBphwj_IOOb8GwWLHY-8A
提取码:00ri
接下来,对相关代码进行解释
1. 各种参数初始化
- 导入库MCMChybridGP
- 均值点(峰值点)1:(-1,-1) u 11 = − 1 , u 12 = − 1 u_{11}=-1,u_{12}=-1 u11=−1,u12=−1
- 均值点(峰值点)2:(+1,+1) u 21 = + 1 , u 22 = + 1 u_{21}=+1,u_{22}=+1 u21=+1,u22=+1
- 标准差:0.1225
- 点的x坐标上限:1.5,y坐标上限:3
library('MCMChybridGP')
mu1 <- c(-1, -1)
mu2 <- c(+1, +1)
sigma.sq <- 0.1225
ub <- c(1.5, 3)
2.产生多个样本x
在上下限ub,lb的范围内产生若干样本
X0 <- generateX0(lb=c(-2,-2), ub=ub)
其中,generateX0函数如下所示
generateX0 <- function (lb, ub, n0 = 10, npool = 100)
{
if(!is.null(dim(lb))) stop("lb in error")
if(!is.null(dim(ub))) stop("ub in error")
d <- length(lb)
if(length(ub) != d) stop("Dimension mismatch for lb, ub")
if(sum(abs(lb)+abs(ub)) == Inf) stop("Finite lb, ub required")
ranX <- function() {
X <- matrix(rep(NA, n0 * d), ncol = d)
for (i in 1:d) {
X[, i] <- sample(seq(lb[i], ub[i], length.out = n0))
}
return(X)
}
X <- Xbest <- as.matrix(ranX())
if (n0 < 2) {
return(Xbest)
}
dmax <- -Inf
DIST <- function(x, y) sum(((x - y)/(ub - lb))^2)
for (pool in 1:npool) {
dmin <- Inf
for (i in 1:(n0 - 1))
for (j in (i + 1):n0) if (DIST(X[i, ], X[j, ]) < dmin)
dmin <- DIST(X[i, ], X[j, ])
if (dmin > dmax) {
dmax <- dmin
Xbest <- X
}
if (pool < npool)
X <- as.matrix(ranX())
}
return(Xbest)
}
3. 定义密度函数(单项似然函数)
P
(
x
)
=
P
(
x
1
,
x
2
)
=
1
4
π
σ
exp
(
−
1
2
σ
(
x
1
−
μ
11
)
2
+
(
x
1
−
μ
12
)
2
)
+
1
4
π
σ
exp
(
−
1
2
σ
(
x
1
−
μ
21
)
2
+
(
x
1
−
μ
22
)
2
)
P(x)=P(x_1,x_2)=\frac{1}{4\pi\sigma}\exp(-\frac{1}{2\sigma}(x_1-\mu_{11})^2+(x_1-\mu_{12})^2)+\frac{1}{4\pi\sigma}\exp(-\frac{1}{2\sigma}(x_1-\mu_{21})^2+(x_1-\mu_{22})^2)
P(x)=P(x1,x2)=4πσ1exp(−2σ1(x1−μ11)2+(x1−μ12)2)+4πσ1exp(−2σ1(x1−μ21)2+(x1−μ22)2)
f
(
x
)
=
log
P
(
x
)
f(x)=\log P(x)
f(x)=logP(x)
f <- function(x) {
px <- 1/4/pi/sqrt(sigma.sq) * exp(-1/2/sigma.sq *
sum((x - mu1)^2)) + 1/4/pi/sqrt(sigma.sq) *
exp(-1/2/sigma.sq * sum((x - mu2)^2))
return(log(px))
}
4. explore 探索阶段
explore.out <- hybrid.explore(f, X0, ub=ub, n=150, graph=TRUE)
接下来分析hybrid.explore 函数
4.1 函数参数
- f :密度函数 f ( x ) = log P ( x ) f(x)=\log P(x) f(x)=logP(x)
- X0: X 0 = x 1 , . . . , x 10 X_0={x_1,...,x_{10}} X0=x1,...,x10 10个观测输入
- y0
- n
- L
- delta
- nchains
- T.mult
- lb
- ub
- maxleap
- finetune
- Tinclude
- nswaps
- graph
hybrid.explore <-
function (f, X0, ..., y0=NULL, n = 200, L = 1000, delta = 0.003, nchains = 5,
T.mult = 1.5, lb = NULL, ub = NULL, maxleap=0.95, finetune = FALSE,
Tinclude = nchains, nswaps = choose(nchains, 2), graph = FALSE)
4.2 参数接收
- x=X0
- f n ( x ) = f ( x ) fn(x)=f(x) fn(x)=f(x)
# 随机矩阵传递
X <- as.matrix(X0)
# 函数传递
fn <- function(par) f(par, ...)
4.3 初始化
# 声明yfinal 和 Xfinal
yfinal <- Xfinal <- NULL
# X 的行数(观测点数)
n0 <- dim(X)[1]
# x的列数(观测点维度)
d <- dim(X)[2]
# Taccept:6 6 6 6 6 6 6 6 6 6 由n0个Tinclude+1组成
Taccept <- rep(Tinclude+1, n0)
# 声明接受
acceptance <- NULL
# 检查维度
if (d < 2)
stop("Points with dimension of at least 2 assumed for X")
if (d < 2)
graph <- FALSE
# 检查样本错误
if (n0 > 1)
for (i in 2:n0)
for (j in 1:(i - 1))
if (sum(abs(X[i,] - X[j, ])) == 0)
stop(paste(sep = "", "Duplicate rows (", i, " & ",
j, ") in X not allowed"))
# 是否有界
BOUNDS <- FALSE
if ((!is.null(lb)) || (!is.null(ub))) BOUNDS <- TRUE
if(is.null(lb)) lb <- rep(-Inf, d)
# 下界传入
low <- lb
negInf <- function(X)
as.double(apply(X, 2, function(x) 101*min(x)-100*max(x)))
low[!(low>-Inf)] <- negInf(X)[!(low>-Inf)]
if(is.null(ub)) ub <- rep(Inf, d)
# 上界引入
upp <- ub
posInf <- function(X)
as.double(apply(X, 2, function(x) 101*max(x)-100*min(x)))
upp[!(upp<Inf)] <- posInf(X)[!(upp<Inf)]
# 界调整
if (BOUNDS) {
if (!is.null(lb))
if (length(lb) == 1)
lb <- rep(lb, d)
if (!is.null(ub))
if (length(ub) == 1)
ub <- rep(ub, d)
if ((length(lb) != d) || (length(lb) != d))
stop("lb, ub incorrect dimension")
if (is.na(sum(lb + ub)))
stop("NaN lb, ub")
}
- 没太看懂的
KEY.VARS <- NULL
# key.vars=1,2
key.vars <- 1:dim(X)[2]
for (i in 1:(length(key.vars) - 1))
for (j in (i + 1):length(key.vars)) {
pair <- c(key.vars[i], key.vars[j])
KEY.VARS <- rbind(KEY.VARS, pair)
}
- keyVars=1,2
if (graph) {
if(dim(X)[2] <= 2)
nrefresh.graph <- Inf
else
nrefresh.graph <- ceiling(10/nchains)#向上取整
graph.template <- .hybrid.template# 实例化函数
key.indx <- 1
keyVars <- KEY.VARS[key.indx, ]
}
其中:.hybrid.template为画图模板函数如下
.hybrid.template <-
function (X, key.vars, lb, ub)
{
if(is.null(lb)) lb <- rep(-Inf, length(x1))
if(is.null(ub)) ub <- rep(Inf, length(x1))
# 按列分离
# 第一列x1变量
x1 <- X[, key.vars[1]]
# 第二列x2变量
x2 <- X[, key.vars[2]]
# 获取边界
low1 <- min(x1)
upp1 <- max(x1)
low2 <- min(x2)
upp2 <- max(x2)
extra1 <- extra2 <- 0.25
if(sum(abs(lb)) < Inf) {
low1 <- lb[key.vars[1]]
low2 <- lb[key.vars[2]]
extra1 <- 0.05
}
if(sum(abs(ub)) < Inf) {
upp1 <- ub[key.vars[1]]
upp2 <- ub[key.vars[2]]
extra2 <- 0.05
}
l1 <- low1 - extra1 * (upp1 - low1)
l2 <- low2 - extra1 * (upp2 - low2)
u1 <- upp1 + extra2 * (upp1 - low1)
u2 <- upp2 + extra2 * (upp2 - low2)
# 获取合适的坐标范围
xlim <- c(l1, u1)
ylim <- c(l2, u2)
# 设定标签x1,x2,和范围,以及步长显示
plot(x1, x2, xlim=xlim, type="n", ylim=ylim,
xlab=paste(sep="", "x", key.vars[1]),
ylab=paste(sep="", "x", key.vars[2]))
# 标出边界
abline(v=lb[key.vars[1]], lty=2)
abline(v=ub[key.vars[1]], lty=2)
abline(h=lb[key.vars[2]], lty=2)
abline(h=ub[key.vars[2]], lty=2)
#设置图例
legend(xlim[2], ylim[1], c("Accepted points", "Rejected points"),
pch=c(20, 4), pt.cex=c(1.2, 1),
cex=0.7, col=c("black", "red"), xjust=1,
yjust=0)
}
- 回火
temp : 1.0000 1.5000 2.2500 3.3750 5.0625
# 温度取值T.mult=1.5
# 1.0000 1.5000 2.2500 3.3750 5.0625
Temp <- T.mult^(1:nchains - 1)
# 初始化交换记录
swaps.record <- NULL
# f的样本数
fcalls <- 0
if(!is.null(y0)) {
y <- y0
}
# 获取样本输出 y
# 以及统计样本输出数量 fcalls
else {
if (T.mult < 1)
stop("T.mult < 1 not allowed")
# n0为样本数
y <- rep(NA, n0)
date1 <- date2 <- date()
for (j in 1:n0) {
functionOK <- FALSE
try({
Xj <- X[j,]
OUTSIDE_BOUNDS <- FALSE
if (BOUNDS) {
for (i in 1:d) {
if (Xj[i] < low[i]) {
OUTSIDE_BOUNDS <- TRUE
Xj[i] <- low[i]
}
if (Xj[i] > upp[i]) {
OUTSIDE_BOUNDS <- TRUE
Xj[i] <- upp[i]
}
}
}
if(OUTSIDE_BOUNDS) stop("X0 violates bounds supplied")
date1 <- date()
y[j] <- fn(X[j,])
date2 <- date()
functionOK <- TRUE
})
if(!functionOK) stop("f(x) failed")
if (is.na(y[j])) stop("f(x) NaN")
if (y[j] == Inf) stop("Infinite f(x) not allowed")
}
fcalls <- n0
}
# 给每条链选择初始x值
select <- sample(1:n0, nchains)
x <- X[select, ]
if (is.null(dim(x)))
x <- t(x)
# 给每条链初始x值对应的y值
fx <- y[select]
if (graph) {
#初始化图
graph.template(X, key.vars = keyVars, lb, ub)
#画初始点
points(X[, keyVars[1]], X[, keyVars[2]], pch = 20, col = "grey")
# Xfinal=NULL
points(Xfinal[, keyVars[1]], Xfinal[, keyVars[2]], pch = 20, col = "black")
#设置标题
title(c("", "", "", "Exploratory phase"), adj = 0, cex.main = 0.8)
# nchains条链,每条连按照"green"->"turquoise"->"orange",
# ->"yellow"->"red"-> "grey"->"pink"
clrs <- c("blue", rep(c("green", "turquoise", "orange",
"yellow", "red", "grey", "pink"), nchains))
reds <- c("blue", rep(c("green", "turquoise", "orange",
"yellow", "red", "grey", "pink"), nchains))
}
# 初始化计数器
count10 <- 0
nacc <- 0
# 初始化恢复计数器
refresh_count <- 1
# 参数数量为x维度+1
params <- rep(1, d+1)
#初始化平均接受率
mean.acceptance <- 0
4.4 重复采样
repeat { 内容如下 }
4.4.1 gp过程拟合
# 高斯过程拟合
GPfit <- GProcess(X, y, params = params, request.functions = FALSE,
finetune = finetune)
具体内容如下:
- X :样本输入
- y :样本输出
- param:params <- rep(1, d+1)(表示3个待优化的参数)
- request.functions:例子中是False
- finetune :例子中是False
GProcess <-
function (X, y, params = NULL, request.functions = TRUE, finetune=FALSE)
{
# X转为样本输入矩阵
X <- as.matrix(X)
# X行数即数据量为n,维度为d
n <- dim(X)[1]
d <- dim(X)[2]
if(d < 2) stop("Points with dimension of at least 2 assumed for X")
# y中心化(分布在0的2侧)
# 求出y的均值mY
mY <- mean(y)
# y×=y-mY
ystar <- y - mY
if (is.null(params)) {
params <- rep(1, 1 + d)
finetune <- TRUE
}
#例子中走else
else factr <- 1e10
if(finetune)
factr <- 1e15
Lreject <- -1e13
Lok <- TRUE
# 初始化协方差矩阵Sigma
Sigma <- matrix(rep(0, n*n), ncol=n)
# 待优化函数L=likehood(params)
L <- function(params) {
# 第一个参数
lsq <- params[1]
# 除第一个外,所有其他参数
eta <- params[-1]
# 求方差元素函数
c.scalar <- function(xi, xj) {
h <- abs(xi - xj)
return(lsq * prod((1 + eta * h) * exp(-eta * h)))
}
# 求 x与X 协方差函数
c.vec <- function(x) {
vec <- rep(NA, n)
for (j in 1:n) vec[j] <- c.scalar(x, X[j, ])
return(vec)
}
# 协方差矩阵??
Sigma <- .C("GPcovar", as.double(X), as.integer(n), as.integer(d),
as.double(params), Sigma = as.double(Sigma))$Sigma
# 修正协方差矩阵的格式
dim(Sigma) <- c(n, n)
# 判断 Sigma 是否能够chol分解为 R
cholOK <- FALSE
try({
# R表示分解后的Sigma
R <- chol(Sigma)
cholOK <- TRUE
}, silent=TRUE)
if (!cholOK) {
val <- Lreject * runif(1, 1, 10)
Lok <- FALSE
return(val)
}
# log|Sigma|见公式6右边的第一项https://blog.csdn.net/ygf666/article/details/125393906
ldet.Sigma <- 2 * sum(log(diag(R)))
# 求逆
Sigma.inv <- chol2inv(R)
# 求似然函数
val <- -1/2 * ldet.Sigma - 1/2 * t(ystar) %*% Sigma.inv %*%
ystar
if (is.na(val)) {
val <- Lreject * runif(1, 1, 10)
Lok <- FALSE
message(paste("L(lsq, eta) NaN set to", val))
return(val)
}
val <- as.double(val)
return(val)
}
try({
# 优化参数
solveL <- optim(params, L, control = list( fnscale = -1, factr=factr ),
method = "L-BFGS-B", lower = 1e-06)
if (Lok)
#返回优化之后的参数
params <- solveL$par
})
#优化之后的参数
lsq <- params[1]
eta <- params[-1]
Sigma <- .C("GPcovar", as.double(X), as.integer(n), as.integer(d),
as.double(params), Sigma = as.double(Sigma))$Sigma
dim(Sigma) <- c(n, n)
# 定义能否求逆
inverseOK <- FALSE
try({
Sigma.inv <- ginv(Sigma)
inverseOK <- TRUE
})
if (!request.functions)
# 探索过程到此返回,不再往下计算gp的预测值
return(list(Sigma = Sigma, Sigma.inv = Sigma.inv, inverseOK = inverseOK,
X = X, y = y, params = params))
c.scalar <- function(xi, xj) {
h <- abs(xi - xj)
val <- lsq * prod((1 + eta * h) * exp(-eta * h))
return(val)
}
c.vec <- function(x) {
vec <- rep(NA, dim(X)[1])
for (j in 1:dim(X)[1]) vec[j] <- c.scalar(x, X[j, ])
return(vec)
}
#定义GP对y的预测均值
if (!inverseOK)
Ef <- function(x) NA
else Ef <- function(x) {
# GP对y×的预测均值
Ey_x <- as.double(t(c.vec(x)) %*% Sigma.inv %*% ystar)
# GP对y的预测均值
return(mY + Ey_x)
}
if (!inverseOK)
sigmaf <- function(x) NA
else sigmaf <- function(x) {
c.vec_x <- c.vec(x)
val <- lsq - as.double(t(c.vec_x) %*% Sigma.inv %*% c.vec_x)
if (is.na(val))
return(Inf)
if (val < 0) {
if (val > -0.001)
val <- -val
else {
rprt <- paste("sigmaf(")
for (i in 1:length(x)) rprt <- paste(rprt, x[i])
rprt <- paste(rprt, ") =", val)
stop(rprt)
}
}
return(sqrt(val))
}
return(list(Sigma = Sigma, Sigma.inv = Sigma.inv, inverseOK = inverseOK,
X = X, y = y, params = params, Ef = Ef, sigmaf = sigmaf))
# Sigma: 协方差矩阵
# params: 优化后的参数
# Ef: 预测输出均值
# sigmaf: 预测输出协方差矩阵
}
4.4.2 返回拟合结果
if(!GPfit$inverseOK)
stop("GProcess inverse covariance matrix failed")
# 协方差的逆
Sigma.inv <- GPfit$Sigma.inv
# 传回已优化的参数
params <- GPfit$params
lsq <- params[1]
eta <- params[-1]
4.4.3 定义相关函数
sigmaf : 求 σ \sigma σ
c.scalar <- function(xi, xj) {
h <- abs(xi - xj)
val <- lsq * prod((1 + eta * h) * exp(-eta * h))
return(val)
}
c.vec <- function(x) {
vec <- rep(NA, dim(X)[1])
for (j in 1:dim(X)[1]) vec[j] <- c.scalar(x, X[j,])
return(vec)
}
sigmaf <- function(x) {
c.vec_x <- c.vec(x)
val <- lsq - as.double(t(c.vec_x) %*% Sigma.inv %*% c.vec_x)
if (is.na(val))
return(Inf)
if (val < 0) {
if (val > -0.001)
val <- -val
else {
xrep <- (x)
rprt <- paste("sigmaf(")
for (i in 1:length(xrep))
rprt <- paste(rprt,xrep[i])
rprt <- paste(rprt, ") =", val)
stop(rprt)
}
}
return(sqrt(val))
}
4.4.4 链信息交换
nswaps : C n c h a i n s 2 C_{nchains}^2 Cnchains2
# 链信息交换
if (nchains >= 2) {
# 迭代次数:C_chains^2, 平均每2个链需要进行一次按照条件交换
for (reps in 1:nswaps)
# 分解每个链
for (index1 in sample(1:nchains))
for (index2 in sample((1:nchains)[-index1])) #任意选择2个链,判断是否交换
{
if (T.mult == 1)
Tindex <- 1:nchains
else
Tindex <- sort(Temp, index.return = TRUE)$ix
swap <- Tindex[c(index1, index2)]
T1 <- Temp[swap[1]]# 链1的温度
T2 <- Temp[swap[2]]# 链2的温度
sdf1 <- sigmaf(x[swap[1]])# 链1的标准差
sdf2 <- sigmaf(x[swap[2]])# 链1的标准差
corf1 <- sdf1/sqrt(lsq)
corf2 <- sdf2/sqrt(lsq)
fswap1 <- fx[swap[1]] + sdf1
fswap2 <- fx[swap[2]] + sdf2
alpha <- (fswap2/T1 - fswap1/T1 + fswap1/T2 - fswap2/T2)
if(is.na(alpha)) alpha <- -Inf
if (log(runif(1)) < alpha) {
Temp[swap[1]] <- T2
Temp[swap[2]] <- T1
swaps.record <- c(swaps.record, 1)
}
else {
swaps.record <- c(swaps.record, 0)
}
}
}
4.4.5 对每个链采样
Xnext <- X
ynext <- y
if (T.mult == 1)
Rank <- 1:nchains
else
Rank <- rank(Temp)
# 对每个链进行采样
for (chain in 1:nchains) {
path <- Rank[chain]
# 链对应的当前输入
x.C <- as.double(x[chain, ])
# 声明链对应的建议输入
p.C <- NULL
# 标准差
sdf_x.C <- sigmaf(x.C)
# 相关性
corf_x.C <- sdf_x.C/sqrt(lsq)
# 实际当前输出
fx.C <- fx[chain]
xp_Early <- NULL
count <- 0
repeat {
# 建议
p.C <- rnorm(d)
# 组合:原始+建议+0
xp_Early <- matrix(c(x.C, p.C, rep(0, d)), ncol = 3)
xOK <- FALSE
try({
out <- .C("Leap", as.double(X), as.integer(dim(X)[1]),
as.integer(d), as.double(y), as.double(x.C),
as.double(p.C), as.integer(L), as.double(delta),
as.double(GPfit$Sigma.inv), as.double(params),
as.double(Temp[chain]), as.double(sqrt(lsq)*maxleap),
as.double(low), as.double(upp),
as.double(rep(0,n)), as.double(rep(0,n)),
as.double(rep(0,d)), as.double(rep(0,d)),
xp_Early = as.double(xp_Early) )
xp_Early <- out$xp_Early
dim(xp_Early) <- c(d,3)
xOK <- TRUE
})
if (is.na(sum(xp_Early)))
xOK <- FALSE
if (xOK)
break
message("hybrid.explore: Proposed x failed")
count <- count + 1
if (count == 10) {
for (remv in 1:nchains) {
X <- X[-length(y), ]
y <- y[-length(y)]
}
GPfit <- GProcess(X, y, params = params,
request.functions = TRUE)
if(!GPfit$inverseOK)
stop("GProcess inverse covariance matrix failed")
Sigma.inv <- GPfit$Sigma.inv
params <- GPfit$params
lsq <- params[1]
eta <- params[-1]
sigmaf <- GPfit$sigmaf
Xnext <- X
ynext <- y
count <- 0
}
}#endrepeat
out <- list(x = xp_Early[, 1], p = xp_Early[, 2], Early = xp_Early[1, 3])
x.P <- out$x
OUTSIDE_BOUNDS <- FALSE
if (BOUNDS) {
for (i in 1:d) {
if (x.P[i] < lb[i]) {
OUTSIDE_BOUNDS <- TRUE
}
if (x.P[i] > ub[i]) {
OUTSIDE_BOUNDS <- TRUE
}
}
}
p.P <- out$p
sdf_x.P <- sigmaf(x.P)
corf_x.P <- sdf_x.P/sqrt(lsq)
if(as.integer(count10/10) == count10/10)
MAX10 <- 0
if(corf_x.P > MAX10)
MAX10 <- corf_x.P
if (out$Early < 0) {
message(paste(sep="","Early stop with sd(f(x))/lambda = ",
round(corf_x.P,5), " where maxleap = ", maxleap))
}
else {
if (corf_x.P > maxleap)
stop(paste("Caution: Leapfrog gave sigmaf =",
out$Early/sqrt(lsq), "when sigmaf(x)/lambda =", corf_x.P))
}
if (graph) {
clr <- clrs[path]
clr_red <- reds[path]
if(!OUTSIDE_BOUNDS)
lines(c(x.C[keyVars[1]], x.P[keyVars[1]]),
c(x.C[keyVars[2]], x.P[keyVars[2]]), lwd = 0.2,
lty = 2, col = clr)
}
if(OUTSIDE_BOUNDS) {
message(paste(sep="","T = ", Temp[chain],": Ignore point out of bounds"))
fx.P <- alpha <- -Inf
}
else {
date1 <- date()
fx.P <- fn(x.P)
date2 <- date()
if (is.na(fx.P))
stop("f(x) NaN")
if (fx.P == Inf)
stop("Infinite f(x) not allowed")
fcalls <- fcalls + 1
H_xp.C <- -fx.C - sdf_x.C + W(p.C)
H_xp.P <- -fx.P - sdf_x.P + W(p.P)
# 接受率
alpha <- min(((-H_xp.P + H_xp.C)/Temp[chain]), 0)
}
if (log(runif(1)) < alpha) {
x[chain, ] <- x.P
fx[chain] <- fx.P
Xnext <- rbind(Xnext, x.P)
ynext <- c(ynext, fx.P)
if(path <= Tinclude) {
Xfinal <- rbind(Xfinal, x.P)
yfinal <- c(yfinal, fx.P)
Taccept <- c(Taccept, path)
acceptance <- c(acceptance, 1)
if(dim(Xfinal)[1] %% floor(n/10) == 0)
message(paste(sep="","hybrid.explore: ",
round(100*dim(Xfinal)[1]/n),"% Complete with ",
round(100*mean(acceptance),1),"% acceptance of proposals"))
}
if (graph)
points(x.P[keyVars[1]], x.P[keyVars[2]],
pch = 20, col = clr)
}
#用X表示被拒绝的样本
else {
if(path == 1) if(!OUTSIDE_BOUNDS) {
Xnext <- rbind(Xnext, x.P)
ynext <- c(ynext, fx.P)
Taccept <- c(Taccept, Tinclude+1)
}
if(path <= Tinclude)
acceptance <- c(acceptance, 0)
if (graph) if(!OUTSIDE_BOUNDS)
points(x.P[keyVars[1]], x.P[keyVars[2]],
pch = "X", col = clr_red)
}
# 当样本数量足够n时,计算接受率
if(dim(Xnext)[1] > n) {
i <- 0
repeat {
i <- i+1
if(Taccept[i] > Tinclude) {
Xnext <- Xnext[-i,]
ynext <- ynext[-i]
i <- i-1
}
if(length(ynext) <= n)
break
}
}
if (is.null(acceptance))
mean.acceptance <- 0
else
mean.acceptance <- mean(acceptance[ceiling(length(acceptance)/2):length(acceptance)])
if(!is.null(Xfinal)) if(dim(Xfinal)[1] >= n)
break
count10 <- count10+1
}
4.4.6 处理样本
# 返回所有样本
X <- Xnext
y <- ynext
if (is.null(acceptance))
mean.acceptance <- NA
else
mean.acceptance <- mean(acceptance)
if (graph) {
if (refresh_count < nrefresh.graph)
refresh_count <- refresh_count + 1
else {
refresh_count <- 1
key.indx <- key.indx + 1
if (key.indx > dim(KEY.VARS)[1])
key.indx <- 1
keyVars <- KEY.VARS[key.indx, ]
graph.template(X, key.vars = keyVars, lb, ub)
title(c("", "", "", "Exploratory phase"), adj = 0,
cex.main = 0.8)
points(X[, keyVars[1]], X[, keyVars[2]], pch = 20, col="grey")
points(Xfinal[, keyVars[1]], Xfinal[, keyVars[2]], pch = 20)
}
}
# 当样本数量达到n时,停止重复采样
if(!is.null(Xfinal)) if (dim(Xfinal)[1] >= n) break
4.5 获取探索阶段成果
- 样本x,y
- 训练出的 gp
- 训练细节:
- 链数:nchains
- 温度数:T.mute
- 交换次数 :nswaps
- L:似然函数
- 密度函数:f
- fcall:函数数
X <- Xfinal
y <- yfinal
GPfit <- GProcess(X, y, params, request.functions = TRUE, finetune=TRUE)
if(!GPfit$inverseOK)
message("hybrid.explore: GProcess inverse covariance matrix failed")
details <- list(nchains = nchains, T.mult = T.mult, nswaps = nswaps, L = L, delta = delta,
lb = lb, ub = ub, KEY.VARS = KEY.VARS)
return(list(X = X, y = y, f = fn, maxleap=maxleap, function.calls = fcalls, details = details, GPfit = GPfit))
5. sample 采样阶段
sample.out <- hybrid.sample(explore.out, n=500, graph=TRUE)
接下来分析hybrid.explore 函数
5.1 函数参数
- Explore:探索阶段的成果
- n:采样数
hybrid.sample <-
function (Explore, n = 1000, replace.target = c(0, 1, 2),
lb=NULL, ub=NULL, L = NULL, delta = NULL, nchains = NULL,
T.mult = NULL, maxleap=NULL, r = 5, nswaps = NULL, graph = FALSE)
{
5.2 准备阶段(初始化)
5.2.1 参数接收与校准
negInf <- function(X)
as.double(apply(X, 2, function(x) 101*min(x)-100*max(x)))
posInf <- function(X)
as.double(apply(X, 2, function(x) 101*max(x)-100*min(x)))
#获取探索阶段的样本
X <- Explore$X
y <- Explore$y
f <- Explore$f
d <- dim(X)[2]
if (d < 2)
graph <- FALSE
nexplore <- dim(X)[1]
if (is.null(L)) L <- Explore$details$L
if (is.null(L)) L <- 1000
if (is.null(delta)) Explore$details$delta
if (is.null(delta)) delta <- 0.003
if (is.null(nchains)) Explore$details$nchains
if (is.null(nchains)) nchains <- 5
if (is.null(nswaps)) nswaps <- Explore$details$nswaps
if (is.null(nswaps)) nswaps <- choose(nchains, 2)
if (is.null(T.mult)) T.mult <- Explore$details$nchains
if (is.null(T.mult)) T.mult <- 1.5
if (T.mult == 1)
if (replace.target[1] == 1)
replace.target <- 0
Temp <- T.mult^(1:nchains - 1)
if(is.null(lb)) lb <- Explore$details$lb
if(is.null(ub)) ub <- Explore$details$ub
BOUNDS <- FALSE
if ((!is.null(lb)) || (!is.null(ub)))
BOUNDS <- TRUE
if(is.null(lb))
lb <- rep(-Inf, d)
low <- lb
low[!(low>-Inf)] <- negInf(X)[!(low>-Inf)]
if(is.null(ub))
ub <- rep(Inf, d)
upp <- ub
upp[!(upp<Inf)] <- posInf(X)[!(upp<Inf)]
if(is.null(lb))
lb <- rep(-Inf,d)
if(is.null(ub))
ub <- rep(Inf,d)
if (BOUNDS) {
if (!is.null(lb))
if (length(lb) == 1)
lb <- rep(lb, d)
if (!is.null(ub))
if (length(ub) == 1)
ub <- rep(ub, d)
if ((length(lb) != d) || (length(lb) != d))
stop("lb, ub incorrect dimension")
if (is.na(sum(abs(lb)+abs(ub))))
stop("NaN for lb, ub")
}
W <- function(p) return(sum(p^2)/2)
if (!replace.target[1] %in% 0:2)
stop(paste("hybrid.sample: Choose replace.target from:\n",
"1: Use true target distribution in primary chain only\n",
"0: Use true target distribution in all chains\n",
"2: Replace target by Gaussian process target approximation\n"))
# 样本索引
select <- 1:nexplore
# 去除违规样本
for(i in nexplore:1)
for(j in 1:d) {
if ((X[i,j] < lb[j]) || (X[i,j] > ub[j]) )
select <- select[-i]
}
# 过滤后的样本数
nselect <- length(select)
if(nselect < nchains)
stop("Not enough points supplied within bounds")
y_select <- y[select]
X_select <- X[select,]
indx_best <- sort(y_select, decreasing=TRUE, index.return=TRUE)$ix[1:nchains]
x <- X_select[indx_best, ]
fx <- y_select[indx_best]
if(is.null(dim(x)))
x <- t(x)
fcalls <- 0
x1 <- x[1, ]
fx1 <- fx[1]
###本质上这一块没用
digits <- rep(NA, d)
for (j in 1:d) {
rangeX <- IQR(X[, j])
if (rangeX == 0)
digits[j] <- 4
else
digits[j] <- max(1, round(3 - log10(rangeX)))
}
rnd <- function(x) return(round(10^digits * x)/10^digits)
###本质上这一块没用
KEY.VARS <- NULL
key.vars <- 1:d
for (i in 1:(length(key.vars) - 1))
for (j in (i + 1):length(key.vars)) {
pair <- c(key.vars[i], key.vars[j])
KEY.VARS <- rbind(KEY.VARS, pair)
}
if (graph) {
if(dim(X)[2] <= 2)
nrefresh.graph <- Inf
else
nrefresh.graph <- ceiling(10/nchains)
graph.template <- .hybrid.template
count <- key.indx <- 1
if (is.null(graph.template))
graph.template <- Explore$details$graph.template
keyvars <- KEY.VARS[key.indx, ]
graph.template(X, key.vars = keyvars, lb, ub)
title(c("", "", "", "Sampling phase"), adj = 0, cex.main = 0.8)
}
clrs <- c("blue", rep(c("green", "turquoise", "orange", "yellow",
"red", "grey", "pink"), nchains))
reds <- c("blue", rep(c("green", "turquoise", "orange", "yellow",
"red", "grey", "pink"), nchains))
# 温度设置
if (T.mult == 1)
Rank <- 1:nchains
else Rank <- rank(Temp)
if (graph) {
keyvars <- KEY.VARS[key.indx, ]
points(X[, keyvars[1]], X[, keyvars[2]], col = "grey",
pch = 20)
}
if (T.mult == 1)
Rank <-1:nchains
else
Rank <- rank(Temp)
for (chain in 1:nchains) {
path <- Rank[chain]
if (graph)
points(x[chain, keyvars[1]], x[chain, keyvars[2]],
pch = 19, col = clrs[path])
}
5.2.2.高斯过程初始化
- 检查并校准
if(is.null(Explore$GPfit))
Explore$GPfit <- GProcess(X, y, params = NULL, request.functions = FALSE)
GPfit <- Explore$GPfit
if (!GPfit$inverseOK)
stop("hybrid.sample: Gaussian Process inverse covariance matrix failed")
params <- GPfit$params
Sigma.inv <- GPfit$Sigma.inv
ystar <- y - mean(y)
lsq <- params[1]
eta <- params[-1]
- 准备
c.scalar <- function(xi, xj) {
h <- abs(xi - xj)
val <- lsq * prod((1 + eta * h) * exp(-eta * h))
return(val)
}
c.vec <- function(x) {
vec <- rep(NA, nexplore)
for (j in 1:nexplore) vec[j] <- c.scalar(x, X[j, ])
return(vec)
}
Ef <- function(x) {
Ey_x <- as.double(t(c.vec(x)) %*% Sigma.inv %*% ystar)
return(Ey_x)
}
sigmaf <- function(x) {
c.vec_x <- c.vec(x)
val <- lsq - as.double(t(c.vec_x) %*% Sigma.inv %*% c.vec_x)
if (is.na(val)) {
warning("hybrid.sample: NaN sigmaf(", rnd(x), ")\n")
return(Inf)
}
if (val < 0) {
if (abs(val) < 0.001)
val <- abs(val)
else {
rprt <- paste("sigmaf(")
for (i in 1:length(x)) rprt <- paste(rprt, x[i])
rprt <- paste(rprt, ") =", val)
stop(rprt)
}
}
return(sqrt(val))
}
#声明
Ey <- cory <- NULL
for(i in 1:nexplore) {
Ey <- c(Ey, Ef(X[i,]))
cory <- c(cory, sigmaf(X[i,])/sqrt(lsq))
}
if (is.null(maxleap))
maxleap <- max(cory)
SAMP <- ySAMP <- NULL
its <- 1
acceptance <- NULL
swaps.record <- swaps.record1 <- NULL
5.3重复采样
repeat { 内容如下 }
5.3.1 链信息交换
case1:
if (nchains >= 3)
for (reps in 1:nswaps)
for (index1 in sample(2:(nchains - 1))) {
index2 <- index1 + 1
if (T.mult == 1)
Tindex <- 1:nchains
else
Tindex <- sort(Temp, index.return = TRUE)$ix
swap <- Tindex[c(index1, index2)]
T1 <- Temp[swap[1]]
T2 <- Temp[swap[2]]
if (replace.target[1] == 0) {
Efswap1 <- fx[swap[1]]
Efswap2 <- fx[swap[2]]
}
else {
corf1 <- sigmaf(x[swap[1], ])/sqrt(lsq)
corf2 <- sigmaf(x[swap[1], ])/sqrt(lsq)
Efswap1 <- Ef(x[swap[1], ]) - r * (corf1 - maxleap)^2/(1 - corf1)^2
Efswap2 <- Ef(x[swap[2], ]) - r * (corf2 - maxleap)^2/(1 - corf2)^2
}
alpha <- (Efswap2/T1 - Efswap1/T1 + Efswap1/T2 - Efswap2/T2)
if(is.na(alpha))
alpha <- -Inf
if (log(runif(1)) < alpha) {
Temp[swap[1]] <- T2
Temp[swap[2]] <- T1
swaps.record <- c(swaps.record, 1)
}
else {
swaps.record <- c(swaps.record, 0)
}
}
case2:
if (nchains >= 2) {
if (T.mult == 1)
Tindex <- 1:nchains
else Tindex <- sort(Temp, index.return = TRUE)$ix
swap <- Tindex[c(1, 2)]
T1 <- Temp[swap[1]]
if (T1 != 1)
stop(paste("hybrid.sample swaps: T1 =", T1))
T2 <- Temp[swap[2]]
if (replace.target[1] == 0) {
fswap1 <- Efswap1 <- fx[swap[1]]
fswap2 <- Efswap2 <- fx[swap[2]]
}
else if (replace.target[1] == 2) {
corf1 <- sigmaf(x[swap[1], ])/sqrt(lsq)
corf2 <- sigmaf(x[swap[1], ])/sqrt(lsq)
Efswap1 <- fswap1 <- Ef(x[swap[1], ]) - r * (corf1 - maxleap)^2/(1 - corf1)^2
Efswap2 <- fswap2 <- Ef(x[swap[2], ]) - r * (corf2 - maxleap)^2/(1 - corf2)^2
}
else if (replace.target[1] == 1) {
fswap1 <- fx1
xswap2 <- x[swap[2], ]
corf1 <- sigmaf(x[swap[1], ])/sqrt(lsq)
corf2 <- sigmaf(x[swap[1], ])/sqrt(lsq)
Efswap1 <- Ef(x[swap[1], ]) - r * (corf1 - maxleap)^2/(1 - corf1)^2
Efswap2 <- Ef(x[swap[2], ]) - r * (corf2 - maxleap)^2/(1 - corf2)^2
date1 <- date()
fswap2 <- f(x[swap[2], ])
date2 <- date()
mean.acceptance <- 0
if (!is.null(acceptance))
mean.acceptance <- mean(acceptance)
if (is.na(fswap2))
stop("f(x) NaN")
if (fswap2 == Inf)
stop(paste("Swaps: Infinite f(x) not allowed:\n",
"f(", deparse(xswap2), ") =", fswap2))
fcalls <- fcalls + 1
if (graph)
.show.time(date1, date2)
}
alpha <- ((fswap2 - fswap1)/1 + (Efswap1 - Efswap2)/T2)
if(is.na(alpha)) alpha <- -Inf
if (log(runif(1)) < alpha) {
Temp[swap[1]] <- T2
Temp[swap[2]] <- 1
swaps.record1 <- c(swaps.record1, 1)
if (replace.target[1] == 1) {
x1 <- xswap2
fx1 <- fswap2
}
}
else
swaps.record1 <- c(swaps.record1, 0)
}
5.3.2 重排温度
if (T.mult == 1)
Rank <- 1:nchains
else
Rank <- rank(Temp)
5.3.3 对每个链采样
for (chain in 1:nchains) {
path <- Rank[chain]
x.C <- x[chain, ]
p.C <- NULL
if (replace.target[1] == 0)
fx.C <- fx[chain]
else if ((replace.target[1] == 1) && (path == 1))
fx.C <- fx1
else
fx.C <- Ef(x[chain, ])
xp_Early <- NULL
repeat {
p.C <- rnorm(d)
xp_Early <- matrix(c(x.C, p.C, rep(0, d)), ncol = 3)
xOK <- FALSE
delta_adj <- delta
try({
out <- .C("Leap", as.double(X), as.integer(dim(X)[1]),
as.integer(d), as.double(y), as.double(x.C),
as.double(p.C), as.integer(L), as.double(delta),
as.double(GPfit$Sigma.inv), as.double(params),
as.double(Temp[chain]), as.double(sqrt(lsq)*maxleap),
as.double(low), as.double(upp),
as.double(rep(0,n)), as.double(rep(0,n)),
as.double(rep(0,d)), as.double(rep(0,d)),
xp_Early = as.double(xp_Early) )
xp_Early <- out$xp_Early
dim(xp_Early) <- c(d,3)
xOK <- TRUE
xOK <- TRUE
})
xout <- xp_Early[, 1]
if (is.na(sum(xp_Early)))
xOK <- FALSE
if (xOK)
break
}
out <- list(x = xp_Early[, 1], p = xp_Early[, 2])
H_xp.C <- -fx.C + W(p.C)
x.P <- out$x
p.P <- out$p
if (graph)
lines(c(x.C[keyvars[1]], x.P[keyvars[1]]),
c(x.C[keyvars[2]], x.P[keyvars[2]]), lwd = 0.5,
lty = 2, col = clrs[path])
if (replace.target[1] == 2)
fx.P <- Ef(x.P)
else if ((replace.target[1] == 1) && (path > 1))
fx.P <- Ef(x.P)
else {
date1 <- date()
fx.P <- f(x.P)
date2 <- date()
if (is.na(fx.P))
stop("f(x) NaN")
if (fx.P == Inf)
stop(paste("Leapfrog: Infinite f(x) not allowed:\n",
"f(", deparse(x.P), ") =", fx.P))
fcalls <- fcalls + 1
if (graph)
if (path == 1)
.show.time(date1, date2)
}
H_xp.P <- -fx.P + W(p.P)
if ((replace.target[1] == 2) || ((replace.target == 1) && (path > 1))) {
corf_x.C <- sigmaf(x.C)/sqrt(lsq)
corf_x.P <- sigmaf(x.P)/sqrt(lsq)
H_xp.C <- H_xp.C + r * (corf_x.C - maxleap)^2/(1 - corf_x.C)^2
H_xp.P <- H_xp.P + r * (corf_x.P - maxleap)^2/(1 - corf_x.P)^2
}
alpha <- min(((-H_xp.P + H_xp.C)/Temp[chain]), 0)
if(is.na(alpha)) alpha <- -Inf
if (log(runif(1)) < alpha) {
x[chain, ] <- x.P
if (replace.target[1] == 0)
fx[chain] <- fx.P
else if (replace.target[1] == 1)
if (path == 1)
fx1 <- fx.P
if (path == 1) {
SAMP <- rbind(SAMP, x.P)
ySAMP <- c(ySAMP, fx.P)
acceptance <- c(acceptance, 1)
if(dim(SAMP)[1] %% floor(n/10) == 0)
message(paste(sep="","hybrid.sample: ",
round(100*dim(SAMP)[1]/n),"% Complete with ",
round(100*mean(acceptance),1),"% acceptance of proposals"))
}
if (graph)
points(x.P[keyvars[1]], x.P[keyvars[2]],
pch = 20, col = clrs[path])
}
else {
if (graph)
points(x.P[keyvars[1]], x.P[keyvars[2]],
pch = "X", col = reds[path])
if (path == 1) {
SAMP <- rbind(SAMP, x.C)
ySAMP <- c(ySAMP, fx.C)
acceptance <- c(acceptance, 0)
}
}
mean.acceptance <- 0
if (!is.null(acceptance))
mean.acceptance <- mean(acceptance)
}
5.3.4 样本处理与检查
当采样数量一定时,退出循环
if (graph) {
if (count >= nrefresh.graph) {
count <- 1
key.indx <- key.indx + 1
if (key.indx > dim(KEY.VARS)[1])
key.indx <- 1
keyvars <- KEY.VARS[key.indx, ]
graph.template(X, key.vars = keyvars, lb, ub)
points(X[, keyvars[1]], X[, keyvars[2]], col = "grey", pch = 20)
points(x.P[keyvars[1]], x.P[keyvars[2]], pch = 20, col = "grey")
title(c("", "", "", "Sampling phase"), adj = 0, cex.main = 0.8)
}
points(x[, keyvars[1]], x[, keyvars[2]], pch = 20, col = "grey")
points(SAMP[acceptance>0, keyvars[1]], SAMP[acceptance>0, keyvars[2]], pch = 20, col = "black")
count <- count + 1
}
its <- its + 1
if (length(acceptance) > n)
break
5.4 抽样结束
当5.4样本检查跳出循环后,返回采样结果:
return(list(SAMP = SAMP, y = ySAMP, acceptance = acceptance, function.calls = fcalls))
6.画图
opar <- par(mfrow=c(2,1))
plot(density(sample.out$SAMP[,1]), xlab="x1", ylab="f(x)")
plot(density(sample.out$SAMP[,2]), xlab="x2", ylab="f(x)")
par(opar)
7.实验结果