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

非正方形栅格数组作为CNN输入的问题及报错解决求助

问题描述

我有6个单波段滑坡参数栅格,转换为numpy数组后堆叠成形状为(1612, 2885, 6)的数组,同时有1个形状为(1612, 2885, 1)的滑坡编目栅格作为目标数据。

因为数组是非正方形的,我在定义CNN输入形状时很困惑——是否需要把数组调整为更小的正方形?尝试直接用数组尺寸定义输入形状时,一直出现以下报错:

ValueError: Input 0 of layer "conv2d" is incompatible with the layer:
expected min_ndim=4, found ndim=3. Full shape received: (None, 2885, 6)

已经被这个问题困扰一个月,求解决方案,同时希望获取输入形状相关的学习建议,方便以后解决类似问题。

我的代码

读取栅格并转为数组

#Reading raster stack
Elevation = gdal.Open(r"C:/Users/Neo/NEO/Belajar Python/S3/Data jadi/Resampled data/Elevation.tif")  
Wetness= gdal.Open(r"C:/Users/Neo/NEO/Belajar Python/S3/Data jadi/Resampled data/Wetness.tif") 
Slope= gdal.Open(r"C:/Users/Neo/NEO/Belajar Python/S3/Data jadi/Resampled data/Slope.tif")
Distanceroad= gdal.Open(r"C:/Users/Neo/NEO/Belajar Python/S3/Data jadi/Resampled data/DistanceRoad.tif") 
Distanceriver= gdal.Open(r"C:/Users/Neo/NEO/Belajar Python/S3/Data jadi/Resampled data/DistanceRiver.tif") 
Aspect= gdal.Open(r"C:/Users/Neo/NEO/Belajar Python/S3/Data jadi/Resampled data/Aspect.tif")
Target= gdal.Open(r"C:/Users/Neo/NEO/Belajar Python/S3/Data jadi/Resampled data/inventory.tif") 

#Read raster as array
ElevationArray = np.array(Elevation.GetRasterBand(1).ReadAsArray())
WetnessArray = np.array(Wetness.GetRasterBand(1).ReadAsArray())
SlopeArray = np.array(Slope.GetRasterBand(1).ReadAsArray())
DistanceRoadArray = np.array(Distanceroad.GetRasterBand(1).ReadAsArray())
DistanceRiverArray = np.array(Distanceriver.GetRasterBand(1).ReadAsArray())
AspectArray = np.array(Aspect.GetRasterBand(1).ReadAsArray())
TargetArray = np.array(Target.GetRasterBand(1).ReadAsArray())

#Array stacking
Dataarray = np.dstack((ElevationArray,WetnessArray,SlopeArray,DistanceRoadArray,DistanceRiverArray,AspectArray))

print(Dataarray.shape)

输出:(1612, 2885, 6)

划分训练测试集

#Target and factor array
row = Dataarray.shape[0]
col = Dataarray.shape[1]
bands = Dataarray.shape[2]

X_data = Dataarray
y_data = TargetArray

#data split into X and Y
X_train, X_test, y_train, y_test = train_test_split(X_data, y_data, test_size=0.3, random_state=42)
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)

输出:(1128, 2885, 6) (484, 2885, 6) (1128, 2885) (484, 2885)

CNN模型定义

# CNN model #

inputshape = (row, col, bands)
model = Sequential()
model.add(Conv2D(6, (3,3), activation='relu', input_shape=inputshape[1:]))
model.add(MaxPool2D(2))
model.add(Flatten())
model.add(Dense(50, activation='sigmoid'))
model.add(Dense(15, activation='sigmoid'))
model.add(Dense(1, activation='softmax'))
optimizer = optimizers.Adam(lr=0.01)
model.compile(loss='categorical_crossentropy',
             optimizer=optimizer, metrics=['accuracy'])

def lr_scheduler(epoch):
    if epoch % 100 == 0:
        K.set_value(optimizer.lr, K.eval(optimizer.lr) * 0.1)
    return K.eval(optimizer.lr)

reduce_lr = LearningRateScheduler(lr_scheduler)
EarlyStop = EarlyStopping(monitor='val_loss', patience=200, verbose=0, mode='min')
modelcheck = ModelCheckpoint('CNN_model.h5', monitor='val_acc',
        verbose=1, save_best_only=True, mode='max')

callable = [modelcheck, reduce_lr, EarlyStop]

model.fit(X_train, y_train, batch_size=100, 
    callbacks=callable, verbose=2, epochs=10)

model.save('CNN_model.h5')

print(model.summary())

运行后报错:

ValueError: Input 0 of layer "conv2d" is incompatible with the layer: expected min_ndim=4, found ndim=3. Full shape received: (None, 2885, 6)

解决方案

1. 核心问题:输入维度与样本逻辑错误

Keras的Conv2D层要求输入是4维张量:(样本数, 高度, 宽度, 通道数),但你的数据处理完全搞错了样本定义:

  • 你用train_test_split直接分割第一维度,把栅格的行(高度)当成了样本数,导致输入变成(1128, 2885, 6)——这是3维数据,缺少了CNN要求的样本维度,同时原本的高度维度被错误识别为样本数,最终引发维度不匹配报错。

正确的数据处理方式

遥感栅格用CNN训练,必须把局部像素窗口作为样本,步骤如下:

  • 用滑动窗口从大栅格中截取固定大小的小块(比如32x32或64x64,长方形也可以,无需强制正方形),每个小块对应一个样本,窗口中心的标签作为该样本的目标值。
  • 可以用skimage.util.view_as_windows实现滑动窗口切割,既符合CNN局部特征学习的逻辑,也能避免大尺寸栅格带来的内存溢出问题。

快速验证模型的临时修复

如果只是想验证模型逻辑,可临时给数据增加样本维度(仅适合小尺寸栅格,你的大尺寸图可能会内存溢出):

# 给X增加样本维度
X_train = X_train[np.newaxis, ...]
X_test = X_test[np.newaxis, ...]
# 给y增加样本和通道维度(适配像素级分类)
y_train = y_train[np.newaxis, ..., np.newaxis]
y_test = y_test[np.newaxis, ..., np.newaxis]

2. 模型定义的其他修正点

  • input_shape参数应设为(row, col, bands),你之前取inputshape[1:]导致缺失高度维度,必须保证输入形状与数据的单样本维度一致。
  • 损失函数与激活层不匹配:滑坡编目通常是二分类任务,应将最后一层改为sigmoid激活,损失函数用binary_crossentropy;如果是多分类且标签未做独热编码,用sparse_categorical_crossentropy替代categorical_crossentropy。
学习建议
  • 牢记CNN输入维度规则:TensorFlow后端的2D卷积层输入必须是4维,顺序为(batch_size, height, width, channels),PyTorch则是(batch_size, channels, height, width),注意区分框架差异。
  • 掌握栅格样本切割逻辑:遥感栅格几乎都用滑动窗口切割小样本训练,这是解决大尺寸数据内存问题和适配CNN局部特征学习的核心方法。
  • 模型与任务匹配:根据任务类型(二分类/多分类/语义分割)选择对应的激活层和损失函数,不要随意混用。
  • 无需强制正方形输入:CNN支持任意长方形输入,只要卷积核尺寸能适配即可(比如输入宽度2885用3x3卷积核,步长1时输出宽度为2885-3+1=2883,完全合法)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 03:31:05