高光谱图像分类的CNN-RNN混合网络设计与实践

高光谱图像分类的CNN-RNN混合网络设计与实践 1. 项目背景与核心价值高光谱图像分类是遥感领域的重要研究方向相比传统RGB三通道图像高光谱数据包含数十至数百个连续光谱波段能够捕捉地物更精细的光谱特征。这种图谱合一的特性使其在精准农业、环境监测、矿物勘探等领域具有独特优势。然而波段间的强相关性和高维度特性也给分类任务带来了挑战。我在实际项目中发现传统机器学习方法如SVM、随机森林处理高光谱数据时往往需要复杂的特征工程且对空间-光谱联合特征的提取能力有限。而深度学习的端到端特性恰好能解决这一痛点。本次分享的CNN-RNN混合网络正是针对高光谱数据特性设计的解决方案CNN模块擅长提取局部空间特征如纹理、形状RNN模块可建模波段间的时间序列依赖关系两者结合实现了空间-光谱特征的协同学习2. 网络架构设计解析2.1 整体框架设计模型采用双分支并行结构通过特征融合层实现信息交互输入层(3D立方体数据) ↓ [CNN分支] [RNN分支] ↓ ↓ 空间特征提取 光谱序列建模 ↓ ↓ 特征融合层(Concatenate) ↓ 全连接分类层 ↓ Softmax输出关键设计输入数据保持原始三维结构(H×W×C)避免传统方法中破坏空间/光谱关系的展平操作2.2 CNN模块实现细节采用轻量化的3D-CNN结构兼顾计算效率与特征提取能力class SpatialFeatureExtractor(nn.Module): def __init__(self, in_channels): super().__init__() self.conv1 nn.Conv3d(1, 16, kernel_size(3,3,7), stride(1,1,2)) self.bn1 nn.BatchNorm3d(16) self.conv2 nn.Conv3d(16, 32, kernel_size(3,3,5)) self.bn2 nn.BatchNorm3d(32) self.conv3 nn.Conv3d(32, 64, kernel_size(3,3,3)) self.bn3 nn.BatchNorm3d(64) def forward(self, x): x F.relu(self.bn1(self.conv1(x))) x F.relu(self.bn2(self.conv2(x))) x F.relu(self.bn3(self.conv3(x))) return x.flatten(start_dim2) # 保留空间维度参数选择考量核大小递减大核捕捉宏观特征 → 小核提取细节光谱维度stride2降低波段冗余BN层加速收敛且缓解过拟合2.3 RNN模块优化方案创新性采用双向LSTMAttention机制class SpectralFeatureExtractor(nn.Module): def __init__(self, input_size, hidden_size): super().__init__() self.lstm nn.LSTM(input_size, hidden_size, bidirectionalTrue) self.attention nn.Sequential( nn.Linear(2*hidden_size, 1), nn.Softmax(dim1) ) def forward(self, x): # x shape: [batch, bands, features] x x.permute(1,0,2) # 调整为序列输入 outputs, _ self.lstm(x) weights self.attention(outputs) return (outputs * weights).sum(dim0)技术亮点双向LSTM捕获波段间前后向依赖Attention机制突出重要波段如水分吸收特征波段参数量比传统RNN减少40%3. 数据集处理实战3.1 印度松数据集(Indian Pines)原始数据特点145×145像素224波段(0.4-2.5μm)16类农作物/植被预处理关键步骤# 波段筛选去除噪声/水吸收波段 valid_bands [i for i in range(200) if 9i76 or 108i150 or 167i200] # 数据标准化 def normalize(data): mean data.reshape(-1, data.shape[-1]).mean(axis0) std data.reshape(-1, data.shape[-1]).std(axis0) return (data - mean) / (std 1e-8) # 样本增强 transform Compose([ RandomRotate90(), RandomFlip(p0.5), AddGaussianNoise(var_limit0.001) ])3.2 帕维亚大学数据集(Pavia University)特殊处理技巧空间下采样(610×340→305×170)缓解显存压力采用滑动窗口(32×32)生成样本类别平衡策略class_sample_count np.bincount(y_train) weight 1. / class_sample_count samples_weight weight[y_train] sampler WeightedRandomSampler(samples_weight, len(samples_weight))4. 模型训练技巧实录4.1 超参数优化方案通过贝叶斯优化确定的最终配置learning_rate: 0.0015 batch_size: 64 epochs: 150 optimizer: AdamW scheduler: CosineAnnealingLR(T_max50) loss: FocalLoss(gamma2, alpha0.25)关键发现学习率0.002会导致梯度爆炸早停机制(patience15)有效防止过拟合FocalLoss缓解样本不平衡问题4.2 混合精度训练实现scaler GradScaler() with autocast(): outputs model(inputs) loss criterion(outputs, labels) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update()实测效果训练速度提升1.8倍显存占用减少35%精度损失0.5%5. 性能对比与结果分析5.1 分类精度对比(OA%)方法Indian PinesPavia University2D-CNN86.3289.153D-CNN88.9191.07HybridSN90.2492.33本方案93.6795.415.2 消融实验验证组件OA%变化参数量(M)仅CNN-4.212.1仅RNN-6.871.8CNNRNN(无Attention)-1.523.0完整模型-3.26. 工程实践中的挑战6.1 显存优化方案当遇到CUDA out of memory时的解决策略梯度累积技术loss loss / 4 # 假设accum_steps4 if (i1)%4 0: optimizer.step() optimizer.zero_grad()通道剪枝from torch.nn.utils import prune prune.l1_unstructured(conv1, nameweight, amount0.2)6.2 标签噪声处理针对标注误差的鲁棒训练技巧class LabelSmoothingLoss(nn.Module): def __init__(self, smoothing0.1): super().__init__() self.confidence 1.0 - smoothing self.smoothing smoothing def forward(self, pred, target): logprobs F.log_softmax(pred, dim-1) nll_loss -logprobs.gather(dim-1, indextarget.unsqueeze(1)) smooth_loss -logprobs.mean(dim-1) loss self.confidence * nll_loss self.smoothing * smooth_loss return loss.mean()7. 部署优化建议7.1 模型轻量化方案知识蒸馏# 教师模型预测 with torch.no_grad(): teacher_logits teacher_model(inputs) # 学生模型损失 student_logits student_model(inputs) loss 0.7*F.cross_entropy(student_logits, labels) 0.3*KLDivLoss(student_logits, teacher_logits)TensorRT加速trtexec --onnxmodel.onnx --saveEnginemodel.engine \ --fp16 --workspace20487.2 实际应用技巧滑动窗口预测时重叠区域处理output torch.zeros_like(full_image) count torch.zeros_like(full_image) for window in sliding_windows: pred model(window) output[y1:y2, x1:x2] pred count[y1:y2, x1:x2] 1 final output / count多时相数据融合策略# 时相差异特征增强 diff_feature torch.abs(feature2023 - feature2022) combined torch.cat([feature2023, diff_feature], dim1)