1. 项目背景与核心价值
高光谱图像分类是遥感领域的重要研究方向,相比普通RGB图像,高光谱数据包含数十至数百个连续波段的光谱信息,能够捕捉地物更精细的光谱特征。但这也带来了"维度灾难"问题——如何在有限样本下有效提取空间-光谱联合特征成为关键挑战。
去年处理实验室积压的高光谱数据时,我发现传统方法存在明显局限:单纯使用CNN难以充分建模光谱维度相关性,而仅用RNN又无法有效提取空间局部特征。于是尝试将二者结合,在PyTorch框架下实现了一个混合架构,实测在Indian Pines和Pavia University两个经典数据集上,仅用20%训练数据就达到了96%以上的分类准确率。
2. 关键技术方案解析
2.1 网络架构设计
核心模型采用CNN-RNN混合结构,其创新点在于:
- 空间特征提取层:3x3卷积配合BatchNorm和ReLU,捕获局部纹理特征
- 光谱序列建模层:双向GRU网络处理光谱维度序列关系
- 特征融合方式:将CNN输出的特征图空间维度展开为序列输入RNN
class HybridModel(nn.Module): def __init__(self, input_channels, num_classes): super().__init__() self.cnn = nn.Sequential( nn.Conv2d(input_channels, 32, 3, padding=1), nn.BatchNorm2d(32), nn.ReLU(), nn.MaxPool2d(2) ) self.rnn = nn.GRU(32, 64, batch_first=True, bidirectional=True) self.classifier = nn.Linear(128, num_classes)2.2 数据预处理策略
高光谱数据通常为(height, width, bands)的三维结构,需要特殊处理:
- 波段归一化:各波段单独进行Z-score标准化
- 空间增强:随机裁剪生成固定尺寸(如7x7)的样本块
- 维度转换:将通道维度调整至PyTorch要求的顺序
class HyperDataset(Dataset): def __getitem__(self, index): x = self.data[index] y = self.label[index] h, w, c = x.shape i = random.randint(0, h-self.patch_size) j = random.randint(0, w-self.patch_size) patch = x[i:i+self.patch_size, j:j+self.patch_size, :] return torch.FloatTensor(patch.transpose(2,0,1)), y3. 工程实现细节
3.1 训练流程优化
采用分阶段训练策略:
- 冻结RNN层,仅训练CNN部分(100轮)
- 解冻全部参数联合微调(50轮)
- 使用余弦退火学习率调度
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3) scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=50)3.2 模型评估机制
实现了一套完整的评估流水线:
- 实时验证集准确率监控
- 最佳模型自动保存(带时间戳)
- 预测结果持久化存储
if acc > best_acc: best_acc = acc torch.save(model.state_dict(), f"best_model_{time.strftime('%m%d%H%M')}.pth")4. 关键问题与解决方案
4.1 显存溢出问题
当输入尺寸较大时容易出现:
- 解决方案:采用梯度累积技术
- 设置
accum_steps=4,每4个batch更新一次参数
loss = loss / accum_steps loss.backward() if (i+1) % accum_steps == 0: optimizer.step() optimizer.zero_grad()4.2 类别不平衡问题
某些地物类别样本极少:
- 应对措施:
- 采用加权交叉熵损失
- 在数据加载器中实现过采样
class_weights = compute_class_weight('balanced', classes=np.unique(train_labels), y=train_labels) criterion = nn.CrossEntropyLoss(weight=torch.FloatTensor(class_weights).to(device))5. 实验配置与结果
5.1 硬件环境
- GPU: RTX 3060 (12GB显存)
- 内存: 32GB DDR4
- 单轮训练时间: ≈28秒(Indian Pines数据集)
5.2 超参数设置
| 参数 | 取值 | 说明 |
|---|---|---|
| 批大小 | 64 | 兼顾显存和稳定性 |
| 初始LR | 1e-3 | 配合AdamW优化器 |
| 权重衰减 | 0.01 | 防止过拟合 |
| Patch尺寸 | 7x7 | 平衡局部和全局信息 |
5.3 性能对比
| 方法 | Indian Pines | Pavia University |
|---|---|---|
| 单纯CNN | 93.2% | 94.7% |
| 单纯RNN | 89.5% | 91.3% |
| 本文方法 | 96.5% | 96.8% |
6. 实用技巧与注意事项
- 可复现性保障:
def set_seed(seed=42): torch.backends.cudnn.deterministic = True torch.backends.cudnn.benchmark = False- 数据泄露预防:
- 确保训练/验证集来自不同空间区域
- 对每个样本块添加位置编码
- 部署优化建议:
- 使用TorchScript导出模型
- 实现基于滑动窗口的大图预测
实际部署中发现,当处理整幅高光谱图像时,直接切片预测会导致边缘信息丢失。改进方案是:
def sliding_window_prediction(image, model, window_size=7, stride=3): # 实现带重叠的滑动窗口预测 # 对边缘区域进行镜像填充 # 使用加权平均融合重叠区域预测结果这套代码已在GitHub开源,包含完整的数据预处理、模型训练和预测模块。特别建议关注数据加载器的实现细节——正确处理高光谱数据的维度转换对最终性能影响显著。对于想快速上手的同学,项目中的demo.ipynb提供了从数据加载到预测的完整示例。