深度学习与遥感入门(六)|轻量化 MobileNetV2 高光谱分类

系列回顾:
(一)CNN 基础:高光谱图像分类可视化全流程
(二)HybridNet(CNN+Transformer):提升全局感受野
(三)GCN 入门实战:基于光谱 KNN 的图卷积分类与全图预测
(四)空间–光谱联合构图的 GCN:RBF 边权 + 自环 + 早停,得到更稳更自然的全图分类结果
(五)GAT & 构图消融 + 分块全图预测:更稳更快的高光谱图分类(PyTorch Geometric 实战)
合集链接:https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzkwMTE0MjI4NQ==&action=getalbum&album_id=4007114522736459789#wechat_redirect
本篇(六)聚焦“数据泄露”,采用仅训练集像素拟合 StandardScaler+PCA,并在全图预测中共享同一变换空间;模型选用轻量化 MobileNetV2深度可分离卷积,在显存友好的坐标批推理下实现全图预测

0. 前言:PCA 与高光谱分类中的“数据泄露”

  • 什么是泄露? 训练阶段直接/间接使用了测试数据统计信息(均值、方差、主成分方向等)。
  • 怎么产生? 在整图上 fit 标准化与 PCA,然后再切训练/测试或直接做全图分类。
  • 为什么常见? 历史习惯、样本少时稳定性考虑、对比研究图省事、实现方便。
  • 影响大吗? 小数据集上常为 0.1%~1% 的 OA 差异;但在类分布差异大训练样本极少时,差距可达数个百分点。真实部署场景绝不允许整图 fit

本文做法先分层抽样得到训练/测试索引仅用训练像素 fit 标准化与 PCA用该变换对整图 transform训练与预测均在同一(训练集拟合得到的)特征空间,从源头避免泄露。

1. 任务要点

  1. 严格无泄露预处理:只用训练像素拟合 StandardScaler+PCA;全图在同一变换空间中变换。
  2. 轻量模型:用 MobileNetV2 的深度可分离卷积(3 段)+ GAP + FC。
  3. 全图预测显存友好:按坐标批收集 patch → 堆成 batch → 前向推理。
  4. 评估classification_report、混淆矩阵、OA;可视化支持 Windows 阻塞显示。

2. 方法详解

2.1 严格无泄露的 PCA 流程

  • 先划分后拟合:对有标签像素做分层抽样得到训练/测试索引;仅训练像素拟合 StandardScalerPCA
  • 全图共享空间:将整图 (H×W×Bands) 用训练集拟合的变换进行标准化与降维,得到 (H×W×PCA_DIM)
  • 提取 patch:在 PCA 空间内按坐标提取 (PATCH_SIZE×PATCH_SIZE×PCA_DIM) 的 patch 作为输入。

这样做的关键测试像素从未参与统计,评估更可信。

2.2 轻量化 MobileNetV2(HSI 版)

  • Depthwise Separable Conv:逐通道 3×3 深度卷积 + 1×1 点卷积,大幅降参与算力需求。
  • 网络骨干:3 段深度可分离卷积 → GAP(自适应全局平均池化)→ 全连接输出。
  • 输入通道:这里输入为 PCA 后的通道数(例如 30),以二维 patch 形式输入(C×H×W)。

2.3 全图预测策略(坐标批)

  • 坐标遍历:生成所有像素坐标。
  • 反射填充:边界像素也能提取完整 patch。
  • 批量收集:按 batch_size 组装 patch → 前向 → 填回 pred_map
  • 显存稳定:避免一次性张量过大导致溢出。

3. 代码逐段 + 解释

下面先按逻辑分段展示与解释;最末提供“一键可跑脚本(整合版)”,复制后仅需修改数据路径即可运行。

3.1 全局与可视化设置

import os, time, numpy as np, scipy.io as sio
import torch, torch.nn as nn
from torch.utils.data import Dataset, DataLoader
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import classification_report, confusion_matrix, accuracy_score
from sklearn.model_selection import train_test_split
import matplotlib

# Windows 下 TkAgg 更稳;Linux/服务器用 Agg(无显示)
if os.name == 'nt':
    matplotlib.use('TkAgg')
else:
    matplotlib.use('Agg')

import matplotlib.pyplot as plt
import seaborn as sns

matplotlib.rcParams['font.family'] = 'SimHei'
matplotlib.rcParams['axes.unicode_minus'] = False
plt.rcParams['figure.dpi'] = 120
sns.set_theme(context="notebook", style="whitegrid", font="SimHei")

torch.backends.cudnn.benchmark = True

3.2 随机种子

def set_seeds(seed=42):
    import random
    random.seed(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)

固定随机性,保证复现。

3.3 轻量化网络

class DepthwiseSeparableConv(nn.Module):
    def __init__(self, in_ch, out_ch, stride=1):
        super().__init__()
        self.depthwise = nn.Conv2d(in_ch, in_ch, 3, stride=stride, padding=1, groups=in_ch, bias=False)
        self.pointwise = nn.Conv2d(in_ch, out_ch, 1, bias=False)
        self.bn = nn.BatchNorm2d(out_ch)
        self.act = nn.ReLU6(inplace=True)

    def forward(self, x):
        x = self.depthwise(x)
        x = self.pointwise(x)
        x = self.bn(x)
        return self.act(x)

class MobileNetV2_HSI(nn.Module):
    def __init__(self, in_ch, num_classes, width_mult=1.0):
        super().__init__()
        c1, c2, c3 = int(32 * width_mult), int(64 * width_mult), int(128 * width_mult)
        self.layer1 = DepthwiseSeparableConv(in_ch, c1)
        self.layer2 = DepthwiseSeparableConv(c1, c2)
        self.layer3 = DepthwiseSeparableConv(c2, c3)
        self.gap = nn.AdaptiveAvgPool2d
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

遥感AI实战

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值