You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用sigmoid激活与BinaryAccuracy始终获0准确率,模型形状不匹配

问题分析与解决方案

核心问题有两个:模型输出形状与标签不匹配导致准确率计算失效;loss为负说明训练逻辑存在异常。以下是具体修正方案:

1. 修正模型输入形状的定义错误

你的模型第一层是GRU,但input_shape参数却写在后面的Conv1D层中,这会导致Keras无法正确推断输入数据的形状,进而引发后续层的形状混乱。

修正:
将input_shape移到GRU层(模型的第一层),并移除Conv1D层的input_shape参数:

model.add(
    tf.keras.layers.GRU(
        gru_units,
        return_sequences=True,
        input_shape=(X_train_scaled.shape[1], X_train_scaled.shape[2])  # 移到这里
    )
)

model.add(
    tf.keras.layers.Conv1D(
        filters=conv_filters,
        kernel_size=conv_kernel_size,
        activation="relu"  # 移除input_shape
    )
)

2. 修正模型输出形状与标签不匹配的问题

你当前的模型结构中,GRU返回序列(return_sequences=True),后续Conv1D、MaxPooling1D都保留了序列维度,即使添加Flatten,也可能因为中间层的3D输出导致最终输出形状仍为3D([72,14,1]),而标签是2D的[72,1],这会导致BinaryAccuracy无法正确计算,直接输出0。

正确做法:
在序列层之后使用全局池化层(如GlobalMaxPool1D或GlobalAveragePool1D)压缩序列维度,将3D输出转为2D的样本级特征向量,确保最终输出与标签形状匹配:

model.add(tf.keras.layers.MaxPooling1D(pool_size=2))

if use_batch_norm:
    model.add(tf.keras.layers.BatchNormalization())

# 新增全局池化层,替换后续的Flatten
model.add(tf.keras.layers.GlobalMaxPool1D())

model.add(tf.keras.layers.Dense(dense_units))
model.add(tf.keras.layers.Dropout(dense_dropout))
# 移除原来的Flatten层
model.add(
    tf.keras.layers.Dense(
        units=1,
        activation="sigmoid",
    )
)

修改后,模型最终输出形状为[batch_size, 1],与标签形状完全匹配。

3. 解决loss为负的异常问题

BinaryCrossentropy的loss值不可能为负,出现负数说明训练过程中存在数值异常:

  • 确保标签是float类型:将y_train和y_val转换为float32:
    y_train = y_train.astype('float32')
    y_val = y_val.astype('float32')
    
  • 调整学习率范围:你的lr上限是1e-2,部分超参数组合可能导致模型发散,可尝试将上限降至5e-3:
    lr = hp.Float("lr", min_value=1e-4, max_value=5e-3, sampling="LOG")
    
  • 确认loss参数:因为最后一层用了sigmoid激活,BinaryCrossentropy默认from_logits=False是正确的,不要修改这个参数。

4. 验证模型形状

修改完成后,可以在模型编译前添加一行代码,打印模型的输出形状,确认与标签匹配:

print("模型输出形状:", model.output_shape)  # 应该输出 (None, 1)

修正后的完整模型代码

def search_model_gru_cnn(hp):
    # Hyperparameters
    lr = hp.Float("lr", min_value=1e-4, max_value=5e-3, sampling="LOG")
    dense_dropout = hp.Float("dense_dropout", min_value=0.0, max_value=0.5, step=0.05)
    use_batch_norm = hp.Boolean("use_batch_norm", default=False)

    conv_filters = hp.Int("conv_filters", min_value=32, max_value=128, step=16)
    conv_kernel_size = hp.Int("conv_kernel_size", min_value=3, max_value=7, step=2)

    gru_units = hp.Int("gru_units", min_value=32, max_value=256, step=8)

    dense_units = hp.Int("dense_units", min_value=16, max_value=128, step=4)

    model = tf.keras.models.Sequential()

    model.add(
        tf.keras.layers.GRU(
            gru_units,
            return_sequences=True,
            input_shape=(X_train_scaled.shape[1], X_train_scaled.shape[2])
        )
    )

    model.add(
        tf.keras.layers.Conv1D(
            filters=conv_filters,
            kernel_size=conv_kernel_size,
            activation="relu",
        )
    )
    model.add(tf.keras.layers.MaxPooling1D(pool_size=2))

    if use_batch_norm:
        model.add(tf.keras.layers.BatchNormalization())

    model.add(tf.keras.layers.GlobalMaxPool1D())

    model.add(tf.keras.layers.Dense(dense_units))

    model.add(tf.keras.layers.Dropout(dense_dropout))
    model.add(
        tf.keras.layers.Dense(
            units=1,
            activation="sigmoid",
        )
    )

    # Compile the model
    optimizer = tf.keras.optimizers.Adam(learning_rate=lr)
    model.compile(
        optimizer=optimizer,
        loss=tf.keras.losses.BinaryCrossentropy(),
        metrics=[
            tf.keras.metrics.BinaryAccuracy(
                name="binary_accuracy", dtype=None, threshold=0.5
            )
        ],
    )

    # 验证输出形状
    print("模型输出形状:", model.output_shape)
    return model

内容的提问来源于stack exchange,提问作者Furkan Öztürk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 17:40:54