754 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			754 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | #!/usr/bin/env python3 | |||
|  | """
 | |||
|  | Advanced Parameter Optimization for TTA-E Neural Decoding | |||
|  | 支持多种优化算法:差分进化、遗传算法、贝叶斯优化、粒子群优化 | |||
|  | """
 | |||
|  | 
 | |||
|  | import os | |||
|  | import sys | |||
|  | import numpy as np | |||
|  | import pickle | |||
|  | import argparse | |||
|  | import time | |||
|  | from concurrent.futures import ThreadPoolExecutor, as_completed | |||
|  | from typing import Dict, List, Tuple, Optional | |||
|  | import json | |||
|  | from dataclasses import dataclass | |||
|  | from pathlib import Path | |||
|  | 
 | |||
|  | # GPU加速支持 | |||
|  | try: | |||
|  |     import cupy as cp | |||
|  |     GPU_AVAILABLE = True | |||
|  |     print("GPU acceleration available with CuPy") | |||
|  | except ImportError: | |||
|  |     import numpy as cp | |||
|  |     GPU_AVAILABLE = False | |||
|  |     print("Using CPU computation with NumPy") | |||
|  | 
 | |||
|  | # 优化算法库 | |||
|  | try: | |||
|  |     from scipy.optimize import differential_evolution | |||
|  |     SCIPY_AVAILABLE = True | |||
|  | except ImportError: | |||
|  |     SCIPY_AVAILABLE = False | |||
|  |     print("SciPy not available, some algorithms will be disabled") | |||
|  | 
 | |||
|  | try: | |||
|  |     import skopt | |||
|  |     from skopt import gp_minimize | |||
|  |     from skopt.space import Real | |||
|  |     SKOPT_AVAILABLE = True | |||
|  | except ImportError: | |||
|  |     SKOPT_AVAILABLE = False | |||
|  |     print("scikit-optimize not available, Bayesian optimization disabled") | |||
|  | 
 | |||
|  | # 设置随机种子 | |||
|  | np.random.seed(42) | |||
|  | if GPU_AVAILABLE: | |||
|  |     cp.random.seed(42) | |||
|  | 
 | |||
|  | @dataclass | |||
|  | class OptimizationResult: | |||
|  |     """优化结果数据类""" | |||
|  |     best_params: Dict | |||
|  |     best_score: float | |||
|  |     optimization_history: List[Tuple[Dict, float]] | |||
|  |     total_evaluations: int | |||
|  |     elapsed_time: float | |||
|  |     algorithm: str | |||
|  | 
 | |||
|  | def to_cpu(x): | |||
|  |     """将CuPy数组转换为NumPy数组""" | |||
|  |     if GPU_AVAILABLE and hasattr(x, 'get'): | |||
|  |         return x.get() | |||
|  |     return x | |||
|  | 
 | |||
|  | def load_base_predictions(cache_file='base_predictions_cache.pkl'): | |||
|  |     """加载预计算的基础预测结果""" | |||
|  |     if os.path.exists(cache_file): | |||
|  |         print(f"Loading base predictions from {cache_file}") | |||
|  |         with open(cache_file, 'rb') as f: | |||
|  |             return pickle.load(f) | |||
|  |     else: | |||
|  |         print(f"Cache file {cache_file} not found. Please run generate_base_predictions() first.") | |||
|  |         return None | |||
|  | 
 | |||
|  | def evaluate_config_gpu(params_dict, base_predictions_data): | |||
|  |     """GPU加速的配置评估函数""" | |||
|  |     try: | |||
|  |         # 解析参数 | |||
|  |         tta_weights = [params_dict[f'tta_weight_{i}'] for i in range(5)] | |||
|  |         gru_weight = params_dict['gru_weight'] | |||
|  |          | |||
|  |         # 转换为GPU数组(如果可用) | |||
|  |         if GPU_AVAILABLE: | |||
|  |             tta_weights = cp.array(tta_weights) | |||
|  |         else: | |||
|  |             tta_weights = np.array(tta_weights) | |||
|  |          | |||
|  |         total_per = 0.0 | |||
|  |         total_chars = 0 | |||
|  |          | |||
|  |         for trial_data in base_predictions_data: | |||
|  |             gru_probs = trial_data['gru_probs']  # shape: (5, seq_len, vocab_size) | |||
|  |             lstm_probs = trial_data['lstm_probs']  # shape: (5, seq_len, vocab_size) | |||
|  |             true_chars = trial_data['true_chars'] | |||
|  |              | |||
|  |             # 转换为GPU数组 | |||
|  |             if GPU_AVAILABLE: | |||
|  |                 gru_probs = cp.asarray(gru_probs) | |||
|  |                 lstm_probs = cp.asarray(lstm_probs) | |||
|  |              | |||
|  |             # 计算TTA加权平均 | |||
|  |             tta_weights_norm = tta_weights / cp.sum(tta_weights) if cp.sum(tta_weights) > 0 else cp.ones_like(tta_weights) / len(tta_weights) | |||
|  |              | |||
|  |             # 对每个TTA样本加权 | |||
|  |             gru_weighted = cp.sum(gru_probs * tta_weights_norm[:, None, None], axis=0) | |||
|  |             lstm_weighted = cp.sum(lstm_probs * tta_weights_norm[:, None, None], axis=0) | |||
|  |              | |||
|  |             # 模型集成 | |||
|  |             total_weight = gru_weight + (1 - gru_weight) | |||
|  |             if total_weight > 0: | |||
|  |                 ensemble_probs = (gru_weighted * gru_weight + lstm_weighted * (1 - gru_weight)) / total_weight | |||
|  |             else: | |||
|  |                 ensemble_probs = (gru_weighted + lstm_weighted) / 2 | |||
|  |              | |||
|  |             # 解码预测 | |||
|  |             if GPU_AVAILABLE: | |||
|  |                 predicted_chars = cp.argmax(ensemble_probs, axis=1) | |||
|  |                 predicted_chars = to_cpu(predicted_chars) | |||
|  |             else: | |||
|  |                 predicted_chars = np.argmax(ensemble_probs, axis=1) | |||
|  |              | |||
|  |             # 计算PER | |||
|  |             per = calculate_per(predicted_chars, true_chars) | |||
|  |             total_per += per * len(true_chars) | |||
|  |             total_chars += len(true_chars) | |||
|  |          | |||
|  |         avg_per = total_per / total_chars if total_chars > 0 else 1.0 | |||
|  |         return avg_per | |||
|  |          | |||
|  |     except Exception as e: | |||
|  |         print(f"Error in evaluate_config_gpu: {e}") | |||
|  |         return 1.0  # 返回最差分数 | |||
|  | 
 | |||
|  | def calculate_per(predicted, true): | |||
|  |     """计算音素错误率 (PER)""" | |||
|  |     if len(predicted) == 0 and len(true) == 0: | |||
|  |         return 0.0 | |||
|  |     if len(predicted) == 0 or len(true) == 0: | |||
|  |         return 1.0 | |||
|  |      | |||
|  |     # 简单的字符级编辑距离 | |||
|  |     n, m = len(predicted), len(true) | |||
|  |     dp = np.zeros((n + 1, m + 1)) | |||
|  |      | |||
|  |     for i in range(n + 1): | |||
|  |         dp[i][0] = i | |||
|  |     for j in range(m + 1): | |||
|  |         dp[0][j] = j | |||
|  |      | |||
|  |     for i in range(1, n + 1): | |||
|  |         for j in range(1, m + 1): | |||
|  |             if predicted[i-1] == true[j-1]: | |||
|  |                 dp[i][j] = dp[i-1][j-1] | |||
|  |             else: | |||
|  |                 dp[i][j] = 1 + min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) | |||
|  |      | |||
|  |     return dp[n][m] / max(n, m) | |||
|  | 
 | |||
|  | class DifferentialEvolution: | |||
|  |     """差分进化算法""" | |||
|  |      | |||
|  |     def __init__(self, bounds, popsize=15, maxiter=100, mutation=0.5, recombination=0.7): | |||
|  |         self.bounds = bounds | |||
|  |         self.popsize = popsize | |||
|  |         self.maxiter = maxiter | |||
|  |         self.mutation = mutation | |||
|  |         self.recombination = recombination | |||
|  |          | |||
|  |     def optimize(self, objective_func, base_predictions): | |||
|  |         """运行差分进化优化""" | |||
|  |         print(f"Starting Differential Evolution (popsize={self.popsize}, maxiter={self.maxiter})") | |||
|  |          | |||
|  |         param_names = list(self.bounds.keys()) | |||
|  |         scipy_bounds = [self.bounds[name] for name in param_names] | |||
|  |          | |||
|  |         def objective_wrapper(x): | |||
|  |             params = {param_names[i]: x[i] for i in range(len(x))} | |||
|  |             return objective_func(params, base_predictions) | |||
|  |          | |||
|  |         start_time = time.time() | |||
|  |          | |||
|  |         if SCIPY_AVAILABLE: | |||
|  |             result = differential_evolution( | |||
|  |                 objective_wrapper, | |||
|  |                 scipy_bounds, | |||
|  |                 popsize=self.popsize, | |||
|  |                 maxiter=self.maxiter, | |||
|  |                 mutation=self.mutation, | |||
|  |                 recombination=self.recombination, | |||
|  |                 seed=42, | |||
|  |                 disp=True | |||
|  |             ) | |||
|  |              | |||
|  |             best_params = {param_names[i]: result.x[i] for i in range(len(param_names))} | |||
|  |              | |||
|  |             return OptimizationResult( | |||
|  |                 best_params=best_params, | |||
|  |                 best_score=result.fun, | |||
|  |                 optimization_history=[],  # SciPy doesn't provide history | |||
|  |                 total_evaluations=result.nfev, | |||
|  |                 elapsed_time=time.time() - start_time, | |||
|  |                 algorithm="Differential Evolution" | |||
|  |             ) | |||
|  |         else: | |||
|  |             # 简单的手动实现 | |||
|  |             return self._manual_de(objective_wrapper, scipy_bounds, param_names, start_time) | |||
|  |      | |||
|  |     def _manual_de(self, objective_func, bounds, param_names, start_time): | |||
|  |         """手动实现的差分进化""" | |||
|  |         n_params = len(bounds) | |||
|  |          | |||
|  |         # 初始化种群 | |||
|  |         population = np.random.rand(self.popsize, n_params) | |||
|  |         for i in range(n_params): | |||
|  |             low, high = bounds[i] | |||
|  |             population[:, i] = population[:, i] * (high - low) + low | |||
|  |          | |||
|  |         # 评估初始种群 | |||
|  |         fitness = np.array([objective_func(ind) for ind in population]) | |||
|  |          | |||
|  |         history = [] | |||
|  |         best_idx = np.argmin(fitness) | |||
|  |         best_individual = population[best_idx].copy() | |||
|  |         best_fitness = fitness[best_idx] | |||
|  |          | |||
|  |         print(f"Initial best fitness: {best_fitness:.6f}") | |||
|  |          | |||
|  |         for generation in range(self.maxiter): | |||
|  |             new_population = population.copy() | |||
|  |              | |||
|  |             for i in range(self.popsize): | |||
|  |                 # 选择三个不同的个体 | |||
|  |                 candidates = list(range(self.popsize)) | |||
|  |                 candidates.remove(i) | |||
|  |                 a, b, c = np.random.choice(candidates, 3, replace=False) | |||
|  |                  | |||
|  |                 # 变异 | |||
|  |                 mutant = population[a] + self.mutation * (population[b] - population[c]) | |||
|  |                  | |||
|  |                 # 边界处理 | |||
|  |                 for j in range(n_params): | |||
|  |                     low, high = bounds[j] | |||
|  |                     mutant[j] = np.clip(mutant[j], low, high) | |||
|  |                  | |||
|  |                 # 交叉 | |||
|  |                 trial = population[i].copy() | |||
|  |                 crossover_points = np.random.rand(n_params) < self.recombination | |||
|  |                 trial[crossover_points] = mutant[crossover_points] | |||
|  |                  | |||
|  |                 # 评估试验个体 | |||
|  |                 trial_fitness = objective_func(trial) | |||
|  |                  | |||
|  |                 # 选择 | |||
|  |                 if trial_fitness < fitness[i]: | |||
|  |                     new_population[i] = trial | |||
|  |                     fitness[i] = trial_fitness | |||
|  |                      | |||
|  |                     if trial_fitness < best_fitness: | |||
|  |                         best_individual = trial.copy() | |||
|  |                         best_fitness = trial_fitness | |||
|  |                         print(f"Generation {generation+1}: New best fitness {best_fitness:.6f}") | |||
|  |              | |||
|  |             population = new_population | |||
|  |             history.append((best_individual.copy(), best_fitness)) | |||
|  |          | |||
|  |         best_params = {param_names[i]: best_individual[i] for i in range(len(param_names))} | |||
|  |          | |||
|  |         return OptimizationResult( | |||
|  |             best_params=best_params, | |||
|  |             best_score=best_fitness, | |||
|  |             optimization_history=history, | |||
|  |             total_evaluations=self.popsize * (1 + self.maxiter), | |||
|  |             elapsed_time=time.time() - start_time, | |||
|  |             algorithm="Differential Evolution (Manual)" | |||
|  |         ) | |||
|  | 
 | |||
|  | class GeneticAlgorithm: | |||
|  |     """遗传算法""" | |||
|  |      | |||
|  |     def __init__(self, bounds, popsize=50, generations=100, mutation_rate=0.1, crossover_rate=0.8): | |||
|  |         self.bounds = bounds | |||
|  |         self.popsize = popsize | |||
|  |         self.generations = generations | |||
|  |         self.mutation_rate = mutation_rate | |||
|  |         self.crossover_rate = crossover_rate | |||
|  |      | |||
|  |     def optimize(self, objective_func, base_predictions): | |||
|  |         """运行遗传算法优化""" | |||
|  |         print(f"Starting Genetic Algorithm (popsize={self.popsize}, generations={self.generations})") | |||
|  |          | |||
|  |         param_names = list(self.bounds.keys()) | |||
|  |         n_params = len(param_names) | |||
|  |          | |||
|  |         start_time = time.time() | |||
|  |          | |||
|  |         # 初始化种群 | |||
|  |         population = [] | |||
|  |         for _ in range(self.popsize): | |||
|  |             individual = {} | |||
|  |             for name in param_names: | |||
|  |                 low, high = self.bounds[name] | |||
|  |                 individual[name] = np.random.uniform(low, high) | |||
|  |             population.append(individual) | |||
|  |          | |||
|  |         # 评估初始种群 | |||
|  |         fitness_scores = [objective_func(ind, base_predictions) for ind in population] | |||
|  |          | |||
|  |         history = [] | |||
|  |         best_idx = np.argmin(fitness_scores) | |||
|  |         best_individual = population[best_idx].copy() | |||
|  |         best_score = fitness_scores[best_idx] | |||
|  |          | |||
|  |         print(f"Initial best fitness: {best_score:.6f}") | |||
|  |          | |||
|  |         for generation in range(self.generations): | |||
|  |             # 选择(锦标赛选择) | |||
|  |             new_population = [] | |||
|  |             for _ in range(self.popsize): | |||
|  |                 parent1 = self._tournament_selection(population, fitness_scores) | |||
|  |                 parent2 = self._tournament_selection(population, fitness_scores) | |||
|  |                  | |||
|  |                 # 交叉 | |||
|  |                 if np.random.rand() < self.crossover_rate: | |||
|  |                     child = self._crossover(parent1, parent2, param_names) | |||
|  |                 else: | |||
|  |                     child = parent1.copy() | |||
|  |                  | |||
|  |                 # 变异 | |||
|  |                 child = self._mutate(child, param_names) | |||
|  |                 new_population.append(child) | |||
|  |              | |||
|  |             # 评估新种群 | |||
|  |             population = new_population | |||
|  |             fitness_scores = [objective_func(ind, base_predictions) for ind in population] | |||
|  |              | |||
|  |             # 更新最佳个体 | |||
|  |             current_best_idx = np.argmin(fitness_scores) | |||
|  |             current_best_score = fitness_scores[current_best_idx] | |||
|  |              | |||
|  |             if current_best_score < best_score: | |||
|  |                 best_individual = population[current_best_idx].copy() | |||
|  |                 best_score = current_best_score | |||
|  |                 print(f"Generation {generation+1}: New best fitness {best_score:.6f}") | |||
|  |              | |||
|  |             history.append((best_individual.copy(), best_score)) | |||
|  |          | |||
|  |         return OptimizationResult( | |||
|  |             best_params=best_individual, | |||
|  |             best_score=best_score, | |||
|  |             optimization_history=history, | |||
|  |             total_evaluations=self.popsize * (1 + self.generations), | |||
|  |             elapsed_time=time.time() - start_time, | |||
|  |             algorithm="Genetic Algorithm" | |||
|  |         ) | |||
|  |      | |||
|  |     def _tournament_selection(self, population, fitness_scores, tournament_size=3): | |||
|  |         """锦标赛选择""" | |||
|  |         tournament_indices = np.random.choice(len(population), tournament_size, replace=False) | |||
|  |         tournament_fitness = [fitness_scores[i] for i in tournament_indices] | |||
|  |         winner_idx = tournament_indices[np.argmin(tournament_fitness)] | |||
|  |         return population[winner_idx].copy() | |||
|  |      | |||
|  |     def _crossover(self, parent1, parent2, param_names): | |||
|  |         """均匀交叉""" | |||
|  |         child = {} | |||
|  |         for name in param_names: | |||
|  |             if np.random.rand() < 0.5: | |||
|  |                 child[name] = parent1[name] | |||
|  |             else: | |||
|  |                 child[name] = parent2[name] | |||
|  |         return child | |||
|  |      | |||
|  |     def _mutate(self, individual, param_names): | |||
|  |         """高斯变异""" | |||
|  |         mutated = individual.copy() | |||
|  |         for name in param_names: | |||
|  |             if np.random.rand() < self.mutation_rate: | |||
|  |                 low, high = self.bounds[name] | |||
|  |                 # 高斯变异,标准差为范围的10% | |||
|  |                 noise = np.random.normal(0, (high - low) * 0.1) | |||
|  |                 mutated[name] = np.clip(individual[name] + noise, low, high) | |||
|  |         return mutated | |||
|  | 
 | |||
|  | class ParticleSwarmOptimization: | |||
|  |     """粒子群优化算法""" | |||
|  |      | |||
|  |     def __init__(self, bounds, n_particles=30, max_iter=100, w=0.5, c1=1.5, c2=1.5): | |||
|  |         self.bounds = bounds | |||
|  |         self.n_particles = n_particles | |||
|  |         self.max_iter = max_iter | |||
|  |         self.w = w  # 惯性权重 | |||
|  |         self.c1 = c1  # 个体学习因子 | |||
|  |         self.c2 = c2  # 社会学习因子 | |||
|  |      | |||
|  |     def optimize(self, objective_func, base_predictions): | |||
|  |         """运行粒子群优化""" | |||
|  |         print(f"Starting Particle Swarm Optimization (particles={self.n_particles}, iterations={self.max_iter})") | |||
|  |          | |||
|  |         param_names = list(self.bounds.keys()) | |||
|  |         n_params = len(param_names) | |||
|  |          | |||
|  |         start_time = time.time() | |||
|  |          | |||
|  |         # 初始化粒子位置和速度 | |||
|  |         positions = np.zeros((self.n_particles, n_params)) | |||
|  |         velocities = np.zeros((self.n_particles, n_params)) | |||
|  |         personal_best_positions = np.zeros((self.n_particles, n_params)) | |||
|  |         personal_best_scores = np.full(self.n_particles, float('inf')) | |||
|  |          | |||
|  |         # 初始化位置 | |||
|  |         for i in range(n_params): | |||
|  |             low, high = self.bounds[param_names[i]] | |||
|  |             positions[:, i] = np.random.uniform(low, high, self.n_particles) | |||
|  |             velocities[:, i] = np.random.uniform(-abs(high-low)*0.1, abs(high-low)*0.1, self.n_particles) | |||
|  |          | |||
|  |         # 评估初始位置 | |||
|  |         for i in range(self.n_particles): | |||
|  |             params = {param_names[j]: positions[i, j] for j in range(n_params)} | |||
|  |             score = objective_func(params, base_predictions) | |||
|  |              | |||
|  |             personal_best_positions[i] = positions[i].copy() | |||
|  |             personal_best_scores[i] = score | |||
|  |          | |||
|  |         global_best_idx = np.argmin(personal_best_scores) | |||
|  |         global_best_position = personal_best_positions[global_best_idx].copy() | |||
|  |         global_best_score = personal_best_scores[global_best_idx] | |||
|  |          | |||
|  |         print(f"Initial best fitness: {global_best_score:.6f}") | |||
|  |          | |||
|  |         history = [] | |||
|  |          | |||
|  |         for iteration in range(self.max_iter): | |||
|  |             for i in range(self.n_particles): | |||
|  |                 # 更新速度 | |||
|  |                 r1, r2 = np.random.rand(2) | |||
|  |                 velocities[i] = (self.w * velocities[i] +  | |||
|  |                                self.c1 * r1 * (personal_best_positions[i] - positions[i]) + | |||
|  |                                self.c2 * r2 * (global_best_position - positions[i])) | |||
|  |                  | |||
|  |                 # 更新位置 | |||
|  |                 positions[i] += velocities[i] | |||
|  |                  | |||
|  |                 # 边界处理 | |||
|  |                 for j in range(n_params): | |||
|  |                     low, high = self.bounds[param_names[j]] | |||
|  |                     positions[i, j] = np.clip(positions[i, j], low, high) | |||
|  |                  | |||
|  |                 # 评估新位置 | |||
|  |                 params = {param_names[j]: positions[i, j] for j in range(n_params)} | |||
|  |                 score = objective_func(params, base_predictions) | |||
|  |                  | |||
|  |                 # 更新个体最佳 | |||
|  |                 if score < personal_best_scores[i]: | |||
|  |                     personal_best_positions[i] = positions[i].copy() | |||
|  |                     personal_best_scores[i] = score | |||
|  |                      | |||
|  |                     # 更新全局最佳 | |||
|  |                     if score < global_best_score: | |||
|  |                         global_best_position = positions[i].copy() | |||
|  |                         global_best_score = score | |||
|  |                         print(f"Iteration {iteration+1}: New best fitness {global_best_score:.6f}") | |||
|  |              | |||
|  |             history.append((global_best_position.copy(), global_best_score)) | |||
|  |          | |||
|  |         best_params = {param_names[i]: global_best_position[i] for i in range(len(param_names))} | |||
|  |          | |||
|  |         return OptimizationResult( | |||
|  |             best_params=best_params, | |||
|  |             best_score=global_best_score, | |||
|  |             optimization_history=history, | |||
|  |             total_evaluations=self.n_particles * (1 + self.max_iter), | |||
|  |             elapsed_time=time.time() - start_time, | |||
|  |             algorithm="Particle Swarm Optimization" | |||
|  |         ) | |||
|  | 
 | |||
|  | class BayesianOptimization: | |||
|  |     """贝叶斯优化(需要scikit-optimize)""" | |||
|  |      | |||
|  |     def __init__(self, bounds, n_calls=100, n_initial_points=10, acq_func='gp_hedge'): | |||
|  |         self.bounds = bounds | |||
|  |         self.n_calls = n_calls | |||
|  |         self.n_initial_points = n_initial_points | |||
|  |         self.acq_func = acq_func | |||
|  |      | |||
|  |     def optimize(self, objective_func, base_predictions): | |||
|  |         """运行贝叶斯优化""" | |||
|  |         if not SKOPT_AVAILABLE: | |||
|  |             raise ImportError("scikit-optimize is required for Bayesian optimization") | |||
|  |          | |||
|  |         print(f"Starting Bayesian Optimization (calls={self.n_calls}, initial_points={self.n_initial_points})") | |||
|  |          | |||
|  |         param_names = list(self.bounds.keys()) | |||
|  |         dimensions = [Real(self.bounds[name][0], self.bounds[name][1], name=name) for name in param_names] | |||
|  |          | |||
|  |         def objective_wrapper(x): | |||
|  |             params = {param_names[i]: x[i] for i in range(len(x))} | |||
|  |             return objective_func(params, base_predictions) | |||
|  |          | |||
|  |         start_time = time.time() | |||
|  |          | |||
|  |         result = gp_minimize( | |||
|  |             func=objective_wrapper, | |||
|  |             dimensions=dimensions, | |||
|  |             n_calls=self.n_calls, | |||
|  |             n_initial_points=self.n_initial_points, | |||
|  |             acq_func=self.acq_func, | |||
|  |             random_state=42 | |||
|  |         ) | |||
|  |          | |||
|  |         best_params = {param_names[i]: result.x[i] for i in range(len(param_names))} | |||
|  |          | |||
|  |         # 构建历史记录 | |||
|  |         history = [] | |||
|  |         for i in range(len(result.x_iters)): | |||
|  |             params = {param_names[j]: result.x_iters[i][j] for j in range(len(param_names))} | |||
|  |             score = result.func_vals[i] | |||
|  |             history.append((params, score)) | |||
|  |          | |||
|  |         return OptimizationResult( | |||
|  |             best_params=best_params, | |||
|  |             best_score=result.fun, | |||
|  |             optimization_history=history, | |||
|  |             total_evaluations=len(result.x_iters), | |||
|  |             elapsed_time=time.time() - start_time, | |||
|  |             algorithm="Bayesian Optimization" | |||
|  |         ) | |||
|  | 
 | |||
|  | def generate_base_predictions(): | |||
|  |     """生成基础预测结果缓存""" | |||
|  |     print("Generating base predictions cache...") | |||
|  |     # 这里应该调用原始的评估代码来生成所有TTA样本的预测 | |||
|  |     # 为了演示,我们创建一个简单的模拟数据 | |||
|  |      | |||
|  |     cache_file = 'base_predictions_cache.pkl' | |||
|  |     if os.path.exists(cache_file): | |||
|  |         print(f"Cache file {cache_file} already exists.") | |||
|  |         return | |||
|  |      | |||
|  |     # 模拟数据 - 实际使用时应该替换为真实的预测生成代码 | |||
|  |     print("Generating mock base predictions for demonstration...") | |||
|  |      | |||
|  |     n_trials = 10  # 模拟10个试验 | |||
|  |     seq_len = 50   # 序列长度 | |||
|  |     vocab_size = 31  # 词汇表大小 | |||
|  |     n_tta = 5      # TTA样本数 | |||
|  |      | |||
|  |     base_predictions = [] | |||
|  |      | |||
|  |     for trial in range(n_trials): | |||
|  |         # 模拟GRU和LSTM的概率预测 | |||
|  |         gru_probs = np.random.rand(n_tta, seq_len, vocab_size) | |||
|  |         lstm_probs = np.random.rand(n_tta, seq_len, vocab_size) | |||
|  |          | |||
|  |         # 归一化为概率分布 | |||
|  |         gru_probs = gru_probs / np.sum(gru_probs, axis=2, keepdims=True) | |||
|  |         lstm_probs = lstm_probs / np.sum(lstm_probs, axis=2, keepdims=True) | |||
|  |          | |||
|  |         # 模拟真实字符序列 | |||
|  |         true_chars = np.random.randint(0, vocab_size, seq_len) | |||
|  |          | |||
|  |         base_predictions.append({ | |||
|  |             'gru_probs': gru_probs, | |||
|  |             'lstm_probs': lstm_probs, | |||
|  |             'true_chars': true_chars | |||
|  |         }) | |||
|  |      | |||
|  |     # 保存缓存 | |||
|  |     with open(cache_file, 'wb') as f: | |||
|  |         pickle.dump(base_predictions, f) | |||
|  |      | |||
|  |     print(f"Base predictions cache saved to {cache_file}") | |||
|  | 
 | |||
|  | def save_results(results: List[OptimizationResult], output_dir='optimization_results'): | |||
|  |     """保存优化结果""" | |||
|  |     os.makedirs(output_dir, exist_ok=True) | |||
|  |      | |||
|  |     # 保存详细结果 | |||
|  |     for result in results: | |||
|  |         filename = f"{result.algorithm.lower().replace(' ', '_')}_result.json" | |||
|  |         filepath = os.path.join(output_dir, filename) | |||
|  |          | |||
|  |         result_dict = { | |||
|  |             'algorithm': result.algorithm, | |||
|  |             'best_params': result.best_params, | |||
|  |             'best_score': result.best_score, | |||
|  |             'total_evaluations': result.total_evaluations, | |||
|  |             'elapsed_time': result.elapsed_time, | |||
|  |             'optimization_history': [ | |||
|  |                 {'params': params if isinstance(params, dict) else params.tolist(), 'score': score} | |||
|  |                 for params, score in result.optimization_history | |||
|  |             ] | |||
|  |         } | |||
|  |          | |||
|  |         with open(filepath, 'w') as f: | |||
|  |             json.dump(result_dict, f, indent=2) | |||
|  |          | |||
|  |         print(f"Results saved to {filepath}") | |||
|  |      | |||
|  |     # 保存汇总比较 | |||
|  |     summary_file = os.path.join(output_dir, 'optimization_summary.json') | |||
|  |     summary = { | |||
|  |         'comparison': [ | |||
|  |             { | |||
|  |                 'algorithm': result.algorithm, | |||
|  |                 'best_score': result.best_score, | |||
|  |                 'total_evaluations': result.total_evaluations, | |||
|  |                 'elapsed_time': result.elapsed_time, | |||
|  |                 'best_params': result.best_params | |||
|  |             } | |||
|  |             for result in results | |||
|  |         ], | |||
|  |         'best_overall': min(results, key=lambda x: x.best_score).__dict__ | |||
|  |     } | |||
|  |      | |||
|  |     # 处理numpy数组序列化 | |||
|  |     best_overall = summary['best_overall'] | |||
|  |     if hasattr(best_overall['best_params'], 'tolist'): | |||
|  |         best_overall['best_params'] = best_overall['best_params'].tolist() | |||
|  |      | |||
|  |     with open(summary_file, 'w') as f: | |||
|  |         json.dump(summary, f, indent=2, default=str) | |||
|  |      | |||
|  |     print(f"Summary saved to {summary_file}") | |||
|  | 
 | |||
|  | def main(): | |||
|  |     parser = argparse.ArgumentParser(description='Advanced Parameter Optimization for TTA-E') | |||
|  |     parser.add_argument('--algorithms', type=str, nargs='+',  | |||
|  |                        default=['de', 'ga', 'pso'], | |||
|  |                        choices=['de', 'ga', 'pso', 'bayes', 'all'], | |||
|  |                        help='Optimization algorithms to run') | |||
|  |     parser.add_argument('--generate_cache', action='store_true', | |||
|  |                        help='Generate base predictions cache') | |||
|  |     parser.add_argument('--cache_file', type=str, default='base_predictions_cache.pkl', | |||
|  |                        help='Base predictions cache file') | |||
|  |     parser.add_argument('--output_dir', type=str, default='optimization_results', | |||
|  |                        help='Output directory for results') | |||
|  |      | |||
|  |     # 算法特定参数 | |||
|  |     parser.add_argument('--de_popsize', type=int, default=15, help='DE population size') | |||
|  |     parser.add_argument('--de_maxiter', type=int, default=50, help='DE max iterations') | |||
|  |     parser.add_argument('--ga_popsize', type=int, default=30, help='GA population size') | |||
|  |     parser.add_argument('--ga_generations', type=int, default=50, help='GA generations') | |||
|  |     parser.add_argument('--pso_particles', type=int, default=20, help='PSO particle count') | |||
|  |     parser.add_argument('--pso_iterations', type=int, default=50, help='PSO iterations') | |||
|  |     parser.add_argument('--bayes_calls', type=int, default=100, help='Bayesian optimization calls') | |||
|  |      | |||
|  |     args = parser.parse_args() | |||
|  |      | |||
|  |     # 生成缓存(如果需要) | |||
|  |     if args.generate_cache: | |||
|  |         generate_base_predictions() | |||
|  |         return | |||
|  |      | |||
|  |     # 加载基础预测 | |||
|  |     base_predictions = load_base_predictions(args.cache_file) | |||
|  |     if base_predictions is None: | |||
|  |         print("Please run with --generate_cache first to create base predictions") | |||
|  |         return | |||
|  |      | |||
|  |     # 定义参数边界 | |||
|  |     bounds = { | |||
|  |         'tta_weight_0': (0.0, 2.0),  # 原始 | |||
|  |         'tta_weight_1': (0.0, 2.0),  # 噪声 | |||
|  |         'tta_weight_2': (0.0, 2.0),  # 缩放 | |||
|  |         'tta_weight_3': (0.0, 2.0),  # 偏移 | |||
|  |         'tta_weight_4': (0.0, 2.0),  # 平滑 | |||
|  |         'gru_weight': (0.0, 1.0)     # GRU权重 | |||
|  |     } | |||
|  |      | |||
|  |     # 处理算法选择 | |||
|  |     if 'all' in args.algorithms: | |||
|  |         algorithms_to_run = ['de', 'ga', 'pso'] | |||
|  |         if SKOPT_AVAILABLE: | |||
|  |             algorithms_to_run.append('bayes') | |||
|  |     else: | |||
|  |         algorithms_to_run = args.algorithms | |||
|  |      | |||
|  |     # 运行优化算法 | |||
|  |     results = [] | |||
|  |      | |||
|  |     for algo in algorithms_to_run: | |||
|  |         print(f"\n{'='*60}") | |||
|  |         print(f"Running {algo.upper()} optimization...") | |||
|  |         print(f"{'='*60}") | |||
|  |          | |||
|  |         try: | |||
|  |             if algo == 'de': | |||
|  |                 optimizer = DifferentialEvolution( | |||
|  |                     bounds=bounds, | |||
|  |                     popsize=args.de_popsize, | |||
|  |                     maxiter=args.de_maxiter | |||
|  |                 ) | |||
|  |             elif algo == 'ga': | |||
|  |                 optimizer = GeneticAlgorithm( | |||
|  |                     bounds=bounds, | |||
|  |                     popsize=args.ga_popsize, | |||
|  |                     generations=args.ga_generations | |||
|  |                 ) | |||
|  |             elif algo == 'pso': | |||
|  |                 optimizer = ParticleSwarmOptimization( | |||
|  |                     bounds=bounds, | |||
|  |                     n_particles=args.pso_particles, | |||
|  |                     max_iter=args.pso_iterations | |||
|  |                 ) | |||
|  |             elif algo == 'bayes': | |||
|  |                 if not SKOPT_AVAILABLE: | |||
|  |                     print("Skipping Bayesian optimization (scikit-optimize not available)") | |||
|  |                     continue | |||
|  |                 optimizer = BayesianOptimization( | |||
|  |                     bounds=bounds, | |||
|  |                     n_calls=args.bayes_calls | |||
|  |                 ) | |||
|  |             else: | |||
|  |                 print(f"Unknown algorithm: {algo}") | |||
|  |                 continue | |||
|  |              | |||
|  |             result = optimizer.optimize(evaluate_config_gpu, base_predictions) | |||
|  |             results.append(result) | |||
|  |              | |||
|  |             print(f"\n{result.algorithm} Results:") | |||
|  |             print(f"Best Score: {result.best_score:.6f}") | |||
|  |             print(f"Best Parameters: {result.best_params}") | |||
|  |             print(f"Total Evaluations: {result.total_evaluations}") | |||
|  |             print(f"Elapsed Time: {result.elapsed_time:.2f}s") | |||
|  |              | |||
|  |         except Exception as e: | |||
|  |             print(f"Error running {algo}: {e}") | |||
|  |             continue | |||
|  |      | |||
|  |     # 保存结果 | |||
|  |     if results: | |||
|  |         save_results(results, args.output_dir) | |||
|  |          | |||
|  |         print(f"\n{'='*60}") | |||
|  |         print("FINAL COMPARISON") | |||
|  |         print(f"{'='*60}") | |||
|  |          | |||
|  |         # 按分数排序 | |||
|  |         results.sort(key=lambda x: x.best_score) | |||
|  |          | |||
|  |         for i, result in enumerate(results, 1): | |||
|  |             print(f"{i}. {result.algorithm}") | |||
|  |             print(f"   Score: {result.best_score:.6f}") | |||
|  |             print(f"   Time: {result.elapsed_time:.2f}s") | |||
|  |             print(f"   Evaluations: {result.total_evaluations}") | |||
|  |             print(f"   Parameters: {result.best_params}") | |||
|  |             print() | |||
|  |          | |||
|  |         print(f"Best overall: {results[0].algorithm} with score {results[0].best_score:.6f}") | |||
|  | 
 | |||
|  | if __name__ == '__main__': | |||
|  |     main() |