首页 > 解决方案 > 未在 PyGAD 中训练二元分类 NN 模型权重

问题描述

这是我正在编写的代码: 假新闻检测 Google Colab Notebook

我使用的数据集: fake_or_real_news

手套嵌入层: glove.twitter.27B.200d

我一直在尝试 PyGAD,这是一个用于机器学习的遗传算法的 Python 库。

我想要实现的是假新闻检测。我所做的是对文章进行预处理,并将它们转换为向量。我使用 Glove 作为 NN 中的嵌入层。我尝试在没有 GA 的情况下使用 NN 模型进行训练,并且效果很好。然后我按照教程将 NN 应用于 PyGAD GA:如何使用 PyGAD 的遗传算法训练 Keras 模型,这个过程似乎运行良好,但即使经过 200 代,适应度得分也没有上升。我试图改变突变方法和其他一些超参数,但它似乎并没有改变结果。我在构建 PyGAD GA 模型的过程中做错了什么?大多数 PyGAD 模型设置与上面教程中的示例相同。

指定我遇到的问题:下面是我正在使用的主要 PyGAD 代码:

训练输入(X_train):

array([[ 4981,  2484, 22458, ...,  1019,   135,   892],
   [ 7075,   189, 26439, ...,  4982,    43,     2],
   [ 6168,   335,     2, ...,    73,    27,    73],
   ...,
   [  374,    10,   162, ...,   736,  1744,   484],
   [  500,   118,     2, ...,   348,  2890,  5689],
   [ 8194,  2404,   117, ...,   357,  6332,   186]], dtype=int32)
shape: (3753, 50)

训练输出(y_train):

array([[1., 0.],
   [0., 1.],
   [0., 1.],
   ...,
   [0., 1.],
   [1., 0.],
   [0., 1.]], dtype=float32)
shape:  (3753, )

Python代码:

import tensorflow.keras
import pygad.kerasga
import numpy
import pygad
def fitness_func(solution, sol_idx):
    global data_inputs, data_outputs, keras_ga, model

    model_weights_matrix = pygad.kerasga.model_weights_as_matrix(model=model, weights_vector=solution)

    model.set_weights(weights=model_weights_matrix)

    predictions = model.predict(data_inputs)
    
    bce = tensorflow.keras.losses.BinaryCrossentropy()
    solution_fitness = 1.0 / (bce(data_outputs, predictions).numpy() + 0.00000001)

    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]))

sequence_length = X_train.shape[1]
filter_sizes = [3,4]
num_filters = 100
drop = 0.4
#the NN 
inputs = Input(shape=(sequence_length,))
embedding = embedding_layer(inputs)
reshape = Reshape((sequence_length,EMBEDDING_DIM,1))(embedding)

conv_0 = Conv2D(num_filters, (filter_sizes[0], EMBEDDING_DIM),activation='relu',kernel_regularizer=regularizers.l2(0.01))(reshape)
conv_1 = Conv2D(num_filters, (filter_sizes[1], EMBEDDING_DIM),activation='relu',kernel_regularizer=regularizers.l2(0.01))(reshape)

maxpool_0 = MaxPooling2D((sequence_length - filter_sizes[0] + 1, 1), strides=(1,1))(conv_0)
maxpool_1 = MaxPooling2D((sequence_length - filter_sizes[1] + 1, 1), strides=(1,1))(conv_1)

merged_tensor = concatenate([maxpool_0, maxpool_1], axis=1)
flatten = Flatten()(merged_tensor)
reshape = Reshape((2*num_filters,))(flatten)
dropout = Dropout(drop)(flatten)
conc = Dense(40)(dropout)
output = Dense(units=2, activation='sigmoid',kernel_regularizer=regularizers.l2(0.01))(conc)
#create model
model = Model(inputs, output)
keras_ga = pygad.kerasga.KerasGA(model=model, num_solutions=10)

# Data inputs
data_inputs = X_train
# Data outputs
data_outputs = y_train
data_outputs = tensorflow.keras.utils.to_categorical(data_outputs)
num_generations = 200
num_parents_mating = 8
initial_population = keras_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.run() 之后得到的结果:

Generation = 1
Fitness    = 1.4091019376092528
Generation = 2
Fitness    = 1.4091019376092528
...
Generation = 200
Fitness    = 1.4091019376092528

预测结果:

Ground Truth:
array([[1., 0.],
[0., 1.],
[0., 1.],
...,
[0., 1.],
[1., 0.],
[0., 1.]], dtype=float32)

Without GA:
Predictions : 
[[0.9889404  0.00634338]
[0.03020517 0.9684899 ]
[0.28220823 0.76921546]
...
[0.08805525 0.92023355]
[0.9115724  0.08401334]
[0.15908712 0.8055146 ]]

With PyGAD GA:
Predictions : 
[[0.4274468  0.47953305]
[0.40091008 0.38568377]
[0.3937818  0.41261795]
...
[0.3366004  0.43762493]
[0.43253532 0.4112898 ]
[0.40255183 0.4059006 ]]

经过 200 代之后,Fitness Score 保持不变,最终模型准确率低于 50%,这意味着它比随机猜测更差。我想我的模型权重根本没有被训练。当我使用二元交叉熵作为损失函数(也用于 GA 适应度函数)训练没有 ga 的相同 NN 模型时,它起作用了。我可以看到每个 epoch 的准确率都在上升,最终的 acc 都在 90% 以上;但是,当我尝试使用 PyGAD 库通过遗传算法训练模型时,它不起作用。是NN模型的问题还是我使用的适应度函数的问题?我已经尝试更改模型结构和一些可以在 PyGAD 库中使用的超参数,例如突变类型或父母交配的数量,但似乎没有什么对我有用。

编辑:我尝试创建 nn 模型,并在没有任何培训的情况下进行预测。然后我运行 ga_instance.run() 代码用 ga 训练模型(仍然,适应度根本没有上升),然后用那个应该训练的模型进行预测,有和没有 ga 训练的预测输出是一样的,这意味着在 ga 的过程中没有找到更好的预测。为什么会这样?

我打印了 ga 解决方案的每一代的适应度,我可以看到每一代都会产生不同的适应度分数(每一代的适应度分数都有非常小的改善),这意味着 ga 确实产生了不同的输出,但它们是只是比模型的初始重量差很多。即使经过许多代,也没有产生比初始重量更好的解决方案。这是否意味着我只需要更多的世代(比如成千上万的世代)来获得更好的解决方案?还是我选择的适应度函数有问题,使改进进度如此缓慢?

标签: pythonmachine-learningkerasneural-networkgenetic-algorithm

解决方案


您的模型有大量参数 (>6.1M)。只有嵌入层本身有 6M。对于这样的许多参数,预计遗传算法将花费大量时间来训练模型。这并不意味着你出了问题。我之前已经尝试过与一个巨大的 CNN 合作,并且取得了进展,但非常小。

根据您机器的能力,您应该尽可能增加解决方案的数量。也尽可能多地使用一代。

感谢您使用PyGAD


推荐阅读