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

Keras中U-Net立体视觉模型形状不兼容问题求助

解决U-Net立体视觉任务中的形状不兼容问题

首先,你的报错核心原因是模型的输出尺寸和标签(视差图)的尺寸不匹配,这是因为你模型中的大部分卷积层没有设置padding='same',导致每次卷积都会缩小特征图的尺寸,后续上采样后无法还原到原始输入的尺寸,最终出现形状冲突。

问题分析

看你的模型结构:

  • 多个Convolution2D层(比如Convolution2D(64, (3, 3)))没有设置padding='same',使用默认的padding='valid',这会让特征图的宽高每次减少kernel_size - 1(比如3x3卷积会减少2)。
  • 经过3次MaxPooling2D下采样后,再通过UpSampling2D上采样,中间的卷积操作已经改变了特征图尺寸,最终输出的尺寸比原始输入的视差图尺寸更大,导致[1,370,1242,3] vs [1,368,1240,3]的冲突。

解决方案:保证卷积层的尺寸一致性

要让模型输出和输入视差图尺寸完全匹配,你需要给所有的卷积层(包括Convolution2D和Conv2DTranspose)添加padding='same',这样卷积操作不会改变特征图的宽高(除了池化和上采样的倍数变化)。

另外,标准U-Net是包含跳跃连接的(编码器层和解码器层的特征融合),你的Sequential模型没有实现这一点,虽然不是当前报错的原因,但会影响最终的视差图效果,我也会在修改后的代码里补充这部分。

修改后的完整代码

import pickle
from keras.models import Model
from keras.layers import Input, Convolution2D, MaxPooling2D, UpSampling2D, Conv2DTranspose, concatenate
import numpy as np
import cv2

# 加载数据
pkl_file = open('data.p', 'rb')
data_dict = pickle.load(pkl_file)
X_data = data_dict['images']
Y_data = data_dict['disparity']
data_num = len(X_data)
train_num = int(data_num * 0.8)
X_train = X_data[:train_num]
X_test = X_data[train_num:]
Y_train = Y_data[:train_num]
Y_test = Y_data[train_num:]

# 数据生成器
def gen(X, Y):
    while True:
        for x, y in zip(X, Y):
            yield x, y

# 使用Functional API构建标准U-Net(带跳跃连接)
inputs = Input(shape=(None, None, 6))

# 编码器部分
c1 = Convolution2D(64, (3, 3), activation='relu', padding='same')(inputs)
c1 = Convolution2D(64, (3, 3), activation='relu', padding='same')(c1)
p1 = MaxPooling2D(pool_size=(2, 2))(c1)

c2 = Convolution2D(128, (3, 3), activation='relu', padding='same')(p1)
c2 = Convolution2D(128, (3, 3), activation='relu', padding='same')(c2)
p2 = MaxPooling2D(pool_size=(2, 2))(c2)

c3 = Convolution2D(256, (3, 3), activation='relu', padding='same')(p2)
c3 = Convolution2D(256, (3, 3), activation='relu', padding='same')(c3)
p3 = MaxPooling2D(pool_size=(2, 2))(c3)

# 瓶颈层
c4 = Convolution2D(512, (3, 3), activation='relu', padding='same')(p3)
c4 = Convolution2D(512, (3, 3), activation='relu', padding='same')(c4)

# 解码器部分(带跳跃连接)
u5 = UpSampling2D(size=(2, 2))(c4)
u5 = Conv2DTranspose(256, (3, 3), activation='relu', padding='same')(u5)
concat5 = concatenate([c3, u5])
c5 = Convolution2D(256, (3, 3), activation='relu', padding='same')(concat5)
c5 = Convolution2D(256, (3, 3), activation='relu', padding='same')(c5)

u6 = UpSampling2D(size=(2, 2))(c5)
u6 = Conv2DTranspose(128, (3, 3), activation='relu', padding='same')(u6)
concat6 = concatenate([c2, u6])
c6 = Convolution2D(128, (3, 3), activation='relu', padding='same')(concat6)
c6 = Convolution2D(128, (3, 3), activation='relu', padding='same')(c6)

u7 = UpSampling2D(size=(2, 2))(c6)
u7 = Conv2DTranspose(64, (3, 3), activation='relu', padding='same')(u7)
concat7 = concatenate([c1, u7])
c7 = Convolution2D(64, (3, 3), activation='relu', padding='same')(concat7)
c7 = Convolution2D(64, (3, 3), activation='relu', padding='same')(c7)

# 输出层:视差图,这里假设你的视差图是3通道?如果是单通道可以改成1
outputs = Convolution2D(3, (3, 3), activation='relu', padding='same')(c7)

model = Model(inputs=[inputs], outputs=[outputs])
model.compile(loss=['mse'], optimizer='adam', metrics=['accuracy'])

# 训练模型
model.fit_generator(gen(X_train, Y_train), steps_per_epoch=len(X_train), epochs=5)
scores = model.evaluate(X_test, Y_test, verbose=0)

关键修改点说明

  1. 所有卷积层添加padding='same':确保每次卷积操作后特征图的宽高不变,只有池化和上采样会改变尺寸(倍数关系)。
  2. 使用Functional API构建带跳跃连接的U-Net:标准U-Net的跳跃连接能保留编码器的细节特征,大幅提升视差图的预测效果,这比Sequential模型更适合你的任务。
  3. 调整通道数匹配:根据你的任务需求调整输出层的通道数(如果视差图是单通道,把Convolution2D(3, ...)改成Convolution2D(1, ...))。

额外注意事项

  • 如果你的输入尺寸不是8的倍数,3次MaxPooling2D(2,2)后再上采样3次,最终输出尺寸会和输入尺寸完全一致(因为padding='same'保证了卷积不改变尺寸),所以不需要提前调整图片尺寸。
  • 如果你坚持使用Sequential模型,只需要给每一个Convolution2D和Conv2DTranspose添加padding='same'即可,但还是推荐使用带跳跃连接的U-Net结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:29:37