基于Keras构建卫星图像到冠层高度的回归模型技术咨询
卫星图像冠层高度回归任务的Keras实现方案
1. 适配任务的基础Sequential模型代码
你的任务属于图像到图像的回归任务,输入为5×5×3的RGB卫星图像,输出为5×8的单波段冠层高度数据。基础模型可采用卷积+转置卷积结构,既保留空间特征,又能精准调整输出尺寸:
from keras.models import Sequential from keras.layers import Conv2D, Conv2DTranspose, BatchNormalization, Activation # 定义模型 model = Sequential([ # 输入层:匹配(5,5,3)的输入尺寸 Conv2D(32, (3,3), padding='same', input_shape=(5,5,3)), BatchNormalization(), Activation('relu'), Conv2D(64, (3,3), padding='same'), BatchNormalization(), Activation('relu'), # 转置卷积将宽度从5扩展到8,保持高度5不变 Conv2DTranspose(32, (3,3), strides=(1, 2), padding='same', output_padding=(0,1)), BatchNormalization(), Activation('relu'), # 输出层:单波段(5,8,1),线性激活适配连续值回归 Conv2D(1, (3,3), padding='same', activation='linear') ]) # 查看模型结构 model.summary()
模型说明:
- 普通卷积层负责提取输入图像的空间特征
Conv2DTranspose(转置卷积)配合步长和输出补零,实现从5到8的宽度扩展- 最终线性激活层输出连续的冠层高度值,符合回归任务需求
2. 合适的损失函数与编译代码
你的任务是回归任务,提供的categorical_crossentropy是多分类任务损失,完全不适用。以下是两组适配的编译方案:
方案一:均方误差(MSE)优先(推荐)
MSE对较大预测误差惩罚更重,适合追求高精度拟合的场景:
model.compile( optimizer='adam', loss='mse', metrics=['mse', 'mae'] )
方案二:平均绝对误差(MAE)优先
MAE对异常值鲁棒性更强,若冠层高度数据存在大量极端值(如超高/超低冠层),可选择此方案:
model.compile( optimizer='adam', loss='mae', metrics=['mae', 'mse'] )
注意:
mape(平均绝对百分比误差)需谨慎使用,若真实值存在0会导致计算错误adam优化器因自适应学习率,适配大多数回归任务
3. 是否需要对输出数据集进行归一化
强烈建议对输出的冠层高度数据进行归一化,原因如下:
- 冠层高度数值范围通常较大(如0到数十米),归一化可缩小数值区间,避免梯度爆炸/消失,加速模型收敛
- 归一化能让不同量级的特征对模型的影响更均衡
归一化实现示例:
使用MinMaxScaler将输出值缩放到0-1区间,训练完成后再反归一化得到真实高度:
from sklearn.preprocessing import MinMaxScaler # 将Y从(样本数,5,8)转为(样本数*5*8, 1),便于归一化 y_flatten = Y.reshape(-1, 1) scaler = MinMaxScaler() y_flatten_scaled = scaler.fit_transform(y_flatten) # 还原为原形状(样本数,5,8) Y_scaled = y_flatten_scaled.reshape(Y.shape) # 分割数据集时使用归一化后的Y x_train, x_test, y_train, y_test = train_test_split(X, Y_scaled, test_size=0.25) # 预测后反归一化得到真实冠层高度 y_pred_scaled = model.predict(x_test) y_pred_flatten = y_pred_scaled.reshape(-1,1) y_pred = scaler.inverse_transform(y_pred_flatten).reshape(y_pred_scaled.shape)
关键提示:
- 仅用训练集拟合归一化器(
scaler.fit只在训练集执行),避免数据泄露 - 若冠层高度分布接近正态分布,也可使用
StandardScaler(标准化为均值0、方差1)
优化后的完整代码(整合数据加载+归一化+模型)
import os import numpy as np from sklearn.model_selection import train_test_split from sklearn.preprocessing import MinMaxScaler from keras.models import Sequential from keras.layers import Conv2D, Conv2DTranspose, BatchNormalization, Activation from PIL import Image # 加载输入数据X并归一化 X = [] train_folder = 'D:/satellite/data/train/' for file in os.listdir(train_folder): if file.endswith('.png'): img = Image.open(os.path.join(train_folder, file)) X.append(np.array(img)) X = np.array(X) / 255.0 # 归一化到0-1 # 加载输出数据Y并归一化 Y = [] train_folder_y = 'D:/canopy/data/train/' for file in os.listdir(train_folder_y): if file.endswith('.png'): img = Image.open(os.path.join(train_folder_y, file)) Y.append(np.array(img)) Y = np.array(Y) # 对Y进行归一化处理 y_flatten = Y.reshape(-1, 1) scaler = MinMaxScaler() y_flatten_scaled = scaler.fit_transform(y_flatten) Y_scaled = y_flatten_scaled.reshape(Y.shape) # 分割训练/测试集 x_train, x_test, y_train, y_test = train_test_split(X, Y_scaled, test_size=0.25) # 定义模型 model = Sequential([ Conv2D(32, (3,3), padding='same', input_shape=(5,5,3)), BatchNormalization(), Activation('relu'), Conv2D(64, (3,3), padding='same'), BatchNormalization(), Activation('relu'), Conv2DTranspose(32, (3,3), strides=(1, 2), padding='same', output_padding=(0,1)), BatchNormalization(), Activation('relu'), Conv2D(1, (3,3), padding='same', activation='linear') ]) # 编译模型(选用MSE方案) model.compile(optimizer='adam', loss='mse', metrics=['mse', 'mae']) # 训练模型 history = model.fit( x_train, y_train, batch_size=32, epochs=50, validation_data=(x_test, y_test) ) # 预测并反归一化得到真实高度 y_pred_scaled = model.predict(x_test) y_pred = scaler.inverse_transform(y_pred_scaled.reshape(-1,1)).reshape(y_pred_scaled.shape)
内容的提问来源于stack exchange,提问作者pnz1337
相关产品推荐
相关产品推荐

