
高光谱图像分类一直是遥感图像处理中的核心任务但一个现实问题始终困扰着研究者像素级标注成本太高。每张高光谱影像包含大量波段人工对每个像素打标签往往需要专家知识且工作量非常大。因此如何用少量标注样本结合大量未标注数据完成可靠分类就成为一个非常有价值的研究方向。本文将围绕Fermat Active Laplace Learning for Semi-Supervised Hyperspectral Image Classification这个学术主题从概念到代码实现进行系统拆解。我们会先讲清楚半监督学习、主动学习、拉普拉斯学习、Fermat 距离这几个关键概念再给出一个可运行的最小实验框架。无论你是刚接触高光谱图像分类的研究生还是希望在遥感项目中降低标注成本的同学都可以从这篇文章中获得一套完整的思路和可复用代码。1. 背景与核心概念1.1 高光谱图像分类面临的现实挑战高光谱图像与普通 RGB 图像最大的区别在于波段数。RGB 图像通常只有 3 个波段而高光谱传感器可以在可见光到近红外乃至短波红外范围内获取几十到几百个连续波段。每个像素因此对应一条光谱曲线包含丰富的光谱信息。理论上这种丰富的光谱信息可以帮助我们更精细地区分地物类别比如不同作物类型、矿物成分或者水体污染情况。但随之而来的问题是特征维度高容易引发“维度灾难”标注样本稀缺人工标注成本高光谱之间可能存在大量冗余信息地物分布往往呈现复杂的空间相关性和非线性的流形结构。在这样的背景下仅仅依靠经典的监督学习方法比如支持向量机或随机森林在小样本场景下很容易出现过拟合或泛化能力不足的问题。1.2 半监督学习利用未标注数据半监督学习Semi-Supervised Learning, SSL的核心思想非常直观既然标注样本贵而未标注样本便宜那为什么不把大量未标注数据也利用起来常见的半监督学习思路包括一致性正则化要求模型对输入的小扰动保持稳定的输出伪标签法先用少量标注样本训练初始模型再对未标注样本打上伪标签并加入训练基于图的半监督学习把样本看成图上的节点用边表示样本之间的相似度通过图结构进行标签传播或拉普拉斯正则化。在高光谱图像分类中基于图的方法尤其有吸引力。因为高光谱图像本身具有天然的空间邻域关系相邻像素通常属于同一地物类型。这种空间先验可以被自然地编码到图结构中从而帮助未标注像素获得合理的标签。1.3 主动学习把标注预算花在“最有价值”的样本上主动学习Active Learning, AL则是从另一个角度解决标注成本问题与其随机挑选样本去标注不如让算法主动选出“对模型提升最大”的样本交给标注者。常见主动学习策略包括不确定性采样选择当前模型最不确定的样本多样性采样选择能代表不同区域的样本期望模型变化选择让模型参数变化最大或损失下降最多的样本。主动学习与半监督学习经常结合使用形成主动半监督学习。先用少量标注样本启动模型再通过主动学习挑选一批最有价值的未标注样本送入人工标注更新模型如此反复迭代。1.4 什么是 Fermat Active Laplace Learning从标题可以看出Fermat Active Laplace Learning是三个技术要素的组合Fermat费马距离一种基于图最短路径的测地距离度量Laplace Learning拉普拉斯学习一种基于图拉普拉斯正则化的半监督学习方法Active Learning主动样本选择策略。它的整体思路可以概括为在高光谱图像上先利用 Fermat 距离构造更能反映样本流形结构的图再在图上执行拉普拉斯学习最后通过主动学习策略反复挑选最有标注价值的像素从而在极小标注预算下获得较好的分类性能。这个思路不仅可以用于高光谱图像分类也适用于其他特征维度高、标注稀缺、样本间存在流形结构的数据集。2. 相关技术原理拆解2.1 图拉普拉斯与标签传播基于图的半监督学习首先要构建一个图 ( G (V, E) )其中节点 ( V ) 表示所有样本包括标注和未标注样本边 ( E ) 表示样本之间的相似关系。假设图的邻接矩阵为 ( W )那么度矩阵 ( D ) 是一个对角矩阵对角线上的元素为[ D_{ii} \sum_{j} W_{ij} ]图拉普拉斯矩阵定义为[ L D - W ]拉普拉斯矩阵有一个非常重要的性质对于任意向量 ( f )都有[ f^T L f \frac{1}{2} \sum_{i,j} W_{ij} (f_i - f_j)^2 ]也就是说如果两个节点在图中边权很大但它们的标签 ( f_i ) 和 ( f_j ) 差异很大那么惩罚项就会很大。这正是“相邻样本应该具有相似标签”这一先验的数学表达。2.2 拉普拉斯学习的优化目标拉普拉斯学习通常被建模为如下优化问题[ \min_{F} ; \sum_{i \in L} | F_i - Y_i |^2 \mu \cdot \mathrm{tr}(F^T L F) ]其中( F ) 是模型为所有样本预测的标签矩阵( Y ) 是标注样本的真实标签矩阵( L ) 是图拉普拉斯矩阵( \mu ) 是正则化系数控制平滑项的重要性。这个目标函数有两层含义标注样本的预测结果要尽量接近真实标签图上有强连接的样本之间预测结果要尽量平滑。由于目标函数是二次的因此存在闭式解。对 ( F ) 求导并令导数为零可以得到一个线性方程组直接求解即可。这也是拉普拉斯学习相比深度半监督方法的一大优势参数少、实现简单、可解释性强。2.3 Fermat 距离考虑流形结构的距离度量在构建图时最直接的方式是用欧氏距离衡量样本之间的相似度。但欧氏距离是直线距离它没有考虑样本所处的数据流形。举个例子两个像素之间光谱特征看起来有一定差异但如果它们可以通过一系列光谱差异很小的像素连接起来那么在流形意义上它们的“真实距离”其实很近。反之如果两个像素之间不存在平滑的路径那么即使欧氏距离很小它们也可能属于完全不同的地物。Fermat 距离正是为了解决这个问题而提出的。它的定义可以理解为加权图上的最短路径距离[ d_F(i,j) \min_{P} \sum_{(u,v) \in P} c(u,v) ]其中 ( P ) 是节点 ( i ) 到节点 ( j ) 的一条路径( c(u,v) ) 是相邻节点的连接代价。通常这个代价可以取为样本特征之间的欧氏距离的 ( p ) 次方也可以取为基于相似度的某种权重。使用 Fermat 距离构造图的优势在于能够捕捉数据空间的非线性流形结构对噪声和异常点具有更强的鲁棒性在高光谱图像中有研究表明基于 Fermat 距离构造的图能更好地区分光谱相似但属于不同类别的地物。当然计算 Fermat 距离需要运行最短路径算法比如 Dijkstra 算法因此在大型数据集上的计算开销会明显高于直接计算欧氏距离。后面我们会讨论如何缓解这个问题。2.4 主动拉普拉斯学习两个模块如何协作主动拉普拉斯学习可以看成是一个迭代过程当前有个标注样本集合 ( L ) 和未标注样本集合 ( U )在图上执行拉普拉斯学习得到所有节点的预测标签根据预测结果计算每个未标注样本的信息量选择信息量最大的若干个样本交给人工标注把新标注的样本加入 ( L )更新图标签然后回到第 2 步。在每轮迭代中拉普拉斯学习负责“从已知到未知”的传播主动学习负责“从最不确定到最确定”的探索。两者结合可以在少量标注预算下逐步逼近理想分类边界。3. Fermat Active Laplace Learning 算法框架3.1 整体流程下面这张图展示了算法的整体流程用文字描述如下读入高光谱图像数据并按像素提取光谱特征随机或按特定策略选择少量像素作为初始标注集基于特征计算样本之间的 Fermat 距离利用 Fermat 距离构建 KNN 图或 Gaussian 核图计算图拉普拉斯矩阵执行拉普拉斯学习得到所有像素的预测标签如果尚未达到预算则执行主动学习策略选择新的像素把新像素加入标注集返回第 6 步达到预算后输出最终分类结果并计算评价指标。3.2 基于 Fermat 距离的图构造这一步是整个方法的关键。与常规 KNN 图不同这里不使用原始特征空间的欧氏距离而是使用 Fermat 距离。具体步骤如下初始化一个图节点为所有像素边权为相邻像素之间的欧氏距离在图上运行最短路径算法求得任意两点之间的 Fermat 距离基于 Fermat 距离用 KNN 或 (\epsilon)-ball 方法得到新的邻接关系对邻接矩阵进行对称化并设置自环权重为 1使用 Gaussian 核或其他方式将距离转换为相似度权重。由于高光谱图像中像素数量可能很大直接计算全图 Fermat 距离矩阵是不现实的。常见做法是先对像素进行块状采样或使用超像素分割或者只计算局部区域内的像素之间的 Fermat 距离或者使用锚点图Anchor Graph思想把部分代表点作为锚点。3.3 拉普拉斯学习的求解细节在得到图拉普拉斯矩阵 ( L ) 和标注矩阵 ( Y ) 后我们需要求解如下方程[ (C \mu L) F C Y ]其中 ( C ) 是对角矩阵对角线元素为 1 表示该样本已标注0 表示未标注。由于 ( C \mu L ) 是一个正定稀疏矩阵可以使用共轭梯度法或者稀疏 Cholesky 分解来求解。在 Python 中scipy.sparse.linalg.spsolve是一个不错的选择。3.4 主动学习策略选择在拉普拉斯学习框架下主动学习不仅要考虑样本的不确定性还要考虑样本在图中的传播影响力。这里给出两种常用策略最小置信度Least Confidence选择当前预测概率中最大类概率最小的样本。这个策略比较直观适合作为基线方法。期望风险减少Expected Error Reduction模拟为某个未标注样本添加标签后模型在全部未标注样本上的损失变化。这种策略理论上更优但计算成本较高。影响最大化Influence-based在拉普拉斯学习中可以通过扰动分析估计某个样本被标注后对整体预测结果的影响从而选择影响力最大的样本。在本文的代码示例中我们先实现最小置信度策略因为它的计算快适合快速验证整体流程。后续可以替换为更复杂的策略。4. 实验环境与数据准备4.1 环境依赖本文代码基于 Python 3.8 编写核心依赖库如下numpy数值计算scipy稀疏矩阵运算、最短路径算法scikit-learnKNN 搜索、数据预处理、评价指标matplotlib结果可视化。以下是一个可直接安装依赖的命令pip install numpy scipy scikit-learn matplotlib版本方面作者使用的常见组合是numpy 1.24、scipy 1.10、scikit-learn 1.2这些版本相互兼容。如果你使用更新的版本只要接口没有大的变化代码仍然可以正常运行。4.2 高光谱数据集高光谱图像分类领域常用的公开数据集包括Indian Pines印第安纳州西北部的一块农业区包含 200 个波段共 16 类地物Pavia University意大利帕维亚大学周边城区包含 103 个波段共 9 类地物Salinas美国加州萨利纳斯山谷包含 224 个波段共 16 类地物。这些数据集通常以.mat格式发布包含一个三维高光谱数据立方体data和一个二维标签矩阵gt。你可以使用scipy.io.loadmat读取。注意使用这些数据集时应遵守数据源的许可协议在论文或项目中引用原始出处。下面给出一个读取.mat数据的通用函数示例from scipy.io import loadmat def load_hsi_data(mat_path, data_keydata, label_keygt): 读取高光谱 .mat 数据。 :param mat_path: .mat 文件路径 :param data_key: 高光谱数据立方体的键名 :param label_key: 真实标签矩阵的键名 :return: data 三维数组 (H, W, C), labels 二维数组 (H, W) mat loadmat(mat_path) data mat[data_key] labels mat[label_key] return data, labels4.3 特征矩阵构建高光谱图像原始数据是一个三维立方体例如形状为(height, width, bands)。为了输入到图模型我们需要把每个像素的光谱向量展平成一行得到特征矩阵X同时把标签矩阵展平成标签向量y。如果考虑空间邻域信息还可以提取每个像素周围窗口内的局部特征比如求窗口内的光谱均值或主成分特征。这一步可以显著提升分类效果但也会增加特征维度。5. 核心代码实现本章节给出一个完整的Fermat Active Laplace Learning最小实现。代码分为四部分Fermat 距离计算图拉普拉斯构造与求解主动学习采样策略主流程整合。5.1 计算 Fermat 距离我们用scipy.sparse.csgraph.dijkstra来计算加权图上的最短路径代价。import numpy as np from scipy.sparse import csr_matrix from scipy.sparse.csgraph import dijkstra from sklearn.neighbors import NearestNeighbors def compute_fermat_matrix(X, k10, p2): 计算样本之间的 Fermat 距离矩阵。 参数: X : ndarray, shape (n_samples, n_features) 样本特征矩阵。 k : int 局部近邻数量用于构建初始图。 p : float 边权指数边权 欧氏距离 ** p。 返回: fermat_dist : ndarray, shape (n_samples, n_samples) Fermat 距离矩阵仅对有限近邻有效其他位置填充 np.inf。 n X.shape[0] # 1. 使用 KNN 找到近邻 nn NearestNeighbors(n_neighborsk 1, metriceuclidean) nn.fit(X) dists, indices nn.kneighbors(X) # 2. 构建初始邻接矩阵 row_list, col_list, data_list [], [], [] for i in range(n): for j, d in zip(indices[i], dists[i]): if i j: continue cost d ** p row_list.append(i) col_list.append(j) data_list.append(cost) adj csr_matrix((data_list, (row_list, col_list)), shape(n, n)) # 3. 用 Dijkstra 求最短路径距离作为 Fermat 距离 fermat_dist dijkstra(adj, directedFalse) return fermat_dist说明这里把局部欧氏距离作为边的代价Dijkstra 会得到有边可达的节点间最短路径距离由于高光谱图像相对密集采样同一个连通分量内的像素都可得到有限距离值。5.2 用 Fermat 距离构造相似度图得到 Fermat 距离矩阵后我们通过 Gaussian 核函数把它转换为相似度矩阵def build_graph_from_fermat(fermat_dist, k10, sigma1.0): 根据 Fermat 距离矩阵构建 KNN 加权图。 返回邻接矩阵 W 和图拉普拉斯矩阵 L。 n fermat_dist.shape[0] W np.zeros((n, n)) for i in range(n): # 对每个样本取距离最近的 k 个非自身样本 row fermat_dist[i].copy() row[i] np.inf idx np.argpartition(row, k)[:k] for j in idx: dist fermat_dist[i, j] weight np.exp(-dist ** 2 / (2 * sigma ** 2)) W[i, j] weight W[j, i] weight # 度矩阵 D np.diag(W.sum(axis1)) L D - W return W, L注意这里我们没有限制 neighbors 的连通性。如果某些样本在图上是孤立的需要额外处理否则拉普拉斯学习可能出现异常。5.3 拉普拉斯学习求解在得到图拉普拉斯矩阵 ( L ) 后求解优化问题[ \min_{F} \sum_{i \in L} |F_i - Y_i|^2 \mu \cdot \mathrm{tr}(F^T L F) ]对应的线性系统为[ (C \mu L) F C Y ]其中 ( C ) 是对角矩阵已标注样本的位置为 1其余为 0。def laplace_learning(W, y, labeled_idx, n_classes, mu1.0): 拉普拉斯学习求解。 参数: W : ndarray, shape (n_samples, n_samples) 相似度矩阵。 y : ndarray, shape (n_samples,) 标签向量未标注位置为 -1。 labeled_idx : list or ndarray 已标注样本下标。 n_classes : int 类别数。 mu : float 平滑正则化参数。 返回: pred : ndarray, shape (n_samples,) 每个样本的预测类别。 F : ndarray, shape (n_samples, n_classes) 预测软标签矩阵。 n W.shape[0] D np.diag(W.sum(axis1)) L D - W # 构造 C 矩阵 C np.zeros((n, n)) for idx in labeled_idx: C[idx, idx] 1.0 # 构造 Y 矩阵 Y np.zeros((n, n_classes)) for i, idx in enumerate(labeled_idx): label int(y[idx]) Y[idx, label] 1.0 A C mu * L B C Y F np.linalg.solve(A, B) pred np.argmax(F, axis1) return pred, F5.4 主动学习采样策略这里实现一个最小置信度策略选择当前预测最大概率最小的未标注样本def active_learning_query(F, unlabeled_idx, n_query5): 主动采样选择最不确定的未标注样本。 参数: F : ndarray, shape (n_samples, n_classes) 预测软标签矩阵。 unlabeled_idx : ndarray 当前未标注样本下标。 n_query : int 本轮要挑选的样本数量。 返回: query_idx : ndarray 被选中需要人工标注的样本下标。 confidence F[unlabeled_idx].max(axis1) sorted_idx np.argsort(confidence) return unlabeled_idx[sorted_idx[:n_query]]也可以扩展到熵策略def active_learning_entropy(F, unlabeled_idx, n_query5): 熵采样选择预测熵最大的未标注样本。 probs np.clip(F[unlabeled_idx], 1e-12, 1.0) entropy -np.sum(probs * np.log(probs), axis1) sorted_idx np.argsort(entropy)[::-1] return unlabeled_idx[sorted_idx[:n_query]]5.5 主流程整合下面把以上模块整合成一个完整的实验流程方便你在自己的数据集上运行。import numpy as np from sklearn.metrics import accuracy_score, cohen_kappa_score def active_fl_loop(X, y, n_classes, init_num10, query_num5, max_iters20, k10, sigma1.0, mu1.0): Fermat Active Laplace Learning 主流程。 参数: X : ndarray, shape (n_samples, n_features) 样本特征。 y : ndarray, shape (n_samples,) 真实标签。调用方需要保证只提供少量已标注样本。 n_classes : int 类别数。 init_num : int 初始随机标注样本数。 query_num : int 每轮主动采样的样本数。 max_iters : int 最大迭代轮数。 k : int Fermat 距离 KNN 近邻数。 sigma : float Gaussian 核带宽。 mu : float 拉普拉斯正则化系数。 返回: history : list of dict 每轮的预测准确率和已标注数量。 n len(y) # 第一步计算 Fermat 距离矩阵 print(Computing Fermat distance matrix ...) fermat_dist compute_fermat_matrix(X, kk, p2) # 第二步构建图 print(Building graph ...) W, L build_graph_from_fermat(fermat_dist, kk, sigmasigma) # 初始化标签-1 表示未标注 y_work np.full(n, -1, dtypeint) # 随机选择初始标注样本 all_idx np.arange(n) labeled_idx np.random.choice(all_idx, sizeinit_num, replaceFalse) y_work[labeled_idx] y[labeled_idx] history [] for it in range(max_iters): # 拉普拉斯学习 pred, F laplace_learning(W, y_work, labeled_idx, n_classes, mumu) # 记录在未标注样本上的准确率 unlabeled_idx all_idx[y_work -1] if len(unlabeled_idx) 0: acc accuracy_score(y[unlabeled_idx], pred[unlabeled_idx]) else: acc accuracy_score(y, pred) print(fIter {it1}: labeled {len(labeled_idx)}, acc {acc:.4f}) history.append({ iter: it, labeled_num: len(labeled_idx), acc: acc }) # 若已经没有未标注样本则退出 if len(unlabeled_idx) 0: break # 主动学习选择下一批样本 query_idx active_learning_query(F, unlabeled_idx, n_queryquery_num) # 模拟人工标注 y_work[query_idx] y[query_idx] labeled_idx np.concatenate([labeled_idx, query_idx]) return history, pred调用示例# 假设 X 是特征矩阵y 是真实标签 # history, pred active_fl_loop(X, y, n_classes16, # init_num20, query_num10, max_iters10)5.6 直接基于欧氏距离的对比实现为了验证 Fermat 距离的效果通常还要实现一个基于普通欧氏距离的对比实验。只需要把compute_fermat_matrix替换为直接计算欧氏距离即可。由于我们使用的是sklearn可以直接用pairwise_distances函数from sklearn.metrics import pairwise_distances def compute_euclidean_matrix(X): return pairwise_distances(X, metriceuclidean)后面用同一个build_graph_from_fermat函数构建图保持其他设置不变。6. 运行与验证6.1 验证目标在实验部分你至少需要关注以下几个问题在固定标注预算下基于 Fermat 距离的图是否比基于欧氏距离的图分类准确率更高主动学习策略是否优于随机采样迭代过程中准确率曲线如何变化是否收敛不同参数近邻数 ( k )、带宽 ( \sigma )、正则化系数 ( \mu )对结果的影响如何6.2 结果可视化使用matplotlib画出分类结果图以及与随机采样对比的曲线。import matplotlib.pyplot as plt def plot_history(hist_fermat, hist_euclidean): plt.figure(figsize(8, 5)) plt.plot([h[labeled_num] for h in hist_fermat], [h[acc] for h in hist_fermat], markero, labelFermat graph) plt.plot([h[labeled_num] for h in hist_euclidean], [h[acc] for h in hist_euclidean], markers, labelEuclidean graph) plt.xlabel(Number of labeled samples) plt.ylabel(Accuracy on unlabeled set) plt.legend() plt.grid(True) plt.show()这种图能直观展示不同图构造方式在相同标注预算下的性能差异。6.3 指标说明高光谱图像分类常用的评价指标包括Overall AccuracyOA所有测试样本中被正确分类的比例Average AccuracyAA每个类别准确率的平均值能体现类别均衡性Kappa Coefficient一致性系数消除了随机分类的影响。在实验报告中通常需要同时给出这三个指标。但由于不同实验设置训练集大小、类别数、是否包含背景类差异很大本文不给出固定的精度数值。你应该在自己的数据划分下运行代码记录并比较结果。7. 常见问题与排查思路7.1 常见问题表格问题现象常见原因解决思路程序报错Fermat 距离矩阵包含inf或NaN图不连通部分节点之间没有路径增大近邻数 ( k )或添加图连通性检查拉普拉斯学习求解时矩阵奇异图连通性差或正则化系数 ( \mu ) 过小增大 ( \mu )或改为np.linalg.lstsq求解主动学习不断选到同一个类别样本采样策略过于简单未考虑类别平衡引入类别均衡约束或改用 Batch 主动学习迭代多轮后准确率反而下降主动学习选入错误标注样本或拉普拉斯平滑过度检查标注噪声减小 ( \mu )增加查询批量内存不足全图 Fermat 距离矩阵过大使用采样、锚点图或近似最短路径算法scipy.sparse.csgraph.dijkstra运行缓慢图节点数过多边数过多降低近邻数 ( k )或先使用超像素降维7.2 深入排查建议问题一图不连通。高光谱图像中如果包含强噪声像素KNN 图可能出现孤立小连通分量。建议计算连通分量数量如果分量大于 1在构建图后添加一个虚拟节点把所有分量连接到该虚拟节点或者增大 ( k )。问题二拉普拉斯学习预测结果全部为同一类。这种情况通常发生在类别不平衡严重、初始标注很少的时候。建议增加初始标注样本数量在主动学习策略中加入类别多样性约束或者对拉普拉斯学习的解加入类别先验正则化。问题三Fermat 距离计算时间过长。对于上百万像素的高光谱图像全图 Dijkstra 不可行。可选的优化方案包括只对“代表点”计算 Fermat 距离再通过标签传播扩展到全图使用超像素分割以超像素为单位建图使用分块策略在空间局部窗口内计算最短路径。8. 最佳实践与工程建议8.1 数据预处理高光谱数据往往包含噪声波段和冗余波段。在构建图之前建议先做以下处理去掉吸水波段很多高光谱数据集中存在受大气水汽影响的波段这些波段噪声较大归一化对每个样本的光谱向量做零均值、单位方差归一化或对全部波段做 Min-Max 归一化降维使用 PCA 降到 30 到 60 维不仅减少计算量还能去除部分噪声。降维代码示例from sklearn.decomposition import PCA pca PCA(n_components30) X_pca pca.fit_transform(X)8.2 图构造参数调优图构造是半监督学习中最敏感的部分。建议在实验中控制变量逐一调参近邻数 ( k )太小导致图不连通太大则图结构趋于全局失去局部流形信息。常见取值为 5 到 20路径代价指数 ( p )( p ) 越大长路径的代价越高图会更偏向局部结构( p 2 ) 在不少实验中表现较好但也可以尝试 ( p 1 ) 或 ( p 4 )Gaussian 核带宽 ( \sigma )可设为所有距离值的中位数这是一种常见且稳定的启发式策略正则化系数 ( \mu )控制平滑项强度。( \mu ) 过大所有预测都趋于平滑过小则标注样本过拟合。建议在 ([0.1, 10]) 范围内进行网格搜索。8.3 主动学习策略设计不要一上来就用复杂的采样策略。建议先跑通最小置信度或者熵采样再逐步提升在每轮主动学习中如果数据类别不平衡可以按类别进行分组选择如果一次性需要选择多批样本使用 Batch Active Learning 时应注意样本之间的多样性避免重复选择信息冗余样本主动学习的每次迭代都会更新模型建议记录每轮的选中样本和预测分布便于后续分析。8.4 工程化与可维护性如果你要把这个方法应用到实际项目中建议把实验代码按模块拆分project/ ├── data/ │ └── load_hsi.py ├── graph/ │ ├── fermat.py │ └── laplacian.py ├── active/ │ └── strategies.py ├── experiments/ │ └── run_experiment.py └── utils/ └── metrics.py在函数设计上尽量让每个模块只做一件事。例如compute_fermat_matrix只负责计算距离不负责建图build_graph只负责从距离矩阵构造图不负责分类这样后期替换距离度量或主动学习策略都非常方便。8.5 安全与合规提示使用公开数据集时注意遵循相应的数据许可协议如果涉及生产环境的遥感数据处理确保数据来源和授权使用范围合法在发布实验代码时不要附带可能包含敏感地理信息的大幅原始图像。9. 总结与下一步方向本文围绕Fermat Active Laplace Learning for Semi-Supervised Hyperspectral Image Classification主题拆解了三个关键技术点Fermat 距离、拉普拉斯学习、主动学习。并给出了一套 Python 最小实现涵盖了图构造、半监督求解、主动采样和迭代训练全流程。核心要点可以总结为以下几句话高光谱图像分类的瓶颈是标注成本高半监督与主动学习是有效的降本方案Fermat 距离比欧氏距离更适合捕捉高光谱数据的流形结构但计算开销更大拉普拉斯学习实现简单、求解稳定是一个非常好的基线方法主动学习在拉普拉斯学习框架下可以灵活迭代每轮挑选最有价值的样本。接下来你可以从以下几个方向继续深入在更大规模的数据集上验证 Fermat 距离的增益并尝试与空间特征提取方法结合把主动学习策略从最小置信度升级为期望误差减少或影响最大化引入深度特征表示用预训练卷积网络提取特征后再构建图尝试将 Fermat 图构造扩展到大规模数据场景比如 Nyström 近似或锚点图方案。如果你在实验过程中遇到问题建议先从减小数据集、简化参数开始一步步排查。代码跑通只是第一步理解每一步为什么有效才是真正提升实验水平的捷径。希望这篇文章对你有所启发。