ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SVDD与OCSVM深度对比:单类分类算法原理、差异与选型实践

SVDD与OCSVM深度对比:单类分类算法原理、差异与选型实践 做异常检测这几年SVDD和OCSVM这两个名字几乎每次都一起出现。很多人问过我这两个到底什么区别选哪个好为什么我换了数据集之后结果“风水轮流转”说实话这两个算法确实长得像亲兄弟都出身SVM家族都能做单类分类One-Class Classification甚至在高斯核下数学形式只有一线之隔。但这“一线之隔”恰恰决定了它们在真实数据上的表现差异。这篇文章我就把这两个方法的原理、差异、实操细节和踩坑经验一次性讲清楚希望能帮你少走弯路。OCSVMOne-Class Support Vector Machine单类支持向量机和SVDDSupport Vector Data Description支持向量数据描述都是解决“只有正常样本没有异常样本”这类问题的经典方法。它们不需要你提供反例只需要从一堆正常数据里学出一个边界边界之外的东西就被判定为异常。这种范式在工业质检、故障诊断、金融反欺诈、医疗异常筛查里非常实用。我最早接触这对算法是在一个轴承故障检测项目里当时手里只有正常状态下的振动数据故障数据少得可怜传统分类器完全没法训练。后来换成单类分类的思路问题才豁然开朗。这篇文章适合正在做异常检测、新颖性检测、工业健康管理或者想做数据分布边界建模的同学。我会从问题定义讲起逐步深入到原理推导再落到代码实操和调参经验。不管你是刚接触单类分类的新手还是已经在用OCSVM但想搞清楚SVDD差异的老手这篇都能给你一些实实在在的参考。1. 问题定义与应用场景1.1 单类分类到底在解决什么问题先说一个反直觉的事情很多异常检测任务其实没有“异常样本”可以训练。“异常”这个概念在数据采集阶段往往太模糊、太罕见、太昂贵。比如生产线上某台设备还没坏你怎么采到“坏了”的数据就算采到了故障模式可能有一百种根本采不全。这种场景下监督学习没法做半监督也缺一半材料只能做单类分类。单类分类的设定很纯粹训练阶段只给你一类样本通常是正常样本你要学出一个“正常范围”的边界。推理阶段落在边界内的判为正常落在边界外的判为异常。用一句更通俗的话讲它不是在学“什么是异常”而是在学“什么是正常”凡是跟正常长得不一样的都算异常。这套思路跟密度估计有相似之处但也有本质区别。密度估计比如高斯混合模型是把概率密度建模出来然后设一个密度阈值。密度估计的问题是数据一旦高维密度估计极难做准而且“低密度区域”和“异常区域”并不总是相等。SVDD和OCSVM走的是另一条路不做概率建模直接在特征空间里找一个几何边界让边界尽量贴合正常数据的分布范围。1.2 真实场景里的典型应用我接触到这几个方法的场景基本都是“数据只有一正类”的业务工业设备健康管理传感器持续采集振动、温度、电流信号绝大多数时间设备是正常的故障数据极其稀少。用单类分类模型对正常运行状态建模实时打分分数突变就报警。金融反欺诈正常交易数据海量欺诈交易比例极低且攻击手法不断变化。用单类分类对正常用户行为画像偏离画像的交易会被标记出来人工复核。医疗异常筛查体检指标中健康人群的数据容易获取而某种罕见病的病例可能只有几十条。先对健康样本建模偏离模型的个体进一步做检查。图像缺陷检测良品图片很多缺陷图片各种各样且新缺陷不断出现。用单类分类学“良品的样子”像素级或特征级偏离都算缺陷。在这些场景里SVDD和OCSVM都曾被大量使用。它们不依赖负样本、对高维数据有一定容忍度、决策边界灵活这些都是它们能火这么多年的原因。2. 算法原理深挖2.1 从SVM的间隔最大化说起要说清楚这两个算法得先回到SVMSupport Vector Machine支持向量机的思想源头。普通二分类SVM在做的事情是在高维特征空间里找到一个超平面把两类数据分开同时让这个超平面离两边最近样本的距离之和即间隔最大化。间隔越大泛化越好这是统计学习理论里的核心结论。但单类分类的问题里没有两类数据只有一个类怎么套用“间隔最大化”的思路这就派生出了两种不同的处理策略策略一把坐标原点当成“虚拟的另一个类”学一个超平面把原点和正常数据分开同时最大化超平面到原点的距离。这就是OCSVM的出发点。策略二不再找超平面而是找一个能够把正常数据全部包住的最小超球体让球边界尽量贴合数据。球心到边界的半径就相当于SVM里的间隔。这就是SVDD的出发点。两种策略都把“正常数据”和“某个人造参照物”做了一次二分类从而巧妙地借用SVM的机制。你可以这样理解OCSVM是“以原点为假想敌”SVDD是“以球心为基准点”。一个画线一个画圈。2.2 OCSVM的目标函数OCSVM由Schölkopf等人于2001年提出。设正常样本为 x1, x2, ..., xn通过核函数 φ(x) 把它们映射到高维特征空间。OCSVM想找一个超平面 w·φ(x) - ρ 0使得大部分正常样本满足 w·φ(x) ≥ ρ也就是落在超平面的“正侧”同时让原点到超平面的距离 ρ/||w|| 最大。因为原点本身就在原点这一侧优化目标等价于 min ½||w||² (1/(νn))∑ξᵢ - ρ约束条件 w·φ(xᵢ) ≥ ρ - ξᵢξᵢ ≥ 0对所有 i这里的 ξᵢ 是松弛变量允许部分正常样本越过边界增强模型对噪声的鲁棒性。参数 ν 的作用非常关键它同时控制了两件事训练样本中被判定为异常即落在边界另一侧的样本比例的上界训练样本中成为支持向量的样本比例的下界ν 的取值范围是 (0, 1]取值越大边界越紧越多的正常点会被当成异常模型对正常数据的覆盖越少但对异常越敏感。实际项目中 ν 通常在 0.01 到 0.1 之间调。2.3 SVDD的目标函数SVDD由Tax和Duin于2004年正式提出。它的思路是找一个最小半径的超球体让所有正常样本都尽量落在球内。设球心为 a半径为 R优化目标为 min R² C ∑ξᵢ约束条件 ||φ(xᵢ) - a||² ≤ R² ξᵢξᵢ ≥ 0对所有 i这里 C 是惩罚系数控制松弛变量的权重。C 越大模型越不允许样本落在球外边界越紧C 越小模型越宽容。直观理解C 就像弹簧允许少量样本越过球面换取更紧凑的球体边界。用拉格朗日对偶求解后SVDD的对偶问题可以写成只包含内积的形式。很多教材里总结过如果核函数选择高斯径向基核SVDD的对偶解里球心a可以表示为支持向量的线性组合决策函数只需要计算新样本到球心的距离是否小于半径R。2.4 两者的对偶形式对比比较对偶问题是最能看清两者亲缘关系的地方。当采用核函数 k(x, y) 时OCSVM 的对偶问题中目标函数里有关于数据的一项是一次项∑αᵢ k(xᵢ, xᵢ)并且约束是 ∑αᵢ 10 ≤ αᵢ ≤ 1/(νn)。SVDD 的对偶问题中同样有 ∑αᵢ k(xᵢ, xᵢ)但还多了一个二次项∑∑αᵢαⱼ k(xᵢ, xⱼ)约束同样是 ∑αᵢ 10 ≤ αᵢ ≤ C。问题就出在这个二次项上。OCSVM对每个样本只单独看它自己跟自己的内积而SVDD要考虑样本两两之间的内积。这个差异看似细微实际效果却有很大区别。当使用高斯核 k(x,x) 恒等于 1 时OCSVM里那个一次项 ∑αᵢ·1 就变成了常数对优化没有实质影响而SVDD里的二次项仍然存在它刻画的是样本两两之间的相似性结构。换句话说在高斯核下OCSVM实际上只需要维护每个样本跟其他样本的关系来决定谁做支持向量而SVDD则更直接地利用样本间的距离信息。这个数学差异直接导致了两个算法在边界形状、参数敏感度和高维表现上的不同。这也是为什么很多人在自己的数据上对比后发现两个算法结果经常不一致的根本原因。3. 核心差异对比3.1 几何直观一个找球一个找平面SVDD是找一个包围数据的超球体决策边界是一个闭合的球面。这个球面会对所有方向一视同仁因为球体本身是各向同性的。如果正常数据在不同方向上的分布宽度相差很大SVDD的球体边界就会在窄方向上多出一些“空余”在宽方向上又显得太紧绷。OCSVM是找一个超平面理论上这个超平面是开放的但因为计算时加入了核映射实际决策边界在原始空间里也可以形成闭合曲线或复杂曲面。不过OCSVM有一个内在偏向分离超平面经过了原点方向。当数据的均值不在原点附近时OCSVM会倾向于把数据分布的“朝向”考虑进去所以它对某些非对称分布的数据反而更友好。打个比方。SVDD像一个圆规画出一个尽可能小的圆把点围住圆一定是圆的。OCSVM像一个裁纸刀把纸一刀切开这一刀的角度和位置会被优化切完之后朝有数据的一侧就是正常区域。如果你的数据是一团云圆规画圈很合适如果你的数据是一条带方向的长条云裁纸刀一刀切可能更贴合。3.2 参数体系C和ν的语义差异这是实际调参时最容易困惑的地方。SVDD的惩罚参数 C 和 OCSVM 的 ν 看起来都能控制边界松紧但语义不完全一样。SVDD的 C 是用在约束项 R² C∑ξᵢ 里。它不是直接告诉你“多大比例的点会落在外边”而是通过惩罚力度间接控制。要让多少点落在外边得先解优化问题才知道。C 越大边界越紧可能导致过拟合把噪声也学进“正常范围”的边缘C 越小边界越松可能把真正的异常也包进“正常范围”。OCSVM的 ν 有一个非常优雅的性质它直接给出训练集中异常点比例的上界和支持向量比例的下界。也就是说你设定 ν 0.05算法就会自动调整边界让至多5%的训练样本落在边界的另一侧。这个可解释性在工程里非常有用因为业务方往往能给出“我大概能接受多少比例的误报”这种需求。实际项目中我会先问自己我是要控制错误的预算还是只想要一个稳健的边界要控制错误预算优先用OCSVM的ν想要一个边界尽可能紧凑、可解释的几何包络就考虑SVDD。当然这只是初始倾向最终要看验证集上的表现。3.3 高斯核下的关系很多人听说过一个说法“高斯核下SVDD和OCSVM是等价的”。这个说法并不完全准确。准确的说法是当数据在特征空间中的均值被归一化到原点附近或者核函数满足特定条件时两者的决策函数会趋同。但真实数据很难保证这个条件所以实际结果往往有差异。具体来说高斯核 k(x,y) exp(-γ||x-y||²)有 k(x,x) 1所以SVDD对偶问题中的一次项变成了常数对优化方向影响减弱OCSVM同样如此。两者差别就主要集中在SVDD多出来的那个二次项上。这个二次项使得SVDD对数据点之间的相对距离更加敏感。换句话说SVDD更像是在“学习数据的形状”而OCSVM更侧重于“找数据的支撑方向”。一个经验结论当数据分布比较球形、且没有明显的偏好方向时SVDD和OCSVM表现接近SVDD的球状假设也不会造成太大偏差当数据分布存在明显的椭球形状或方向性时OCSVM往往能利用超平面的方向适应性获得更好的边界而SVDD的球状边界会显得力不从心。3.4 计算复杂度与可扩展性两者都涉及核矩阵的计算训练阶段复杂度都是 O(n²) 到 O(n³) 级别n是训练样本数。样本数量到几万级别时直接训练会非常吃力。在线推断阶段两者都需要计算新样本与支持向量的核函数值复杂度与支持向量数量成正比。SVDD的球心表示通常更紧凑一些因为它把所有支持向量的线性组合聚成一个球心向量OCSVM的超平面虽然也由支持向量线性表示但它没有一个像“球心”这样直观的几何量。所以SVDD在存储和推理效率上偶尔有一点优势但差距不大SVM家族方法都不太擅长处理超大规模数据。数据量太大时一般会考虑采样、Mini-batch优化或者换用基于深度的异常检测方法。4. 实战工具、代码与参数调优4.1 工具体选型Python生态里OCSVM直接可以用sklearn的sklearn.svm.OneClassSVM非常方便。SVDD则没有集成到sklearn主库中通常用第三方实现比如pyod库里有OCSVM模型但没有内置SVDD。如果需要使用SVDD常见的选择是自己按对偶问题实现如果你熟悉凸优化或者SMO算法用一些开源库如svdd相关的GitHub项目用MATLAB的dd_tools工具箱很多早期文献用这个我建议你在动手前想清楚你的核心目标是搞懂算法、复现论文还是快速落地一个基线模型。快速落地OCSVM sklearn是最省事的路径细致研究边界自己实现SVDD也不难因为它的对偶形式很规整。下面我给一个简化的SVDD实现思路。先说好这个实现主要用来理解原理工程上要追求性能的话还是推荐集成更成熟的库或者用SMO优化。4.2 用sklearn快速搭一个OCSVM基线假设你已经有一批正常样本保存在X_train中每个样本是d维特征向量。下面是用OCSVM建模并做预测的标准流程import numpy as np from sklearn.svm import OneClassSVM from sklearn.preprocessing import StandardScaler # 1. 标准化 scaler StandardScaler() X_scaled scaler.fit_transform(X_train) # 2. 初始化模型 model OneClassSVM( kernelrbf, gamma0.1, # 这个参数很关键后面专门讲 nu0.05 # 预期异常比例上界 ) # 3. 训练 model.fit(X_scaled) # 4. 预测返回1表示正常-1表示异常 y_pred model.predict(X_scaled) # 5. 获取异常得分距离决策边界的带符号距离 score model.decision_function(X_scaled)这里有个我反复踩过的坑decision_function的分数正负号。在sklearn的OneClassSVM里正数表示在边界内侧负数表示边界外侧。但具体数值的大小并不直接等于距离只是有单调关系。后续如果要做阈值调整建议直接用这个分数排序而不是硬套某个固定阈值。4.3 自己实现一个简单的SVDDSVDD的对偶问题可以写成一个带约束的二次规划。为了简化我直接给出一个基于拉格朗日对偶的实现轮廓import numpy as np from scipy.optimize import minimize def rbf_kernel(X, Y, gamma1.0): # 高斯核矩阵 sq_dist np.sum(X**2, axis1)[:, None] np.sum(Y**2, axis1)[None, :] - 2 * X Y.T return np.exp(-gamma * np.clip(sq_dist, 0, None)) def train_svdd(X, C1.0, gamma1.0): n X.shape[0] K rbf_kernel(X, X, gamma) # 目标函数: 0.5 * sum_ij alpha_i alpha_j K_ij - sum_i alpha_i K_ii # scipy minimize默认求最小值所以取负号的那个对偶目标改成求 min # 实际最小化: 0.5 * alpha^T K alpha - sum(alpha) def objective(alpha): return 0.5 * alpha K alpha - np.sum(alpha) # 约束: sum alpha_i 1, 0 alpha_i C constraints [{type: eq, fun: lambda a: np.sum(a) - 1}] bounds [(0, C)] * n # 初始化 alpha0 np.ones(n) / n res minimize( objective, alpha0, methodSLSQP, boundsbounds, constraintsconstraints, options{maxiter: 200} ) alpha res.x # 计算球心在特征空间中的表示如果要用核函数计算距离需要保存支持向量 sv_idx np.where(alpha 1e-6)[0] # 计算半径 R^2: 任选一个支持向量计算它到球心的距离 alpha_sv alpha[sv_idx] X_sv X[sv_idx] # K(x_sv, x_sv) diag_sv np.sum(alpha_sv[:, None] * alpha_sv[None, :] * rbf_kernel(X_sv, X_sv, gamma)) # 实际上 R^2 可以用公式计算这里省略细节 # 预测时比较新样本到球心距离和半径 return alpha, sv_idx需要注意的是这种基于scipy.optimize.minimize的通用QP解法在样本量大时非常慢只能用来跑几十到几百个样本的小实验。工程上SVDD一般用SMO序列最小优化或者随机梯度下降来优化。另外上面代码只是为了展示对偶问题怎么落到优化函数上真正复现SVDD还需要仔细处理拉格朗日乘子的初始化和边界条件。如果你不太想自己敲这些数学我建议直接用比较成熟的第三方实现。GitHub上搜索SVDD可以找到一些实现有些基于PyTorch支持GPU加速。但一定要自己先读一下代码确认它实现了标准SVDD而不是简化版本否则结果会有偏差。4.4 关键参数gamma和nu的调优说到调参gamma和nu是两个最核心的旋钮。很多人上来就默认gamma 1/n_features然后发现模型一团糟。实际上gamma的合理范围跟数据的尺度、样本量、维度都有关系。gamma过大高斯核只对非常近的点敏感决策边界会变得非常复杂容易过拟合把正常数据边界画成碎片。gamma过小高斯核退化成一个接近常数的核所有点之间的相似度都差不多模型学不到有效结构边界会非常简单。实践中我会用网格搜索配合验证集来做选择。验证集上没有标准答案因为单类分类没有真实标签所以更常见的做法是你有少量标记的异常样本但不足以训练模型把这些异常样本单独留出来作为验证集看模型在“拒绝异常”上的表现。用AUC、F1k这类指标来选参数会比纯粹看训练集上的边界紧凑度靠谱得多。nu的选择相对直观。你先根据业务容忍度估算一个“异常比例上界”比如误报率不能超过3%那就设定nu在0.03附近。然后观察验证集上的精确率和召回率再微调。有一点要注意nu设得很小时模型会倾向于把所有训练数据都包进正常边界决策边界离数据很远这时候对异常样本的敏感度会下降实际就是“宁可放过不可误杀”的倾向。4.5 对比实验的评估方法做SVDD和OCSVM的对比实验时很多新手直接用准确率。在极度不平衡的数据上准确率毫无意义。我见到的比较规范的评估方式把正常样本分成训练集和验证集训练集只用来建模验证集用来调参。准备少量真实异常样本作为测试集不参与训练。计算每个样本的异常得分后用AUCROC曲线下面积评估排序能力。如果要设阈值用Precisionk或者F1-beta这类指标。在实验报告里我通常同时报告正常样本的召回率模型能覆盖多少正常样本和异常样本的命中率模型能抓出多少异常。这两个指标之间存在权衡参数的选取本质上就是在找这个权衡的平衡点。5. 真实数据上的表现差异与原因分析5.1 实验设置为了说明问题我用一个仿真数据做过对比实验。数据分三种形状第一组是各向同性的高斯团正常数据均匀分布在球体周围第二组是带方向性的长条高斯分布正常数据形成明显椭球第三组是环形分布中心区域基本没有数据。三组数据各生成2000个正常样本作为训练和验证另生成200个真实异常样本从远离正常区域的均匀分布中采样作为测试。两个模型都使用RBF核。OCSVM的nu设置为0.05SVDD的C通过交叉验证在[0.01, 0.1, 1, 10]里选。gamma在两组模型中都从[0.01, 0.1, 1, 10]里网格搜索。评估指标用AUC。5.2 结果观察第一组各向同性高斯团上SVDD和OCSVM的AUC非常接近差距在0.5%以内。这符合理论预期数据分布越接近球对称SVDD的球假设越不受惩罚OCSVM的超平面也能很好地工作。第二组带方向性的椭圆分布上OCSVM明显更好AUC高了大概4到6个百分点。原因在于OCSVM的超平面可以适应数据的主方向边界在长轴方向宽松、短轴方向紧凑而SVDD的球体边界会在这个椭圆分布的长轴方向上出现很大的“空洞”把一部分异常样本也包进了球内。第三组环形分布上SVDD的表现反而更好。环形分布的中心是空的OCSVM由于超平面必须经过原点方向在特征空间中把原点和数据分开会把环形中心错误地判为正常SVDD则能把整个数据区域围成一个“球形壳”外的区域中心空洞得以保留模型对中心区域样本的异常敏感度更高。当然这个优势的前提是支持向量集中在环的外侧球心也在环中心附近。5.3 背后的关键影响因素从这几个实验结果里我总结出影响两者选择的三个关键因素数据分布是否近似球对称。越接近球对称SVDD越占优越有方向性OCSVM越灵活。数据中的“空洞”结构。如果正常数据包围着一块空白区域SVDD能更好地保留这个空洞OCSVM可能直接把这一块也看成正常。高维空间中的距离集中效应。在高维数据里样本之间的距离趋向于均匀化SVDD对距离的二次项利用可能退化OCSVM对方向的利用更稳健。我实测过几十到几百维的特征OCSVM在高维上的鲁棒性确实更好SVDD在高维上更容易出现边界退化。但这都不是绝对的。真实业务数据往往混合了多种效应所以我始终建议在你自己数据上做一次小规模对比实验再下结论。6. 常见问题与避坑指南6.1 标准化不是可选项是必选项SVDD和OCSVM都非常依赖特征尺度。RBF核里的距离是欧氏距离如果某个特征的数值范围是0到10000另一个是0到1距离计算完全被第一个特征主导模型基本瞎了。标准化StandardScaler或MinMaxScaler能避免这个问题。但我提醒一句标准化必须在训练集上做然后拿着训练集的均值和方差去变换验证集和测试集。6.2 “无负样本”不代表没有标签可用很多人陷入了“单类分类不能使用任何负样本”的教条。实际上哪怕只有几十条异常样本把它们作为验证集用来选参数、选模型都是完全合理且推荐的。单类分类的训练过程确实只用正常样本但评估和调参环节引入少量异常样本能显著提升模型效果。6.3 别把普通异常检测的评测指标照搬过来我在项目里常见的问题甲方要求报告“准确率”然后发现不管怎么调参准确率都超过95%因为异常比例只有2%。这个指标没有意义。正确做法是报告在固定误报率下的检出率或者直接报告AUC。6.4 核函数不是越多越好SVDD和OCSVM常用RBF核因为它能逼近任意形状的边界。线性核相当于只在原始空间画一个超平面/球面表达能力有限多项式核的阶数不好控制容易过拟合。我建议从一开始就用RBF核把精力花在调gamma上而不是折腾核函数类型。6.5 样本量太少怎么办如果你的正常样本只有几十条SVDD和OCSVM的效果都不会太好因为它们本质上是基于距离的方法需要足够的支持向量来刻画边界。这种情况下我建议先考虑数据增强、特征降维或者使用基于深度自编码器的方法来做异常打分然后再考虑单类分类模型。6.6 决策边界的可视化调试在二维数据上我强烈建议把决策边界可视化出来看一版。sklearn的OneClassSVM可以配合matplotlib画等高线图能直观看到边界是否合理。SVDD同样可以可视化出球心和半径。可视化会比单纯看指标更容易发现问题比如边界在某个方向上明显空洞、或者模型把少数正常样本排得太靠外了。7. 选型建议与个人体会7.1 我的选择框架说了这么多给出一个实际可操作的选型建议。我会按下面的顺序判断如果特征维度很高比如大于100优先OCSVM它对方向性结构更稳健。如果数据分布近似球对称且希望决策边界是闭合的、每个方向都公平优先SVDD。如果业务方需要“我大概能接受多少误报”这类的可解释参数优先OCSVM因为ν直接对应异常比例上界。如果数据中存在明显的空洞结构正常数据环绕一块空白区域优先SVDD。如果两个模型在验证集上AUC差距很小选更简单的那个——多数情况下是OCSVM因为它有sklearn原生支持工程成本低很多。7.2 最后再分享一个小技巧我经常遇到一种情况OCSVM和SVDD在同一个数据集上一个效果好一个差。这并不说明某个算法“更好”而是它们对数据分布的隐含假设不同。所以与其纠结选哪一个不如把两个模型的异常得分融合一下。最简单的做法是把两个得分分别做分位数归一化然后取加权平均或者取这两个得分的最小值也就是“只要有一个模型认为是异常就标记为异常”。这个方法在我做过的好几个故障检测项目里都有效融合后的AUC通常不会低于表现较好的那一个。另外如果你想深挖这两个算法的理论基础建议读一读Schölkopf等人在2001年发表的关于单类SVM的论文以及Tax和Duin的SVDD原始文献。两篇论文都不长但对理解算法边界非常有用。看懂对偶形式的那一刻你就能明白它们为什么是“同源异流”的兄弟算法了。
返回列表