活动介绍
file-type

优化Switch语句性能的编译技巧

版权申诉
4KB | 更新于2024-11-03 | 151 浏览量 | 0 下载量 举报 收藏
download 限时特惠:#14.90
1. 编译器与解释器的区别和联系: 编译器( Compiler)是一种将高级语言或脚本语言翻译成机器语言的程序。它的工作过程通常包括词法分析、语法分析、语义分析、代码优化和目标代码生成等几个阶段。编译器生成的是目标计算机上可直接运行的可执行文件。 解释器(Interpreter)则是逐行解释执行源代码,不需要像编译器那样生成可执行文件。解释执行通常更慢,因为每行代码都需要解释器解释执行,但其优点在于跨平台性好和易于调试。 在C/C++开发中,编译器如GCC和Clang等更为常见,因为C/C++通常需要编译成机器码运行,以获得更高的执行效率。解释器则更多用于脚本语言如Python、Ruby和JavaScript等。 2. Switch语句的底层实现: Switch语句在C/C++中常用于基于不同的条件执行不同的代码分支。编译器会根据switch的使用情况,选择不同的优化策略将其转化成底层代码。 其中最常见的优化策略有两种:跳转表(Jump Table)和比较链(或比较树)。 跳转表是一种索引表,编译器会为每个case生成一个表项,通过计算偏移量来实现快速跳转。这种方法在case数量较多且值连续时特别有效。 比较链则是编译器基于if-else-if嵌套逻辑构建的分支结构。在这种方式中,程序会顺序地比较每个case的值,并在找到匹配的条件时执行相应的代码分支。 这两种策略各有利弊,通常情况下,编译器会根据case的数量、值的分布和连续性等因素来选择最优的实现方式。 3. Switch语句性能优化技巧: 在Switch语句中,由于if-else-if的比较链是从上到下顺序执行的,因此可以通过合理安排case值的顺序来提高执行效率。将最可能发生的case放在比较链的最前面,可以减少执行分支判断的次数,从而提高程序性能。 例如,如果case 1是最常见的分支,那么应该将case 1放在switch语句的最顶端,这样编译器生成的比较链就会首先比较这个值,从而加快执行速度。 4. C/C++编译器优化选项: 许多C/C++编译器都提供了优化选项,允许开发者针对不同的编译需求进行代码优化。开发者可以使用-O(数字)选项来指定优化的级别,例如使用-O1、-O2、-O3等来开启不同程度的优化。 优化选项会指导编译器如何处理代码,例如代码重排、循环展开、内联函数等。这些优化有助于提升程序的执行速度和内存使用效率,但同时也可能增加编译时间。 5. C/C++编译器实例: C/C++编译器种类繁多,一些常见的编译器包括GCC(GNU Compiler Collection)、Clang、MSVC(Microsoft Visual C++)、Intel C++ Compiler(ICC)和Embarcadero C++ Builder等。 这些编译器提供了丰富的命令行选项和配置参数,允许开发者针对不同的编译环境和性能需求进行定制化编译。例如,GCC和Clang支持广泛的优化选项,开发者可以根据需要调整编译器的行为以获得最佳的性能表现。 总结: 在C/C++编程中,合理地使用Switch语句并对其进行性能优化是一项重要的技能。理解编译器如何将Switch语句转换为机器码,以及如何通过排序case值来优化性能,对编写高效的程序至关重要。此外,掌握编译器的优化选项和熟悉各种编译器的特性,可以帮助开发者编写出既快速又可靠的应用程序。

相关推荐

filetype
filetype

import pandas as pd import numpy as np from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.metrics import r2_score, mean_squared_error, mean_absolute_error from tensorflow.keras.models import load_model from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, Callback from tensorflow.keras.optimizers import Adam from tensorflow.keras.regularizers import l2 import matplotlib.pyplot as plt import os import gc from tensorflow.keras import backend as K from tensorflow.keras.layers import Dense # 添加这一行 # 1. 定义数据加载与预处理函数 # 该函数负责读取数据文件、进行特征选择、数据标准化以及数据集划分等操作 def load_and_preprocess_data(file_path): data = pd.read_excel(file_path) x = data[['t1', 't2', 'G1', 'G2', 'DAl2O3', 'CI', 'CA', 'ZETA', 'JD']] y = data['RV'] scaler_x = StandardScaler() # 初始化标准化器,StandardScaler为z-score标准化工具 x_scaled = scaler_x.fit_transform(x) # 对特征数据进行标准化处理.scaler_x和scaler_y分别保存了特征数据和响应数据在标准化过程中的均值和标准差。 scaler_y = StandardScaler() y_scaled = scaler_y.fit_transform(y.values.reshape(-1, 1)) # 对响应值进行标准化处理 # 先划分出训练集和临时集(包含验证集和测试集) x_train, x_temp, y_train, y_temp = train_test_split( x_scaled, y_scaled, test_size=0.2, random_state=42) # 再从临时集中划分出验证集和测试集 x_val, x_test, y_val, y_test = train_test_split( x_temp, y_temp, test_size=0.5, random_state=42) print("初始参数scaler_x:", scaler_x.mean_, scaler_x.scale_) print("初始参数scaler_y:", scaler_y.mean_, scaler_y.scale_) return x_train, x_val, x_test, y_train, y_val, y_test, scaler_x, scaler_y # scaler_x, scaler_y为标准化器,以便后续进行反标准化操作 # 3. 自定义回调类用于计算额外指标 # 此自定义回调类用于在每个训练周期结束时计算额外的评估指标,由于后续的训练函数会用到该类,所以将其定义在前面是合适的。 class CustomMetricsCallback(Callback): def __init__(self, x_train, y_train, x_val, y_val, scaler_x, scaler_y): super().__init__() self.X_train = x_train[:] # 使用内存视图 self.y_train = y_train[:] self.X_val = x_val[:] self.y_val = y_val[:] self.scaler_x = scaler_x # 保存 scaler_x 作为类的实例变量 self.scaler_y = scaler_y def on_epoch_end(self, epoch, logs=None): # 处理训练集 y_pred_train = self.model.predict(self.X_train, verbose=0) # 训练集预测 y_train_true = self.y_train.squeeze() y_train_pred = y_pred_train.squeeze() # 反标准化 y_train_true_unscaled = self.scaler_y.inverse_transform(y_train_true.reshape(-1, 1)).squeeze() y_train_pred_unscaled = self.scaler_y.inverse_transform(y_train_pred.reshape(-1, 1)).squeeze() # 打印 scaler_x 和 scaler_y的均值和标准差 print(f"训练{epoch}参数scaler_x:", self.scaler_x.mean_, self.scaler_x.scale_) # 使用 self.scaler_x print(f"训练{epoch}参数scaler_y:", self.scaler_y.mean_, self.scaler_y.scale_) # 计算训练集指标 train_rmse_unscaled = np.sqrt(mean_squared_error(y_train_true_unscaled, y_train_pred_unscaled)) train_true_mean_unscaled = np.mean(y_train_true_unscaled) train_rmse_percentage_unscaled = (train_rmse_unscaled / train_true_mean_unscaled) * 100 train_r2_unscaled = r2_score(y_train_true_unscaled, y_train_pred_unscaled) train_d_unscaled = 1 - (np.sum((y_train_pred_unscaled - y_train_true_unscaled) ** 2) / np.sum((np.abs(y_train_pred_unscaled - np.mean(y_train_true_unscaled)) + np.abs(y_train_true_unscaled - np.mean(y_train_true_unscaled))) ** 2)) print( f"Epoch {epoch + 1}: Train RMSE_unscaled = {train_rmse_unscaled:.4f}, Train True Mean_unscaled = {train_true_mean_unscaled:.4f}") # 将计算结果加入 logs 中 logs['rmse'] = train_rmse_unscaled logs['rmse%'] = train_rmse_percentage_unscaled logs['r2'] = train_r2_unscaled logs['d'] = train_d_unscaled # 添加 loss 和 mae 到 logs 中 logs['loss'] = logs.get('loss', 0) logs['mae'] = logs.get('mae', 0) # 处理验证集 y_pred_val = self.model.predict(self.X_val, verbose=0) y_val_true = self.y_val.squeeze() y_val_pred = y_pred_val.squeeze() # 反标准化 y_val_true_unscaled = self.scaler_y.inverse_transform(y_val_true.reshape(-1, 1)).squeeze() y_val_pred_unscaled = self.scaler_y.inverse_transform(y_val_pred.reshape(-1, 1)).squeeze() # 计算验证集指标 val_rmse_unscaled = np.sqrt(mean_squared_error(y_val_true_unscaled, y_val_pred_unscaled)) val_measured_mean_unscaled = np.mean(y_val_true_unscaled) val_rmse_percentage_unscaled = (val_rmse_unscaled / val_measured_mean_unscaled) * 100 val_r2_unscaled = r2_score(y_val_true_unscaled, y_val_pred_unscaled) val_d_unscaled = 1 - (np.sum((y_val_pred - y_val_true) ** 2) / np.sum((np.abs(y_val_pred - np.mean(y_val_true)) + np.abs(y_val_true - np.mean(y_val_true))) ** 2)) print( f"Epoch {epoch + 1}: Val RMSE_unscaled = {val_rmse_unscaled:.4f}, Val True Mean_unscaled = {val_measured_mean_unscaled:.4f}") logs['val_rmse'] = val_rmse_unscaled logs['val_rmse%'] = val_rmse_percentage_unscaled logs['val_r2'] = val_r2_unscaled logs['val_d'] = val_d_unscaled # 4. 训练模型 # 通过 load_model 函数加载一个已保存的模型。这个模型是经过之前训练过程保存的,所以加载时,超参数以及模型的架构、权重都会被一起加载。具体来说,load_model 会加载以下信息: # 模型的架构 # 模型的训练权重(通过训练过程中的优化) # 所有的训练配置,包括超参数(如学习率、批量大小、正则化等),这些配置可能在训练时通过模型的编译过程设置,并且它们会随着模型一起保存。 def train_model(model, x_train, y_train, x_val, y_val, scaler_x, scaler_y, run_num): checkpoint = ModelCheckpoint( f'bestmodel.h5', # 修改文件名, # 每次验证集损失出现新的最小值时,模型就会被保存到指定路径 monitor='val_loss', # 监控验证集损失 save_best_only=True, # 只保存验证集损失最小的模型 verbose=1 ) # 验证集发挥作用:防止训练过程中模型过拟合 early_stopping = EarlyStopping( monitor='val_loss', patience=15, # EarlyStopping 的 patience 并不会直接从模型文件中继承。patience 是 EarlyStopping 回调的超参数,而回调函数并不会自动从模型加载的配置中获取这些超参数。因此,需要手动设置。 restore_best_weights=True, # 当训练停止时,会将模型的参数恢复到验证集损失最小的那个周期的参数,防止过拟合的模型被使用 verbose=1 ) custom_metrics = CustomMetricsCallback(x_train, y_train, x_val, y_val, scaler_x, scaler_y) # history保存模型在训练过程中的详细信息:训练过程中训练集和验证集的loss值 history = model.fit( x_train, y_train, validation_data=(x_val, y_val), epochs=1000, batch_size=8, callbacks=[checkpoint, early_stopping, custom_metrics], verbose=1 ) return history # 5. 测试阶段--预测和评估 def evaluate_and_visualize(model, history, x_test, y_test, best_test_rmse, scaler_x, scaler_y): # 预测测试集 y_pred = model.predict(x_test) # 得到测试集的真实值和预测值 y_test_true = y_test.squeeze() y_test_pred = y_pred.squeeze() # 反标准化 y_test_true_unscaled = scaler_y.inverse_transform(y_test_true.reshape(-1, 1)).squeeze() y_test_pred_unscaled = scaler_y.inverse_transform(y_test_pred.reshape(-1, 1)).squeeze() print("测试参数scaler_x:", scaler_x.mean_, scaler_x.scale_) print("测试参数scaler_y:", scaler_y.mean_, scaler_y.scale_) # 计算测试集的所有指标,用于决定 test_mse_unscaled = mean_squared_error(y_test_true_unscaled, y_test_pred_unscaled) test_mae_unscaled = mean_absolute_error(y_test_true_unscaled, y_test_pred_unscaled) test_rmse_unscaled = np.sqrt(test_mse_unscaled) test_measured_mean_unscaled = np.mean(y_test_true_unscaled) test_rmse_percentage_unscaled = test_mse_unscaled / test_measured_mean_unscaled * 100 test_r2_unscaled = r2_score(y_test_true_unscaled, y_test_pred_unscaled) test_d = 1 - (np.sum((y_test_pred_unscaled - y_test_true_unscaled) ** 2) / np.sum((np.abs(y_test_pred_unscaled - np.mean(y_test_true_unscaled)) + np.abs(y_test_pred_unscaled - np.mean(y_test_true_unscaled))) ** 2)) # 如果测试集的rmse比以往的都要小 if test_rmse_unscaled < best_test_rmse: best_test_rmse = test_rmse_unscaled # 保存当前最优模型 model.save('final-bestmodel.h5') # 保存当前最优模型的各项训练过程指标数据 train_metrics = history.history # history.history是字典,键是指标名称,值是对应指标在每个训练周期的值的列表 epochs = range(1, len(train_metrics['loss']) + 1) train_metrics['Epoch'] = epochs # 指定列顺序 column_order = ['Epoch', 'loss', 'val_loss', 'mae', 'val_mae', 'mse', 'val_mse', 'r2', 'val_r2', 'd', 'val_d', 'rmse', 'val_rmse', 'rmse%', 'val_rmse%'] train_metrics_df = pd.DataFrame(train_metrics)[column_order] train_metrics_df.to_csv(f'final-train_metrics.csv', index=False) # 保存测试集数据,添加测试集指标 test_metrics = { '指标': ['test_R2', 'test_MSE', 'test_MAE', 'test_RMSE', 'test_RMSE%', "test_Willmott's d"], '值': [test_r2_unscaled, test_mse_unscaled, test_mae_unscaled, test_rmse_unscaled, test_rmse_percentage_unscaled, test_d] } test_metrics_df = pd.DataFrame(test_metrics) test_data_df = pd.DataFrame({ 'Experimental Data': y_test_true_unscaled, 'Predicted Value': y_test_pred_unscaled }) with open(f'final-test_data.csv', 'w', newline='') as f: test_metrics_df.to_csv(f, index=False) f.write('\n') test_data_df.to_csv(f, index=False) # 保存模型结构信息到 CSV 文件 model_structure = [] for layer in model.layers: if isinstance(layer, Dense): layer_info = { 'Layer Type': 'Dense', 'Number of Neurons': layer.units, 'Activation Function': layer.activation.__name__ } model_structure.append(layer_info) model_structure_df = pd.DataFrame(model_structure) model_structure_df.to_csv(f'final-model-structure.csv', index=False) # 绘制训练过程指标 plt.figure(figsize=(20, 12)) # 定义要绘制的训练和验证指标,第一列是键名,第二列是该指标在可视化图表中的标题 metrics = [ ('loss', 'Loss'), ('mse', 'MSE'), ('rmse', 'RMSE'), ('rmse%', 'RMSE%'), ('r2', 'R²'), ('d', "Willmott's d"), ] epochs = range(1, len(history.history['loss']) + 1) for i, (metric, title) in enumerate(metrics, 1): plt.subplot(2, 4, i) if metric: plt.plot(epochs, history.history[metric], label=f'Train {title}') plt.plot(epochs, history.history[f'val_{metric}'], label=f'Val {title}') plt.title(f'{title} Evolution') plt.ylabel(title) plt.xlabel('Epoch') plt.legend() plt.grid(True) # 单独绘制点线图到第七个子图:测试集的真实值和预测值的点线图 plt.subplot(2, 4, 7) sorted_indices = np.argsort(y_test_true_unscaled) plt.plot(y_test_true_unscaled[sorted_indices], label='True Value', marker='o') plt.plot(y_test_pred_unscaled[sorted_indices], label='Predicted Value', marker='o') plt.xlabel('Sample Index') plt.ylabel('Value') plt.title('True vs Predicted Values (Line Plot)') plt.legend() plt.grid(True) # 单独绘制散点图到第八个子图:测试集的真实值和预测值的线性拟合图,含R2 plt.subplot(2, 4, 8) plt.scatter(y_test_true_unscaled, y_test_pred_unscaled, alpha=0.6) plt.plot([y_test_true_unscaled.min(), y_test_true_unscaled.max()], [y_test_true_unscaled.min(), y_test_true_unscaled.max()], 'k--', lw=2) plt.xlabel('Experimental Data') plt.ylabel('Predicted Value') plt.title(f'Experimental vs Predicted (test_R²={test_r2_unscaled:.3f})') plt.tight_layout() plt.savefig(f'final-training_plot.png') # 保存png图片 plt.close() # 确保无论如何都会执行清理 K.clear_session() del model # 确保在不再需要模型对象时,彻底切断对它的所有引用 gc.collect() return test_r2_unscaled, best_test_rmse # 6. 定义主函数 # main函数是程序的入口,它按照顺序调用前面定义的函数,依次完成数据加载、模型构建、训练、评估和可视化等操作,最后输出每个神经元组合的最佳模型信息并保存相关文件 def main(): file_path = "dataAl-paixu.xlsx" num_runs = 1 # final模型的大训练次数 # 加载数据,划分好训练集、验证集和测试集 x_train, x_val, x_test, y_train, y_val, y_test, scaler_x, scaler_y = load_and_preprocess_data(file_path) # 根据大训练次数进行循环 best_test_rmse = float('inf') # 每个神经元组合开始时,将best_test_rmse初始化为正无穷 for run_num in range(1, num_runs + 1): print(f"\n开始第 {run_num} 次大训练...") try: # 尝试加载已训练好的模型 model = load_model('bestmodel_lr_0.001_bs_5_reg_l1_0.01_patience_30.h5') optimizer = Adam(learning_rate=0.00025) model.compile(optimizer=optimizer, loss='mse', metrics=['mae', 'mse'] # 指定在训练和评估过程中要监控的指标,包括训练集和验证集的mae和mse ) print("成功加载已训练好的模型。") except Exception: print("未找到已训练好的模型,将重新开始训练。") # 这里如果不需要重新构建模型,可以直接跳过 continue # 调用 train_model 函数,使用前面加载的模型(model)对训练集数据(x_train 和 y_train)进行训练,并在验证集数据(x_val 和 y_val)上进行验证 # history 包含了训练过程中的各种指标(如损失值、评估指标等)随训练轮数的变化情况 history = train_model(model, x_train, y_train, x_val, y_val, scaler_y, scaler_y, run_num) # 打印loss和mse值 print("Loss:", history.history['loss'][0]) print("MSE:", history.history['mse'][0]) # 对训练好的模型(model)在测试集数据(x_test 和 y_test)上进行评估,并进行可视化展示,history用于绘制模型训练过程中记录的各项指标变化过程 test_r2, best_test_rmse = evaluate_and_visualize(model, history, x_test, y_test, best_test_rmse, scaler_y, scaler_y) history = None # 及时清理 history 对象 # 释放当前大循环相关数据 del model, test_r2 gc.collect() print(f"\n已清理本次大循环的内存占用") # 在所有循环结束后再进行数据对象的清理 del x_train, x_val, x_test, y_train, y_val, y_test, scaler_x, scaler_y gc.collect() K.clear_session() # 7. 程序入口 # 确保只有在直接运行该脚本时才会执行main函数,是 Python 脚本的常见做法。 if __name__ == "__main__": main() 这段代码的初始参数scaler_x: [ 1.64 19.8 194.74924818 6.97009447 20.023875 0.88624117 70.7951176 -66.99666667 57.4 ] [ 0.48 5.82752091 61.86222321 4.18697263 4.5545304 0.14119498 28.24787447 18.99195707 8.2 ] 初始参数scaler_y: [77.61059223] [20.30024049],但是训练0参数scaler_x: [77.61059223] [20.30024049] 训练0参数scaler_y: [77.61059223] [20.30024049],且测试参数scaler_x: [77.61059223] [20.30024049] 测试参数scaler_y: [77.61059223] [20.30024049] 这是为什么?

filetype
pudn01
  • 粉丝: 55
上传资源 快速赚钱