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])
完全不符合实际的特征图尺寸,经过两次卷积+池化后,特征图已经被缩小了,我们来一步步算:
- 输入层:
128×128×3 - conv1(same padding):输出还是
128×128×28,然后pool1(2×2 stride2):变成64×64×28 - conv2(same padding):输出
64×64×14,然后pool2(2×2 stride2):变成32×32×14
所以正确的展平应该是32×32×14,或者更省心的用TensorFlow自带的flatten层,不用手动计算:
pool2_flat = tf.layers.flatten(pool2)
其他可以优化的小细节(帮你提升模型效果)
- 优化器选择:新手用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 )
- 数据归一化:你把图像转成了float32,但没有做归一化,像素值在0-255之间会导致模型训练不稳定,建议除以255缩到0-1区间:
data = np.float32(np.asarray(data_images)) / 255.0 # 新增归一化
- 损失函数适配二分类:二分类任务其实可以用
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
相关产品推荐
相关产品推荐

