遗传算法结合 PyTorch 训练神经网络(1)

这是我参与更文挑战的第 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
"""
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享