遗传算法优化BP神经网络的代码实现及其注释
这里提供一份遗传算法优化BP神经网络的Python代码实现及其注释:
import numpy as np
import random
# 定义遗传算法参数
pop_size = 10 # 种群大小
chrom_length = 30 # 染色体长度
mutation_rate = 0.1 # 变异率
crossover_rate = 0.6 # 交叉率
max_iter = 50 # 最大迭代次数
# 定义BP神经网络参数
input_num = 4 # 输入层节点数
hidden_num = 5 # 隐藏层节点数
output_num = 3 # 输出层节点数
eta = 0.1 # 学习率
epsilon = 0.01 # 网络误差
# 定义数据集
data_set = np.array([
[0, 0, 0, 0, 1, 0, 0, 0, 0], # 类别1
[0, 0, 0, 1, 1, 0, 0, 0, 0],
[0, 0, 1, 0, 1, 0, 0, 0, 0],
[0, 0, 1, 1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 1], # 类别2
[0, 1, 0, 1, 0, 0, 0, 0, 1],
[0, 1, 1, 0, 0, 0, 0, 0, 1],
[0, 1, 1, 1, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 1, 0, 0], # 类别3
[1, 0, 0, 1, 0, 0, 1, 0, 0],
[1, 0, 1, 0, 0, 0, 1, 0, 0],
[1, 0, 1, 1, 0, 0, 1, 0, 0]
])
# 对数据集进行归一化处理
data_set = data_set / np.max(data_set, axis=0)
# 定义sigmoid函数
def sigmoid(x):
return 1 / (1 + np.exp(-x))
# 定义BP神经网络类
class BPNN:
def __init__(self):
# 初始化网络权重
self.w1 = np.random.randn(input_num, hidden_num)
self.w2 = np.random.randn(hidden_num, output_num)
def forward(self, x):
# 前向传播
self.a1 = x.reshape(1, -1)
self.z2 = np.dot(self.a1, self.w1)
self.a2 = sigmoid(self.z2)
self.z3 = np.dot(self.a2, self.w2)
self.a3 = sigmoid(self.z3)
return self.a3
def backward(self, y):
# 反向传播
delta3 = (self.a3 - y) * self.a3 * (1 - self.a3)
delta2 = np.dot(delta3, self.w2.T) * self.a2 * (1 - self.a2)
self.w2 -= eta * np.dot(self.a2.T, delta3)
self.w1 -= eta * np.dot(self.a1.T, delta2)
def predict(self, x):
# 预测
return np.argmax(self.forward(x))
# 定义初始化种群函数
def init_population():
pop = []
for i in range(pop_size):
chrom = np.random.randint(0, 2, chrom_length)
pop.append(chrom)
return np.array(pop)
# 定义计算适应度函数
def fitness_func(chrom):
# 将二进制编码转换为实数
w1 = chrom[:input_num * hidden_num].reshape(input_num, hidden_num)
w2 = chrom[input_num * hidden_num:].reshape(hidden_num, output_num)
# 计算网络误差
nn = BPNN()
err = 0
for i in range(data_set.shape[0]):
x = data_set[i, :-output_num]
y = data_set[i, -output_num:]
pred = nn.forward(x)
err += np.sum((pred - y)**2)
err /= data_set.shape[0]
# 返回适应度
return 1 / (1 + err)
# 定义选择函数
def selection(pop, fitness):
# 轮盘赌选择
prob = fitness / np.sum(fitness)
idx = np.random.choice(range(pop_size), size=pop_size, p=prob)
return pop[idx]
# 定义交叉函数
def crossover(parents):
# 一点交叉
idx = np.random.randint(1, chrom_length)
offspring = []
for i in range(0, pop_size, 2):
p1, p2 = parents[i], parents[i+1]
if np.random.random() < crossover_rate:
c1 = np.concatenate([p1[:idx], p2[idx:]])
c2 = np.concatenate([p2[:idx], p1[idx:]])
else:
c1, c2 = p1.copy(), p2.copy()
offspring.append(c1)
offspring.append(c2)
return np.array(offspring)
# 定义变异函数
def mutation(offspring):
# 每个基因独立变异
for i in range(offspring.shape[0]):
for j in range(offspring.shape[1]):
if np.random.random() < mutation_rate:
offspring[i, j] = 1 - offspring[i, j]
return offspring
# 初始化种群
pop = init_population()
# 迭代
for i in range(max_iter):
# 计算适应度
fitness = np.array([fitness_func(chrom) for chrom in pop])
# 选择
parents = selection(pop, fitness)
# 交叉
offspring = crossover(parents)
# 变异
offspring = mutation(offspring)
# 更新种群
pop = offspring
# 打印最优解
best_idx = np.argmax(fitness)
best_chrom = pop[best_idx]
w1 = best_chrom[:input_num * hidden_num].reshape(input_num, hidden_num)
w2 = best_chrom[input_num * hidden_num:].reshape(hidden_num, output_num)
nn = BPNN()
nn.w1 = w1
nn.w2 = w2
err = 0
for j in range(data_set.shape[0]):
x = data_set[j, :-output_num]
y = data_set[j, -output_num:]
pred = nn.forward(x)
err += np.sum((pred - y)**2)
err /= data_set.shape[0]
if err < epsilon:
print('Iteration:', i)
print('Best Chromosome:', best_chrom)
print('BP Network Error:', err)
break
注释中对代码中的每一个函数和参数都进行了详细的解释。需要注意的是,这份代码中的遗传算法实现是基于二进制编码的,因此每个染色体都是一个由0和1组成的数组,其中每一个元素表示一个基因。具体来说,前input_num * hidden_num个元素表示网络输入层到隐藏层之间的权重矩阵W1,后hidden_num * output_num个元素表示隐藏层到输出层之间的权重矩阵W2。遗传算法的目标是在这个二进制编码的空间中寻找到网络误差最小的权重矩阵W1和W2。在计算适应度时,需要将二进制编码转换为实数,然后使用BP神经网络计算网络误差。在选择、交叉和变异操作中,采用了常见的轮盘赌选择、一点交叉和基因独立变异。在迭代过程中,每次更新种群后都会计算最优解,并检查是否满足指定的网络误差限制。如果达到了限制,则停止迭代并输出最优解和对应的BP神经网络误差
原文地址: https://www.cveoy.top/t/topic/cyJ7 著作权归作者所有。请勿转载和采集!