这是我参与更文挑战的第 25 天,活动详情查看: 更文挑战
遗传算法今天广泛应用到机器学习一些算法,不仅可以代替梯度下降算法来优化参数还,还可以用于在参数空间搜索神经网络的参数,本次分享主要来看看如何在 Pytorch 训练过程,使用遗传算法来优化权重参数。
步骤总结
- 创建 PyTorch 模型
- 实例化一个
pygad.torchga.TorchGA
类 - 准备训练数据
- 定义评估函数
- 实例化一个
pygad.GA
类 - 运行遗传算法
创建 PyTorch 模型
import torch
# 定义神经网络,包含一个隐含层,然后输出层
input_layer = torch.nn.Linear(3, 5)
relu_layer = torch.nn.ReLU()
output_layer = torch.nn.Linear(5, 1)
model = torch.nn.Sequential(input_layer,
relu_layer,
output_layer)
复制代码
pygad.torchga.TorchGA Class
pygad.torchga 模块有一个名为 TorchGA 的类,用于为基于 PyTorch 模型的遗传算法创建初始种群。该类中的构造函数、方法和属性。
pygad.torchga.TorchGA 类构造函数接受以下参数:
- model: 接受 PyTorch 模型的一个实例
- num_solutions: 群体中的解决方案的数量。每个解决方案都有不同的模型参数
实例属性
pygad.torchga.TorchGA 类构造函数中的所有参数都被用作实例属性,此外还增加了一个名为 population_weights 的新属性。
下面是所有实例属性的列表:
- model
- num_solutions
- population_weights: 一个嵌套的列表,包含了种群中所有解决方案的权重
TorchGA 类中的方法
接下来聊一聊 pygad.torchga.TorchGA 类的实例提供的方法
create_population()
create_population()
方法将遗传算法的初始群体创建为一个解决方案的列表,每个解决方案表示不同的模型参数。网络列表被分配给实例的 population_weights 属性。
pygad.torchga.model_weights_as_vector()
model_weights_as_vector()
函数仅接受 model 一个参数,类型为 PyTorch 模型。返回一个包含所有模型权重的向量。将模型权重表示为向量的原因是,遗传算法希望任何解决方案的所有参数都是一维向量形式。
函数的参数。
- model: PyTorch model
返回值为模型权重的一维向量。
pygad.torch.model_weights_as_dict()
model_weights_as_dict()函数接受以下参数。
- model:PyTorch 的模型
- weights_vector: 向量形式的模型参数
该函数返回值与 state_dict() 返回值相同都是模型的权重。返回的模型可以用 load_state_dict() 方法来加载到 PyTorch 模型的参数。
pygad.torchga.predict()
predict()函数基于一个解决方案进行预测。接受参数
- model:PyTorch 模型。
- solution: 进化出的解决方案
- data: 测试数据的输入
返回数据样本的预测结果
根据上一次分享提到如何用遗传算法来更新 Pytorch 模型的参数来实现训练 Pytorch 模型的一般步骤来结合这个例子,我们来一步一步回顾以下代码。
创建 Pytorch 模型
第一步是创建一个 PyTorch 的模型,下面是使用 Pytorch 的 API 来创建一个简单 Pytorch 模型,模型由 2 层神经网络构成,一层隐藏层和一个输出层。一共有 10 个神经元作为权重
import torch
input_layer = torch.nn.Linear(3, 5)
relu_layer = torch.nn.ReLU()
output_layer = torch.nn.Linear(5, 1)
model = torch.nn.Sequential(input_layer,
relu_layer,
output_layer)
复制代码
实例化 pygad.torchga.TorchGA Class 类
第二步是实例化一个 pygad.torchga.TorchGA 类的实例,每个种群有 10 个解决方案对应上面神经网络 10 权重参数。
import pygad.torchga
torch_ga = torchga.TorchGA(model=model,
num_solutions=10)
复制代码
torchga.TorchGA 构造函数接受 2 参数分别是 pytorch 模型,每个个体向量的维数,对应模型要学习参数的个数。
准备训练数据集
第三步是准备训练数据的输入(样本特征)和输出(样本标签),有一个例子,有 4 个样本。每个样本有 3 个特征作为输入和 1 作为标签。
import numpy
# Data inputs
data_inputs = numpy.array([[0.02, 0.1, 0.15],
[0.7, 0.6, 0.8],
[1.5, 1.2, 1.7],
[3.2, 2.9, 3.1]])
# Data outputs
data_outputs = numpy.array([[0.1],
[0.6],
[1.3],
[2.5]])
复制代码
定义评估函数
第四步是定义评估函数,这个函数必须接受 2 个参数,第一个个体(解决方案)和个体在群体中的位置。下一个评估函数根据解决方案中的参数计算 PyTorch 模型的 MAE(平均绝对误差)。MAE 的倒数作为评估值返回。
loss_function = torch.nn.L1Loss()
def fitness_func(solution, sol_idx):
global data_inputs, data_outputs, torch_ga, model, loss_function
predictions = pygad.torchga.predict(model=model,
solution=solution,
data=data_inputs)
abs_error = loss_function(predictions, data_outputs).detach().numpy() + 0.00000001
solution_fitness = 1.0 / abs_error
return solution_fitness
复制代码
ga_instance.run()
复制代码
在PyGAD 完成的执行后,会通过图表直观表示整个训练过程,调用plot_fitness()方法来显示该图。
ga_instance.plot_fitness(title="PyGAD & PyTorch - Iteration vs. Fitness", linewidth=4)
复制代码
完整代码
import torch
import pygad.torchga
import pygad
def fitness_func(solution, sol_idx):
global data_inputs, data_outputs, torch_ga, model, loss_function
"""
- model:模型
- solution: 也就是遗传算法群体中的个体
- data: 数据
"""
predictions = pygad.torchga.predict(model=model,
solution=solution,
data=data_inputs)
# 计算误差
abs_error = loss_function(predictions, data_outputs).detach().numpy() + 0.00000001
# 因为评估值是越大越好
solution_fitness = 1.0 / abs_error
return solution_fitness
def callback_generation(ga_instance):
print("Generation = {generation}".format(generation=ga_instance.generations_completed))
print("Fitness = {fitness}".format(fitness=ga_instance.best_solution()[1]))
# 创建 PyTorch 模型
input_layer = torch.nn.Linear(3, 5)
relu_layer = torch.nn.ReLU()
output_layer = torch.nn.Linear(5, 1)
# 定义模型
model = torch.nn.Sequential(input_layer,
relu_layer,
output_layer)
# 在初始化种群时,实例化 pygad.torchga.TorchGA
torch_ga = pygad.torchga.TorchGA(model=model,
num_solutions=10)
# 定义 loss 函数
loss_function = torch.nn.L1Loss()
# 数据集输入数据
data_inputs = torch.tensor([[0.02, 0.1, 0.15],
[0.7, 0.6, 0.8],
[1.5, 1.2, 1.7],
[3.2, 2.9, 3.1]])
# 数据集
data_outputs = torch.tensor([[0.1],
[0.6],
[1.3],
[2.5]])
num_generations = 250 # 迭代次数
num_parents_mating = 5 # 每次从父类中选择的个体进行交叉、和突变的数量
initial_population = torch_ga.population_weights # 初始化网络权重
ga_instance = pygad.GA(num_generations=num_generations,
num_parents_mating=num_parents_mating,
initial_population=initial_population,
fitness_func=fitness_func,
on_generation=callback_generation)
ga_instance.run()
ga_instance.plot_fitness(title="PyGAD & PyTorch - Iteration vs. Fitness", linewidth=4)
# 返回最优参数的详细信息
solution, solution_fitness, solution_idx = ga_instance.best_solution()
print("Fitness value of the best solution = {solution_fitness}".format(solution_fitness=solution_fitness))
print("Index of the best solution : {solution_idx}".format(solution_idx=solution_idx))
# 基于最好的个体来进行预测
predictions = pygad.torchga.predict(model=model,
solution=solution,
data=data_inputs)
print("Predictions : \n", predictions.detach().numpy())
abs_error = loss_function(predictions, data_outputs)
print("Absolute Error : ", abs_error.detach().numpy())
# 以下是评估效果
"""
Fitness value of the best solution = 74.17345574365933
Index of the best solution : 0
预测结果 :
[[0.09415314]
[0.6399874 ]
[1.2981992 ]
[2.5062926 ]]
错误率的绝对值 : 0.013481902
"""
复制代码