尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Fermat距离与主动拉普拉斯学习:高光谱图像半监督分类方法解析

Fermat距离与主动拉普拉斯学习:高光谱图像半监督分类方法解析 这次我们来看一个偏学术但非常实用的方向Fermat Active Laplace Learning for Semi-Supervised Hyperspectral Image Classification。它解决的问题很直接高光谱图像的像素级标注成本极高人工标注一张图往往需要大量专业人力而半监督方法能用尽量少的标注样本把分类精度拉上去。这个方向的核心组合很清晰Fermat 距离Active Learning主动学习Laplace Learning拉普拉斯学习。从应用角度看它适合遥感地物分类、农业监测、矿物识别、环境评估等场景从技术角度看它属于“基于图的半监督学习 主动采样”的经典路线关键点在于如何用 Fermat 距离构造更好的图结构以及如何选到最有价值的样本让人工标注。这篇文章会从方法原理、数据准备、环境配置、代码复现思路、实验验证、批量跑参、资源占用和常见问题几个角度展开。没有开源库就按论文思路搭一套可验证的流程有论文源码就按对应仓库跑。先看这个东西到底在做什么再判断值不值得在你的项目里引入。1. 核心能力速览先把核心信息整理成一张表方便快速判断。能力项说明项目类型半监督高光谱图像分类算法/方法论文型工作核心任务高光谱图像逐像素分类核心技术Fermat 距离、Active Learning、Laplace Learning是否依赖大规模标注否目标是用少量标注样本完成分类是否需要 GPU视数据量而定小尺寸高光谱数据集 CPU 可跑整图大区域建议 GPU 加速支持平台通用 Python 环境Windows/Linux/macOS 均可Linux 更适合批处理典型框架PyTorch / TensorFlow或仅用 NumPy SciPy批量任务支持可在不同标注比例、不同邻居数、不同采样策略下批量实验接口 API论文方法一般不直接提供 API需要自行封装适合场景遥感地物分类、精细农业、矿物填图、环境监测、少量标注下的像素分类需要明确一点我目前没有拿到该论文的完整开源实现所以下面所有内容基于“标题中的三个技术点 半监督高光谱分类的通用流程”展开。具体参数和结论要以论文原文和官方源码为准。2. 方法原理拆解Fermat 距离、Active Learning 与 Laplace Learning这个方法的标题直接点出了三个关键组件。要理解它先把三块分开看。2.1 Laplace Learning图半监督分类的底座Laplace Learning 是经典的基于图的半监督学习方法。思路是这样的把每个像素看作图上的一个节点。用像素之间的相似度如光谱距离、空间距离连边并计算边的权重。构造图的拉普拉斯矩阵。把少量有标签节点的标签信息通过图结构传播到无标签节点。数学上通常要解一个优化问题[ \min_{F} \sum_{i,j} w_{ij} |f_i - f_j|^2 ]其中 ( w_{ij} ) 是节点 ( i ) 和 ( j ) 之间的边权重( f_i ) 是节点 ( i ) 的标签向量。这个优化问题可以转化为求解拉普拉斯矩阵的线性方程组。优点是实现简单、可解释强缺点是图结构依赖相似度度量谱特征复杂时容易传播错误。2.2 Fermat 距离用更合理的路径度量替代欧氏距离高光谱图像最大的特点是“维度高”每个像素可能对应几十到几百个光谱波段。在高维空间里欧氏距离容易被噪声和无关波段干扰两个位置近但光谱差异大的像素或两个空间距离远但光谱相似的像素直接用欧氏距离算边权并不稳定。Fermat 距离的核心是用“路径积分”的方式重新定义两点之间的距离。它不再只看两点的直接直线距离而是考虑两点之间所有可能路径并计算路径上经过节点的代价总和最终取最小代价路径作为距离度量。这种距离对高维流形结构更敏感有助于保留光谱-空间联合分布中的真实结构。放到这个方法里Fermat 距离被用来构造更合理的图边权重让拉普拉斯传播时“沿光谱流形走”而不是在高维空间里“直线穿越”。2.3 Active Learning主动挑样本而不是随机标注半监督训练只需要少量标注但“少量标注”从哪里来很关键。如果随机标注可能很多样本落在冗余区域信息量不高。Active Learning 的思路是先用当前模型/算法对无标签样本给出预测。挑选“最有价值”的样本比如模型最不确定的样本、分类边界附近的样本、能最大程度改善图结构的样本。把挑出来的样本交给人工标注。加入标注集重新训练反复迭代。这个方法把 Active Learning 和 Laplace Learning 结合起来目标是在每轮标注预算内选到信息量最大的像素点从而让半监督分类精度更快上升。2.4 三个模块如何串起来整体训练流程可以概括为输入高光谱图像提取每个像素的光谱向量。用 Fermat 距离度量像素间的相似性构建图结构。在图上运行 Laplace Learning把初始少量标签传播到全图。用 Active Learning 策略选出下一批最有标注价值的像素。人工标注这批像素加入标签集合。重复步骤 2-5直到标注预算耗尽或精度满足要求。在测试集上评估分类结果。从标题看这个工作最大的贡献点应该是“Fermat 距离 主动拉普拉斯学习”的组合优化。它在理论上的优势是减少标注成本同时提升分类稳定性。3. 适用场景与使用边界3.1 适合谁用遥感算法工程师做地物分类、变化检测、地表覆盖制图的团队。农业科技团队用无人机或卫星高光谱数据做作物分类、病虫害监测但没精力给每个地块做精细标注。科研人员研究半监督学习、主动学习、基于图的分类方法。初学者想了解图半监督学习和主动学习如何在真实高光谱数据上落地。3.2 能解决什么问题标注预算有限只标注 1%-10% 的像素用半监督方法完成整图分类。高维特征处理Fermat 距离比直接使用欧氏距离更适应高光谱的高维特性。标注策略优化Active Learning 避免随机标注带来的信息冗余。分类流程自动化在训练、传播、采样、标注、再训练之间形成闭环。3.3 不适合什么场景数据量极大且需要实时处理超大区域的整图逐像素构图内存和耗时压力会很大。标签极其稀疏且分布偏差严重如果初始标注集中在一两个类别Active Learning 大量迭代也难救回来。对可解释性有极端要求的业务图方法能给出分类结果但逐像素传播过程对业务人员不够直观。3.4 使用边界与合规提醒高光谱图像很多来自卫星或无人机使用前必须确认数据来源和授权范围。涉及特定区域、敏感目标的数据更要谨慎处理不要触碰数据合规红线。本文涉及的代码和测试流程一律使用公开数据集和个人自采的合规数据。人脸、声音、隐私这类风险在这个方向不直接相关但如果把方法论迁移到医学影像、生物组织切片等场景同样要遵守数据授权和隐私保护规范。4. 环境准备与前置条件4.1 基础环境清单项目建议操作系统Windows 10/11、Ubuntu 20.04/22.04、macOSPython3.8 及以上包管理器pip 或 condaGPU可选NVIDIA 显卡建议 CUDA 11.x/12.x 对应版本CPU普通多核即可图构建阶段 KNN 搜索较耗时内存16GB 以上更稳妥磁盘数据集 中间结果预留 20GB 以上4.2 Python 依赖推荐用 conda 创建独立环境避免污染系统 Python。conda create -n hsics python3.9 -y conda activate hsics pip install numpy scipy scikit-learn matplotlib pillow pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118如果不想用 GPU可以不安装 PyTorch但后续如果要接深度特征提取器还是建议保留。4.3 高光谱数据读取库高光谱数据集格式多样常见的有 .mat、.tif、.hdr 等。推荐装这些库pip install spectral pip install rasterio pip install h5pyspectral适合读取 ENVI 格式和部分经典数据集。rasterio适合读取 GeoTIFF 格式的高光谱影像。h5py适合读取 HDF5 格式数据。5. 高光谱数据准备与预处理5.1 公开数据集参考常用高光谱分类数据集包括 Indian Pines、Pavia University、Salinas、Houston 2013 等。这些数据集自带像素级标签适合用来验证半监督分类方法。以 Indian Pines 为例通常的做法是读取图像立方体形状为 ( H \times W \times B )其中 ( H ) 和 ( W ) 是空间尺寸( B ) 是波段数。读取标签矩阵形状为 ( H \times W )像素值为类别编号0 表示无标签背景。去掉背景像素只保留有标签的像素及其光谱向量。按论文设定划分训练集、验证集和测试集。5.2 数据加载示例代码import numpy as np import scipy.io as sio from sklearn.model_selection import train_test_split # 以 .mat 格式数据为例具体字段名需按实际数据集调整 data sio.loadmat(Indian_pines_corrected.mat)[indian_pines_corrected] label sio.loadmat(Indian_pines_gt.mat)[indian_pines_gt] # 数据形状 H, W, B data.shape print(图像尺寸:, H, W, 波段数:, B) print(标签类别数:, np.unique(label)) # 拉平成像素级 pixels data.reshape(-1, B) labels label.reshape(-1) # 去掉背景 0 valid_idx np.where(labels 0)[0] X pixels[valid_idx] y labels[valid_idx] # 划分有标注/无标注半监督模拟 X_labeled, X_unlabeled, y_labeled, y_unlabeled train_test_split( X, y, test_size0.95, stratifyy, random_state42 ) print(有标注样本数:, len(X_labeled)) print(无标注样本数:, len(X_unlabeled))注意这里的分割只是最简单的半监督模拟。论文一般的做法是固定每一类的标注数量比如每类 5、10、20 个样本。要复现论文结果必须按论文设置切分不要随意用比例切分。5.3 波段选择与标准化高光谱波段多部分波段噪声大。常见的预处理包含去掉吸水波段和噪声波段。对每个像素做标准化z-score 或 min-max。用 PCA 降维后做可视化但分类是否降维要看论文设计。标准化示例from sklearn.preprocessing import StandardScaler scaler StandardScaler() X_all_scaled scaler.fit_transform(X)标准化结束后再构图能避免个别波段数值过大主导距离计算。6. 核心模块复现思路这一部分重点说明 Fermat 距离、Laplace Learning、Active Learning 三个模块怎么用代码组织。下面的代码是通用示例不是论文官方实现但可以帮你搭出实验框架。6.1 Fermat 距离计算模块Fermat 距离的严格实现比较复杂通常需要构造 KNN 图然后在图上跑最短路或类测地线距离。可以用 Dijkstra 或 Bellman-Ford 做全源最短路径但像素量大时性能很差。工程上常用近似方法先 KNN 构图再计算 KNN 图中节点间的最短路径距离。from sklearn.neighbors import kneighbors_graph from scipy.sparse.csgraph import shortest_path def fermat_distance_matrix(X, n_neighbors10, metriceuclidean): 基于 KNN 图的最短路径距离作为 Fermat 距离的近似。 实际论文中的 Fermat 距离可能有更复杂的权重定义。 # 构建 KNN 图返回稀疏邻接矩阵 knn_graph kneighbors_graph( X, n_neighborsn_neighbors, modedistance, metricmetric ) # 将稀疏图转成最短路径距离矩阵 dist_matrix shortest_path(csgraphknn_graph, methodD, directedFalse) return dist_matrix这个写法在中等规模数据上可用但 ( N \times N ) 距离矩阵会占用大量内存。如果像素数超过 2 万建议用 mini-batch 或分块计算不要一次性全量矩阵。6.2 Laplace Learning 标签传播模块图拉普拉斯传播的核心是解一个线性系统。先构造图权重矩阵再计算拉普拉斯矩阵最后对有标签部分的解做约束。import scipy.sparse as sp from scipy.sparse.linalg import spsolve def laplace_label_propagation(W, labeled_idx, label_matrix, alpha1.0): 参数 W: 稀疏对称相似度矩阵 labeled_idx: 有标签节点索引列表 label_matrix: 标签矩阵形状 [n_samples, n_classes]one-hot 格式 n_nodes W.shape[0] D np.array(W.sum(axis1)).flatten() D_inv_sqrt 1.0 / np.sqrt(D 1e-10) L sp.eye(n_nodes) - D_inv_sqrt * W * D_inv_sqrt # 按有标签/无标签分块 unlabeled_idx np.setdiff1d(np.arange(n_nodes), labeled_idx) L_uu L[np.ix_(unlabeled_idx, unlabeled_idx)].tocsr() L_ul L[np.ix_(unlabeled_idx, labeled_idx)].tocsr() F_u spsolve(L_uu, -L_ul label_matrix[labeled_idx]) F np.zeros((n_nodes, label_matrix.shape[1])) F[labeled_idx] label_matrix[labeled_idx] F[unlabeled_idx] F_u return F这里用的是标准拉普拉斯传播公式。实际论文中可能使用带 ( \alpha ) 正则项的变体需要按原文调整。6.3 Active Learning 采样模块Active Learning 采样方式很多最常用的是“不确定性采样”。在拉普拉斯传播得到每个节点的标签概率估计后可以选熵最大的样本作为下一批标注对象。def entropy_sampling(F, n_select): 按预测熵选择最不确定的 n_select 个样本。 # 归一化成概率 prob F / (F.sum(axis1, keepdimsTrue) 1e-10) entropy -np.sum(prob * np.log(prob 1e-10), axis1) candidate_idx np.argsort(entropy)[::-1][:n_select] return candidate_idx更高级的策略可能结合密度、代表性、多样性避免选到一堆聚集在同一个区域的“不确定样本”。如果论文中有自己的采样函数直接替换这个模块即可。6.4 训练循环把三个模块串起来def active_laplace_learning_loop( X, y, labeled_idx, n_iter5, batch_size20, n_neighbors10 ): # 初始化标签矩阵 n_classes len(np.unique(y)) label_matrix np.zeros((len(X), n_classes)) for i in labeled_idx: label_matrix[i, y[i] - 1] 1.0 all_idx np.arange(len(X)) unlabeled_idx np.setdiff1d(all_idx, labeled_idx) for it in range(n_iter): # 1. 计算 Fermat 距离并用它构建图相似矩阵 W dist_mat fermat_distance_matrix(X[labeled_idx], n_neighborsn_neighbors) # 实际工程应全量构图这里只做演示 # 2. 构建 W 并拉普拉斯传播 W build_similarity_from_distance(X, dist_mat) F laplace_label_propagation(W, labeled_idx, label_matrix) # 3. 主动选择本批次样本 new_samples entropy_sampling(F, batch_size) # 4. 模拟人工标注 for idx in new_samples: if idx not in labeled_idx: label_matrix[idx, y[idx] - 1] 1.0 labeled_idx.append(idx) unlabeled_idx np.setdiff1d(all_idx, labeled_idx) print(fIter {it 1}: labeled {len(labeled_idx)} samples) return F, labeled_idx这个循环只适合理解流程实际要高效率跑完整实验还需要优化相似度矩阵构建和标签传播的批次大小。7. 实验验证与效果评估7.1 实验设计复现算法后要做对比实验。建议至少包含四组实验组说明全监督基线大量标注样本训练一个分类器如 SVM 或 1D-CNN随机标注 Laplace Learning等量标注样本随机选择不带主动学习Active Learning Laplace Learning相同标注预算使用主动采样本文方法Fermat 距离 Active Laplace Learning如果不能一次完整复现论文至少做“有/无 Fermat 距离”和“有/无 Active Learning”的消融判断两个组件各自贡献多少。7.2 评估指标高光谱像素分类常用三个指标OAOverall Accuracy全部分类正确的样本比例。AAAverage Accuracy各类别精度的平均值对类别不均衡更敏感。Kappa 系数衡量分类结果与真实类别的一致性排除了随机一致性的影响。计算方式from sklearn.metrics import accuracy_score, cohen_kappa_score, confusion_matrix def evaluate_model(y_true, y_pred): oa accuracy_score(y_true, y_pred) cm confusion_matrix(y_true, y_pred) aa np.mean(cm.diagonal() / (cm.sum(axis1) 1e-10)) kappa cohen_kappa_score(y_true, y_pred) return {OA: oa, AA: aa, Kappa: kappa}7.3 可视化输出分类结果建议输出成与原始图像同尺寸的伪彩色标签图方便和地面真值对比。import matplotlib.pyplot as plt def plot_classification_map(label_map, shape, save_path): label_image label_map.reshape(shape) plt.figure(figsize(8, 8)) plt.imshow(label_image, cmaptab20) plt.axis(off) plt.savefig(save_path, dpi300, bbox_inchestight) plt.close()目视检查时重点看地物边缘是否连续、小目标区域是否被吞掉、各类别是否有椒盐噪声。7.4 判断方法是否有效的标准相同标注预算下精度是否高于随机标注基线。增加 Active Learning 迭代后精度是否稳定上升。Fermat 距离构图是否比欧氏距离构图有明显改善。Kappa 是否和 OA 趋势一致避免只提高大类别精度、牺牲小类别。8. 批量实验与资源占用8.1 批量跑参设计半监督方法最怕“一个参数跑一次全流程”。建议用脚本批量跑参数并保存实验记录。import itertools import pandas as pd def run_experiment(params): # 每次实验返回结果字典 pass param_grid { labeled_per_class: [5, 10, 20, 40], n_neighbors: [5, 10, 20], active_strategy: [entropy, random], use_fermat: [True, False], } results [] keys list(param_grid.keys()) for values in itertools.product(*param_grid.values()): params dict(zip(keys, values)) result run_experiment(params) result.update(params) results.append(result) df pd.DataFrame(results) df.to_csv(experiment_results.csv, indexFalse) print(df.groupby([labeled_per_class, use_fermat])[OA].mean())用这种网格搜索脚本可以一次性把所有关键组合跑完用 CSV 记录结果方便复盘。8.2 资源占用观察方法高光谱数据是三维立方体构图阶段内存压力最大。运行代码时重点观察CPU 内存topLinux或任务管理器Windows。GPU 显存nvidia-smi。运行耗时在每个模块前后打时间戳。import time start time.time() # 模块代码 end time.time() print(f耗时: {end - start:.2f}s)如果内存不够优先做这三件事减少 KNN 邻居数。用稀疏矩阵存储图结构不用稠密距离矩阵。对大图做分块或随机采样先在小规模上验证流程。8.3 降低显存和内存的技巧没必要在一开始就用整张图构图先用一个子区域验证代码逻辑。拉普拉斯矩阵用scipy.sparse表示不要转成 dense。Active Learning 的熵计算只需要预测概率不需要保存全部中间传播结果。如果引入深度特征提取器可以用小批次提取特征特征保存到磁盘避免频繁读原始高光谱数据。9. 常见问题与排查方法问题现象可能原因排查方式解决方案运行pip install spectral失败网络源不稳定或缺少编译环境检查 pip 源换清华或阿里源pip install spectral -i https://pypi.tuna.tsinghua.edu.cn/simple标签矩阵全是 0读取 .mat 时字段名不对打印.keys()查看字段确认数据字段名并替换KNN 构图速度极慢像素数太多距离计算压力大查看日志和 CPU 使用率先抽样 1 万像素测试再用分块或近似最近邻拉普拉斯传播报内存错误矩阵转为稠密格式检查是否有.toarray()全流程使用稀疏矩阵传播结果全是一类初始标签过于集中或图权重尺度问题查看标签分布按类别均衡初始化标签调整权重缩放Active Learning 选的样本聚集在一起只用了不确定性没有考虑多样性可视化采样点位置增加空间距离约束或聚类-多样性采样分类精度提升不明显Fermat 距离参数不合适或标注预算太低做消融实验调 KNN 邻居数增加标注迭代轮数CUDA 不可用驱动或 PyTorch 版本不匹配torch.cuda.is_available()检查重新安装对应 CUDA 版本的 PyTorch同一实验不同随机种子结果差异大半监督本身对初始标注敏感固定随机种子多次重复实验取均值和方差10. 最佳实践与总结这个方向的工程化落地建议先跑通小规模流程再逐步放大。第一次实验不要直接上全数据集先用 Indian Pines 这类中小型数据集的子区域把“数据加载 → Fermat 构图 → 拉普拉斯传播 → 主动采样 → 评估”整条链路跑通再做网格搜索。如果论文提供了官方代码优先用官方实现因为 Fermat 距离的严格定义、图中的权重公式、主动学习的采样函数都可能和我这里给的通用模板不同。本文的代码价值更多在于帮你理解模块边界而不是替代官方实现。比较容易踩的坑有三个一是把距离矩阵做成稠密形式导致内存崩溃二是初始标注不均衡导致传播结果偏科三是盲目相信一次实验的精度没有做多随机种子平均。后续扩展方向可以考虑把 Fermat 距离和深度特征结合比如先用自编码器或预训练模型提取光谱特征再在特征空间构图也可以把 Active Learning 换成池式或流式策略适配在线标注场景。需要再次强调高光谱标注数据本身可能涉及数据授权和使用边界。使用公开数据集或自有数据时确认来源合规如果涉及特定区域影像按数据提供方的许可要求使用不把数据用于未授权场景。标注样本选择上也要避免对稀有类别“零标注”导致模型完全无法识别该类。这个方向最大的吸引力在于用更少标注拿到更高精度。Fermat 距离负责构建更合理的光谱空间结构Active Learning 负责把每一笔标注预算花在刀刃上Laplace Learning 负责在图上完成标签传播。三者结合后既保留了图方法的可解释性又缓解了高光谱高维、高噪声、少标注的痛点。建议先跑一次基础流程验证一下在你的数据上增益有多大再决定是否纳入正式算法管线。
返回列表