|
|
# coding:utf-8
|
|
|
import math
|
|
|
import random
|
|
|
|
|
|
# 神经网络3层, 1个隐藏层; 4个input和1个output
|
|
|
network = [4, [16], 1] # 网络结构:输入4个神经元,隐藏层1层,每层16个神经元,输出1个神经元
|
|
|
# 遗传算法相关参数
|
|
|
population = 1 # 种群数量
|
|
|
elitism = 0.2 # 精英比例,保留前一代中最好的个体
|
|
|
random_behaviour = 0.1 # 随机比例,随机生成个体
|
|
|
mutation_rate = 0.5 # 变异率
|
|
|
mutation_range = 2 # 变异范围
|
|
|
historic = 0 # 历史基因组数量
|
|
|
low_historic = False # 是否启用历史记录
|
|
|
score_sort = -1 # 分数排序规则,-1表示降序
|
|
|
n_child = 1 # 每代子代数量
|
|
|
|
|
|
|
|
|
# 激活函数
|
|
|
def sigmoid(z):
|
|
|
return 1.0 / (1.0 + math.exp(-z))
|
|
|
|
|
|
|
|
|
# 生成随机数
|
|
|
def random_clamped():
|
|
|
return random.random() * 2 - 1
|
|
|
|
|
|
|
|
|
# "神经元"
|
|
|
# 初始化神经元的权重和偏置
|
|
|
class Neuron():
|
|
|
def __init__(self):
|
|
|
self.biase = 0 # 偏置
|
|
|
self.weights = [] # 权重
|
|
|
|
|
|
def init_weights(self, n):
|
|
|
self.weights = []
|
|
|
for i in range(n):
|
|
|
self.weights.append(random_clamped())
|
|
|
|
|
|
def __repr__(self):
|
|
|
return 'Neuron weight size:{} biase value:{}'.format(len(self.weights), self.biase)
|
|
|
|
|
|
|
|
|
# 层
|
|
|
# 初始化每一层神经元的数量
|
|
|
class Layer():
|
|
|
# 初始化层对象
|
|
|
def __init__(self, index):
|
|
|
self.index = index # 层的索引
|
|
|
self.neurons = [] # 该层包含的神经元列表
|
|
|
|
|
|
# 初始化神经元
|
|
|
def init_neurons(self, n_neuron, n_input):
|
|
|
self.neurons = [] # 清空神经元列表
|
|
|
for i in range(n_neuron):
|
|
|
neuron = Neuron() # 创建神经元对象
|
|
|
neuron.init_weights(n_input) # 初始化神经元的权重
|
|
|
self.neurons.append(neuron) # 将神经元添加到该层的神经元列表中
|
|
|
|
|
|
# 返回该层的字符串表示
|
|
|
# def __repr__(self):
|
|
|
# return 'Layer ID:{} Layer neuron size:{}'.format(self.index, len(self.neurons))
|
|
|
|
|
|
|
|
|
|
|
|
# 神经网络 初始化神经网络结构、获取和设置神经网络权重、前向传播等
|
|
|
class NeuroNetwork():
|
|
|
def __init__(self):
|
|
|
self.layers = []
|
|
|
|
|
|
# 初始化网络结构
|
|
|
def init_neuro_network(self, input, hiddens, output):
|
|
|
index = 0 # 初始化层的索引
|
|
|
previous_neurons = 0 # 初始化前一层的神经元数量
|
|
|
|
|
|
# 输入层
|
|
|
layer = Layer(index) # 创建输入层对象
|
|
|
layer.init_neurons(input, previous_neurons) # 初始化输入层的神经元
|
|
|
previous_neurons = input # 更新前一层的神经元数量为输入层的神经元数量
|
|
|
self.layers.append(layer) # 将输入层添加到神经网络的层列表中
|
|
|
index += 1 # 更新层的索引为下一层
|
|
|
|
|
|
# 隐藏层
|
|
|
for i in range(len(hiddens)):
|
|
|
layer = Layer(index) # 创建隐藏层对象
|
|
|
layer.init_neurons(hiddens[i], previous_neurons) # 初始化隐藏层的神经元
|
|
|
previous_neurons = hiddens[i] # 更新前一层的神经元数量为当前隐藏层的神经元数量
|
|
|
self.layers.append(layer) # 将隐藏层添加到神经网络的层列表中
|
|
|
index += 1 # 更新层的索引为下一层
|
|
|
|
|
|
# 输出层
|
|
|
layer = Layer(index) # 创建输出层对象
|
|
|
layer.init_neurons(output, previous_neurons) # 初始化输出层的神经元
|
|
|
self.layers.append(layer) # 将输出层添加到神经网络的层列表中
|
|
|
|
|
|
# 获取神经网络权重
|
|
|
def get_weights(self):
|
|
|
data = {'network': [], 'weights': []} # 初始化数据字典,用于存储神经网络结构和权重
|
|
|
for layer in self.layers: # 遍历神经网络的每一层
|
|
|
data['network'].append(len(layer.neurons)) # 将每层的神经元数量添加到网络结构列表中
|
|
|
for neuron in layer.neurons: # 遍历每层的神经元
|
|
|
for weight in neuron.weights: # 遍历神经元的权重
|
|
|
data['weights'].append(weight) # 将权重添加到权重列表中
|
|
|
return data # 返回存储了网络结构和权重的数据字典
|
|
|
|
|
|
# 设置神经网络权重
|
|
|
def set_weights(self, data):
|
|
|
previous_neurons = 0 # 初始化前一层的神经元数量
|
|
|
index = 0 # 初始化层的索引
|
|
|
index_weights = 0 # 初始化权重索引
|
|
|
|
|
|
self.layers = [] # 清空神经网络的层列表
|
|
|
for i in data['network']: # 遍历网络结构列表中的每个值(表示每层的神经元数量)
|
|
|
layer = Layer(index) # 创建新的层对象
|
|
|
layer.init_neurons(i, previous_neurons) # 初始化层的神经元
|
|
|
for j in range(len(layer.neurons)): # 遍历每层的神经元
|
|
|
for k in range(len(layer.neurons[j].weights)): # 遍历每个神经元的权重
|
|
|
layer.neurons[j].weights[k] = data['weights'][index_weights] # 将权重值从数据中赋给神经元
|
|
|
index_weights += 1 # 更新权重索引
|
|
|
previous_neurons = i # 更新前一层的神经元数量
|
|
|
index += 1 # 更新层的索引
|
|
|
self.layers.append(layer) # 将新创建的层添加到神经网络的层列表中
|
|
|
|
|
|
# 前向传播
|
|
|
def feed_forward(self, inputs):#进行前向传播计算输
|
|
|
# 设置输入层神经元的偏置值为输入值
|
|
|
for i in range(len(inputs)):
|
|
|
self.layers[0].neurons[i].biase = inputs[i]
|
|
|
|
|
|
prev_layer = self.layers[0] # 初始化前一层为输入层
|
|
|
for i in range(len(self.layers)): # 遍历每一层
|
|
|
if i == 0: # 跳过输入层
|
|
|
continue
|
|
|
for j in range(len(self.layers[i].neurons)): # 遍历当前层的每个神经元
|
|
|
sum = 0 # 初始化加权和
|
|
|
for k in range(len(prev_layer.neurons)): # 遍历前一层的每个神经元
|
|
|
sum += prev_layer.neurons[k].biase * self.layers[i].neurons[j].weights[k] # 计算加权和
|
|
|
# 将加权和经过激活函数 sigmoid 处理后作为当前神经元的偏置值
|
|
|
self.layers[i].neurons[j].biase = sigmoid(sum)
|
|
|
prev_layer = self.layers[i] # 更新前一层为当前层
|
|
|
|
|
|
out = [] # 初始化输出列表
|
|
|
last_layer = self.layers[-1] # 获取最后一层
|
|
|
for i in range(len(last_layer.neurons)): # 遍历最后一层的每个神经元
|
|
|
out.append(last_layer.neurons[i].biase) # 将每个神经元的偏置值添加到输出列表
|
|
|
return out # 返回输出列表
|
|
|
|
|
|
# 打印网络信息
|
|
|
def print_info(self):
|
|
|
for layer in self.layers: # 遍历每一层
|
|
|
print(layer) # 打印每一层的信息
|
|
|
|
|
|
# "基因组"
|
|
|
class Genome():
|
|
|
def __init__(self, score, network_weights):
|
|
|
self.score = score # 评分
|
|
|
self.network_weights = network_weights # 神经网络权重
|
|
|
|
|
|
# 添加基因组、生成下一代、交叉和突变等
|
|
|
class Generation():
|
|
|
def __init__(self):
|
|
|
self.genomes = [] # 初始化一个空列表,用于存储基因组
|
|
|
|
|
|
def add_genome(self, genome):
|
|
|
i = 0
|
|
|
# 遍历已有的基因组列表
|
|
|
for i in range(len(self.genomes)):
|
|
|
if score_sort < 0: # 如果评分排序小于0(假设为升序排列)
|
|
|
if genome.score > self.genomes[i].score: # 如果新基因组的评分高于当前基因组
|
|
|
break # 中断循环
|
|
|
else:
|
|
|
if genome.score < self.genomes[i].score: # 如果新基因组的评分低于当前基因组
|
|
|
break # 中断循环
|
|
|
self.genomes.insert(i, genome) # 将新基因组插入到适当的位置
|
|
|
|
|
|
# 杂交+突变
|
|
|
def breed(self, genome1, genome2, n_child):
|
|
|
datas = [] # 初始化一个空列表,用于存储子代基因组数据
|
|
|
for n in range(n_child):
|
|
|
data = genome1 # 子代基因组初始化为父代1的基因组
|
|
|
for i in range(len(genome2.network_weights['weights'])):
|
|
|
if random.random() <= 0.5: # 以50%的概率选择来自父代2的基因
|
|
|
data.network_weights['weights'][i] = genome2.network_weights['weights'][i]
|
|
|
|
|
|
for i in range(len(data.network_weights['weights'])):
|
|
|
if random.random() <= mutation_rate: # 根据突变率进行突变
|
|
|
data.network_weights['weights'][i] += random.random() * mutation_range * 2 - mutation_range
|
|
|
datas.append(data) # 将子代基因组数据添加到列表中
|
|
|
return datas # 返回生成的子代基因组数据列表
|
|
|
|
|
|
# 生成下一代
|
|
|
def generate_next_generation(self):
|
|
|
nexts = [] # 初始化一个空列表,用于存储下一代基因组数据
|
|
|
for i in range(int(elitism * population)):
|
|
|
if len(nexts) < population:
|
|
|
nexts.append(self.genomes[i].network_weights) # 将精英个体的基因组数据添加到下一代中
|
|
|
|
|
|
for i in range(int(random_behaviour * population)):
|
|
|
n = self.genomes[0].network_weights
|
|
|
for k in range(len(n['weights'])):
|
|
|
n['weights'][k] = random_clamped() # 随机生成基因组数据作为下一代的一部分
|
|
|
if len(nexts) < population:
|
|
|
nexts.append(n) # 将随机生成的基因组数据添加到下一代中
|
|
|
|
|
|
max_n = 0
|
|
|
while True:
|
|
|
for i in range(max_n):
|
|
|
# 对父代中的基因组进行杂交和突变,生成子代基因组
|
|
|
childs = self.breed(self.genomes[i], self.genomes[max_n], n_child if n_child > 0 else 1)
|
|
|
for c in range(len(childs)):
|
|
|
nexts.append(childs[c].network_weights) # 将子代基因组数据添加到下一代中
|
|
|
if len(nexts) >= population:
|
|
|
return nexts # 如果下一代的数量达到了指定的种群数量,则返回下一代的基因组数据列表
|
|
|
max_n += 1
|
|
|
if max_n >= len(self.genomes) - 1:
|
|
|
max_n = 0
|
|
|
# "基因组"类,用于存储神经网络的权重及其评分
|
|
|
class Genome():
|
|
|
def __init__(self, score, network_weights):
|
|
|
self.score = score # 评分
|
|
|
self.network_weights = network_weights # 神经网络权重
|
|
|
|
|
|
# "代"类,管理基因组的添加、生成下一代、杂交和突变等操作
|
|
|
class Generation():
|
|
|
def __init__(self):
|
|
|
self.genomes = [] # 初始化一个空列表,用于存储基因组
|
|
|
|
|
|
def add_genome(self, genome):
|
|
|
i = 0
|
|
|
# 根据评分排序将基因组插入到适当位置
|
|
|
for i in range(len(self.genomes)):
|
|
|
if score_sort < 0: # 如果评分排序小于0(假设为升序排列)
|
|
|
if genome.score > self.genomes[i].score: # 如果新基因组的评分高于当前基因组
|
|
|
break # 中断循环
|
|
|
else:
|
|
|
if genome.score < self.genomes[i].score: # 如果新基因组的评分低于当前基因组
|
|
|
break # 中断循环
|
|
|
self.genomes.insert(i, genome) # 将新基因组插入到适当的位置
|
|
|
|
|
|
# 杂交+突变
|
|
|
def breed(self, genome1, genome2, n_child):
|
|
|
datas = [] # 初始化一个空列表,用于存储子代基因组数据
|
|
|
for n in range(n_child):
|
|
|
data = genome1 # 子代基因组初始化为父代1的基因组
|
|
|
for i in range(len(genome2.network_weights['weights'])):
|
|
|
if random.random() <= 0.5: # 以50%的概率选择来自父代2的基因
|
|
|
data.network_weights['weights'][i] = genome2.network_weights['weights'][i]
|
|
|
|
|
|
for i in range(len(data.network_weights['weights'])):
|
|
|
if random.random() <= mutation_rate: # 根据突变率进行突变
|
|
|
data.network_weights['weights'][i] += random.random() * mutation_range * 2 - mutation_range
|
|
|
datas.append(data) # 将子代基因组数据添加到列表中
|
|
|
return datas # 返回生成的子代基因组数据列表
|
|
|
|
|
|
# 生成下一代
|
|
|
def generate_next_generation(self):
|
|
|
nexts = [] # 初始化一个空列表,用于存储下一代基因组数据
|
|
|
for i in range(int(elitism * population)):
|
|
|
if len(nexts) < population:
|
|
|
nexts.append(self.genomes[i].network_weights) # 将精英个体的基因组数据添加到下一代中
|
|
|
|
|
|
for i in range(int(random_behaviour * population)):
|
|
|
n = self.genomes[0].network_weights
|
|
|
for k in range(len(n['weights'])):
|
|
|
n['weights'][k] = random_clamped() # 随机生成基因组数据作为下一代的一部分
|
|
|
if len(nexts) < population:
|
|
|
nexts.append(n) # 将随机生成的基因组数据添加到下一代中
|
|
|
|
|
|
max_n = 0
|
|
|
while True:
|
|
|
for i in range(max_n):
|
|
|
# 对父代中的基因组进行杂交和突变,生成子代基因组
|
|
|
childs = self.breed(self.genomes[i], self.genomes[max_n], n_child if n_child > 0 else 1)
|
|
|
for c in range(len(childs)):
|
|
|
nexts.append(childs[c].network_weights) # 将子代基因组数据添加到下一代中
|
|
|
if len(nexts) >= population:
|
|
|
return nexts # 如果下一代的数量达到了指定的种群数量,则返回下一代的基因组数据列表
|
|
|
max_n += 1
|
|
|
if max_n >= len(self.genomes) - 1:
|
|
|
max_n = 0
|
|
|
|
|
|
# "代"的管理类,生成第一代和下一代,并管理基因组的添加
|
|
|
class Generations():
|
|
|
def __init__(self):
|
|
|
self.generations = [] # 初始化一个空列表,用于存储代的信息
|
|
|
|
|
|
def first_generation(self):
|
|
|
out = [] # 初始化一个空列表,用于存储第一代的神经网络权重数据
|
|
|
for i in range(population): # 遍历种群中的个体数量
|
|
|
nn = NeuroNetwork() # 创建神经网络对象
|
|
|
nn.init_neuro_network(network[0], network[1], network[2]) # 初始化神经网络结构
|
|
|
out.append(nn.get_weights()) # 将神经网络的权重数据添加到输出列表中
|
|
|
self.generations.append(Generation()) # 将第一代的信息添加到代的列表中
|
|
|
return out # 返回第一代的神经网络权重数据列表
|
|
|
|
|
|
def next_generation(self):
|
|
|
if len(self.generations) == 0: # 如果代的列表为空
|
|
|
return False # 返回假值
|
|
|
|
|
|
gen = self.generations[-1].generate_next_generation() # 生成下一代
|
|
|
self.generations.append(Generation()) # 将下一代的信息添加到代的列表中
|
|
|
return gen # 返回下一代的神经网络权重数据列表
|
|
|
|
|
|
def add_genome(self, genome):
|
|
|
if len(self.generations) == 0: # 如果代的列表为空
|
|
|
return False # 返回假值
|
|
|
|
|
|
return self.generations[-1].add_genome(genome) # 将基因组添加到当前代的基因组列表中
|
|
|
|
|
|
# "祖代"的管理类,管理祖代的创建和迭代
|
|
|
class NeuroEvolution():
|
|
|
def __init__(self):
|
|
|
self.generations = Generations() # 初始化代的信息
|
|
|
|
|
|
def restart(self):
|
|
|
self.generations = Generations() # 重新开始演化过程,清空代的信息
|
|
|
|
|
|
def next_generation(self):
|
|
|
networks = []
|
|
|
if len(self.generations.generations) == 0:
|
|
|
networks = self.generations.first_generation() # 如果没有代的信息,则生成第一代
|
|
|
else:
|
|
|
networks = self.generations.next_generation() # 否则生成下一代
|
|
|
|
|
|
nn = []
|
|
|
for i in range(len(networks)):
|
|
|
n = NeuroNetwork() # 创建神经网络对象
|
|
|
n.set_weights(networks[i]) # 设置神经网络的权重数据
|
|
|
nn.append(n) # 将神经网络对象添加到列表中
|
|
|
|
|
|
if low_historic: # 如果低历史标志为真
|
|
|
if len(self.generations.generations) >= 2: # 如果有足够的历史记录
|
|
|
genomes = self.generations.generations[len(self.generations.generations) - 2].genomes # 获取倒数第二代的基因组
|
|
|
for i in range(genomes): # 遍历基因组
|
|
|
genomes[i].network = None # 清空神经网络对象
|
|
|
|
|
|
if historic != -1: # 如果历史记录不为-1
|
|
|
if len(self.generations.generations) > historic + 1: # 如果历史记录超过指定的数量
|
|
|
del self.generations.generations[0:len(self.generations.generations) - (historic + 1)] # 删除多余的历史记录
|
|
|
|
|
|
return nn # 返回神经网络对象列表
|
|
|
|
|
|
def network_score(self, score, network):
|
|
|
self.generations.add_genome(Genome(score, network.get_weights()))
|
|
|
|
|
|
|
|
|
# 以上代码是一个简单的神经网络遗传算法实现,用于训练一个具有输入层、隐藏层和输出层的神经网络。以下是代码的主要组成部分和功能:
|
|
|
#
|
|
|
# 1. 定义了一个神经网络类 `NeuroNetwork`,其中包括初始化神经网络结构、获取和设置神经网络权重、前向传播等方法。
|
|
|
# 2. 定义了一个神经元类 `Neuron`,用于初始化神经元的权重和偏置。
|
|
|
# 3. 定义了一个层类 `Layer`,用于初始化每一层神经元的数量。
|
|
|
# 4. 定义了一个遗传算法相关的类 `Generation`,其中包括添加基因组、生成下一代、交叉和突变等方法。
|
|
|
# 5. 定义了一个祖代类 `Generations`,用于生成第一代和下一代,并管理基因组的添加。
|
|
|
# 6. 定义了一个神经进化类 `NeuroEvolution`,用于管理祖代的创建和迭代。
|
|
|
#
|
|
|
# 整个系统的流程是:首先生成初始种群,然后对种群进行评估(可能是在某些问题上进行游戏或其他任务),评估的结果(如分数)用于选择基因组进行交叉和突变生成下一代种群。这个过程重复进行直到满足停止条件。
|
|
|
#
|
|
|
# 这个代码的目的是通过遗传算法优化神经网络的权重和偏置,以适应特定的任务或问题。 |