【读点论文】DEEP ANOMALY DETECTION WITH OUTLIER EXPOSURE构建一个分布外数据集,让模型知道自己不知道的是什么,有点鸡肋

DEEP ANOMALY DETECTION WITH OUTLIER EXPOSURE

ABSTRACT

  • 在部署机器学习系统时,检测异常输入非常重要。在深度学习中使用更大和更复杂的输入放大了区分异常和分布内例子的难度。同时,大量不同的图像和文本数据是可用的。我们建议利用这些数据,通过针对异常值的辅助数据集训练异常检测器来改进深度异常检测,这种方法我们称为异常值暴露(OE)。这使得异常检测器能够归纳和检测看不见的异常。在自然语言处理和小规模和大规模视觉任务的大量实验中,我们发现离群点暴露显著提高了检测性能。我们还观察到,在CIFAR-10上训练的尖端生成模型可以向SVHN图像分配比CIFAR-10图像更高的可能性;我们使用运行经验来缓解这个问题。我们还分析了异常值暴露的灵活性和鲁棒性,并确定了提高性能的辅助数据集的特征。
  • 论文地址:[1812.04606] Deep Anomaly Detection with Outlier Exposure
  • 提出了 Outlier Exposure(OE)方法来提升异常检测性能。首先,研究目标应该是解决深度学习模型在面对分布外数据时容易产生高置信度错误预测的问题,也就是高 false positive 的问题。通过引入辅助的异常数据集来训练模型,让模型学习区分分布内和分布外数据,从而降低对未知异常的误判。OE 应该是在训练时加入额外的异常数据,让模型在学习过程中接触到更多样化的异常样本,从而提高检测未知异常的能力。
  • 传统分类假设 “所有测试数据均在训练类别中”,而 OE 承认模型的 “未知未知”,通过主动暴露未知模式,使模型学会 “谦逊”—— 对未知保持低置信度,而非强行分类。这呼应了人工智能安全中的 “可解释性” 与 “可靠性” 需求,即模型不仅需正确分类已知,更需识别未知。

INTRODUCTION

  • 部署中的机器学习系统经常遇到与模型的训练数据不同的数据。这可能发生在发现新的天文现象、发现未知疾病或检测传感器故障时。在这些情况下,可以检测异常的模型能够正确标记人为干预的不寻常的例子,或谨慎地进行更保守的回退策略。

  • 许多机器学习系统的背后是深度学习模型,这些模型可以在各种应用程序中提供高性能,只要测试时看到的数据与训练数据相似。然而,当存在分布不匹配时,深度神经网络分类器往往会对异常测试示例给出高置信度预测 。这可能会使预测概率作为校准置信估计的使用失效 ,并使检测异常样本变得更加重要。

  • 一些先前的工作试图通过给予深度神经网络分类器一种为输入分配异常分数的方法来解决这些问题。然后,这些分数可用于检测不符合分布(OOD)的例子 。这些方法已经被证明对于复杂的输入空间,例如图像、文本和语音,工作得非常好。此外,它们不需要建模完整的数据分布,而是可以使用试探法来检测未建模的现象。这些方法中的一些通过使用仅来自分布内数据的表示来检测未建模现象。

  • 在本文中,我们研究了一种补充方法,通过学习输入是否未建模的线索来训练模型以检测未建模数据。虽然很难对完整的数据分布进行建模,但我们可以通过将模型暴露给OOD示例来学习检测分布外输入的有效启发式方法,从而学习更保守的内联概念,并能够检测新形式的异常。为此,我们建议利用不同的、真实的数据集,采用一种我们称之为离群值暴露(OE)的方法。运行经验为持续改进现有的食品检测方法提供了一种简单有效的方法。

  • 通过大量的实验,我们广泛地评估了离群值暴露的广泛适用性。对于多类神经网络,我们提供了关于计算机视觉和自然语言处理任务的全面结果,这些结果表明异常值暴露可以帮助异常检测器概括异常值的不可见分布并在其上表现良好,甚至在大规模图像上。我们还证明了离群点暴露比现有的几种非分布检测方法更有优势。我们的结果还显示了异常值暴露的灵活性,因为我们可以用不同的异常值分布来源训练各种模型。此外,我们发现异常值暴露可以使食品样本的密度估计对食品检测更有用。最后,我们证明了离群点暴露改善了神经网络分类器在部分数据为OOD的现实环境中的校准。我们的准则在 GitHub - hendrycks/outlier-exposure: Deep Anomaly Detection with Outlier Exposure (ICLR 2019).公开发布

  • 深度学习模型在面对分布外(Out-of-Distribution, OOD)数据时,常因过度自信而产生高置信度错误预测(高 False Positive),即模型将未知类别的样本错误分类为已知类别且置信度极高。例如,传统分类器在 OOD 样本(如噪声图像、非训练类别图像)上的最大 Softmax 概率可能高于部分分布内样本,导致误判。提出 Outlier Exposure (OE) 方法,通过在训练中引入辅助的异常数据集,使模型学习区分分布内与分布外数据,降低对未知异常的误判率,提升 OOD 检测的可靠性。利用真实且多样的外部异常数据集(如 80 Million Tiny Images、ImageNet-22K 等)作为辅助训练数据,让模型在学习过程中接触到更广泛的异常模式,从而显式学习 “未知” 的特征,避免对未见过的分布产生不合理的高置信度。

RELATED WORK

  • 深度网络的非分布检测。深度预训练分类器在异常示例上的最大 softmax 概率低于分布内示例,因此分类器可以方便地兼作始终有用的分布外检测器。在这项工作的基础上,将一个辅助分支附加到一个预训练的分类器上,并从这个分支中得出一个新的OOD分数。提出了一种方法,可以提高使用softmax分布的OOD检测器的性能。特别是,他们通过对具有对抗性扰动的输入数据进行预处理,使最大softmax概率在异常和分布内示例之间更具区分力 。与我们的工作不同,它们的参数是针对每个异常源定制的。

  • 并且分类器被训练为对GAN样本具有较低的置信度。对于异常的每个测试分布,他们使用来自该外分布的样本来调整分类器和GAN,如他们工作的附录B中所讨论的。在这项工作中,我们在不调整参数的情况下训练我们的方法,以适应特定类型的异常测试分布,因此我们的结果不能与他们的结果直接比较。许多其他作品还鼓励模型对异常示例具有较低的置信度。最近,在假设有一个适当强大的异常检测器可用的情况下,为检测非分布示例提供了理论保证。

  • 利用辅助数据集。离群点暴露使用与测试时数据完全分离的辅助数据集,以便教导网络更好地表示异常检测。对对抗性例子进行了训练,以提高鲁棒性。在网络图像数据库上预先训练无监督的深度模型,以获得更强的特征。在亚马逊评论语料库上训练了一个月的无监督网络,以获得高质量的情感表达。在大型 ImageNet 数据库 上预训练网络赋予了网络在许多微调应用中有用的一般表示。 从搜索引擎和照片共享网站的几乎无限的来源中收集的图像中学习的表示提高了对象检测性能。

OUTLIER EXPOSURE

  • 我们考虑判断一个样本是否来自一个叫做Din的已知分布的任务。来自Din的样本称为“分布内”,否则称为“分布外”(OOD)或来自Dout的样本。在实际应用中,可能很难预先知道将要遇到的异常值的分布。因此,我们考虑Dout未知的现实环境。给定一个参数化的OOD检测器和一个离群点暴露(OE)数据集DOE out,与Dtest out不相交,我们训练该模型来发现信号,并学习启发式算法来检测查询是从Din还是从DOE out采样。我们发现这些试探法推广到看不见的分布Dout。

  • 深度参数化异常检测器通常利用来自辅助任务的学习表示,例如分类或密度估计。给定模型 f 和原始学习目标L,我们因此可以将离群点暴露形式化为最小化目标

    • E ( x ; y ) ∼ D i n [ L ( f ( x ) ; y ) + λ E x ′ ∼ D o u t O E [ L O E ( f ( x ′ ) ; f ( x ) ; y ) ] ] E_{(x;y)}∼D_{in} [L(f(x); y) + λE_{x'∼D^{OE} _{out}} [L_{OE}(f(x'); f(x); y)]] E(x;y)Din[L(f(x);y)+λExDoutOE[LOE(f(x);f(x);y)]]

    • 在标记数据不可用的情况下,可以忽略y。

  • 离群点暴露可以应用于许多类型的数据和原始任务。因此, L O E L_{OE} LOE 的具体公式是一种设计选择,取决于手头的任务和所用的OOD检测器。例如,当使用最大 softmax 概率基线检测器时 ,我们将LOE设置为从f(x 0)到均匀分布的交叉熵 。当原始目标L是密度估计并且标签不可用时,我们将LOE设置为对数概率f(x ^ 0)和f(x)上的边际排序损失。

  • 在原有训练目标中加入对辅助异常数据集的约束,迫使模型对异常数据输出均匀分布的概率(而非集中于某一类别)。例如,对异常数据使用交叉熵损失,使其输出接近均匀分布。目标函数:( L = L i n + λ L O E \mathcal{L} = \mathcal{L}_{in} + \lambda \mathcal{L}_{OE} L=Lin+λLOE)。其中,( L i n \mathcal{L}_{in} Lin) 为分布内数据的分类损失,( L O E \mathcal{L}_{OE} LOE) 为异常数据的损失(如均匀分布交叉熵),( λ \lambda λ) 控制异常数据的权重。OE 可增强多种基线方法,如最大 Softmax 概率(MSP)、置信度分支(Confidence Branch)等。例如,在 MSP 中,OE 使模型对异常数据的最大 Softmax 概率显著降低。实验证明,使用真实、多样的异常数据(如自然图像、真实文本)比合成数据(如高斯噪声、GAN 生成数据)更有效,因真实数据包含更复杂的未知模式。

    • λ(异常数据权重):控制异常数据在总损失中的占比,通常图像任务设为 0.5,文本任务设为 1.0。过大可能降低分类准确率,过小则异常约束不足。

    • 辅助数据集规模:实验显示,使用 1% 的 80 Million Tiny Images(约 800k 样本)即可接近最优性能,规模过大致计算成本上升但增益有限。

    • 训练策略:Fine-tuning(微调) vs 从头训练:微调更高效,从头训练可进一步提升性能(如 CIFAR-10 的 FPR95 从 9.5% 降至 6.15%)。

  • 均匀分布约束:对异常数据,强制模型输出接近均匀分布的概率,降低最大 Softmax 概率。例如,交叉熵损失:( L O E = − E x ′ ∼ D o u t O E ∑ c = 1 K 1 K log ⁡ f c ( x ′ ) \mathcal{L}_{OE} = -\mathbb{E}_{x' \sim D_{out}^{OE}} \sum_{c=1}^K \frac{1}{K} \log f_c(x') LOE=ExDoutOEc=1KK1logfc(x)) 其中,( f c ( x ′ ) f_c(x') fc(x)) 为模型对异常样本 (x’) 的类别概率,K为类别数。边际损失(Margin Loss):在密度估计中,通过最大化分布内与异常数据的对数似然差异,提升 OOD 样本的低概率分配。

  • OE 通过扩大内 - 外分布的决策边界,降低误判风险。数学上,通过调整损失函数,使模型在异常数据上的预测分布熵增加,避免集中于错误类别。真实异常数据的多样性迫使模型学习更泛化的特征,而非记忆特定模式,符合 “对抗样本鲁棒性” 的泛化理论。

EXPERIMENTS

  • 我们在广泛的数据集上评估了有无OE的OOD检测器。每个评估包括一个用于训练初始模型的分布数据集Din、一个异常样本数据集DOE和一个我们应用OE的基线检测器。我们将在第4.2节描述数据集。OOD检测器和LOE损失将根据具体情况进行描述。

  • 在第一个实验中,我们展示了 OE 可以帮助检测器归纳出新的文本和图像异常。与以前的许多工作不同,这一切都是在训练或调优期间无需假设访问测试分布的情况下完成的。在置信分支实验中,我们证明了OE是灵活的,是对二元异常检测器的补充。然后,我们证明了使用合成异常值不如使用真实和多样的数据有效;以前,人们认为我们需要合成数据或精心挑选的接近分布的数据,但真实多样的数据就足够了。我们以密度估计的实验来结束。在这些实验中,我们发现一种先进的密度估计器意外地给分布外样本分配了比分布内样本更高的密度,并且我们通过暴露异常值来改善这种令人惊讶的行为

EVALUATING OUT-OF-DISTRIBUTION DETECTION METHODS

  • 我们评估了分布外检测方法检测 OOD 点的能力。为此,我们将OOD实例视为阳性类别,并评估三个指标:受试者工作特征曲线下面积(AUROC)、精确度-召回曲线下面积(AUPR)和N%真阳性率下的假阳性率(FPRN)。AUROC和AUPR是整体指标,总结了检测方法在多个阈值下的性能。AUROC可以被认为是一个异常的例子比一个分布内的例子被给予更高的OOD分数的概率。因此,更高的AUROC更好,无信息探测器的AUROC为50%。当异常实例不常见时,AUPR是有用的,因为它考虑了异常的基本速率。在使用这些指标进行评估的过程中,在我们所有实验的测试示例中,Dtest out与Dtest的基本比率是1:5。

  • 前两个指标代表不同阈值下的检测性能,而FPRN指标代表一个严格阈值下的性能。通过在严格的阈值下观察性能,我们可以在强检测器之间进行清楚的比较。The FPRN metric 是当检测到N%的异常样本(阳性)时,分布内样本(阴性)发出错误警报的概率,因此FPRN越低越好。捕获几乎所有的异常,而很少出现错误警报,这具有很高的实用价值。

DATASETS

IN-DISTRIBUTION DATASETS
  • SVHN。SVHN数据集 包含32 × 32的门牌号彩色图像。有十个由数字0-9组成的类别。训练集有604个;388幅图像,测试集有26032张图片。对于预处理,我们将像素重新缩放到区间[0;1].

  • CIFAR。这两个CIFAR 数据集包含32 × 32幅自然彩色图像。CIFAR-10有10个等级,而CIFAR-100有100个等级。CIFAR-10和CIFAR-100类是不相交的,但具有相似性。例如,CIFAR-10有“汽车”和“卡车”,但没有CIFAR-100的“皮卡”类别。都有50000个训练图像和10000张测试图像。对于这个和剩余的图像数据集,每个图像都是按通道标准化的。

  • Tiny ImageNet. 微小的ImageNet数据集 是ImageNet 数据集的200类子集,其中图像被调整大小并裁剪为64 × 64分辨率。数据集的图像使用边界框信息进行裁剪,以便裁剪后的图像包含目标,这与缩减采样ImageNet不同。训练集有100000幅图像,测试集有10 000张图片。

  • Places365。Places365训练数据集 存在于1803460幅场景的大型照片。每张照片属于365类中的一类。

  • 20个 Newsgroups。20新闻组是新闻组文档的文本分类数据集,有20个类别,大约有20 000个示例平均分布在各个类中。我们使用标准的60/40训练/测试分割。

  • TREC。TREC是一个问题分类数据集,有50个细粒度类,5 952个单项问题。我们为测试集保留了500个例子,其余的用于训练。

  • SST。斯坦福情感树库数据集 由表达积极或消极情感的电影评论组成。SST有8544次训练审查和2 210用于测试。

OUTLIER EXPOSURE DATASETS
  • 八千万个微小的图像。8000万幅微小图像 是一个大规模、多样化的数据集,由32×32幅自然图像组成。我们使用该数据集作为实验,将SVHN、CIFAR-10和CIFAR-100作为Din。我们移除了CIFAR数据集中出现的8000万个微小图像的所有示例,因此DOE out和Dtest out是不相交的。在第5节中,我们注意到只有一小部分数据集是成功运行经验所必需的。

  • ImageNet-22K。我们使用的ImageNet数据集包含来自大约22,000个类别的图像,就像使用Tiny ImageNet和Places365一样,因为来自8,000万个微型图像的图像分辨率太低。为了使DOE out和Dtest out不相交,ImageNet-1K中的图像被去除。

  • WikiText-2。WikiText-2是维基百科文章的语料库,通常用于语言建模。我们使用WikiText-2做语言建模实验,使用Penn Treebank做Din。对于20个新闻组、TREC和SST的分类任务,我们将WikiText-2的每个句子视为一个单独的例子,并使用简单的过滤器来删除低质量的句子。

MULTICLASS CLASSIFICATION

  • 在下文中,我们使用异常暴露来提高现有OOD检测技术的性能,并将多类分类作为原始任务。在接下来的实验中,我们让 x ∈ X x\in X xX 作为分类器的输入, y ∈ Y = { 1 , 2 , . . . , k } y \in Y=\{1,2,...,k\} yY={12,...k} 是一个类。我们还用函数f:X来表示分类器!R k,使得对于任何 x , 1 T f ( x ) ≥ 0 x,1^Tf(x)\geq 0 x,1Tf(x)0

  • 最大 Softmax 概率。考虑最大softmax 概率基线 ,它给出输入OOD得分maxc fc(x)。分布外样本取自各种未知分布(附录A)。对于每一个任务,我们测试的Dtest out分布的数量是大多数其他论文的两倍,我们还测试了NLP任务。OOD示例分数的质量用第4.1节中描述的度量标准来判断。对于这种多类设置,我们通过微调预训练分类器 f 来执行异常值暴露,使得其后验在样本上更加一致。具体来说,微调目标是 E ( x ; y ) ∞ D i n [ − l o g f y ( x ) ] + λ E x ∞ D O E o u t [ H ( U ; f ( x ) ) ] E_{(x;y)∞D_{in}}[-log f_y(x)]+λEx∞D_{OE} out[H(U;f(x))] E(xy)Din[logfy(x)]+λExDOEout[H(Uf(x))];其中H是交叉熵,U是k类上的均匀分布。当存在阶级不平衡时,我们可以鼓励f(x)匹配( P ( y = 1 ) ; . . . ; p ( y = k ) P(y = 1);...;p(y = k) P(y=1)...;p(y=k) );然而对于我们考虑的数据集,匹配 U 足够好。此外,请注意,使用运行经验从头开始进行训练甚至可以获得比微调更好的性能(附录C)。这种方法也适用于不同的架构(附录D)。

  • 我们没有为每个Dtest out分布调整超参数,因此Dtest out像真实世界异常一样保持未知。相反,λ 系数是在实验早期使用附录a中描述的验证分布确定的。特别是,我们使用 λ = 0.5 进行视觉实验,λ = 1.0进行NLP实验。像以前涉及网络微调的OOD检测方法一样,我们选择λ,以便对分类精度的影响可以忽略不计

  • 对于几乎所有的视觉实验,我们训练广泛的残差网络 ,然后用OE微调10个时期的网络副本。然而,我们对位置365使用预训练的 ResNet-18。对于NLP实验,我们训练2层 gru 5个时期,然后用OE微调网络副本2个时期。在CIFAR10或CIFAR-100上训练的网络暴露于来自8000万幅微小图像的图像,微小 ImageNet 和Places365 分类器暴露于ImageNet-22K。NLP分类器暴露于WikiText-2。更多架构和训练细节见附录b。对于所有任务,运行经验大幅提高了平均性能。平均结果如表1和表2所示。样本ROC曲线如图1和图4所示。附录a中的表7和表8列出了单个Dtest out数据集的详细结果。请注意,即使Dtest OE是一个自然图像数据集,带 OE的SVHN分类器也可用于检测表情符号和街景字母表字母等新异常。因此,暴露异常值有助于模型推广到比基线好得多的未知分布

    • 在这里插入图片描述

    • 表1: 最大 softmax 概率(MSP)基线检测器和MSP检测器在使用异常值曝光(OE)进行微调后的分布外图像检测。结果是百分比,也是10次运行的平均值。扩展结果见附录a。

    • 在这里插入图片描述

    • 表2: MSP基线和使用 OE 微调的自然语言分类器的MSP之间的比较。结果是10次运行的百分比和平均值。

  • Confidence Branch. 最近提出的一种OOD检测技术 涉及附加一个OOD评分分支b : X → [ 0 ; 1 ] X\rightarrow[0;1] X[0;1] 进入深层网络。该分支仅使用来自Din的样本进行训练,估计网络对任何输入的置信度。这项技术的创造者公开了他们的代码,所以我们使用他们的代码来训练新的40-4宽残差网络分类器。我们通过向网络的原始优化目标添加 0.5 E x ∞ D O E o u t [ l o g b ( x ) ] 0.5E_{x∞DOE out}[log b(x)] 0.5ExDOEout[logb(x)] 来微调具有离群点暴露的置信分支。在表3中,基线值来源于使用 【Learning confidence for out-of-distribution detection in neural networks】 公开可用的训练代码训练的分类器产生的最大softmax概率。置信分支对MSP检测器进行了改进,在运行经验之后,置信分支可以更有效地检测异常。

    • 在这里插入图片描述

    • 表3:最大softmax概率、置信分支和置信分支+ OE OOD检测器之间的比较。所有三个检测器使用相同的网络架构。所有结果都是百分比,是所有Dtest out数据集的平均值。

  • 合成异常值。离群值暴露利用了下载真实数据集的简单性,但是有可能生成合成的离群值。请注意,我们试图用噪声扭曲图像,并将其作为OE的异常值,但分类器很快记住了这一统计模式,并没有比以前更好地检测到新的OOD示例 。一种更成功的方法来自Lee等人 。他们小心地训练一个GAN,在分类器的决策边界附近生成合成实例。鼓励分类器在这些合成例子上具有低的最大 softmax 概率。对于CIFAR分类器,他们提到GAN可能是比 SVHN 等数据集更好的异常源。相比之下,我们发现从不同的数据集中提取异常的简单方法足以显著改善OOD检测

    • 在这里插入图片描述

    • 图1:带有微小图像网(Din)和纹理(Dtest out)的ROC曲线。

  • 我们使用Lee等人 【Training confidence-calibrated classifiers for detecting out-of-distribution samples】 的公开可用代码训练40-4宽的残差网络,并使用网络的最大softmax概率作为我们的基线。另一个分类器与GAN同时训练,使得分类器给GAN生成的例子分配高的OOD分数。我们希望每个测试都是新颖的。因此,我们使用他们代码的默认超参数,并且恰好一个模型遇到所有测试的Dtest out分布。这与他们的工作不同,因为对于每个Dtest out发行版,他们都要训练和调整一个新的网络。我们不对Tiny ImageNet、Places365和text进行评估,因为DCGANs无法稳定可靠地生成这样的图像和文本。最后,我们使用GAN串联训练的网络,并使用OE对其进行微调。表4显示了与使用来自GAN的合成样本相比,使用真实和多样化数据集的OE的巨大收益

    • 在这里插入图片描述

    • 表4:最大软最大概率(MSP)、MSP + GAN和MSP + GAN + OE OOD 检波器之间的比较。所有三个检测器使用相同的网络架构。所有结果都是百分比,是所有 D o u t t e s t D^{test} _{out} Douttest 数据集的平均值。

DENSITY ESTIMATION

  • 密度估计器学习数据分布 Din 上的概率密度函数。异常实例应具有低概率密度,因为根据定义,它们在Din中是稀缺的 。因此,密度估计是对异常进行评分的另一种方法 。我们展示了运行经验改善低概率、边远数据的密度估计的能力

    • 在这里插入图片描述

    • 图2:pixel CNN ++对来自CIFAR-10和SVHN的图像的OOD评分。

  • PixelCNN++。自回归神经密度估计器提供了一种参数化图像数据概率密度的方法。虽然这些架构的采样速度较慢,但它们允许通过CNN的单次前向传递来评估概率密度,这使它们成为有前途的OOD检测候选。我们使用 PixelCNN++ 作为基线OOD检测器,我们在CIFAR-10上训练它。示例 x 的OOD分数是每像素比特数(BPP),定义为nll(x)=num_pixels,其中nll是负对数似然。对于这种损失,我们使用运行经验对2个时期进行微调,我们发现这足以使训练损失收敛。这里,OE是通过分布内和异常示例之间的对数似然差异的裕量损失来实现的,因此来自Din的样本xin和来自DOE out的点xout的损失为

    • m a x { 0 ; n u m _ p i x e l s + n l l ( x i n ) − n l l ( x o u t ) } : max\{0; num\_pixels + nll(x_{in}) − nll(x_{out})\}: max{0;num_pixels+nll(xin)nll(xout)}:
  • 结果如表5所示。请注意,没有OE的PixelCNN++从SVHN图像分配的BPP意外地比CIFAR-10图像低。对于所有Dtest out数据集,OE显著改善了结果。

    • 在这里插入图片描述

    • 表5:使用PixelCNN++密度估算器和应用OE后的同一估算器的OOD检测结果。模型的每像素位数(BPP)对每个样本进行评分。所有结果都是百分比。测试分布Dtest out在附录a中描述。

  • 语言建模。我们接下来探索在语言模型上使用OE。我们使用 QRNN 作为基线OOD检测器的语言模型。对于OOD得分,我们使用每字符位数(BPC)或每字位数(BPW ),定义为 nll(x)=sequence_length,其中 nll(x) 是序列 x 的负对数似然性。异常值暴露是通过将交叉熵添加到DOE out中序列令牌的均匀分布中作为附加损失项来实现的

  • 对于Din,我们转换了Penn Treebank的语言建模版本,分为长度为70的序列用于单词级模型的反向传播,长度为150的序列用于字符级模型。我们不像在BPTT那样用保留的隐藏状态进行训练或评估。这是因为保留隐藏状态将大大简化OOD检测的任务。因此,OOD检测任务是为不可见的Dtest out数据集中的70或150个令牌序列提供一个分数。

  • 我们为300个时期训练单词级模型,为50个时期训练字符级模型。然后,我们在WikiText-2上使用OE进行了5个时期的微调。对于字符级语言模型,我们通过将单词转换成小写字母并省略 PTB 中没有出现的字符来创建字符级版本的 WikiText-2。单词级和字符级语言模型的OOD检测结果如表6所示;附录f中列出了扩展结果和Dtest out描述。在所有情况下,OE都比基线有所提高,单词级模型的提高尤为显著。

    • 在这里插入图片描述

    • 表6 Penn Treebank语言模型上的OOD检测结果。结果是Dtest out数据集的平均百分比。扩展结果见附录f。

DISCUSSION

  • 多标记分类器和拒绝选项的扩展。离群值暴露可以在更多的分类体系中起作用,而不仅仅是上面考虑的那些。例如,当使用最大预测概率作为OOD分数时,在CIFAR-10上训练的多标签分类器获得88.8%的平均AUROC。通过用OE训练来降低分类器对OOD样本的输出概率,平均AUROC增加到97.1%。这比用OE调优的多类模型的AUROC略低。另一种食品检测公式是给分类器一个“拒绝类” 。异常值暴露也足够灵活,可以在这种情况下提高性能,但我们发现,即使有OE,具有拒绝选项或多标签输出的分类器也不如具有多类输出的OOD检测器有竞争力

  • 选择DOE out的灵活性。在实验的早期,我们发现选择DOE out对于推广到看不见的Dtest out分布是很重要的。例如,向来自Din的样本添加高斯噪声以创建DOE out并没有教导网络推广到复杂Din的看不见的异常分布。类似地,我们在4.3节中发现,合成异常不如真实数据那样有效。相比之下,我们的实验表明,第4.2.2节中描述的真实异常的大型数据集确实推广到看不见的Dtest out分布。

  • 除了规模和真实性,我们发现DOE的多样性也是一个重要因素。具体地说,具有CIFAR-10的CIFAR-100分类器在基线上几乎没有改进。暴露于十个CIFAR-100异常类的CIFAR-10分类器对应于78.5%的平均AUPR。暴露于30个这样的类,分类器的平均AUPR变成85.1%。其次,50个类相当于85.3%,在此基础上增加CIFAR-100类几乎不会提高性能。这表明数据集的多样性很重要,而不仅仅是大小。事实上,本文中的实验经常使用8000万幅微小图像数据集中大约1%的图像,因为我们只是简单地微调了模型。我们还发现,仅使用该数据集中的50,000个样本,检测性能的下降可以忽略不计。此外,对具有显著不同统计数据的数据集进行分析可以类似地执行。例如,在SST实验中使用Gutenberg项目数据集代替WikiText-2进行DOE测试,得到的平均AUROC为90.1%,而不是89.3%。

  • 数据测试输出、数据测试输出和数据测试输入的接近程度。我们的实验显示了所涉及的数据集的紧密程度的几个有趣的影响。首先,我们发现Dtest out和DOE out不需要在使用OE进行训练时接近,以提高Dtest out的性能。在附录A中,我们观察到用于SVHN OOD检测器的性能随着异常值的暴露而提高,即使(1)测试出的样本是自然场景的图像而不是数字,以及(2)测试出的样本包括非自然的例子,例如表情符号。我们在MNIST的初步实验中观察到同样的情况;通过使用8000万张小图片,OE将AUPR从94.2%提高到97.0%。

  • 第二,我们发现输出测试与输入测试的接近程度是运行经验成功的一个重要因素。在NLP实验中,预处理DOE更接近Din显著提高了OOD检测性能。如果不进行预处理,网络可能会发现易于学习的线索,这些线索揭示了输入是符合分布还是不符合分布,因此运行经验训练目标可能会以意想不到的方式得到优化。这导致检测器较弱。在一个单独的实验中,我们使用在线硬示例挖掘,以便困难的异常值在异常值暴露中具有更大的权重。虽然这提高了最难异常的性能,但是没有合理的局部统计数据(如噪声)的异常的检测效率比以前稍低。因此,硬的或接近分布的例子不一定教导检测器所有有价值的用于检测各种形式的异常的启发法。运行经验的实际应用可以使用Sun等人的方法,将一个粗略的DOE输出辅助数据集改进为适当接近Dtest in。

  • OE Improves Calibration. 当使用分类器进行预测时,重要的是,为预测给出的置信度估计不会歪曲经验性能。经过校准的分类器给出了与正确性的经验频率相匹配的置信概率。也就是说,如果校准模型以 30% 的概率预测一个事件,那么该事件发生的概率为30%。

  • 现有的置信度校准方法考虑标准设置,其中测试时的数据总是从Din中提取。我们扩展了这个设置,以包括测试时Dtest out的例子,因为系统应该提供分布内和分布外样本的校准概率。分类器应该对这些OOD实例进行低置信度预测,因为它们没有类别。基于郭等人的温度调谐方法,我们证明了OE可以在这种现实环境中提高校准性能。汇总结果如图3所示。详细结果和指标描述见附录g。

    • 在这里插入图片描述

    • 图3:不同数据集在温度调节和温度调节+ OE下的均方根校准误差值。

CONCLUSION

  • 在本文中,我们提出了异常值暴露,这是一种简单的技术,可以在各种设置下增强许多当前的OOD检测器。它使用分布外样本来指导网络启发式检测新的、未建模的、分布外的样本。我们表明,这种方法广泛适用于视觉和自然语言设置,甚至是大规模的图像任务。OE可以改进模型校准和几种以前的异常检测技术。此外,运行经验可以教导密度估计模型,为非分布样本分配更合理的密度。最后,离群点暴露在计算上是廉价的,并且它可以以低开销应用于现有系统。总之,离群点暴露是增强分布外检测系统的有效补充方法

  • 异常数据暴露提升泛化性:通过训练时接触多样的异常数据,模型能学习到更鲁棒的 “内 - 外” 分布边界,而非依赖表面特征。合成异常(如高斯噪声)易被模型记忆,而真实异常(如 Tiny Images)包含更丰富的语义差异,提升对未知分布的泛化能力。OE 使模型对 OOD 样本输出低置信度,改善传统分类器过度自信的问题,尤其在安全关键场景中至关重要。

  • OE 通过简单而有效的数据增强策略,直击深度学习模型 “过度自信” 的核心缺陷,为开放世界中的可靠 AI 提供了实践路径。其核心价值在于利用外部数据的多样性,迫使模型学习更鲁棒的分布边界,而非依赖训练数据的局部模式。业界可借鉴其 “数据驱动的不确定性建模” 思路,在安全敏感场景中部署更可靠的分类系统,同时为后续研究提供了跨模态、动态优化等探索方向。

  • CIFAR 数据集上使用 Outlier Exposure 方法训练模型。

    • # 导入必要的库
      import numpy as np
      import os
      import pickle
      import argparse
      import time
      import torch
      import torch.nn as nn
      import torch.backends.cudnn as cudnn
      import torchvision.transforms as trn
      import torchvision.datasets as dset
      import torch.nn.functional as F
      from tqdm import tqdm
      from models.allconv import AllConvNet
      from models.wrn import WideResNet
      # 解析命令行参数
      parser = argparse.ArgumentParser(description='Trains a CIFAR Classifier with OE',
                                       formatter_class=argparse.ArgumentDefaultsHelpFormatter)
      parser.add_argument('dataset', type=str, choices=['cifar10', 'cifar100'],
                          help='Choose between CIFAR-10, CIFAR-100.')
      parser.add_argument('--model', '-m', type=str, default='allconv',
                          choices=['allconv', 'wrn'], help='Choose architecture.')
      parser.add_argument('--calibration', '-c', action='store_true',
                          help='Train a model to be used for calibration. This holds out some data for validation.')
      # 其他优化选项、检查点设置等参数...
      args = parser.parse_args()
      # 数据预处理
      mean = [x / 255 for x in [125.3, 123.0, 113.9]]
      std = [x / 255 for x in [63.0, 62.1, 66.7]]
      train_transform = trn.Compose([trn.RandomHorizontalFlip(), trn.RandomCrop(32, padding=4),
                                     trn.ToTensor(), trn.Normalize(mean, std)])
      test_transform = trn.Compose([trn.ToTensor(), trn.Normalize(mean, std)])
      # 加载数据集
      if args.dataset == 'cifar10':
          train_data_in = dset.CIFAR10('/share/data/vision-greg/cifarpy', train=True, transform=train_transform)
          test_data = dset.CIFAR10('/share/data/vision-greg/cifarpy', train=False, transform=test_transform)
          num_classes = 10
      else:
          train_data_in = dset.CIFAR100('/share/data/vision-greg/cifarpy', train=True, transform=train_transform)
          test_data = dset.CIFAR100('/share/data/vision-greg/cifarpy', train=False, transform=test_transform)
          num_classes = 100
      # 划分验证集(如果需要校准)
      calib_indicator = ''
      if args.calibration:
          train_data_in, val_data = validation_split(train_data_in, val_share=0.1)
          calib_indicator = '_calib'
      # 加载异常数据集
      ood_data = TinyImages(transform=trn.Compose(
          [trn.ToTensor(), trn.ToPILImage(), trn.RandomCrop(32, padding=4),
           trn.RandomHorizontalFlip(), trn.ToTensor(), trn.Normalize(mean, std)]))
      # 创建数据加载器
      train_loader_in = torch.utils.data.DataLoader(
          train_data_in,
          batch_size=args.batch_size, shuffle=True,
          num_workers=args.prefetch, pin_memory=True)
      train_loader_out = torch.utils.data.DataLoader(
          ood_data,
          batch_size=args.oe_batch_size, shuffle=False,
          num_workers=args.prefetch, pin_memory=True)
      test_loader = torch.utils.data.DataLoader(
          test_data,
          batch_size=args.batch_size, shuffle=False,
          num_workers=args.prefetch, pin_memory=True)
      # 创建模型
      if args.model == 'allconv':
          net = AllConvNet(num_classes)
      else:
          net = WideResNet(args.layers, num_classes, args.widen_factor, dropRate=args.droprate)
      # 恢复模型(如果需要)
      start_epoch = 0
      if args.load != '':
          for i in range(1000 - 1, -1, -1):
              model_name = os.path.join(args.load, args.dataset + calib_indicator + '_' + args.model +
                                        '_oe_scratch_epoch_' + str(i) + '.pt')
              if os.path.isfile(model_name):
                  net.load_state_dict(torch.load(model_name))
                  print('Model restored! Epoch:', i)
                  start_epoch = i + 1
                  break
          if start_epoch == 0:
              assert False, "could not resume"
      # 多 GPU 支持
      if args.ngpu > 1:
          net = torch.nn.DataParallel(net, device_ids=list(range(args.ngpu)))
      # 模型移到 GPU
      if args.ngpu > 0:
          net.cuda()
          torch.cuda.manual_seed(1)
      cudnn.benchmark = True  # 加速训练
      # 定义优化器和学习率调度器
      optimizer = torch.optim.SGD(
          net.parameters(), state['learning_rate'], momentum=state['momentum'],
          weight_decay=state['decay'], nesterov=True)
      def cosine_annealing(step, total_steps, lr_max, lr_min):
          return lr_min + (lr_max - lr_min) * 0.5 * (
                  1 + np.cos(step / total_steps * np.pi))
      scheduler = torch.optim.lr_scheduler.LambdaLR(
          optimizer,
          lr_lambda=lambda step: cosine_annealing(
              step,
              args.epochs * len(train_loader_in),
              1,  # since lr_lambda computes multiplicative factor
              1e-6 / args.learning_rate))
      # 训练函数
      def train():
          net.train()  # 进入训练模式
          loss_avg = 0.0
          # 随机选择异常数据集的起始点
          train_loader_out.dataset.offset = np.random.randint(len(train_loader_out.dataset))
          for in_set, out_set in zip(train_loader_in, train_loader_out):
              data = torch.cat((in_set[0], out_set[0]), 0)
              target = in_set[1]
              data, target = data.cuda(), target.cuda()
              # 前向传播
              x = net(data)
              # 反向传播
              scheduler.step()
              optimizer.zero_grad()
              # 计算损失
              loss = F.cross_entropy(x[:len(in_set[0])], target)
              # 交叉熵损失:从 softmax 分布到均匀分布
              loss += 0.5 * -(x[len(in_set[0]):].mean(1) - torch.logsumexp(x[len(in_set[0]):], dim=1)).mean()
              loss.backward()
              optimizer.step()
              # 指数移动平均更新损失
              loss_avg = loss_avg * 0.8 + float(loss) * 0.2
          state['train_loss'] = loss_avg
      # 测试函数
      def test():
          net.eval()
          loss_avg = 0.0
          correct = 0
          with torch.no_grad():
              for data, target in test_loader:
                  data, target = data.cuda(), target.cuda()
                  # 前向传播
                  output = net(data)
                  loss = F.cross_entropy(output, target)
                  # 计算准确率
                  pred = output.data.max(1)[1]
                  correct += pred.eq(target.data).sum().item()
                  # 计算测试损失
                  loss_avg += float(loss.data)
          state['test_loss'] = loss_avg / len(test_loader)
          state['test_accuracy'] = correct / len(test_loader.dataset)
      # 主训练循环
      if args.test:
          test()
          print(state)
          exit()
      # 创建保存目录
      if not os.path.exists(args.save):
          os.makedirs(args.save)
      if not os.path.isdir(args.save):
          raise Exception('%s is not a dir' % args.save)
      # 记录训练结果
      with open(os.path.join(args.save, args.dataset + calib_indicator + '_' + args.model +
                                        '_oe_scratch_training_results.csv'), 'w') as f:
          f.write('epoch,time(s),train_loss,test_loss,test_error(%)\n')
      print('Beginning Training\n')
      # 主循环
      for epoch in range(start_epoch, args.epochs):
          state['epoch'] = epoch
          begin_epoch = time.time()
          train()
          test()
          # 保存模型
          torch.save(net.state_dict(),
                     os.path.join(args.save, args.dataset + calib_indicator + '_' + args.model +
                                  '_oe_scratch_epoch_' + str(epoch) + '.pt'))
          # 删除前一个模型以节省空间
          prev_path = os.path.join(args.save, args.dataset + calib_indicator + '_' + args.model +
                                   '_oe_scratch_epoch_' + str(epoch - 1) + '.pt')
          if os.path.exists(prev_path): os.remove(prev_path)
          # 记录训练结果
          with open(os.path.join(args.save, args.dataset + calib_indicator + '_' + args.model +
                                            '_oe_scratch_training_results.csv'), 'a') as f:
              f.write('%03d,%05d,%0.6f,%0.5f,%0.2f\n' % (
                  (epoch + 1),
                  time.time() - begin_epoch,
                  state['train_loss'],
                  state['test_loss'],
                  100 - 100. * state['test_accuracy'],
              ))
          print('Epoch {0:3d} | Time {1:5d} | Train Loss {2:.4f} | Test Loss {3:.3f} | Test Error {4:.2f}'.format(
              (epoch + 1),
              int(time.time() - begin_epoch),
              state['train_loss'],
              state['test_loss'],
              100 - 100. * state['test_accuracy'])
          )
      
    • CIFAR 数据集进行预处理,包括随机裁剪、水平翻转和归一化。同时加载异常数据集(如 80 Million Tiny Images)。支持两种模型架构:AllConvNetWideResNet。在训练过程中,将正常数据集和异常数据集组合在一起进行训练。损失函数包括正常数据的交叉熵损失和异常数据的交叉熵损失(从 softmax 分布到均匀分布)。

  • 数据集加载:

    • import torchvision.datasets as dset
      if args.dataset == 'cifar10':
          train_data_in = dset.CIFAR10('/share/data/vision-greg/cifarpy', train=True, transform=train_transform)
          test_data = dset.CIFAR10('/share/data/vision-greg/cifarpy', train=False, transform=test_transform)
          num_classes = 10
      else:
          train_data_in = dset.CIFAR100('/share/data/vision-greg/cifarpy', train=True, transform=train_transform)
          test_data = dset.CIFAR100('/share/data/vision-greg/cifarpy', train=False, transform=test_transform)
          num_classes = 100
      calib_indicator = ''
      if args.calibration:
          train_data_in, val_data = validation_split(train_data_in, val_share=0.1)
          calib_indicator = '_calib'
      ood_data = TinyImages(transform=trn.Compose(
          [trn.ToTensor(), trn.ToPILImage(), trn.RandomCrop(32, padding=4),
           trn.RandomHorizontalFlip(), trn.ToTensor(), trn.Normalize(mean, std)]))
      
    • 使用 torch.utils.data.DataLoader 创建训练、异常和测试数据的加载器,方便批量处理数据。

    • train_loader_in = torch.utils.data.DataLoader(
          train_data_in,
          batch_size=args.batch_size, shuffle=True,
          num_workers=args.prefetch, pin_memory=True)
      train_loader_out = torch.utils.data.DataLoader(
          ood_data,
          batch_size=args.oe_batch_size, shuffle=False,
          num_workers=args.prefetch, pin_memory=True)
      test_loader = torch.utils.data.DataLoader(
          test_data,
          batch_size=args.batch_size, shuffle=False,
          num_workers=args.prefetch, pin_memory=True)
      
  • 模型定义:

    • if args.model == 'allconv':
          net = AllConvNet(num_classes)
      else:
          net = WideResNet(args.layers, num_classes, args.widen_factor, dropRate=args.droprate)
      model_found = False
      if args.load != '':
          for i in range(1000 - 1, -1, -1):
              model_name = os.path.join(args.load, args.dataset + calib_indicator + '_' + args.model +
                                        '_baseline_epoch_' + str(i) + '.pt')
              if os.path.isfile(model_name):
                  net.load_state_dict(torch.load(model_name))
                  print('Model restored! Epoch:', i)
                  model_found = True
                  break
          if not model_found:
              assert False, "could not find model to restore"
      
  • 优化器和学习率调度器,使用随机梯度下降(SGD)优化器,并使用余弦退火学习率调度器来调整学习率。

    • optimizer = torch.optim.SGD(
          net.parameters(), state['learning_rate'], momentum=state['momentum'],
          weight_decay=state['decay'], nesterov=True)
      def cosine_annealing(step, total_steps, lr_max, lr_min):
          return lr_min + (lr_max - lr_min) * 0.5 * ( 1 + np.cos(step / total_steps * np.pi))
      scheduler = torch.optim.lr_scheduler.LambdaLR(
          optimizer,
          lr_lambda=lambda step: cosine_annealing(
              step,
              args.epochs * len(train_loader_in),
              1,  # since lr_lambda computes multiplicative factor
              1e-6 / args.learning_rate))
      
  • 训练函数,训练函数将正常数据集和异常数据集组合在一起进行训练。损失函数包括正常数据的交叉熵损失和异常数据的交叉熵损失(从 softmax 分布到均匀分布)。

    • def train():
          net.train()  # enter train mode
          loss_avg = 0.0
          train_loader_out.dataset.offset = np.random.randint(len(train_loader_out.dataset))
          for in_set, out_set in zip(train_loader_in, train_loader_out):
              data = torch.cat((in_set[0], out_set[0]), 0)
              target = in_set[1]
              data, target = data.cuda(), target.cuda()
              # forward
              x = net(data)
              # backward
              scheduler.step()
              optimizer.zero_grad()
              loss = F.cross_entropy(x[:len(in_set[0])], target)
              # cross-entropy from softmax distribution to uniform distribution
              loss += 0.5 * -(x[len(in_set[0]):].mean(1) - torch.logsumexp(x[len(in_set[0]):], dim=1)).mean()
              loss.backward()
              optimizer.step()
              # exponential moving average
              loss_avg = loss_avg * 0.8 + float(loss) * 0.2
          state['train_loss'] = loss_avg
      
  • 测试函数,测试函数用于评估模型在测试集上的性能,计算损失和准确率。

    • def test():
          net.eval()
          loss_avg = 0.0
          correct = 0
          with torch.no_grad():
              for data, target in test_loader:
                  data, target = data.cuda(), target.cuda()
                  # forward
                  output = net(data)
                  loss = F.cross_entropy(output, target)
                  # accuracy
                  pred = output.data.max(1)[1]
                  correct += pred.eq(target.data).sum().item()
                  # test loss average
                  loss_avg += float(loss.data)
          state['test_loss'] = loss_avg / len(test_loader)
          state['test_accuracy'] = correct / len(test_loader.dataset)
      
  • 主训练循环迭代多个 epoch,调用训练和测试函数,并保存模型和训练结果。

    • if args.test:
          test()
          print(state)
          exit()
      if not os.path.exists(args.save):
          os.makedirs(args.save)
      if not os.path.isdir(args.save):
          raise Exception('%s is not a dir' % args.save)
      with open(os.path.join(args.save, args.dataset + calib_indicator + '_' + args.model +
                                        '_oe_tune_training_results.csv'), 'w') as f:
          f.write('epoch,time(s),train_loss,test_loss,test_error(%)\n')
      print('Beginning Training\n')
      for epoch in range(0, args.epochs):
          state['epoch'] = epoch
          begin_epoch = time.time()
          train()
          test()
          # Save model
          torch.save(net.state_dict(),os.path.join(args.save, args.dataset + calib_indicator + '_' + args.model +
                                  '_oe_tune_epoch_' + str(epoch) + '.pt'))
          # Let us not waste space and delete the previous model
          prev_path = os.path.join(args.save, args.dataset + calib_indicator + '_' + args.model +
                                   '_oe_tune_epoch_' + str(epoch - 1) + '.pt')
          if os.path.exists(prev_path): os.remove(prev_path)
          # Show results
          with open(os.path.join(args.save, args.dataset + calib_indicator + '_' + args.model +
                                            '_oe_tune_training_results.csv'), 'a') as f:
              f.write('%03d,%05d,%0.6f,%0.5f,%0.2f\n' % (
                  (epoch + 1),
                  time.time() - begin_epoch,
                  state['train_loss'],
                  state['test_loss'],
                  100 - 100. * state['test_accuracy'],
              ))
          print('Epoch {0:3d} | Time {1:5d} | Train Loss {2:.4f} | Test Loss {3:.3f} | Test Error {4:.2f}'.format(
              (epoch + 1),
              int(time.time() - begin_epoch),
              state['train_loss'],
              state['test_loss'],
              100 - 100. * state['test_accuracy'])
          )
      
  • Outlier Exposure (OE) 方法:在训练过程中引入异常数据集,通过最小化异常数据的交叉熵损失(从 softmax 分布到均匀分布),使模型对异常数据更加敏感,从而提高异常检测的性能。使用随机水平翻转和随机裁剪等数据增强技术,增加训练数据的多样性,提高模型的泛化能力。在训练过程中动态调整学习率,有助于模型更快地收敛到最优解。

  • 对模型的预测置信度进行校准,以提高模型预测的可靠性。具体来说,通过调整 softmax 温度参数,使得模型的预测置信度更加准确地反映其预测的准确性。可以对在 CIFAR-10 或 CIFAR-100 数据集上训练的模型进行评估,特别是在离群点检测任务上的性能。通过使用多种不同的 OOD 数据集,如高斯噪声、SVHN、Places365 等,来测试模型区分正常数据和异常数据的能力。

    • 使用验证集的 logits 和标签来计算最优的 softmax 温度参数 T,使得模型的预测置信度更加接近真实的准确率。

    • def get_net_results(data_loader, in_dist=False, t=1):
          logits = []
          confidence = []
          correct = []
          labels = []
          with torch.no_grad():
              for batch_idx, (data, target) in enumerate(data_loader):
                  if batch_idx >= ood_num_examples // args.test_bs and in_dist is False:
                      break
                  data, target = data.cuda(), target.cuda()
                  output = net(data)
                  logits.extend(to_np(output).squeeze())
                  if args.use_01:
                      confidence.extend(to_np(
                          (F.softmax(output/t, dim=1).max(1)[0] - 1./num_classes)/(1 - 1./num_classes)
                      ).squeeze().tolist())
                  else:
                      confidence.extend(to_np(F.softmax(output/t, dim=1).max(1)[0]).squeeze().tolist())
                  if in_dist:
                      pred = output.data.max(1)[1]
                      correct.extend(pred.eq(target).to('cpu').numpy().squeeze().tolist())
                      labels.extend(target.to('cpu').numpy().squeeze().tolist())
          if in_dist:
              return logits.copy(), confidence.copy(), correct.copy(), labels.copy()
          else:
              return logits[:ood_num_examples].copy(), confidence[:ood_num_examples].copy()
      val_logits, val_confidence, val_correct, val_labels = get_net_results(val_loader, in_dist=True)
      t_star = tune_temp(val_logits, val_labels)
      
    • 使用多种不同的 OOD 数据集,如高斯噪声、SVHN、Places365 等,来测试模型的 OOD 检测性能。通过计算不同 OOD 数据集的预测置信度,并与正常数据的预测置信度进行比较,来评估模型的 OOD 检测性能。

    • def get_and_print_results(ood_loader, num_to_avg=args.num_to_avg):
          rmss, mads, sf1s = [], [], []
          for _ in range(num_to_avg):
              out_logits, out_confidence = get_net_results(ood_loader, t=t_star)
              measures = get_measures(
                  concat([out_confidence, test_confidence]),
                  concat([np.zeros(len(out_confidence)), test_correct]))
              rmss.append(measures[0]); mads.append(measures[1]); sf1s.append(measures[2])
          rms = np.mean(rmss); mad = np.mean(mads); sf1 = np.mean(sf1s)
          rms_list.append(rms); mad_list.append(mad); sf1_list.append(sf1)
          if num_to_avg >= 5:
              print_measures_with_std(rmss, mads, sf1s, args.method_name)
          else:
              print_measures(rms, mad, sf1, args.method_name)
      
    • 通过温度校准和离群点检测技术,对在 CIFAR 数据集上训练的模型进行评估和校准,以提高模型的预测可靠性和 OOD 检测性能。通过计算最优的 softmax 温度参数和比较不同数据集的预测置信度,来评估模型的性能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

羞儿

写作是兴趣,打赏看心情

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

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

打赏作者

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

抵扣说明:

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

余额充值