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

资讯详情

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

Fermat主动拉普拉斯学习:半监督高光谱分类的Python实现解析

Fermat主动拉普拉斯学习:半监督高光谱分类的Python实现解析 高光谱图像分类一直是个让人又爱又恨的方向波段信息极其丰富能识别出普通 RGB 图像区分不了的地物类别但也正因为“光谱维度过高、标注样本过少、类别分布不均衡”让模型落地时处处碰壁。最近在整理半监督高光谱分类相关技术方案时我把 Fermat Active Laplace Learning 这条思路重新梳理了一遍——它把 Fermat 距离、Laplace Learning图拉普拉斯半监督学习和主动学习组合在一起用极少量标注像素来驱动分类非常适合标注预算有限的遥感场景。本文将围绕这套方法的动机、原理、完整流程和可运行的 Python 参考实现展开适合正在做高光谱分类、半监督学习、主动学习研究的同学阅读也适合想快速复现一个 baseline 验证效果的开发者。1. 高光谱图像分类的核心难点1.1 什么是高光谱图像分类高光谱图像Hyperspectral Image, HSI由成像光谱仪在数十到数百个连续光谱波段上采集得到。和普通 RGB 图像只有 3 个波段不同高光谱图像中每个像素都是一条“光谱曲线”记录了该地物在不同波长下的反射特性。分类任务的目标就是给每个像素赋予一个地物类别标签例如小麦、玉米、森林、水体、建筑物等。常用的公开数据集包括 Indian Pines、University of Pavia、Salinas 等。以 Indian Pines 为例图像尺寸为 145×145包含 220 个波段其中一部分波段受水和大气吸收影响较大实验中通常去除这些噪声波段后再使用。Pavia University 和 Salinas 也同样是高光谱分类领域公认的评测数据。高光谱分类的价值在于它能把“光谱维度的细微差异”转化为“类别判断依据”所以特别适合农业监测、矿物勘探、生态环境调查等需要精细地物识别的应用。但与此同时它的技术挑战也远比普通图像分类更突出。1.2 标注成本与小样本困境高光谱图像的标注不是简单“框选物体”就能完成的。标注人员需要结合实地调查、光谱库和专家经验才能确认某个像素到底属于哪类地物。这项工作成本高、周期长有时一景图像只能获得很少的标注像素。更麻烦的是高光谱数据具有“高维小样本”特性特征维数可能高达几百维有效的标注样本可能只有每类几十个甚至几个在高维空间中样本分布稀疏传统的 kNN、SVM 等算法容易出现过拟合。这就是经典的 Hughes 现象当训练样本数量固定时分类精度并不随特征维度增加而单调提升反而会在某一点后明显下降。因此如何在极少量标注样本条件下获得可靠分类结果是高光谱分类研究的核心问题之一。1.3 为什么半监督学习适合高光谱场景高光谱图像虽然标注困难但“未标注像素”是海量的。一景图像往往包含数万甚至上百万个像素它们的光谱特征天然存在于数据中只是没有类别标签。半监督学习Semi-Supervised Learning, SSL的核心思想就是同时利用少量有标签样本和大量无标签样本。它依赖一个基本假设数据在特征空间中不是随机散落的而是存在某种结构——同一类地物通常聚集在相近的光谱区域类别边界通常穿过低密度区域。这种结构与高光谱图像的特点高度吻合。于是研究者们提出了大量基于图的半监督方法把每个像素看作图中的一个节点用像素之间的相似度构建边然后让标签沿着图的边传播。这也是本文要讲的 Laplace Learning 的基本出发点。2. Laplace Learning从图构建到标签传播2.1 图构建像素如何连成边基于图的半监督分类第一步是把数据组织成一张图。假设有 n 个像素每个像素是一个 d 维光谱向量那么我们需要构建一个 n×n 的相似度矩阵 W其中 W_ij 表示节点 i 和节点 j 之间边的权重。常见做法有两种kNN 图每个节点只与最近的 k 个节点相连避免全连接带来的计算量ε 邻域图距离小于 ε 的两个节点相连。边的权重通常用径向基函数RBF计算W_ij exp(-||x_i - x_j||² / (2σ²))这里的 σ 控制相似度随距离衰减的速度。σ 太大所有边权重趋于相同图失去结构信息σ 太小图可能断裂成多个孤立分量。实际中常用所有样本距离的中位数来初始化 σ。在高光谱场景中直接使用原始光谱向量计算距离容易受到噪声波段和无关波段的干扰。因此通常先做预处理比如去除噪声波段、归一化、PCA 降维等再构建图。2.2 图拉普拉斯与平滑性约束有了权重矩阵 W就定义了一个带权无向图。接下来定义度矩阵 DD_ii Σ_j W_ij度矩阵是一个对角矩阵表示每个节点的总连接强度。图拉普拉斯矩阵定义为L D - W图拉普拉斯矩阵在图分析中非常重要它有一个直观的性质对于任意向量 f二次型 f^T L f 度量了 f 在图上相邻节点之间的“变化程度”f^T L f (1/2) Σ_ij W_ij (f_i - f_j)²这个公式说明如果一条边权重很大那么这两个节点的标签值就不应该有太大差异。这正是“标签平滑性假设”的数学表达。半监督分类希望找到一个标签函数 f使它在有标签节点上尽量接近真实标签同时在无标签节点上保持图的平滑性。2.3 Laplace Learning 的求解Laplace Learning也叫 harmonic function 方法把上述问题转化为一个带约束的最优化问题已知部分节点标签求解整体标签函数使得图的平滑性约束最小化。对多分类问题可以为每个类别 c 定义一个指示向量 y_c其中已标注节点取值为 1 或 0。求解如下线性系统(L μ I_labeled) f_c μ b_c其中 I_labeled 是仅在已标注节点上有值的对角矩阵μ 是标签约束强度。这个方程等价于让 f 在图上尽量平滑同时不要偏离已知标签太远。更朴素的理解是把已标注节点当作“恒温源”让标签像热量一样沿图的边向未标注节点扩散最终达到稳态。每个未标注节点的软标签就是该节点上各类别的扩散结果。最终取最大值对应的类别作为预测。这种方法的优点是求解过程简单本质是解一个稀疏线性方程组对少量标注非常稳定不需要训练复杂模型天然支持转导式预测适合整幅图像逐像素分类。但它的效果高度依赖图的质量。如果图构建不合理比如相似度计算不准确、图不连通标签传播就会失效。这也是为什么需要引入更合理的距离度量比如下面要讲的 Fermat 距离。3. Fermat 距离与 Fermat 图3.1 Fermat 距离的直观理解在构建图时最常用的距离是欧氏距离。但欧氏距离在高维空间里有一个问题它只衡量两个点的“直线远近”并不能反映数据分布的流形结构。举个例子两个像素可能光谱欧氏距离很近但它们中间隔着一个类别边界另外两个像素欧氏距离较远但沿着高密度区域有一条连续的“光谱渐变路径”实际上更可能属于同一类。Fermat 距离的思路非常巧妙它借鉴了光学中 Fermat 原理光在介质中传播时总是选择耗时最短的路径。如果把数据点的密度看成“介质密度”那么从点 x 到点 y 的最短路径自然会倾向于穿过数据密集的区域而避开稀疏区域。换句话说Fermat 距离不是“两点之间直线距离”而是“沿着数据流形走的最短代价距离”。所以它比欧氏距离更能反映数据的内在几何结构用它来构建图边权重能更真实地表达样本之间的“结构接近性”。3.2 数学定义给定数据集 X {x_1, x_2, ..., x_n}以及一个参数 α 1Fermat 距离定义为所有连接 x 和 y 的路径中路径上相邻点距离的 α 次方之和的最小值d_F(x, y) min_{path} Σ d(p_i, p_{i1})^α其中 p_0 x, p_m yd(p_i, p_{i1}) 是相邻两个点的欧氏距离。可以看到当 α 1 时Fermat 距离退化为普通最短路径距离geodesic distance当 α 1 时单步长距离会被放大路径会更倾向于分成许多小步沿着密度高的区域“小步快走”因为穿过稀疏区域需要大步长而大步长的成本很高。α 越大这种“绕行高密度区”的倾向越明显。这个参数是 Fermat 图最关键的超参数通常需要根据数据分布来调整。3.3 Fermat 图与拉普拉斯 Learning 的结合用 Fermat 距离替换欧氏距离后图的亲和力矩阵变为W_ij exp(-d_F(x_i, x_j)² / (2σ²))这样构建出来的图被称为 Fermat 图。它有两个明显优势属于同一流形结构的节点之间Fermat 距离较小因此边权更大标签更容易沿着流形传播属于不同流形簇的节点之间Fermat 距离较大即使欧氏距离很近也不太容易产生“跨簇连接”。把 Fermat 图用在 Laplace Learning 中就得到基于 Fermat 距离的半监督分类器。这也正是 Fermat Active Laplace Learning 方法中“非主动”部分的基础先用 Fermat 距离构建高质量图再用图拉普拉斯做标签传播。在实际计算时我们不可能枚举所有路径因此通常先在原始特征空间构建一个 kNN 图然后使用 Dijkstra 最短路径算法求解 Fermat 距离的近似值。这是一种常见且高效的近似策略。4. Active Laplace Learning主动学习 半监督分类4.1 主动学习的基本思想Laplace Learning 虽然能在少量标注下工作但它本身不会告诉我们“下一步该标注哪些像素”。如果标注者随便选像素去标注可能选到的都是一些信息量很低、对分类精度提升没有帮助的点。主动学习Active Learning就是为了解决这个问题。它的核心思路是让模型从当前状态出发挑选“最值得标注”的样本交给标注者标注然后把新标注加入训练集继续改进模型。这样可以最大化每一份标注预算的价值。在高光谱场景中标注成本高昂主动学习尤其有价值我们不再随机采样标注而是优先标注那些模型最不确定、对分类边界最有影响的像素。4.2 在拉普拉斯框架下选择样本把主动学习嵌入 Laplace Learning 框架就得到 Active Laplace Learning。它的关键在于回答一个问题如何衡量一个未标注样本的“信息量”一种直观的做法是“不确定性采样”。在标签传播求解完成后每个未标注节点会得到一个软标签分布。如果一个节点的软标签分布非常接近均匀分布说明模型在它身上几乎无法判断类别那么这个节点就是“最不确定”的节点。常见的不确定性指标包括最大类别概率概率越低越不确定熵Entropy分布越均匀熵越高越值得标注边际差异Margin最大两个类别概率差值越小越不确定。另一种更严谨的思路是“最优实验设计”。在 Laplace Learning 中预测值来自一个线性系统的解因此可以解析地计算预测方差。选择使预测方差降低最多的节点进行标注是一种从统计最优性出发的样本选择策略。这类方法计算量更大但理论上更有依据。Fermat Active Laplace Learning 的整体思路就是把上述两块拼起来用 Fermat 距离构造更合理的图用 Laplace Learning 做半监督传播再用主动学习策略迭代挑选最有价值的像素。4.3 完整流程整套方法的运行流程可以概括为以下步骤数据预处理去除噪声波段、归一化、PCA 降维构建 kNN 图并计算 Fermat 距离矩阵由 Fermat 距离生成亲和力矩阵和图拉普拉斯随机选择每类少量像素作为初始标注集求解 Laplace Learning 线性系统得到所有未标注节点的软标签按不确定性指标对未标注节点排序选出最值得标注的节点由标注者给该节点提供真实标签将其加入标注集重复步骤 5 到 7直到达到标注预算。这个流程把“图结构建模”和“标注成本控制”放在一个统一框架内这也是它区别于简单“半监督 随机采样”方案的关键。5. Python 参考实现下面给出一套完整的 Python 参考实现。为了让代码容易理解、能直接运行这里使用合成的三维高斯簇数据来模拟“同类像素聚集”的场景。真实高光谱数据可以替换数据加载部分后续会给出替换建议。5.1 环境与依赖本文示例基于 Python 3.8 以上环境依赖以下库numpy矩阵运算scipy距离计算、最短路径、稀疏线性求解scikit-learn可选用于 PCA 降维和评估指标matplotlib可选用于可视化。安装命令如下pip install numpy scipy scikit-learn matplotlib5.2 构造演示数据首先构造三簇二维数据模拟三个地物类别。真实高光谱数据虽然维数更高但数据结构本质相同。import numpy as np from scipy.spatial.distance import cdist from scipy.sparse.csgraph import shortest_path def make_demo_data(points_per_class150, seed42): 生成三个高斯簇模拟三类地物像素。 rng np.random.default_rng(seed) centers np.array([[0.0, 0.0], [8.0, 0.0], [4.0, 7.0]]) X np.vstack([ rng.normal(locc, scale0.9, size(points_per_class, 2)) for c in centers ]) y np.repeat([0, 1, 2], points_per_class) return X, y这里每个类别 150 个样本共 450 个样本。类别中心之间留有一定距离但簇边缘也存在交叉适合观察半监督传播的效果。5.3 计算 Fermat 距离矩阵Fermat 距离的精确计算代价较高实际中通常在 kNN 图上用最短路径近似。边权重取欧氏距离的 α 次幂。def build_knn_graph(D, k6): 根据距离矩阵构建 kNN 邻接矩阵。 n D.shape[0] graph np.full((n, n), np.inf) for i in range(n): order np.argsort(D[i]) for j in order[1:k 1]: # 跳过自身 graph[i, j] D[i, j] # 保证对称 return np.minimum(graph, graph.T) def compute_fermat_distance(X, k6, alpha2.0): 在 kNN 图上求最短路径近似 Fermat 距离。 D cdist(X, X) knn build_knn_graph(D, kk) # 路径代价为距离的 alpha 次方 weighted np.where(np.isfinite(knn), knn ** alpha, np.inf) F shortest_path(csgraphweighted, directedFalse) return F需要注意alpha1时Fermat 距离退化为普通最短路径距离alpha2时单步长度被平方放大路径会明显偏向于沿着密集点“小步绕行”。这个近似的精度取决于 k 和 α 的选择。5.4 构建图拉普拉斯并求解标签传播拿到 Fermat 距离矩阵后用高斯核生成亲和力矩阵为了控制计算量只保留 kNN 邻域内的边。然后构造图拉普拉斯矩阵。def build_laplacian(F, X, k6, sigmaNone): 由 Fermat 距离矩阵构建图拉普拉斯。 n F.shape[0] if sigma is None: vals F[np.triu_indices(n, 1)] sigma np.median(vals[vals 0]) / 2.0 W_full np.exp(-F ** 2 / (2.0 * sigma ** 2)) # 只保留 kNN 邻接关系控制稠密度 D cdist(X, X) mask np.zeros((n, n), dtypebool) for i in range(n): order np.argsort(D[i]) mask[i, order[1:k 1]] True mask mask | mask.T W np.where(mask, W_full, 0.0) deg W.sum(axis1) L np.diag(deg) - W return L, W, sigma def laplace_learning(L, labeled_idx, y_onehot, mu1.0): 求解 Laplace Learning 线性系统返回软标签矩阵。 n L.shape[0] num_classes y_onehot.shape[1] A L.copy().astype(float) for i in labeled_idx: A[i, :] 0.0 A[i, i] mu b np.zeros((n, num_classes)) b[labeled_idx] mu * y_onehot[labeled_idx] # 小规模数据直接稠密求解大规模数据可换 spsolve F_scores np.linalg.solve(A, b) return F_scores这里的mu控制已标注节点对标签传播的“锚定强度”。mu越大已标注节点的标签越不容易被邻居影响。实际中mu可以取 0.1 到 10 之间的值视数据而定。5.5 主动学习循环下面实现最朴素的不确定性采样策略每次选择软标签熵最高的未标注节点进行标注。def entropy_uncertainty(F_scores, labeled_idx): 计算每个节点的熵不确定性已标注节点置为 -1。 exp_scores np.exp(F_scores - F_scores.max(axis1, keepdimsTrue)) probs exp_scores / exp_scores.sum(axis1, keepdimsTrue) entropy -np.sum(probs * np.log(probs 1e-12), axis1) entropy[labeled_idx] -1.0 return entropy, probs def active_learning_loop(X, y, n_seed_per_class2, n_queries30, alpha2.0, k6, mu1.0): Fermat Active Laplace Learning 主循环。 n X.shape[0] num_classes int(y.max()) 1 rng np.random.default_rng(0) # 每类随机初始化少量标注 labeled_idx [] for c in range(num_classes): cand np.where(y c)[0] labeled_idx.extend( rng.choice(cand, sizen_seed_per_class, replaceFalse).tolist() ) labeled_idx np.array(labeled_idx) onehot (y[:, None] np.arange(num_classes)).astype(float) # 预先算好 Fermat 距离和图拉普拉斯 F_mat compute_fermat_distance(X, kk, alphaalpha) L, _, _ build_laplacian(F_mat, X, kk) for step in range(n_queries): F_scores laplace_learning(L, labeled_idx, onehot, mumu) pred F_scores.argmax(axis1) oa (pred y).mean() entropy, _ entropy_uncertainty(F_scores, labeled_idx) query int(np.argmax(entropy)) # 模拟专家标注真实标签加入标注集 labeled_idx np.append(labeled_idx, query) print(fstep {step 1:2d} | query {query:3d} f| labeled {len(labeled_idx):3d} | OA {oa:.4f}) return labeled_idx if __name__ __main__: X, y make_demo_data(points_per_class150, seed42) active_learning_loop(X, y, n_seed_per_class2, n_queries30)运行后输出大致如下具体数值会受随机种子影响step 1 | query 342 | labeled 7 | OA 0.8844 step 2 | query 385 | labeled 8 | OA 0.9067 step 30 | query 76 | labeled 36 | OA 0.9511可以看到随着主动标注的进行总体精度逐渐提升而且每轮只增加一个标注样本。5.6 替换为真实高光谱数据真实高光谱数据通常是.mat格式包含数据立方体input和标签图output。替换方法如下from scipy.io import loadmat # 以 Indian Pines 风格数据为例具体字段请按数据集调整 mat loadmat(indian_pines.mat) data mat[input] # 例如 (145, 145, 200) labels mat[output] # 例如 (145, 145)然后把三维图像拉平成二维矩阵每个像素一行同时剔除标签为 0 的背景像素。为了控制计算规模可以先用 PCA 降维from sklearn.decomposition import PCA h, w, bands data.shape X_raw data.reshape(h * w, bands) y_flat labels.ravel() # 只保留有效像素 mask y_flat 0 X_all X_raw[mask] y_all y_flat[mask] - 1 # 标签从 1 开始 # 归一化 PCA 降维 X_mean X_all.mean(axis0) X_std X_all.std(axis0) 1e-8 X_norm (X_all - X_mean) / X_std X_pca PCA(n_components30).fit_transform(X_norm)之后把X_pca和y_all传给前面的active_learning_loop即可。需要提醒的是当像素数达到数万甚至更多时稠密的距离矩阵和np.linalg.solve会非常吃力建议改用稀疏矩阵和scipy.sparse.linalg.spsolve并考虑分块计算。6. 常见问题与排查思路在复现和调参过程中最容易遇到以下几类问题这里整理成一张排查表。问题现象常见原因解决思路内存溢出或运行极慢全连接距离矩阵占用 O(n²) 空间减小 k构建稀疏图先 PCA 降维对大图做分块或子采样距离矩阵出现大量 infkNN 图不连通部分节点无路径增大 k适当减小 α检查特征是否包含异常值标签传播后所有节点都被分成同一类图不连通或 μ 设置不当检查图的连通分量对 μ 做小范围网格搜索验证精度波动很大初始标注随机性太强多次随机种子实验报告均值和标准差初始标注采用分层采样主动学习反复选到相似像素只考虑不确定性忽略多样性引入批量采样结合聚类或代表性采样结果不如普通欧氏距离图α 或 k 参数选择不合适在验证集上扫描 α ∈ {1, 1.5, 2, 3} 和 k ∈ {5, 10, 20}排查时建议按下面顺序来先确认数据预处理没有问题特征是否归一化、是否有 NaN检查图是否连通打印连通分量数量用最朴素的欧氏距离图作为 baseline确认 Laplace Learning 本身有效再逐步替换为 Fermat 距离缩小参数搜索范围最后再调主动学习策略不要一开始就同时改所有变量。7. 工程与科研最佳实践7.1 实验协议与评估指标半监督高光谱分类实验最容易犯的错误是“信息泄漏”。构建图时使用了所有像素的光谱特征这本身是转导式学习允许的但必须保证标签只能通过标注集进入模型测试集仅用于最终评估不能参与任何参数调整如果做模型选择需要单独划分验证集或者采用交叉验证。评估指标不要只报总体精度 OA建议同时报告OAOverall Accuracy总体分类精度AAAverage Accuracy各类别精度的平均值Kappa 系数衡量分类结果与随机分类相比的一致性每类单独精度和混淆矩阵用于分析类别混淆情况。高光谱数据类别往往不均衡比如某些类别像素很少单纯看 OA 很容易被大类主导。7.2 超参数调优策略这套方法中的超参数包括Fermat 距离参数 αkNN 图近邻数 k高斯核宽度 σ标签约束强度 μ主动学习每轮查询数。建议采用小规模网格搜索。以 α 为例可以在 {1, 1.5, 2, 3} 中尝试k 可以在 {5, 10, 20} 中尝试。每次实验固定随机种子至少运行 3 到 5 次取均值避免单次随机初始标注造成的偏差。7.3 光谱与空间信息结合纯像素级高光谱分类忽略了图像的空间结构。实际中相邻像素通常属于同一类地物所以引入空间上下文往往能显著提升精度。常见做法有超像素分割如 SLIC在超像素级别构建图对每个像素提取局部邻域均值、方差等空间特征使用形态学滤波或空间-光谱联合特征。如果你在整幅图像上逐像素建图节点数会非常大。一个折中方案是先用超像素把图像分成若干区域把区域作为图的节点。这样既保留了空间上下文又大幅降低了图的规模。7.4 扩展方向与实践建议从 Fermat Active Laplace Learning 出发可以继续探索的方向包括批量主动学习每轮不只查一个样本而是用多样性约束选择一批样本增量式图更新每次加入新标注后不需要重新求解整个线性系统可以借助矩阵分解增量更新与深度特征结合先用自编码器或对比学习提取光谱特征再在特征空间构建 Fermat 图不确定性校准主动学习的不确定性估计有时并不准确可以结合随机森林或深度集成校准。对于实际项目我建议先把“预处理 → 欧氏距离图 → Laplace Learning → 随机采样”这条最小基线跑通记录一组精度然后依次替换为“Fermat 距离图”和“主动查询”。这样每一步的收益都能单独衡量出现问题时也更容易定位。8. 总结与下一步学习建议本文围绕 Fermat Active Laplace Learning for Semi-Supervised Hyperspectral Image Classification 这条技术路线完整梳理了高光谱图像分类的背景、半监督 Laplace Learning 的原理、Fermat 距离的几何意义以及主动学习如何与标签传播结合。文中还给出了一个可运行的 Python 参考实现覆盖了 kNN 图构建、Fermat 距离计算、图拉普拉斯求解、熵不确定性采样和主动学习主循环。如果你正要入门这个方向下一步可以按这样的顺序继续深入先熟悉一个公开高光谱数据集的组织方式和预处理流程然后复现一次基于 SVM 或 kNN 的像素级分类作为 baseline再尝试本文的 Laplace Learning 和 Fermat 图最后引入主动学习并观察标注预算与精度之间的关系。把这套流程在 Indian Pines 等公开数据上跑通再迁移到自己的数据上会是比较稳妥的路径。
返回列表