GNN解决图着色(图论)问题

在tensorflow框架下,模型为GNN模型,要解决图着色(图论)问题,中间大致过程经过编码输入,RNN循环,聚合更新节点,颜色的嵌入,经固定次数嵌入更新,得到最后的节点和颜色的特征,输入MLP,进行预测任务:该图是否接受C中颜色着色?(二分类问题)
其中,负责聚合更新的RNN循环次数设为32时,loss在迭代过程会由很大的值(超过百万以上)逐渐变为lan,循环次数为8,最后loss由50左右经100epoch后会稳定在0.69和acc稳定在0.5左右是什么原因呢?
除此之外,我想在最后一层激活函数sigmoid之前加入BN层应该怎么编写呢,部分段代码如下:

......
 # Get the last embeddings
    last_states = gnn(
      { "M": M_matrix, "VC": VC_matrix, 'chrom_number': chrom_number },
      { "V": vertex_initial_embeddings, "C": colors_initial_embeddings },
      time_steps = time_steps
    )
    GNN["last_states"] = last_states
    V_n = last_states['V'].h
    C_n = last_states['C'].h
    # Compute a vote for each embedding
    V_vote = tf.reshape(V_vote_MLP(V_n), [-1])

    # Compute the number of problems in the batch
    num_problems = tf.shape(n_vertices)[0]

    # Compute a logit probability for each problem
    pred_logits = tf.while_loop(
        lambda i, pred_logits: tf.less(i, num_problems),
        lambda i, pred_logits:
            (
                (i+1),
                pred_logits.write(
                    i,
                    tf.reduce_mean(V_vote[tf.reduce_sum(n_vertices[0:i]):tf.reduce_sum(n_vertices[0:i])+n_vertices[i]])
                )
            ),
        [0, tf.TensorArray(size=num_problems, dtype=tf.float32)]
        )[1].stack()

    # Convert logits into probabilities
    GNN['predictions'] = tf.sigmoid(pred_logits)

或者BN层应该加到其他什么地方呢,希望有详细代码指导?期望得到详细咨询指导,想具体了解代码的可以私信

关于loss变化的问题,可能是因为RNN循环的次数较多(32),导致模型训练较慢,需要更多的迭代才能收敛。此外,模型可能存在梯度爆炸或消失问题,可以尝试加入梯度裁剪或使用其他的优化器和学习率调整策略。

而最后loss和准确率稳定在一个相对较高的数值(0.69和0.5)可能是因为该问题本身就比较困难,即使是一个随机猜测的准确率也是0.5左右。

至于在最后一层激活函数sigmoid之前加入BN层,可以按照以下方式修改代码:


from tensorflow.keras.layers import BatchNormalization

# Get the last embeddings
last_states = gnn(
  { "M": M_matrix, "VC": VC_matrix, 'chrom_number': chrom_number },
  { "V": vertex_initial_embeddings, "C": colors_initial_embeddings },
  time_steps = time_steps
)
GNN["last_states"] = last_states
V_n = last_states['V'].h
C_n = last_states['C'].h
# Compute a vote for each embedding
V_vote = tf.reshape(V_vote_MLP(V_n), [-1])

# Add a Batch Normalization layer before the final output
V_vote = BatchNormalization()(V_vote)

# Compute the number of problems in the batch
num_problems = tf.shape(n_vertices)[0]

# Compute a logit probability for each problem
pred_logits = tf.while_loop(
    lambda i, pred_logits: tf.less(i, num_problems),
    lambda i, pred_logits:
        (
            (i+1),
            pred_logits.write(
                i,
                tf.reduce_mean(V_vote[tf.reduce_sum(n_vertices[0:i]):tf.reduce_sum(n_vertices[0:i])+n_vertices[i]])
            )
        ),
    [0, tf.TensorArray(size=num_problems, dtype=tf.float32)]
    )[1].stack()

# Convert logits into probabilities
GNN['predictions'] = tf.sigmoid(pred_logits)

在最后一层激活函数sigmoid之前,使用Batch Normalization层进行归一化,可以加速模型收敛,提高模型的精度。

图神经网络(GNN)简介

可以借鉴下
https://blog.csdn.net/qq_28368377/article/details/108936199

引用new bing部分指引作答:
首先,关于你的第一个问题,RNN循环次数从32减少到8后,loss值和acc稳定在0.69和0.5左右,这很可能是由于过多的循环次数导致了梯度消失或梯度爆炸的问题。这可能是由于RNN的循环结构以及激活函数的非线性性质导致的,因此减少循环次数是一个解决方法。你可以尝试使用其他的循环结构,比如LSTM或GRU,来避免梯度消失和爆炸问题。

其次,关于在最后一层添加Batch Normalization层,你可以这样实现:

# Get the last embeddings
last_states = gnn(
  { "M": M_matrix, "VC": VC_matrix, 'chrom_number': chrom_number },
  { "V": vertex_initial_embeddings, "C": colors_initial_embeddings },
  time_steps = time_steps
)
GNN["last_states"] = last_states
V_n = last_states['V'].h
C_n = last_states['C'].h

# Compute a vote for each embedding
V_vote = tf.reshape(V_vote_MLP(V_n), [-1])

# Add Batch Normalization layer before activation function
V_vote = tf.keras.layers.BatchNormalization()(V_vote)

# Compute the number of problems in the batch
num_problems = tf.shape(n_vertices)[0]

# Compute a logit probability for each problem
pred_logits = tf.while_loop(
    lambda i, pred_logits: tf.less(i, num_problems),
    lambda i, pred_logits:
        (
            (i+1),
            pred_logits.write(
                i,
                tf.reduce_mean(V_vote[tf.reduce_sum(n_vertices[0:i]):tf.reduce_sum(n_vertices[0:i])+n_vertices[i]])
            )
        ),
    [0, tf.TensorArray(size=num_problems, dtype=tf.float32)]
    )[1].stack()

# Add sigmoid activation function
pred_logits = tf.keras.activations.sigmoid(pred_logits)

# Assign predictions to dictionary
GNN['predictions'] = pred_logits


在添加Batch Normalization层之后,需要在它之前应用激活函数之前。这是因为Batch Normalization层的设计是在激活函数之前应用,以确保激活函数输入的值的均值和方差都接近于1和0。在你的代码中,你需要将GNN['predictions']从sigmoid函数改为pred_logits,因为sigmoid函数已经添加到了while循环体内。

至于你遇到的ValueError: ('Input has undefined axis dimension. Input shape: ', TensorShape([None]))问题,
这个错误通常出现在在输入张量的形状中有一个轴的维度为None,这会导致TensorFlow无法推断张量的形状。通常这个问题可以通过在定义输入张量时明确指定维度大小来解决。下面是一些可能导致这个错误的情况:

1 数据的维度不匹配。例如,如果您的代码需要输入一批图像,但是在输入中有一些图像大小不同,就会导致这个错误。

2 在代码的某个位置,您可能没有正确处理输入张量的形状,导致某个维度的大小变为None。

1、我印象这个在Gpt可以找到回答;
2、有其他的关于这个问题的回答问题可以参考

该回答引用chatgpt:
首先,关于模型训练过程中loss变化的问题,这可能是由于使用的RNN循环次数过多,导致模型在训练初期无法正确地更新参数。这种现象称为“梯度消失”或“梯度爆炸”。您可以尝试减少RNN循环次数或使用更先进的优化器来缓解这个问题。

其次,如果您想在最后一层激活函数sigmoid之前添加批量归一化(Batch Normalization,BN)层,可以使用TensorFlow提供的BatchNormalization函数。您可以将BN层添加到最后一层的输出之前,并将激活函数放在BN层之后。例如:

# Add a Batch Normalization layer
bn_layer = tf.keras.layers.BatchNormalization()(output_of_last_layer)

# Add the activation function after the BN layer
output = tf.keras.activations.sigmoid(bn_layer)


注意,添加BN层后,您需要重新训练模型以使其适应新的层结构。

引用chatGPT作答,对于第一个问题,由于在循环次数为32时,loss会由很大的值逐渐变为较小的值,这表明模型可能存在梯度爆炸的问题,即在反向传播过程中,梯度可能变得非常大,导致无法稳定地更新模型的参数。因此,您可以尝试使用梯度裁剪来限制梯度大小,或者尝试减小循环次数。

对于第二个问题,您可以在最后一层激活函数sigmoid之前添加BN层,如下所示:

# Define the BN layer
bn_layer = tf.keras.layers.BatchNormalization()

# Get the last embeddings
last_states = gnn(
  { "M": M_matrix, "VC": VC_matrix, 'chrom_number': chrom_number },
  { "V": vertex_initial_embeddings, "C": colors_initial_embeddings },
  time_steps = time_steps
)
GNN["last_states"] = last_states
V_n = last_states['V'].h
C_n = last_states['C'].h

# Compute a vote for each embedding
V_vote = tf.reshape(V_vote_MLP(V_n), [-1])

# Add BN layer before the final sigmoid activation function
V_vote = bn_layer(V_vote)
V_vote = tf.keras.activations.sigmoid(V_vote)

# Compute the number of problems in the batch
num_problems = tf.shape(n_vertices)[0]

# Compute a logit probability for each problem
pred_logits = tf.while_loop(
    lambda i, pred_logits: tf.less(i, num_problems),
    lambda i, pred_logits:
        (
            (i+1),
            pred_logits.write(
                i,
                tf.reduce_mean(V_vote[tf.reduce_sum(n_vertices[0:i]):tf.reduce_sum(n_vertices[0:i])+n_vertices[i]])
            )
        ),
    [0, tf.TensorArray(size=num_problems, dtype=tf.float32)]
    )[1].stack()

# Convert logits into probabilities
GNN['predictions'] = tf.sigmoid(pred_logits)

在代码中添加了一个BatchNormalization层,然后使用sigmoid激活函数对其进行了激活,以生成最终的预测。请注意,BatchNormalization层应该在激活函数之前添加。