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

TensorFlow构建屋顶分类CNN时出现Shapes Incompatible错误求助

问题排查与修改建议

嘿,我来帮你搞定这个报错,顺便给你一些CNN入门的实用建议~

首先,直接导致报错的原因:One-Hot编码维度不匹配

你的任务是二分类(类别0、1),但在计算损失时,你把tf.one_hot的depth参数设成了4:

onehot_labels = tf.one_hot(indices=tf.cast(labels, tf.int32), depth=4)

这就生成了形状为(?,4)的标签,但你的logits层输出是2个单元(对应二分类),所以两者形状不兼容,抛出了Shapes (?, 2) and (?, 4) are incompatible的错误。

修改方法:把depth改成2:

onehot_labels = tf.one_hot(indices=tf.cast(labels, tf.int32), depth=2)

第二个严重错误:全连接层前的特征展平维度计算错误

你现在写的:

pool2_flat = tf.reshape(pool2, [-1, 128 * 128 * 3])

完全不符合实际的特征图尺寸,经过两次卷积+池化后,特征图已经被缩小了,我们来一步步算:

  1. 输入层:128×128×3
  2. conv1(same padding):输出还是128×128×28,然后pool1(2×2 stride2):变成64×64×28
  3. conv2(same padding):输出64×64×14,然后pool2(2×2 stride2):变成32×32×14

所以正确的展平应该是32×32×14,或者更省心的用TensorFlow自带的flatten层,不用手动计算:

pool2_flat = tf.layers.flatten(pool2)

其他可以优化的小细节(帮你提升模型效果)

  1. 优化器选择:新手用SGD收敛速度通常很慢,建议换成Adam优化器,提升训练效率:
train_op = tf.contrib.layers.optimize_loss(
    loss=loss,
    global_step=tf.contrib.framework.get_global_step(),
    learning_rate=0.001,
    optimizer="Adam"  # 把SGD改成Adam
)
  1. 数据归一化:你把图像转成了float32,但没有做归一化,像素值在0-255之间会导致模型训练不稳定,建议除以255缩到0-1区间:
data = np.float32(np.asarray(data_images)) / 255.0  # 新增归一化
  1. 损失函数适配二分类:二分类任务其实可以用sigmoid_cross_entropy_with_logits,此时logits层只需要输出1个单元,不过你用softmax配合二分类也没问题,只要维度匹配就好。

修改后的完整cnn_model_fn参考

def cnn_model_fn(features,labels,mode):
    input_layer = tf.reshape(features, [-1,128,128,3])
    #Convolution layer #1
    conv1 = tf.layers.conv2d(input_layer,filters=28,kernel_size=[5,5],padding="same",activation=tf.nn.relu)
    #Pooling layer #1
    pool1=tf.layers.max_pooling2d(inputs=conv1,pool_size=[2,2],strides=2)
    #Convolution layer #2
    conv2 = tf.layers.conv2d(pool1,filters=14,kernel_size=[5,5],padding="same",activation=tf.nn.relu)
    #Pooling layer #2
    pool2=tf.layers.max_pooling2d(inputs=conv2,pool_size=[2,2],strides=2)
    # Dense Layer - 用flatten替代手动reshape
    pool2_flat = tf.layers.flatten(pool2)
    dense = tf.layers.dense(inputs=pool2_flat, units=128, activation=tf.nn.relu)
    dense2 = tf.layers.dense(inputs=dense, units=64, activation=tf.nn.relu)
    dense3 = tf.layers.dense(inputs=dense2, units=32, activation=tf.nn.relu)
    dropout = tf.layers.dropout(inputs=dense3, rate=0.4, training=mode == learn.ModeKeys.TRAIN)
    # Logits Layer
    logits = tf.layers.dense(inputs=dropout, units=2)
    loss = None
    train_op = None
    # Calculate Loss (for both TRAIN and EVAL modes)
    if mode != learn.ModeKeys.INFER:
        # 修正onehot的depth为2
        onehot_labels = tf.one_hot(indices=tf.cast(labels, tf.int32), depth=2)
        loss = tf.losses.softmax_cross_entropy(
            onehot_labels=onehot_labels, logits=logits)
    # Configure the Training Op (for TRAIN mode)
    if mode == learn.ModeKeys.TRAIN:
        train_op = tf.contrib.layers.optimize_loss(
            loss=loss,
            global_step=tf.contrib.framework.get_global_step(),
            learning_rate=0.001,
            optimizer="Adam")  # 换成Adam优化器
    # Generate Predictions
    predictions = {
        "classes": tf.argmax(
            input=logits, axis=1),
        "probabilities": tf.nn.softmax(
            logits, name="softmax_tensor")
    }
    # 补上之前遗漏的EstimatorSpec返回,否则会触发新错误
    return tf.estimator.EstimatorSpec(mode=mode, predictions=predictions, loss=loss, train_op=train_op)

内容的提问来源于stack exchange,提问作者James

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:22:37