贝叶斯优化完整流程详解

贝叶斯优化完整流程详解

总览:五大步骤

复制代码
贝叶斯优化完整流程:

步骤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   输出最优解

关键概念:

  1. 目标函数:黑盒函数,输入超参数,输出性能
  2. 代理模型:用高斯过程近似目标函数
  3. 采集函数:决定下一个评估点,平衡探索和利用
  4. 后验分布:我们对参数空间的认知,不断更新
  5. 迭代优化:循环2-5步,直到找到最优解

优势:

  • 高效:用最少的评估次数找到好结果
  • 智能:每次都基于历史信息做决策
  • 全局:能跳出局部最优
  • 自适应:自动平衡探索和利用

适用场景:

  • ✅ 评估成本高(训练一次模型很耗时)
  • ✅ 参数维度适中(< 20维)
  • ✅ 目标函数相对平滑
  • ✅ 有噪声但可接受

相关推荐
Jerryhut2 小时前
sklearn函数总结五——特征降维 压缩数据 - 特征选择
人工智能·python·机器学习·sklearn
U盘失踪了2 小时前
Django 登录注册功能实现
后端·python·django
deephub2 小时前
自愈型RAG系统:从脆弱管道到闭环智能体的工程实践
人工智能·python·大语言模型·rag
NullPointer82 小时前
【剪映小助手源码精讲】20_视频添加服务
python·aigc
辣椒酱.2 小时前
chromedriver浏览器驱动各版本下载
python·谷歌·谷歌驱动
U盘失踪了2 小时前
Django 登录注册功能实现-样式优化
后端·python·django
彼岸花开了吗2 小时前
构建AI智能体:四十五、从专用插件到通用协议:MCP如何重新定义AI工具生态
人工智能·python·mcp
天天爱吃肉82182 小时前
庖丁解牛:从两张核心电路图,透视新能源汽车的“动脉”与“毛细血管”
python·嵌入式硬件·汽车
谷粒.2 小时前
让缺陷描述更有价值:测试报告编写规范的精髓
java·网络·python·单元测试·自动化·log4j