未在 PyGAD 中训练的二元分类 NN 模型权重

Binary Classification NN Model Weights not being Trained in PyGAD

这是我正在编写的代码: Fake News Detection Google Colab Notebook

我使用的数据集: fake_or_real_news

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

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

我想实现的是假新闻检测。我所做的是对文章进行预处理,然后将它们 t运行sform 成向量。我使用 Glove 作为 NN 中的嵌入层。我尝试在没有 GA 的情况下使用 NN 模型进行训练,并且效果很好。然后我按照教程 How To Train Keras Models Using the Genetic Algorithm with PyGAD 将 NN 应用于 PyGAD GA,过程似乎 运行 很好,但适应度得分甚至在 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%,这意味着它比 运行dom 猜测还差。我想我的模型权重根本没有经过训练。当我使用二元交叉熵作为损失函数(也用于 GA 适应度函数)在没有 ga 的情况下训练相同的 NN 模型时,它起作用了。我可以看到每个 epoch 的准确率都在上升,最终的准确率在 90% 以上;但是,当我尝试使用 PyGAD 库通过遗传算法训练模型时,它不起作用。问题出在 NN 模型上还是我使用的适应度函数上?我已经尝试更改模型结构和一些我可以在 PyGAD 库中使用的超参数,例如突变类型或 parents 交配的数量,但似乎对我没有任何作用。

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

我打印了每一代 ga 解决方案的适应度,我可以看到每一代都产生了不同的适应度分数集(每一代的适应度分数都有很小的提高),这意味着 ga 确实产生了不同的输出,但它们只是比模型的初始权重差很多。即使经过许多代,也没有产生比初始权重更好的解决方案。这是否意味着我只需要更多的世代(比如数千代)来获得更好的解决方案?还是我选择的适应度函数有问题导致提升的速度这么慢?

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

根据自己机器的能力,尽量增加解的数量。也尽可能使用多代。

感谢使用PyGAD