贝叶斯优化完整流程详解
总览:五大步骤
贝叶斯优化完整流程:
步骤1: 初始化
↓
步骤2: 构建代理模型(高斯过程)
↓
步骤3: 使用采集函数选择下一个点
↓
步骤4: 评估目标函数
↓
步骤5: 更新后验分布
↓
重复步骤2-5,直到满足停止条件
📋 详细流程拆解
步骤0:问题设定
在开始优化之前,先明确以下内容:
"""
1. 定义目标函数
2. 确定搜索空间
3. 设定优化目标(最大化/最小化)
4. 确定评估预算(最多尝试多少次)
"""
# 示例:优化深度学习模型
问题设定 = {
"目标函数": "训练模型并返回验证准确率",
"搜索空间": {
"learning_rate": [0.0001, 0.1], # 连续变量
"batch_size": [16, 128], # 离散变量
"dropout": [0.1, 0.5], # 连续变量
"num_layers": [2, 10] # 离散变量
},
"优化目标": "最大化验证准确率",
"评估预算": "最多评估50次"
}
步骤1:初始化阶段
目的:获得初始数据点,为后续建模提供基础
"""
初始化策略:
1. 随机采样 (最常用)
2. 拉丁超立方采样 (Latin Hypercube Sampling, LHS)
3. Sobol序列采样
"""
import numpy as np
class BayesianOptimizer:
def __init__(self, objective_func, bounds, n_initial=5):
"""
objective_func: 目标函数
bounds: 参数边界 [(min1,max1), (min2,max2), ...]
n_initial: 初始采样点数量
"""
self.objective_func = objective_func
self.bounds = np.array(bounds)
self.n_dims = len(bounds)
# 存储观测数据
self.X_observed = [] # 已尝试的参数组合
self.y_observed = [] # 对应的性能得分
def _random_sample(self, n_samples):
"""随机采样"""
samples = np.random.uniform(
low=self.bounds[:, 0],
high=self.bounds[:, 1],
size=(n_samples, self.n_dims)
)
return samples
def initialize(self):
"""初始化:随机评估n_initial个点"""
print("=" * 60)
print("步骤1: 初始化阶段")
print("=" * 60)
X_init = self._random_sample(self.n_initial)
for i, x in enumerate(X_init):
y = self.objective_func(x)
self.X_observed.append(x)
self.y_observed.append(y)
print(f"初始点 {i+1}/{self.n_initial}:")
print(f" 参数: {x}")
print(f" 性能: {y:.4f}\n")
print(f"✓ 初始化完成,已评估 {len(self.X_observed)} 个点")
print(f"✓ 当前最优性能: {max(self.y_observed):.4f}\n")
可视化初始化过程:
初始化示例(2D参数空间):
参数空间:
┌────────────────────────┐
│ │
│ •2 (0.76) │ randomly sampled
│ │ initial points
│ •4 (0.82) │
│ •1 (0.71) │
│ │
│ •3 (0.79) │
│ │
│ •5 (0.68) │
└────────────────────────┘
learning_rate (0.001~0.1)
步骤2:构建代理模型(高斯过程回归)
目的:用便宜的模型近似昂贵的目标函数
2.1 什么是高斯过程?
"""
高斯过程 (Gaussian Process, GP):
核心思想:
• 把函数看作无限维的高斯分布
• 任意有限个点服从多元高斯分布
• 给定观测点后,可以预测新点的分布
关键输出:
• 预测均值 μ(x):最可能的函数值
• 预测标准差 σ(x):不确定性大小
"""
from sklearn.gaussian_process import GaussianProcessRegressor
from sklearn.gaussian_process.kernels import Matern, RBF
def build_surrogate_model(self):
"""构建高斯过程代理模型"""
print("=" * 60)
print("步骤2: 构建代理模型(高斯过程)")
print("=" * 60)
# 选择核函数
kernel = Matern(nu=2.5) # Matern核,控制平滑度
# kernel = RBF() # 径向基函数核(也常用)
# 创建高斯过程模型
self.gp = GaussianProcessRegressor(
kernel=kernel,
alpha=1e-6, # 噪声水平
normalize_y=True, # 标准化输出
n_restarts_optimizer=10, # 超参数优化重启次数
random_state=42
)
# 用已观测数据训练模型
if len(self.X_observed) > 0:
X = np.array(self.X_observed)
y = np.array(self.y_observed)
self.gp.fit(X, y)
print(f"✓ 高斯过程已拟合 {len(X)} 个观测点")
print(f"✓ 核函数: {self.gp.kernel_}")
return self.gp
2.2 高斯过程的预测
def predict_with_uncertainty(self, X_new):
"""
用高斯过程预测新点
返回:
- mu: 预测均值(最可能的值)
- sigma: 预测标准差(不确定性)
"""
X_new = np.array(X_new).reshape(-1, self.n_dims)
mu, sigma = self.gp.predict(X_new, return_std=True)
return mu, sigma
# 示例使用
X_test = [[0.01, 64, 0.3]] # 新的参数组合
mu, sigma = optimizer.predict_with_uncertainty(X_test)
print(f"预测均值: {mu[0]:.4f}") # 例如: 0.8500
print(f"预测标准差: {sigma[0]:.4f}") # 例如: 0.0234
print(f"95%置信区间: [{mu[0]-2*sigma[0]:.4f}, {mu[0]+2*sigma[0]:.4f}]")
可视化高斯过程:
import matplotlib.pyplot as plt
def visualize_gp(self, iteration):
"""可视化高斯过程的预测"""
# 对于2D情况,绘制1D切片
fig, axes = plt.subplots(2, 1, figsize=(12, 10))
# 第一个参数的切片
x1_range = np.linspace(self.bounds[0, 0], self.bounds[0, 1], 100)
# 固定其他参数为最优值
best_idx = np.argmax(self.y_observed)
best_params = self.X_observed[best_idx]
X_plot = np.array([[x1, best_params[1]] for x1 in x1_range])
mu, sigma = self.gp.predict(X_plot, return_std=True)
# 上图:高斯过程拟合
ax1 = axes[0]
ax1.plot(x1_range, mu, 'b-', linewidth=2, label='GP均值')
ax1.fill_between(x1_range, mu - 2*sigma, mu + 2*sigma,
alpha=0.3, label='95%置信区间')
# 标注观测点
X_obs = np.array(self.X_observed)
ax1.scatter(X_obs[:, 0], self.y_observed,
c='red', s=100, zorder=10,
label='已观测点', edgecolors='black')
ax1.set_xlabel('参数1 (learning_rate)')
ax1.set_ylabel('性能 (accuracy)')
ax1.set_title(f'迭代 {iteration}: 高斯过程拟合')
ax1.legend()
ax1.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig(f'gp_iteration_{iteration}.png')
plt.show()
步骤3:采集函数选择下一个点
目的:在探索(Exploration)和利用(Exploitation)之间取得平衡
3.1 三种主流采集函数
from scipy.stats import norm
class AcquisitionFunctions:
"""采集函数集合"""
@staticmethod
def expected_improvement(mu, sigma, y_best, xi=0.01):
"""
期望改进 (Expected Improvement, EI)
公式:EI(x) = E[max(f(x) - f_best, 0)]
参数:
- mu: 预测均值
- sigma: 预测标准差
- y_best: 当前最优值
- xi: 探索参数(控制探索程度)
"""
# 标准化改进量
improvement = mu - y_best - xi
Z = improvement / (sigma + 1e-9)
# 期望改进
ei = improvement * norm.cdf(Z) + sigma * norm.pdf(Z)
ei[sigma == 0.0] = 0.0 # 标准差为0时,EI为0
return ei
@staticmethod
def upper_confidence_bound(mu, sigma, kappa=2.0):
"""
置信上界 (Upper Confidence Bound, UCB)
公式:UCB(x) = μ(x) + κ × σ(x)
参数:
- mu: 预测均值
- sigma: 预测标准差
- kappa: 探索参数(越大越倾向探索)
"""
return mu + kappa * sigma
@staticmethod
def probability_of_improvement(mu, sigma, y_best, xi=0.01):
"""
改进概率 (Probability of Improvement, PI)
公式:PI(x) = P(f(x) > f_best)
参数:
- mu: 预测均值
- sigma: 预测标准差
- y_best: 当前最优值
- xi: 探索参数
"""
Z = (mu - y_best - xi) / (sigma + 1e-9)
return norm.cdf(Z)
def select_next_point(self, method='ei'):
"""
使用采集函数选择下一个要评估的点
method: 'ei', 'ucb', 'pi'
"""
print("=" * 60)
print("步骤3: 使用采集函数选择下一个点")
print("=" * 60)
# 生成候选点
n_candidates = 10000
X_candidates = self._random_sample(n_candidates)
# 用高斯过程预测
mu, sigma = self.gp.predict(X_candidates, return_std=True)
# 计算采集函数值
y_best = max(self.y_observed)
if method == 'ei':
acq_values = AcquisitionFunctions.expected_improvement(
mu, sigma, y_best, xi=0.01
)
print(f"采集函数: Expected Improvement (EI)")
elif method == 'ucb':
acq_values = AcquisitionFunctions.upper_confidence_bound(
mu, sigma, kappa=2.0
)
print(f"采集函数: Upper Confidence Bound (UCB)")
elif method == 'pi':
acq_values = AcquisitionFunctions.probability_of_improvement(
mu, sigma, y_best, xi=0.01
)
print(f"采集函数: Probability of Improvement (PI)")
# 选择采集函数值最大的点
best_idx = np.argmax(acq_values)
X_next = X_candidates[best_idx]
print(f"✓ 选中的参数: {X_next}")
print(f"✓ 采集函数值: {acq_values[best_idx]:.4f}")
print(f"✓ 预测性能: {mu[best_idx]:.4f} ± {sigma[best_idx]:.4f}\n")
return X_next
3.2 探索 vs 利用的权衡
"""
采集函数如何平衡探索和利用?
假设两个候选点:
点A: μ=0.85, σ=0.01 (已知区域,确定性高,预测好)
点B: μ=0.80, σ=0.15 (未知区域,不确定性高,预测一般)
当前最优: 0.83
1. Expected Improvement (EI):
EI_A = (0.85 - 0.83) × P(Z) + 0.01 × φ(Z) ≈ 0.020 (利用)
EI_B = (0.80 - 0.83) × P(Z) + 0.15 × φ(Z) ≈ 0.045 (探索)
→ 选择B(探索未知区域)
2. Upper Confidence Bound (UCB, κ=2):
UCB_A = 0.85 + 2 × 0.01 = 0.87 (利用已知好区域)
UCB_B = 0.80 + 2 × 0.15 = 1.10 (探索高不确定区域)
→ 选择B(乐观探索)
3. Probability of Improvement (PI):
PI_A = P(f(A) > 0.83) ≈ 0.98 (很可能改进)
PI_B = P(f(B) > 0.83) ≈ 0.42 (不太可能改进)
→ 选择A(保守利用)
"""
可视化采集函数:
def visualize_acquisition(self, X_next):
"""可视化采集函数"""
fig, axes = plt.subplots(3, 1, figsize=(12, 15))
# 生成测试点
x_range = np.linspace(self.bounds[0, 0], self.bounds[0, 1], 200)
best_params = self.X_observed[np.argmax(self.y_observed)]
X_test = np.array([[x, best_params[1]] for x in x_range])
# 预测
mu, sigma = self.gp.predict(X_test, return_std=True)
y_best = max(self.y_observed)
# 计算三种采集函数
ei = AcquisitionFunctions.expected_improvement(mu, sigma, y_best)
ucb = AcquisitionFunctions.upper_confidence_bound(mu, sigma)
pi = AcquisitionFunctions.probability_of_improvement(mu, sigma, y_best)
# 绘制
for ax, values, title in zip(axes,
[ei, ucb, pi],
['Expected Improvement',
'Upper Confidence Bound',
'Probability of Improvement']):
ax.plot(x_range, values, 'purple', linewidth=2)
ax.fill_between(x_range, 0, values, alpha=0.3)
ax.axvline(x=X_next[0], color='red', linestyle='--',
linewidth=2, label='选中的点')
ax.set_ylabel('采集函数值')
ax.set_title(title)
ax.legend()
ax.grid(True, alpha=0.3)
axes[-1].set_xlabel('参数值')
plt.tight_layout()
plt.savefig('acquisition_functions.png')
plt.show()
步骤4:评估目标函数
目的:用选中的参数训练模型,获得真实性能
def evaluate_objective(self, X_next):
"""
评估目标函数(这是最耗时的步骤!)
在实际应用中,这里会:
1. 用选中的超参数配置模型
2. 训练模型(可能需要几小时)
3. 在验证集上评估性能
"""
print("=" * 60)
print("步骤4: 评估目标函数")
print("=" * 60)
print(f"开始训练模型,参数: {X_next}")
print("训练中...")
# 调用目标函数(实际训练)
y_next = self.objective_func(X_next)
print(f"✓ 训练完成")
print(f"✓ 验证性能: {y_next:.4f}\n")
return y_next
# 实际使用示例
def train_neural_network(params):
"""
真实的目标函数示例
"""
lr, batch_size, dropout = params
# 1. 配置模型
model = NeuralNetwork(
learning_rate=lr,
batch_size=int(batch_size),
dropout=dropout
)
# 2. 训练模型
model.fit(
train_data,
epochs=50,
validation_data=val_data
)
# 3. 评估性能
val_accuracy = model.evaluate(val_data)
return val_accuracy
步骤5:更新后验分布
目的:将新观测点加入数据集,更新我们的认知
def update_posterior(self, X_next, y_next):
"""
更新后验分布
这一步非常关键:
1. 添加新的观测点
2. 高斯过程会在下一轮自动使用新数据
3. 我们对参数空间的认知变得更准确
"""
print("=" * 60)
print("步骤5: 更新后验分布")
print("=" * 60)
# 添加新观测
self.X_observed.append(X_next)
self.y_observed.append(y_next)
print(f"✓ 已添加新观测点")
print(f"✓ 总观测点数: {len(self.X_observed)}")
print(f"✓ 当前最优性能: {max(self.y_observed):.4f}")
# 显示性能提升
if len(self.y_observed) > 1:
improvement = y_next - max(self.y_observed[:-1])
if improvement > 0:
print(f"✓ 性能提升: +{improvement:.4f} 🎉")
else:
print(f"✓ 性能变化: {improvement:.4f}")
print()
完整的迭代循环
def optimize(self, n_iterations=20, acquisition='ei'):
"""
执行完整的贝叶斯优化
参数:
- n_iterations: 迭代次数(评估预算)
- acquisition: 采集函数类型 ('ei', 'ucb', 'pi')
"""
# 步骤1: 初始化
self.initialize()
# 主循环
for iteration in range(n_iterations):
print("\n" + "█" * 60)
print(f"迭代 {iteration + 1}/{n_iterations}")
print("█" * 60 + "\n")
# 步骤2: 构建代理模型
self.build_surrogate_model()
# 步骤3: 选择下一个点
X_next = self.select_next_point(method=acquisition)
# 步骤4: 评估目标函数
y_next = self.evaluate_objective(X_next)
# 步骤5: 更新后验分布
self.update_posterior(X_next, y_next)
# 可视化当前状态
self.visualize_iteration(iteration + 1)
# 返回最优结果
best_idx = np.argmax(self.y_observed)
best_params = self.X_observed[best_idx]
best_score = self.y_observed[best_idx]
print("\n" + "=" * 60)
print("优化完成!")
print("=" * 60)
print(f"最优参数: {best_params}")
print(f"最优性能: {best_score:.4f}")
print(f"总评估次数: {len(self.X_observed)}")
return best_params, best_score
🎮 完整可运行示例
import numpy as np
import matplotlib.pyplot as plt
from sklearn.gaussian_process import GaussianProcessRegressor
from sklearn.gaussian_process.kernels import Matern
from scipy.stats import norm
class CompleteBayesianOptimizer:
"""完整的贝叶斯优化器"""
def __init__(self, objective_func, bounds, n_initial=5):
self.objective_func = objective_func
self.bounds = np.array(bounds)
self.n_dims = len(bounds)
self.n_initial = n_initial
self.X_observed = []
self.y_observed = []
self.gp = None
def _random_sample(self, n_samples):
"""随机采样"""
return np.random.uniform(
self.bounds[:, 0],
self.bounds[:, 1],
size=(n_samples, self.n_dims)
)
def initialize(self):
"""步骤1: 初始化"""
print("=" * 60)
print("步骤1: 初始化阶段")
print("=" * 60)
X_init = self._random_sample(self.n_initial)
for i, x in enumerate(X_init):
y = self.objective_func(x)
self.X_observed.append(x)
self.y_observed.append(y)
print(f"初始点 {i+1}: 参数={x}, 性能={y:.4f}")
print(f"\n✓ 初始化完成,当前最优: {max(self.y_observed):.4f}\n")
def build_surrogate_model(self):
"""步骤2: 构建代理模型"""
kernel = Matern(nu=2.5)
self.gp = GaussianProcessRegressor(
kernel=kernel,
alpha=1e-6,
normalize_y=True,
n_restarts_optimizer=5
)
X = np.array(self.X_observed)
y = np.array(self.y_observed)
self.gp.fit(X, y)
def expected_improvement(self, X):
"""EI采集函数"""
mu, sigma = self.gp.predict(X, return_std=True)
y_best = max(self.y_observed)
improvement = mu - y_best - 0.01
Z = improvement / (sigma + 1e-9)
ei = improvement * norm.cdf(Z) + sigma * norm.pdf(Z)
return ei
def select_next_point(self):
"""步骤3: 选择下一个点"""
X_candidates = self._random_sample(5000)
ei_values = self.expected_improvement(X_candidates)
best_idx = np.argmax(ei_values)
return X_candidates[best_idx]
def optimize(self, n_iterations=15):
"""完整优化流程"""
# 初始化
self.initialize()
# 迭代优化
for i in range(n_iterations):
print(f"\n{'='*60}")
print(f"迭代 {i+1}/{n_iterations}")
print('='*60)
# 构建模型
self.build_surrogate_model()
print("✓ 步骤2: 高斯过程模型已更新")
# 选择下一个点
X_next = self.select_next_point()
print(f"✓ 步骤3: 选中参数 {X_next}")
# 评估
y_next = self.objective_func(X_next)
print(f"✓ 步骤4: 评估性能 {y_next:.4f}")
# 更新
self.X_observed.append(X_next)
self.y_observed.append(y_next)
current_best = max(self.y_observed)
print(f"✓ 步骤5: 后验分布已更新")
print(f" 当前最优: {current_best:.4f}")
# 返回结果
best_idx = np.argmax(self.y_observed)
best_params = self.X_observed[best_idx]
best_score = self.y_observed[best_idx]
print(f"\n{'='*60}")
print("🎉 优化完成!")
print('='*60)
print(f"最优参数: {best_params}")
print(f"最优性能: {best_score:.4f}")
print(f"总评估次数: {len(self.X_observed)}")
return best_params, best_score
# === 使用示例 ===
def objective_function(params):
"""
模拟目标函数:训练深度学习模型
实际使用时,这里应该是真实的训练代码
"""
lr, batch_size = params
# 模拟函数(实际中是真实训练)
score = np.sin(lr * 50) * 0.2 + \
np.cos(batch_size / 30) * 0.3 + \
0.5 - (lr - 0.02)**2 * 20 - \
((batch_size - 64) / 100)**2 * 0.5
# 添加噪声
score += np.random.normal(0, 0.02)
return max(0, min(1, score)) # 限制在[0,1]
# 定义搜索空间
bounds = [
(0.001, 0.1), # learning_rate
(16, 128) # batch_size
]
# 创建优化器
optimizer = CompleteBayesianOptimizer(
objective_func=objective_function,
bounds=bounds,
n_initial=5
)
# 运行优化
best_params, best_score = optimizer.optimize(n_iterations=20)
完整运行输出:
============================================================
步骤1: 初始化阶段
============================================================
初始点 1: 参数=[0.0456 89.234], 性能=0.6234
初始点 2: 参数=[0.0123 34.567], 性能=0.5891
初始点 3: 参数=[0.0789 112.34], 性能=0.5423
初始点 4: 参数=[0.0234 67.890], 性能=0.7123
初始点 5: 参数=[0.0891 45.678], 性能=0.5678
✓ 初始化完成,当前最优: 0.7123
============================================================
迭代 1/20
============================================================
✓ 步骤2: 高斯过程模型已更新
✓ 步骤3: 选中参数 [0.0198 71.234]
✓ 步骤4: 评估性能 0.7456
✓ 步骤5: 后验分布已更新
当前最优: 0.7456
============================================================
迭代 2/20
============================================================
✓ 步骤2: 高斯过程模型已更新
✓ 步骤3: 选中参数 [0.0176 68.901]
✓ 步骤4: 评估性能 0.7589
✓ 步骤5: 后验分布已更新
当前最优: 0.7589
...
============================================================
🎉 优化完成!
============================================================
最优参数: [0.0189 69.456]
最优性能: 0.7823
总评估次数: 25
📊 可视化完整流程
def visualize_complete_process(optimizer):
"""可视化完整的优化过程"""
fig = plt.figure(figsize=(20, 12))
gs = fig.add_gridspec(3, 3, hspace=0.3, wspace=0.3)
# 1. 性能随迭代变化
ax1 = fig.add_subplot(gs[0, :])
iterations = range(1, len(optimizer.y_observed) + 1)
best_so_far = np.maximum.accumulate(optimizer.y_observed)
ax1.plot(iterations, optimizer.y_observed, 'o-',
alpha=0.6, label='每次评估')
ax1.plot(iterations, best_so_far, 'r-',
linewidth=3, label='历史最优')
ax1.axhline(y=max(optimizer.y_observed),
color='g', linestyle='--', alpha=0.5)
ax1.set_xlabel('评估次数', fontsize=12)
ax1.set_ylabel('性能', fontsize=12)
ax1.set_title('优化过程:性能变化', fontsize=14, fontweight='bold')
ax1.legend(fontsize=11)
ax1.grid(True, alpha=0.3)
# 2. 参数空间探索(learning rate)
ax2 = fig.add_subplot(gs[1, 0])
X_array = np.array(optimizer.X_observed)
scatter = ax2.scatter(X_array[:, 0], range(len(X_array)),
c=optimizer.y_observed, cmap='viridis',
s=100, edgecolors='black')
ax2.set_xlabel('Learning Rate')
ax2.set_ylabel('评估顺序')
ax2.set_title('Learning Rate 探索过程')
plt.colorbar(scatter, ax=ax2)
# 3. 参数空间探索(batch size)
ax3 = fig.add_subplot(gs[1, 1])
scatter = ax3.scatter(X_array[:, 1], range(len(X_array)),
c=optimizer.y_observed, cmap='viridis',
s=100, edgecolors='black')
ax3.set_xlabel('Batch Size')
ax3.set_ylabel('评估顺序')
ax3.set_title('Batch Size 探索过程')
plt.colorbar(scatter, ax=ax3)
# 4. 2D参数空间热图
ax4 = fig.add_subplot(gs[1, 2])
scatter = ax4.scatter(X_array[:, 0], X_array[:, 1],
c=optimizer.y_observed, cmap='viridis',
s=200, alpha=0.7, edgecolors='black', linewidth=2)
# 标记最优点
best_idx = np.argmax(optimizer.y_observed)
ax4.scatter(X_array[best_idx, 0], X_array[best_idx, 1],
c='red', s=500, marker='*',
edgecolors='black', linewidths=3, label='最优点')
ax4.set_xlabel('Learning Rate')
ax4.set_ylabel('Batch Size')
ax4.set_title('参数空间全景')
ax4.legend()
plt.colorbar(scatter, ax=ax4)
# 5. 性能分布直方图
ax5 = fig.add_subplot(gs[2, 0])
ax5.hist(optimizer.y_observed, bins=15,
alpha=0.7, color='skyblue', edgecolor='black')
ax5.axvline(x=max(optimizer.y_observed),
color='red', linestyle='--', linewidth=2)
ax5.set_xlabel('性能')
ax5.set_ylabel('频次')
ax5.set_title('性能分布')
# 6. 改进量统计
ax6 = fig.add_subplot(gs[2, 1])
improvements = np.diff(best_so_far)
ax6.bar(range(len(improvements)), improvements,
alpha=0.7, color='green', edgecolor='black')
ax6.set_xlabel('迭代')
ax6.set_ylabel('性能改进')
ax6.set_title('每次迭代的改进量')
ax6.grid(True, alpha=0.3, axis='y')
# 7. 统计信息
ax7 = fig.add_subplot(gs[2, 2])
ax7.axis('off')
stats_text = f"""
优化统计信息
{'='*30}
总评估次数: {len(optimizer.y_observed)}
最优性能: {max(optimizer.y_observed):.4f}
平均性能: {np.mean(optimizer.y_observed):.4f}
性能标准差: {np.std(optimizer.y_observed):.4f}
最优参数:
- Learning Rate: {X_array[best_idx, 0]:.5f}
- Batch Size: {X_array[best_idx, 1]:.1f}
性能提升:
- 初始最优: {max(optimizer.y_observed[:optimizer.n_initial]):.4f}
- 最终最优: {max(optimizer.y_observed):.4f}
- 总提升: {max(optimizer.y_observed) - max(optimizer.y_observed[:optimizer.n_initial]):.4f}
"""
ax7.text(0.1, 0.9, stats_text,
transform=ax7.transAxes,
fontsize=11,
verticalalignment='top',
fontfamily='monospace',
bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.3))
plt.savefig('complete_optimization_process.png', dpi=300, bbox_inches='tight')
plt.show()
# 使用
visualize_complete_process(optimizer)
🎓 核心要点总结
完整流程回顾:
┌────────────────────────────────────────────────────┐
│ 步骤0: 问题设定 │
│ ├─ 定义目标函数 │
│ ├─ 确定搜索空间 │
│ └─ 设定评估预算 │
└────────────────────────────────────────────────────┘
↓
┌────────────────────────────────────────────────────┐
│ 步骤1: 初始化(随机采样5-10个点) │
│ └─ 建立初始数据集 D = {(x₁,y₁), ..., (xₙ,yₙ)} │
└────────────────────────────────────────────────────┘
↓
┌─────────────┐
│ 主循环开始 │
└─────────────┘
↓
┌────────────────────────────────────────────────────┐
│ 步骤2: 构建代理模型(高斯过程) │
│ ├─ 用当前数据 D 训练 GP │
│ └─ 得到预测函数 f(x) ~ GP(μ(x), σ(x)) │
└────────────────────────────────────────────────────┘
↓
┌────────────────────────────────────────────────────┐
│ 步骤3: 采集函数选择下一个点 │
│ ├─ 计算采集函数 α(x) = EI/UCB/PI │
│ └─ 选择 x_next = argmax α(x) │
└────────────────────────────────────────────────────┘
↓
┌────────────────────────────────────────────────────┐
│ 步骤4: 评估目标函数 │
│ └─ y_next = f(x_next) ← 训练模型! │
└────────────────────────────────────────────────────┘
↓
┌────────────────────────────────────────────────────┐
│ 步骤5: 更新后验分布 │
│ └─ D ← D ∪ {(x_next, y_next)} │
└────────────────────────────────────────────────────┘
↓
┌─────────────┐
│ 满足停止条件?│
└─────────────┘
否↓ 是↓
回到步骤2 输出最优解
关键概念:
- 目标函数:黑盒函数,输入超参数,输出性能
- 代理模型:用高斯过程近似目标函数
- 采集函数:决定下一个评估点,平衡探索和利用
- 后验分布:我们对参数空间的认知,不断更新
- 迭代优化:循环2-5步,直到找到最优解
优势:
- ✅ 高效:用最少的评估次数找到好结果
- ✅ 智能:每次都基于历史信息做决策
- ✅ 全局:能跳出局部最优
- ✅ 自适应:自动平衡探索和利用
适用场景:
- ✅ 评估成本高(训练一次模型很耗时)
- ✅ 参数维度适中(< 20维)
- ✅ 目标函数相对平滑
- ✅ 有噪声但可接受