一、实验目的
学习利用遗传算法实现决策融合,将遗传算法分别和支持向量机、神经网络进行融合。利用遗传算法能够搜索其他网络模型最优解的特性,获取支持向量机的最佳参数和多层感知机网络的最佳神经元数量。在分别获得两个网络的最佳参数和神经元数量后,再将支持向量机算法与神经网络算法进行融合,形成融合式的SVM+MLP网络模型,以达到弥补支持向量机算法不足,获得更好识别结果。通过以下两种数据集对算法进行验证:
- 根鸢尾花数据集包含了三种不同品种的鸢尾花(山鸢尾、变色鸢尾和维吉尼亚鸢尾)的样本,每个样本有四个特征:花萼长度、花萼宽度、花瓣长度和花瓣宽度。每个样本都被标记为属于三个种类中的一个,属于一个三分类问题。
- 红酒数据集包含了三种不同品种的红酒,每个样本有十三个特征,也属于一种三分类问题。
二、实验设备及软件
软件使用Google Cloaboratory的Jupyter笔记,硬件计算单元NAVIDA T4云GPU,编程语言Python。
三、实验原理
遗传算法是一种启发式优化算法,它模拟了自然界中的遗传和进化过程,通过对候选解的适应性评估和遗传操作(初始化种群、选择、交叉和变异)来搜索最优解。
算法融合的方法有很多种:
- 投票(Voting):对多个模型的预测结果进行投票,通常分为硬投票和软投票两种。
- 平均(Averaging):对多个模型的预测结果进行平均,可以是简单的算术平均或加权平均。
- 堆叠(Stacking):将多个模型的预测结果作为输入特征,再训练一个元模型(meta-model)进行最终的预测。这种方法需要将原始数据集划分为训练集和验证集,分别用于训练基模型和元模型。
- 加权融合(Weighted Fusion):对多个模型的预测结果进行加权融合,通过为每个模型分配权重来组合它们的预测结果。
- 贝叶斯模型融合(Bayesian Model Averaging):基于贝叶斯理论,通过对多个模型的预测结果进行加权平均,其中权重是根据模型在验证集上的表现进行计算的。
这些融合方法的原理在于,通过结合不同模型的预测结果,可以弥补单个模型的局限性,提高整体预测性能。本次实验选用较为简单的堆叠方式,进行实验。
四、实验步骤及程序源码
1、实验步骤
(1)通过遗传算法获取SVM最优参数和MLP最佳神经元数量
- 确定适应度函数:使用了SVM模型,其中kernel、C和gamma是需要优化的参数。使用MLP神经网络模型,其中神经元数量是需要优化的参数。
- 初始化种群:随机生成一定数量的个体作为初始种群。
- 选择:根据适应度函数,选择一部分个体作为下一代的父代。
- 交叉:对父代进行交叉操作,生成新的个体。
- 变异:对新的个体进行变异操作,引入新的基因。
- 评估:计算新个体的适应度值。
- 选择:根据适应度函数,选择一部分个体作为下一代的父代。
- 迭代:重复执行交叉、变异、评估和选择步骤,直到满足终止条件。
- 输出最优解:输出适应度值最高的个体作为最优解。
(2) 通过堆叠方法实现SVM与MLP神经网络的融合
- 准备不同的预测模型:首先需要准备不同的预测模型,将SVM的参数设置为通过遗传算法获得的最优参数,MLP神经网络模型的神经元个数设置成通过遗传算法获得的最佳神经元个数。
- SVM模型行训练:使用数据集的训练数据对SVM模型进行训练,得到SVM预测模型。
- MLP模型训练:使用堆叠的学习方法,将SVM模型的预测结果结果作为输入特征,输入到神经网络模型中,获得最终的SVM+MLP融合模型。
- 模型评估:对融合式预测模型进行评估。
2、实验程序源码
(1)iris数据集实验
通过遗传算法获取SVM最优参数:
from google.colab import drive drive.mount('/content/drive')
gpu_info = !nvidia-smi gpu_info = ' '.join(gpu_info) if gpu_info.find('failed') >= 0: print('Not connected to a GPU') else: print(gpu_info)
import array import pandas as pd from sklearn import datasets from sklearn.model_selection import train_test_split from sklearn.svm import SVC from sklearn.metrics import accuracy_score import random import numpy as np # 加载iris数据集 data_path = '/content/drive/MyDrive/大数据与信息融合实验/SVM-CNN-遗传算法/iris.xlsx' data = pd.read_excel(data_path,header=None) data=data.values print(data) print(data.shape) X,y = np.split(data,(4,),axis=1) # 定义适应度函数 def fitness_function(params): kernel = params['kernel'] C = params['C'] gamma = params['gamma'] model = SVC(kernel=kernel, C=C, gamma=gamma) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1) model.fit(X_train, y_train.ravel()) y_pred = model.predict(X_test) return accuracy_score(y_test, y_pred) # 初始化种群 def initialize_population(population_size): population = [] for _ in range(population_size): params = { 'kernel': random.choice(['linear', 'poly', 'rbf', 'sigmoid']), 'C': random.uniform(0.1, 10.0), 'gamma': random.uniform(0.1, 10.0) } population.append(params) return population # 选择操作 def selection(population, fitness_values): return random.choices(population, weights=fitness_values, k=2) # 交叉操作 def crossover(parent1, parent2): child = {} for key in parent1: if random.random() < 0.5: child[key] = parent1[key] else: child[key] = parent2[key] return child # 变异操作 def mutation(params, mutation_rate): for key in params: if random.random() < mutation_rate: if key == 'kernel': params[key] = random.choice(['linear', 'poly', 'rbf', 'sigmoid']) else: params[key] = random.uniform(0.1, 10.0) if key == 'C' else random.uniform(0.1, 10.0) return params # 遗传算法迭代 population_size = 50 mutation_rate = 0.1 num_generations = 200 population = initialize_population(population_size) for generation in range(num_generations): fitness_values = [fitness_function(params) for params in population] new_population = [] for _ in range(population_size // 2): parent1, parent2 = selection(population, fitness_values) child = crossover(parent1, parent2) child = mutation(child, mutation_rate) new_population.append(child) population = new_population best_params = max(population, key=fitness_function) print("最佳超参数:", best_params)
通过遗传算法获取MLP最佳神经元数量:
import random from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split import tensorflow as tf from tensorflow import keras import array import pandas as pd import numpy as np # 加载数据集 data_path = '/content/drive/MyDrive/大数据与信息融合实验/SVM-CNN-遗传算法/iris.xlsx' data = pd.read_excel(data_path,header=None) data=data.values print(data) print(data.shape) X,y = np.split(data,(4,),axis=1) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1) # 创建神经网络模型 def create_neural_network(num_hidden_units): model = keras.Sequential([ keras.layers.Dense(num_hidden_units, input_dim=4, activation='relu'), keras.layers.Dense(num_hidden_units, activation="relu"), keras.layers.Dense(3, activation='softmax') ]) model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']) return model # 适应度函数:使用神经网络进行训练和评估 def fitness_function(num_hidden_units): model = create_neural_network(num_hidden_units) model.fit(X_train, y_train, epochs=100, verbose=0) test_loss, test_accuracy = model.evaluate(X_test, y_test, verbose=0) return test_accuracy # 遗传算法 population_size = 50 num_generations = 200 mutation_rate = 0.1 # 初始化种群 population = [random.randint(5, 20) for _ in range(population_size)] # 遗传算法迭代 for generation in range(num_generations): # 计算适应度 fitness_values = [fitness_function(params) for params in population] # 选择操作 selected_parents = random.choices(population, weights=fitness_values, k=2) # 交叉操作 crossover_point = random.randint(0, 1) child = [selected_parents[crossover_point], selected_parents[1 - crossover_point]] # 变异操作 if random.random() < mutation_rate: mutation_point = random.randint(0, population_size - 1) population[mutation_point] = random.randint(5, 20) best_num_hidden_units = population[fitness_values.index(max(fitness_values))] print("最佳隐藏层神经元数量:", best_num_hidden_units) # 使用最佳参数训练最终模型 best_model = create_neural_network(best_num_hidden_units) best_model.fit(X_train, y_train, epochs=100, verbose=0) test_loss, test_accuracy = best_model.evaluate(X_test, y_test, verbose=0) print("最终测试集准确率:", test_accuracy)
通过堆叠方法实现SVM与MLP神经网络的融合,将MLP模型输出作为SVM输入:
# 输出模型评估报告 cnn_output = model.predict(train_X) cnn_y_pred=model.predict(test_X) print('Accuracy score:', accuracy_score(test_y_ohe.argmax(axis=1), cnn_y_pred.argmax(axis=1))) print(classification_report(test_y_ohe.argmax(axis=1), cnn_y_pred.argmax(axis=1)))
# 3.训练SVM模型 train(clf,cnn_output,train_y)
(2)wine数据集实验
通过遗传算法获取SVM最优参数,部分代码做如下修改:
data_path = '/content/drive/MyDrive/大数据与信息融合实验/SVM-CNN-遗传算法/wine.xlsx' y,X = np.split(data,(1,),axis=1)
通过遗传算法获取MLP最佳神经元数量,部分代码做如下修改:
# 加载数据集 data_path = '/content/drive/MyDrive/大数据与信息融合实验/SVM-CNN-遗传算法/wine.xlsx' y,X = np.split(data,(1,),axis=1) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1) # 创建神经网络模型 def create_neural_network(num_hidden_units): model = keras.Sequential([ keras.layers.Dense(num_hidden_units, input_dim=13, activation='relu'), tf.keras.layers.Dense(num_hidden_units, activation="relu"), keras.layers.Dense(3, activation='softmax') ]) model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']) return model
五、实验结果与分析
1、实验结果
(1)iris数据集结果
# 利用sequential方式构建模型 model = tf.keras.models.Sequential([ # 隐藏层1,激活函数是relu,输入大小有input_shape指定 tf.keras.layers.Dense(15, activation="relu", input_shape=(4,)), # 隐藏层2,激活函数是relu tf.keras.layers.Dense(15, activation="relu"), # 输出层 tf.keras.layers.Dense(3, activation="softmax") ])
#**********************SVM分类器构建************************* def classifier(): clf = svm.SVC(C= 1.8622949295567133,kernel='rbf',gamma=6.353234754941822,decision_function_shape='ovo') return clf
(2)wine数据集结果
# 利用sequential方式构建模型 model = tf.keras.models.Sequential([ # 隐藏层1,激活函数是relu,输入大小有input_shape指定 tf.keras.layers.Dense(20, activation="relu", input_shape=(13,)), # 隐藏层2,激活函数是relu tf.keras.layers.Dense(20, activation="relu"), # 输出层 tf.keras.layers.Dense(3, activation="softmax") ])
#**********************SVM分类器构建************************* def classifier(): clf = svm.SVC(C=0.8429301361295909,kernel='rbf',gamma=8.108145814186694,decision_function_shape='ovo') return clf
2、实验结果分析
在iris数据集的实验结果中,可以看出测试准确率有了明显的提升。可以见得通过遗传算法,获得SVM和MLP最优参数后,再将两种不同算法进行后可以提高模型的准确度。但本次实验所产生的最优参数,只能代表在当前遗传算法参数的情况下的最优解,还可以通过调整遗传算法的不同参数获得更好的结果。
但在wine数据集的处理过程中并没有得到一个很好的训练效果,此种融合方式或者参数并不适合wine数据集。同时在通过遗传算法获得伸进网络最优解时,迭代次数过大,计算效率很低。