You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ai001/forAI.py

359 lines
18 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 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`,用于管理祖代的创建和迭代。
#
# 整个系统的流程是:首先生成初始种群,然后对种群进行评估(可能是在某些问题上进行游戏或其他任务),评估的结果(如分数)用于选择基因组进行交叉和突变生成下一代种群。这个过程重复进行直到满足停止条件。
#
# 这个代码的目的是通过遗传算法优化神经网络的权重和偏置,以适应特定的任务或问题。