Why ReLU networks yield high-confidence predictions far away from the training data and how to mitigate the problem

Abstract

  • 在野外使用的分类器,特别是用于安全关键系统的分类器,不仅应该具有良好的泛化特性,而且应该知道它们何时不知道,特别是远离训练数据进行低置信度预测。我们表明,产生分段线性分类器函数的ReLU型神经网络在这方面失败,因为它们几乎总是产生远离训练数据的高置信度预测。对于像图像这样的有界域,我们提出了一种类似于对抗训练的新的鲁棒优化技术,该技术远离训练数据实施低置信度预测。我们表明,与标准训练相比,这种技术在降低远离训练数据的预测的置信度方面令人惊讶地有效,同时在原始分类任务上保持高置信度预测和测试误差。

  • 论文地址:[1812.05720] Why ReLU networks yield high-confidence predictions far away from the training data and how to mitigate the problem

  • 这个工作指出 ReLU 网络在远离训练数据时会产生高置信度预测,这在安全关键系统中是不可取的。例如自动驾驶或医疗诊断,模型需要知道何时不确定。之前的研究提到过这个问题,但 ReLU 网络的结构导致了这个问题的必然性。我需要确认论文如何解释这一点,可能涉及 ReLU 的分段线性特性。ReLU 网络在安全关键领域(如自动驾驶、医疗诊断)的应用中,需满足两个核心要求:

    • 对训练数据分布外的输入(OOD)应保持低置信度预测;
    • 模型需明确 “何时不知”。
  • 提出了对抗置信增强训练(ACET),类似于对抗训练,但目标是降低远离训练数据的置信度。这里需要理解 ACET 的具体步骤,比如如何结合原始损失和对抗损失,以及使用的噪声分布。数学上,可能涉及优化问题,比如最大化最坏情况下的置信度损失。

  • ReLU 网络的分段线性性质,以及为什么这会导致高置信度。定理 3.1 和 3.2 可能是关键,解释了 ReLU 网络在无穷远处的行为,以及 RBF 网络的不同表现。ACET 的数学公式(如式 4 和式 5)需要详细解析,包括损失函数的设计和优化方法。通过理论证明(定理 3.1)指出,ReLU 网络的分段线性特性导致其在远离训练数据时必然产生高置信度预测。这一现象的根本原因在于 ReLU 网络的输出在无穷远处由线性区域主导,导致某一类的概率趋近于 1

  • ACET 将原始分类损失与对抗噪声损失结合。 ( L = 1 N ∑ L CE + λ E Z ∼ p out [ max ⁡ ∥ u − Z ∥ ∞ ≤ ϵ max ⁡ k log ⁡ e f k ( u ) ∑ e f j ( u ) ] ) (\mathcal{L} = \frac{1}{N}\sum \mathcal{L}_{\text{CE}} + \lambda \mathbb{E}_{Z \sim p_{\text{out}}} \left[ \max_{\|u-Z\|_{\infty} \leq \epsilon} \max_{k} \log \frac{e^{f_k(u)}}{\sum e^{f_j(u)}} \right]) (L=N1LCE+λEZpout[maxuZϵmaxklogefj(u)efk(u)])。其中,( p out p_{\text{out}} pout)为噪声分布(如均匀噪声或置换像素 + 高斯滤波),( ϵ \epsilon ϵ)控制扰动范围。使用投影梯度下降(PGD)生成对抗噪声,最大化最坏情况下的置信度损失,迫使模型在噪声邻域内输出低置信度。

  • ReLU 网络的输出可表示为:( f ( L + 1 ) ( x ) = V ( L + 1 ) x + a ( L + 1 ) f^{(L+1)}(x) = V^{(L+1)}x + a^{(L+1)} f(L+1)(x)=V(L+1)x+a(L+1))。其中,( V ( L + 1 ) ) 和 ( a ( L + 1 ) V^{(L+1)})和(a^{(L+1)} V(L+1))(a(L+1))由网络权重和激活状态决定。当输入沿某方向无限延伸时,( V ( L + 1 ) x V^{(L+1)}x V(L+1)x)主导输出,导致某一类的 logit 值趋近于无穷大(定理 3.1 证明)。通过最大化噪声点Z邻域内的最大置信度,ACET 迫使模型在 OOD 区域输出均匀分布:( max ⁡ ∥ u − Z ∥ ∞ ≤ ϵ max ⁡ k e f k ( u ) ∑ e f j ( u ) \max_{\|u-Z\|_{\infty} \leq \epsilon} \max_{k} \frac{e^{f_k(u)}}{\sum e^{f_j(u)}} maxuZϵmaxkefj(u)efk(u))。该优化通过 PGD 迭代求解,生成的对抗样本进一步降低模型对 OOD 数据的置信度

Introduction

  • 神经网络最近在几个应用领域如目标识别和语音识别中获得了最先进的性能。它们已经成为许多学习任务事实上的标准。尽管取得了巨大的成功和非常好的预测性能,但神经网络也有不尽如人意的地方。任何分类器自然期望的一个属性是,当它不知道或更直接地说:远离训练数据时,分类器不应该做出高置信度预测。这在自动驾驶或医疗诊断系统等安全关键应用中尤为重要,在这些应用中,这种输入要么会导致使用其他冗余传感器,要么会要求医生检查诊断结果。因此,它是分类器的一个重要属性,然而,尽管它似乎是任何分类器的最低要求,但却没有受到太多关注。

  • 已经报道了许多案例,其中通过神经网络在远离训练数据的情况下做出高置信度预测,例如,在fooling images 上,对于非分布图像 或在医学诊断任务中。此外,据观察,即使在最初的任务中,神经网络也经常产生过度自信的预测。一个相关但不同的问题是对立样本,其中输入的非常小的修改可以改变分类器决策。除了为神经网络提供鲁棒性保证的方法之外,这些方法仍然只为小型网络提供合理的保证,据我们所知,唯一没有被再次破坏的方法是使用鲁棒性优化技术的对抗训练。

  • 虽然已经提出了几种方法来使用 softmax 校准、集成技术 或 使用 dropout 的不确定性估计来调整对真实输入分布的过度自信预测,但是直到最近才解决了分布外输入的检测。现有的方法基本上或者通过温度重新标度使用softmax输出的调整技术,或者它们使用类似VAE或GAN的生成模型来模拟真实分布的边界输入,以便在训练过程中直接区分分布内和分布外输入。

  • 虽然所有这些方法都是获得更可靠分类器的重要步骤,但使用生成模型的方法最近受到了的挑战,这些方法报告了生成方法可以为它们应该建模的类之外的输入产生高度可信的密度估计。此外,请注意,对输入分布的置信度校准非常有用的模型不能用于分布外检测,正如在[Leveraging uncertainty information from deep neural networks for disease detection]中观察到的那样。另一种方法是在分类器中引入拒绝选项,以避免分类器不确定的决策。

  • 在本文中,我们将展示对于ReLU类,对于ReLU类网络,即具有全连接、卷积和残差层的网络,其中只有ReLU或泄漏ReLU被用作激活函数,卷积层被用作最大或平均池,基本上任何产生分段仿射分类器函数的神经网络,都可以产生远离训练数据的任意高置信度预测。这意味着对分类器的输出进行操作的技术不能将这些输入识别为分布外输入。

  • 相反,我们形式化了众所周知的事实,即RBF网络在远离训练数据的类上产生几乎一致的置信度,这表明存在满足在从未见过数据的区域中不置信度的最低要求的分类器。此外,我们提出了一种由对抗训练激发的鲁棒优化方案,该方案简单地对噪声图像实施统一的置信度预测,该噪声图像在构造上远离真实图像。我们表明,我们的技术不仅显著降低了对这种噪声图像的置信度,而且降低了对其他不相关的图像分类任务的置信度,在某些情况下,甚至降低了对为原始分类任务生成的对立样本的置信度。训练过程简单,不需要针对不同的分布外任务进行调整,具有与标准对抗训练相似的复杂度,并且在原始分类任务上实现相似的性能。

ReLU networks produce piecewise affine functions

  • 在本节中,我们快速回顾 ReLU 网络导致连续分段仿射分类器的事实,我们对其进行简要总结,以便为我们在第3节中的主要理论结果奠定基础。

  • 定义2.1。如果存在一个有限的多面体集 { Q r } r = 1 M \{Q_r\}^M _{r=1} {Qr}r=1M (称为f的线性区域),使得 ∪ r = 1 M Q r = R d ∪^M _{r=1}Q_r = \R^ d r=1MQr=Rd,且 f 是一个仿射函数,则称函数 f : R d → R f : \R ^d → \R f:RdR 为分段仿射函数。

  • 使用分段仿射激活函数(例如ReLU、leaky ReLU)并且在输出层中是线性的前馈神经网络可以被重写为连续分段仿射函数。这包括全连接、卷积、剩余层,甚至跳过连接,因为所有这些层都只是线性映射。此外,它还包括平均池和最大池。更准确地说,分类器是函数 f : R d → R K f : \R ^d → \R^ K f:RdRK ,其中K是类的数量,使得每个分量 f i : R d → R fi : \R^ d → \R fi:RdR 是连续的分段仿射激活函数,并且K个分量 ( f i ) i = 1 K (f_i) ^K _{i=1} (fi)i=1K 具有相同的线性区域集合。注意,线性区域数量的明确上限已经给出[On the number of linear regions of deep neural networks]。

  • 在下面我们遵循[A randomized gradient-free attack on relu networks]。为简单起见,我们只给出全连接层(注意卷积层是它们的特例)。用 σ : R → R , σ ( t ) = m a x { 0 , t } σ : \R → \R,σ(t) = max\{0,t\} σ:RRσ(t)=max{0t} ,the ReLU激活函数表示,用L + 1表示层数, W ( L ) ∈ R n l × n l − 1 W^{(L)}∈R^{n_l×n_{l- 1}} W(L)Rnl×nl1 b ( l ) ∈ R n l b ^{(l)} ∈ \R ^{nl} b(l)Rnl 分别是层L的权重和偏移向量,其中 l = 1 , . . . , L + 1 l = 1,...,L+ 1 l=1,...,L+1 n 0 = d n_0 = d n0=d。对于 x ∈ R d x ∈ \R^ d xRd,定义 g ( 0 ) ( x ) = x g ^{(0)}(x) = x g(0)(x)=x。然后可以递归地定义每层的预激活和后激活输出为

    • f ( k ) ( x ) = W ( k ) g ( k − 1 ) ( x ) + b ( k ) , a n d g ( k ) ( x ) = σ ( f ( k ) ( x ) ) , k = 1 , . . . , L , f ^{(k)} (x) = W^{(k)} g ^{(k−1)}(x) + b (k) , and \\ g ^{(k)} (x) = σ(f ^{(k)} (x)), k = 1, . . . , L, f(k)(x)=W(k)g(k1)(x)+b(k),andg(k)(x)=σ(f(k)(x)),k=1,...,L,
  • 因此得到的分类器为 f ( L + 1 ) ( x ) = W ( L + 1 ) g ( L ) ( x ) + b ( L + 1 ) f ^{(L+1)}(x) = W^{(L+1)}g ^{(L)} (x) + b ^{(L+1)} f(L+1)(x)=W(L+1)g(L)(x)+b(L+1)。设 ∆ ( l ) , ∑ ( l ) ∈ R n l × n l ∆^{(l)},\sum^{(l)}∈\R ^{nl×nl} (l)(l)Rnl×nl 对于l = 1,…,L是对角矩阵,按元素定义为

    • 在这里插入图片描述

    • 注意,对于 leaky ReLU ,条目将改为1和α。这允许将f (k) (x)写成仿射函数的合成,即

    • 在这里插入图片描述

  • 我们可以将前面的表达式进一步简化为 f ( k ) ( x ) = V ( k ) x + a ( k ) f ^{(k)} (x) = V ^{(k)}x + a ^{(k)} f(k)(x)=V(k)x+a(k),其中 V ( k ) ∈ R n k × d V ^{(k)} ∈ \R ^{nk×d} V(k)Rnk×d a ( k ) ∈ R n k a ^{(k)} ∈ \R ^{nk} a(k)Rnk 由下式给出

    • 在这里插入图片描述

    • polytope Q(x),包含x的线性区域,可以被表征为 N = ∑ l = 1 L n l N = \sum ^L_{l = 1}nl N=l=1Lnl 个半空间的交集,由下式给出

    • 在这里插入图片描述

    • 对于 l = 1 , . . . , L , i = 1 , . . . , n l l = 1,...,L,i = 1,...,n_l l=1...Li=1...nl,即

    • Q ( x ) = ∩ l = 1 , . . . , L ∩ i = 1 , . . . , n l Γ l , i . Q(x) =∩_{l=1,...,L} ∩_{i=1,...,nl} Γl,i. Q(x)=l=1,...,Li=1,...,nlΓl,i.

    • 注意,N也是网络的隐藏单元的数量。最后,我们可以写

    • f L + 1 ( z ) ∣ Q ( x ) = V L + 1 z + a ( L + 1 ) f^{L+1}(z)|_{Q(x)}=V^{L+1}z+a^{(L+1)} fL+1(z)Q(x)=VL+1z+a(L+1)

    • 这是 f 对Q(x)的仿射限制。

Why ReLU networks produce high confidence predictions far away from the training data

  • 通过第2节中 ReLU 型网络产生的分段线性分类器的明确描述,我们现在可以公式化我们的主要定理。它表明,只要网络上的一个非常温和的条件成立,对于任何 ϵ 大于0的情况,人们总是可以在(几乎)所有方向上找到一个远离训练数据的输入z,这实现了对某一类 z 的 1-ϵ 置信度。然而,在我们得出这个结果之前,我们首先提出了证明中所需的一个技术引理,该引理使用所有线性区域都是多面体,因此是凸集

  • 引理3.1。设 { Q i } l = 1 R \{Qi\}^R _{l=1} {Qi}l=1R 是与ReLU分类器 f : R d → R K f:\R^ d→\R^ K f:RdRK 相关的线性区域集。对于任何 x ∈ R d x∈\R ^d xRd,都存在α∈R,α>0,t∈{1,…,R},使得所有 β≥α 的 βx∈Qt。

  • 所有的证据都可以在附录中找到。使用引理3.1,我们现在可以陈述我们的第一个主要结果。

  • 定理3.1。设 R d = ∪ l = 1 R Q l , f ( x ) = V l x + a l \R ^d=∪^R _{l=1}Q_l,f(x)=V ^lx+a ^l Rd=l=1RQlfx=Vlx+al 是 Ql上 ReLU 网络输出的分段仿射表示。假设V l不包含所有l=1,R、 那么对于几乎任何x∈R d和>0,都存在一个α>0和一个类k∈{1,…,k},使得对于z=αx,它成立

    • 在这里插入图片描述
  • 请注意,对于一个区域,线性部分Vl不需要包含两行相同的条件非常弱。很难想象,对于一个正常训练的网络来说,这是真的,除非网络的输出无论如何都是恒定的。即使这是真的,它也只是使定理对位于该区域中的点的断言无效。如果不明确强制执行此条件,似乎不可能对所有可能延伸到无穷大的渐近区域都成立(见图1)。然而,在网络训练期间如何执行这一条件也是完全公开的。

    • 在这里插入图片描述

    • 图1:将 R 2 \R^ 2 R2 分解为两个隐藏层ReLU网络的有限多面体集。外多面体延伸到无穷大。这就是ReLU网络实现任意高置信度预测的地方。这张图片是用代码[Provable certificates for adversarial examples: Fitting a ball in the union of polytopes]制作的。

  • 结果表明,对于ReLU网络,存在无穷多个输入,实现网络的任意高置信度预测。很容易看出,如[Enhancing the reliability of out-of-distribution image detection in neural networks]中所使用的,对于温度T > 0,softmax的温度重新标度 e f k ( x ) / T ∑ l = 1 K e f l ( x ) / T \frac{e ^{fk(x)/T} }{\sum^K _{l=1} e ^{fl (x)/T}} l=1Kefl(x)/Tefk(x)/T 将不能检测这些情况,特别是因为方法的第一步是朝着增加置信度的方向进行。同样明显的是,在分类器中使用拒绝选项,也不会有助于检测这些情况。结果是负面的,因为看起来如果不修改ReLU网络的架构,就不可能防止这种现象。请注意,从贝叶斯决策理论的角度来看,softmax函数是交叉熵损失的正确传递函数,将分类器输出 fk(x) 转换为 x 处条件概率的估计值 P ( Y = k ∣ x , f ) = e f k ( x ) ∑ l = 1 K e f l ( x ) P(Y = k |x,f) = \frac{e ^{fk(x)} }{\sum^K _{l=1} e ^{fl (x)}} P(Y=kxf)=l=1Kefl(x)efk(x)

  • 虽然前面的结果似乎未知,但下面的结果至少在定性上是已知的[Explaining and harnessing adversarial examples],但我们找不到它的参考文献。与ReLU网络相比,径向基函数(RBF)网络具有在远离训练数据的情况下产生近似一致的置信度预测的特性。因此,存在满足我们在第1节中制定的最低要求的分类器。在下面的定理中,我们根据RBF分类器的参数和训练数据来明确量化“远”的含义。

  • 定理3.2。设 f k ( x ) = ∑ l = 1 N α k l e − γ ∣ ∣ x − x l ∣ ∣ 2 2 , k = 1 , . . . , K f_k(x)= \sum^N _{l = 1}α_{kl}e^{-γ||x- xl|| ^2 _2},k = 1,...,K fk(x)=l=1Nαkleγ∣∣xxl22k=1...K 是在训练数据 ( x i , y i ) i = 1 N (x_i,y_i) ^N _{i=1} (xiyi)i=1N 上用交叉熵损失训练的RBF网络。我们定义 r m i n = min ⁡ l = 1 , . . . , N ∣ ∣ x − x l ∣ ∣ 2 r_{min} = \min_{l=1,...,N} ||x-x_l ||^2 rmin=minl=1...N∣∣xxl2 α = m a x r , k ∑ l = 1 N ∣ α r l − α k l ∣ α = max _{r,k}\sum^N _{l = 1} |α_{rl}-α_{kl} | α=maxrkl=1Nαrlαkl。如果 ϵ > 0,

    • r 2 m i n ≥ 1 γ l o g ( α l o g ( 1 + K / ϵ ) ) , r ^2 min ≥\frac 1 γ log (\frac {α} {log(1 + K/ϵ)} ), r2minγ1log(log(1+K/ϵ)α),

    • 那么对于所有的k = 1,…,K,

    • 1 K − ϵ ≤ e f k ( x ) ∑ r = 1 K e f r ( x ) ≤ 1 K + ϵ . \frac1 K − ϵ ≤\frac {e ^{fk(x)} }{\sum^K _{r=1} e ^{fr(x)}} ≤\frac 1 K + ϵ . K1ϵr=1Kefr(x)efk(x)K1+ϵ.

  • 对于一类神经网络,我们认为实现与定理3.2相似的结果是一个非常重要的公开问题。请注意,只有当域无界时,才能获得ReLU网络的任意高置信度预测,例如R d。然而,图像包含在[0,1]d中,因此定理3.1不直接适用,即使该技术原则上可用于产生高置信度预测(见表2)。在下一节中,我们提出一种新的训练方案,对远离训练数据的输入实施低置信度预测

Adversarial Confidence Enhanced Training

  • 在这一节中,我们提出了一种简单的方法来调整远离训练数据的神经网络的置信度估计,而不必局限于定理3.1中研究的ReLU网络。定理3.1告诉我们,对于ReLU网络,softmax分数的后处理不足以避免远离训练数据的高置信度预测,相反,似乎有两种潜在的方法来解决该问题:a)使用额外的生成模型用于内分布或外分布,或者b)通过训练过程的适应直接修改网络,从而远离训练数据实施统一的置信度预测。由于最近指出了生成模型的问题,该模型将高置信度分配给来自外分布的样本[Do deep generative models know what they don’t know?],因此a)看起来不太有希望,我们探索方法b)。定义神经网络模型,包括抽象类BasicNNLeNetResNet等。

    • class BasicNN:
          def fc_layer(self, name, x, n_out, bn=False, last=False):
              """FullyConnected layer for final output."""
              with tf.variable_scope(name):
                  if len(x.shape) == 4:
                      n_in = int(x.shape[1]) * int(x.shape[2]) * int(x.shape[3])
                      x = tf.reshape(x, [-1, n_in])
                  else:
                      n_in = int(x.shape[1])
                  init = tf.random_normal_initializer(stddev=np.sqrt(2.0 / n_in))
                  w = tf.get_variable('weights', [n_in, n_out], initializer=init)
                  b = tf.get_variable('biases', [n_out], initializer=tf.constant_initializer(0.0))
      
                  x = tf.nn.xw_plus_b(x, w, b)
                  x = self.batch_norm(x) if bn else x
                  x = self.activation(x) if not last else x
              return x
      class CNN(BasicNN):
          def __init__(self, hps):
              super().__init__(hps)
          @staticmethod
          def _stride_arr(stride):
              """Map a stride scalar to the stride array for tf.nn.conv2d."""
              return [1, stride, stride, 1]
          def weight_variable(self, shape):
              """ Creates a weight variable of a given shape *for conv layer*
                  First `hps.n_random_layers` will be initialized randomly but not trained.
              """
              self.weights_layer += 1  # just for counting purposes
              n_in = int(shape[0]) * int(shape[1]) * int(shape[2])
              # Mainstream init
              init = tf.truncated_normal_initializer(stddev=np.sqrt(2.0 / n_in))
              weights = tf.get_variable('weights', shape, tf.float32, initializer=init, trainable=True)
              return weights
          def bias_variable(self, shape):
              """ Creates a bias variable of a given shape.
                  First `hps.n_random_layers` will be initialized randomly but not trained.
              """
              init = tf.constant_initializer(0.0)
              return tf.get_variable('biases', shape, initializer=init)
          @staticmethod
          def max_pool(x, size, stride):
              return tf.nn.max_pool(x, ksize=[1, size, size, 1], strides=[1, stride, stride, 1], padding='SAME')
          @staticmethod
          def avg_pool(x, size, stride):
              return tf.nn.avg_pool(x, ksize=[1, size, size, 1], strides=[1, stride, stride, 1], padding='SAME')
          def _conv(self, name, x, filter_size, in_filters, out_filters, stride, biases=False):
              """Convolution."""
              with tf.variable_scope(name):
                  kernel = self.weight_variable([filter_size, filter_size, in_filters, out_filters])
                  x = tf.nn.conv2d(x, kernel, [1, stride, stride, 1], padding='SAME')
                  if biases:
                      x += self.bias_variable([out_filters])
                  return x
          @staticmethod
          def _global_avg_pool(x):
              assert x.get_shape().ndims == 4
              return tf.reduce_mean(x, [1, 2])
          def conv_layer(self, name, x, size, n_out, stride, bn=False, biases=True):
              with tf.variable_scope(name):
                  n_in = x.shape[-1]
                  x = self._conv(name, x, size, n_in, n_out, stride, biases=biases)
                  x = self.batch_norm(x) if bn else x
                  x = self.activation(x)
              return x
      class ResNet(CNN):
          def __init__(self, hps):
              """ResNet constructor.
              ResNet model. Based on Ritchie Ng ResNet model: https://github.com/ritchieng/resnet-tensorflow
              Related papers:
              https://arxiv.org/pdf/1512.03385v1.pdf - main paper
              https://arxiv.org/pdf/1603.05027v2.pdf - Identity Mappings in Deep Residual Networks
              https://arxiv.org/pdf/1605.07146v1.pdf - wide residual networks
              Args:
                flag_train: tf.bool() which is True when we run the comp. graph for training, False for testing
              """
              super().__init__(hps)
              self.use_bottleneck = False
              if self.use_bottleneck:
                  self.res_func = self._bottleneck_residual
              else:
                  self.res_func = self._residual
          def _residual(self, x, in_filter, out_filter, stride, activate_before_residual=False):
              """Residual unit with 2 sub layers."""
              if activate_before_residual:
                  with tf.variable_scope('shared_activation'):
                      x = self.batch_norm(x)
                      x = self.activation(x)
                      orig_x = x
              else:
                  with tf.variable_scope('residual_only_activation'):
                      orig_x = x
                      x = self.batch_norm(x)
                      x = self.activation(x)
              with tf.variable_scope('sub1'):
                  x = self._conv('conv1', x, 3, in_filter, out_filter, stride)
              with tf.variable_scope('sub2'):
                  x = self.batch_norm(x)
                  x = self.activation(x)
                  x = self._conv('conv2', x, 3, out_filter, out_filter, 1)
              with tf.variable_scope('sub_add'):
                  if in_filter != out_filter:
                      orig_x = tf.nn.avg_pool(orig_x, self._stride_arr(stride), self._stride_arr(stride), 'VALID')
                      orig_x = tf.pad(orig_x, [[0, 0], [0, 0], [0, 0],
                                               [(out_filter - in_filter) // 2, (out_filter - in_filter) // 2]])
                  x += orig_x
              tf.logging.info('image after unit %s', x.get_shape())
              return x
          def _bottleneck_residual(self, x, in_filter, out_filter, stride,
                                   activate_before_residual=False):
              """Bottleneck resisual unit with 3 sub layers."""
              if activate_before_residual:
                  with tf.variable_scope('common_bn_relu'):
                      x = self.batch_norm(x)
                      x = self.activation(x)
                      orig_x = x
              else:
                  with tf.variable_scope('residual_bn_relu'):
                      orig_x = x
                      x = self.batch_norm(x)
                      x = self.activation(x)
      
              with tf.variable_scope('sub1'):
                  x = self._conv('conv1', x, 1, in_filter, out_filter / 4, stride)
              with tf.variable_scope('sub2'):
                  x = self.batch_norm(x)
                  x = self.activation(x)
                  x = self._conv('conv2', x, 3, out_filter / 4, out_filter / 4, [1, 1, 1, 1])
              with tf.variable_scope('sub3'):
                  x = self.batch_norm(x)
                  x = self.activation(x)
                  x = self._conv('conv3', x, 1, out_filter / 4, out_filter, [1, 1, 1, 1])
              with tf.variable_scope('sub_add'):
                  if in_filter != out_filter:
                      orig_x = self._conv('project', orig_x, 1, in_filter, out_filter, stride)
                  x += orig_x
              tf.logging.info('image after unit %s', x.get_shape())
              return x
      class ResNetSmall(ResNet):
          def __init__(self, hps):
              super().__init__(hps)
              self.n_filters = [16, 16, 32, 64]
              # self.n_filters = [2, 2, 4, 8]
              # self.n_filters = [64, 64, 128, 256]
          def get_logits(self, x, flag_train):
              self.flag_train = flag_train
              res_func = self.res_func
              strides = [1, 1, 2, 2]
              activate_before_residual = [True, False, False]
              n_resid_units = [0, 3, 3, 3]
              with tf.variable_scope('block_init'):
                  x = self._conv('conv', x, 3, int(x.shape[-1]), self.n_filters[0], strides[0])
              for i in range(1, len(n_resid_units)):
                  with tf.variable_scope('block_' + str(i) + '_0'):
                      x = res_func(x, self.n_filters[i - 1], self.n_filters[i], strides[i], activate_before_residual[0])
                  for j in range(1, n_resid_units[i]):
                      with tf.variable_scope('block_' + str(i) + '_' + str(j)):
                          x = res_func(x, self.n_filters[i], self.n_filters[i], 1, False)
              with tf.variable_scope('unit_last'):
                  x = self.batch_norm(x)
                  x = self.activation(x)
                  x = self._global_avg_pool(x)
              with tf.variable_scope('logit'):
                  f = self.fc_layer('fc', x, self.hps.n_classes, last=True)
              return f
      def he_init(shape):
          """ He init for conv or fc layers."""
          if len(shape) == 4:
              n_in, n_out = shape[0] * shape[1] * shape[2], shape[0] * shape[1] * shape[3]
          else:
              n_in, n_out = shape[0], shape[1]
          return tf.truncated_normal(shape, stddev=np.sqrt(2.0 / n_in))
      class LeNet(CNN):
          def __init__(self, hps):
              super().__init__(hps)
              self.strides = [1, 1]
              self.n_filters = [32, 64]
              self.n_fc = [1024]
          def get_logits(self, x, flag_train):
              """
              Build the core model within the graph.
                x: Batches of images. [batch_size, image_size, image_size, 3]
              """
              self.flag_train = flag_train
              bn = False
              x = self.conv_layer('conv1', x, 5, self.n_filters[0], self.strides[0], bn=bn, biases=not bn)
              x = self.max_pool(x, 2, 2)
              x = self.conv_layer('conv2', x, 5, self.n_filters[1], self.strides[1], bn=bn, biases=not bn)
              x = self.max_pool(x, 2, 2)
              x = self.fc_layer('fc1', x, self.n_fc[0])
              x = self.fc_layer('fc2', x, self.hps.n_classes, last=True)
              return x
      
    • 定义了全连接层,根据输入维度调整形状,初始化权重和偏置,进行矩阵乘法和加法运算,可选择是否使用批量归一化和激活函数。

  • ACET 训练:通过在训练过程中引入对抗样本和随机噪声,增强模型的鲁棒性,缓解 ReLU 网络在远离训练数据处的过自信问题。PGD 攻击:使用 L-infinity 范数的 PGD 攻击生成对抗样本,在训练和评估中使用,检验模型的鲁棒性。 train.py 文件中核心的训练与评估部分,使用 TensorFlow 构建的计算图来训练和评估神经网络模型。

    • with tf.Session(graph=graph, config=config) as sess:
          sess.run(tf.global_variables_initializer())  # run 'init' op
          metrics = []
          log.add('Session started with hyperparameters: {} \n'.format(hps_str))
          time_start = time.time()
          stats_names = ['err_rate', 'max_conf', 'loss', 'reg']  # for tensorboard
          ops_track = [err_rate, avg_conf, mean_loss_clean, mean_loss_out, mean_loss_total, mean_reg]
          ops_upd = [err_rate_upd, avg_conf_upd, mean_loss_clean_upd, mean_loss_out_upd, mean_loss_total_upd, mean_reg_upd]
          counter_summaries = 0
      
    • tf.Session(graph=graph, config=config):创建一个 TensorFlow 会话,使用之前定义的计算图 graph 和配置 configsess.run(tf.global_variables_initializer()):初始化所有全局变量。metrics:用于存储每个 epoch 的训练和测试指标。stats_names:定义用于 TensorBoard 显示的统计指标名称。ops_track:要跟踪的操作列表,包括错误率、平均置信度、各种损失和正则化项。ops_upd:用于更新跟踪指标的操作列表。

    • eval_stats = {}
      if epoch % 2 == 0 or epoch <= 5 or epoch == hps.n_epochs:
          # Evaluating different metrics once per epoch
          err_rate_train, avg_conf_train, mean_loss_clean_train, mean_loss_out_train, mean_loss_total_train, mean_reg_train = sess.run([err_rate, avg_conf, mean_loss_clean, mean_loss_out, mean_loss_total, mean_reg])
          # test - clean
          test_data_iter = dataset.get_test_batches(n_batches=n_batches, shuffle=False)
          feed_dict = {rub_flag_tf: False, adv_flag_tf: False, max_conf_flag_tf: False, at_frac_tf: 0.0, pgd_niter_tf: 0}
          err_rate_test, avg_conf_test, mean_loss_clean_test, mean_loss_out_test, mean_loss_total_test, mean_reg_test = utils_tf.eval_in_batches(
              x_in, y_in, ops_track, ops_upd, sess, test_data_iter, flag_train, init_metric_vars, feed_dict)
      
          # Store the main train/test summaries
          write_summary(train_writer, [err_rate_train, mean_loss_clean_train, mean_loss_out_train, mean_loss_total_train, mean_reg_train, avg_conf_train],
                           ['main/error', 'main/loss_clean', 'main/loss_out', 'main/loss_total', 'main/reg', 'main/avg_conf'],
                           epoch)
          write_summary(test_writer, [err_rate_test, mean_loss_clean_test, mean_loss_out_test, mean_loss_total_test, mean_reg_test, avg_conf_test],
                           ['main/error', 'main/loss_clean', 'main/loss_out', 'main/loss_total', 'main/reg', 'main/avg_conf'],
                           epoch)
          metrics.append([err_rate_train, mean_loss_clean_train, mean_loss_out_train, mean_loss_total_train, err_rate_test, mean_loss_clean_test, mean_loss_out_test, mean_loss_total_test])
      
    • if epoch % 2 == 0 or epoch <= 5 or epoch == hps.n_epochs:在特定的 epoch 进行评估。训练集评估:直接运行 sess.run 获取训练集的指标。测试集评估(干净数据):使用 utils_tf.eval_in_batches 函数对测试集进行评估,传递相应的操作和数据。write_summary:将训练和测试的指标写入 TensorBoard 日志。metrics.append:将当前 epoch 的训练和测试指标添加到 metrics 列表中。

    • # Evaluate only on 2 batches (256 examples) for all epochs, except the last (there full test set evaluation)
      n_adv_batches = 2 if epoch != hps.n_epochs else 'all'
      n_image_evals = 3 + len(rub_dataset_names)  # how many times we evaluate images
      # test - noise
      test_data_iter = dataset.get_test_batches(n_batches=5*n_adv_batches, shuffle=False)
      feed_dict = {rub_flag_tf: True, adv_flag_tf: False, max_conf_flag_tf: False, at_frac_tf: 1.0, pgd_niter_tf: 0}
      eval_stats['test_noise_plain'] = utils_tf.eval_in_batches(
          x_in, y_in, ops_track[:2], ops_upd[:2], sess, test_data_iter, flag_train, init_metric_vars, feed_dict)
      # test - noise + adv constant 80
      test_data_iter = dataset.get_test_batches(n_batches=5*n_adv_batches, shuffle=False)
      feed_dict = {rub_flag_tf: True, adv_flag_tf: True, max_conf_flag_tf: hps.loss=='max_conf', at_frac_tf: 1.0, pgd_niter_tf: 80}
      eval_stats['test_noise_adv_80'] = utils_tf.eval_in_batches(
          x_in, y_in, ops_track[:2], ops_upd[:2], sess, test_data_iter, flag_train, init_metric_vars, feed_dict)
      # test - noise + adv same as training
      test_data_iter = dataset.get_test_batches(n_batches=5*n_adv_batches, shuffle=False)
      feed_dict = {rub_flag_tf: True, adv_flag_tf: True, max_conf_flag_tf: hps.loss=='max_conf', at_frac_tf: 1.0, pgd_niter_tf: hps.pgd_niter}
      eval_stats['test_noise_adv_train'] = utils_tf.eval_in_batches(
          x_in, y_in, ops_track[:2], ops_upd[:2], sess, test_data_iter, flag_train, init_metric_vars, feed_dict)
      # test - adv
      test_data_iter = dataset.get_test_batches(n_batches=n_adv_batches, shuffle=False)
      feed_dict = {rub_flag_tf: False, adv_flag_tf: True, max_conf_flag_tf: False, at_frac_tf: 1.0, pgd_niter_tf: 40}
      eval_stats['test_adv'] = utils_tf.eval_in_batches(
          x_in, y_in, ops_track[:2], ops_upd[:2], sess, test_data_iter, flag_train, init_metric_vars, feed_dict)
      # test - other datasets
      tb_tabs = ['test_{}_plain'.format(rub_dataset_name) for rub_dataset_name in rub_dataset_names]
      for rub_dataset, rub_dataset_name, tb_tab in zip(rub_datasets, rub_dataset_names, tb_tabs):
          test_data_iter = rub_dataset.get_test_batches(n_batches=n_adv_batches, shuffle=False)
          feed_dict = {rub_flag_tf: False, adv_flag_tf: False, max_conf_flag_tf: False, at_frac_tf: 0.0, pgd_niter_tf: 0}
          eval_stats[tb_tab] = utils_tf.eval_in_batches(
              x_in, y_in, ops_track[:2], ops_upd[:2], sess, test_data_iter, flag_train, init_metric_vars,
              feed_dict)
      
    • 对不同测试场景进行评估,包括噪声数据、噪声 + 对抗数据(不同迭代次数)、对抗数据和其他数据集。每个测试场景都有不同的 feed_dict 配置,用于设置相应的标志和参数。使用 utils_tf.eval_in_batches 函数对每个测试场景进行评估,并将结果存储在 eval_stats 字典中。

  • 我们假设有可能表征输入空间上的数据点 pout 的分布,对于这些数据点,我们确信它们不属于真正的分布pin resp。它们的支撑相交的集合具有零或接近零的概率质量。这种外分布pout的一个例子是 [ 0 , 1 ] w × h [0,1]^{w×h} [01]w×h (w × h灰度图像)上的均匀分布或类似的噪声分布。假设内分布由像手写数字这样的某些图像类别组成,那么在pout下手写数字的所有图像的概率质量是零(如果它确实是低维流形)或接近零。在这种情况下,训练目标可以写成两个损失的和:

    • 1 N ∑ i = 1 N L C E ( y i , f ( x i ) ) + λ E [ L p o u t ( f , Z ) ] , ( 1 ) \frac 1 N\sum ^N _{i=1} L_{CE}(y_i , f(x_i)) + λ E[ Lp_{out} (f, Z) ], (1) N1i=1NLCE(yi,f(xi))+λE[Lpout(f,Z)],(1)

    • 其中 ( x i , y i ) i = 1 N (x_i,y_i)^N _{i=1} (xiyi)i=1N 是i.i.d .训练数据,Z具有分布pout和

    • 在这里插入图片描述

    • LCE是原始分类任务上通常的交叉熵损失,Lpout (f,z)是所有类别上的最大对数置信度,其中类别l的置信度由 e f l ( z ) ∑ k = 1 K e f k ( z ) \frac {e fl (z)} {\sum ^K _{k=1} e fk(z)} k=1Kefk(z)efl(z) 给出,其中softmax函数作为链接函数。通过对原始数据使用批次大小为B的SGD,并添加来自pout的dλBe样本,可以很容易地最小化全部损失,其中pout在标签上实施均匀分布。我们称这个过程为增强信心数据增强(CEDA)。我们注意到,在一篇同时发表的论文[Deep anomaly detection with outlier exposure]中提出了一个类似的方案,其中他们使用现有的大型图像数据集作为pout,而我们倾向于一种不可知的方法,其中pout对图像上的某个“噪声”分布进行建模

  • CEDA的问题是,它可能需要太多的样本来加强整个分布的低置信度。此外,在对抗操纵领域,数据扩充对于稳健模型来说是不够的,我们将在第5节中看到,实际上CEDA模型仍然在噪声图像的邻域中产生高置信度的预测。因此,我们建议使用类似于对抗训练的稳健优化的思想 来获得对抗对抗操作的稳健网络。因此,我们不仅在该点本身实施低置信度,而且主动最小化该点附近的最坏情况。这导致了以下对抗性增强信心训练(ACET)的公式

    • 1 N ∑ i = 1 N L C E ( y i , f ( x i ) ) + λ E [ m a x ∣ ∣ u − Z ∣ ∣ p ≤ ϵ L p o u t ( f , u ) ] , \frac 1 N\sum ^N _{i=1} LCE(y_i , f(x_i)) + λ E [max _{||u−Z||_p≤ϵ} L_{pout} (f, u) ] , N1i=1NLCE(yi,f(xi))+λE[max∣∣uZpϵLpout(f,u)],

    • 其中,在每个SGD步骤中,对于给定的z∞pout,求解(近似)优化问题:

    • m a x ∣ ∣ u − Z ∣ ∣ p ≤ ϵ L p o u t ( f , u ) max _{||u−Z||_p≤ϵ} L_{pout} (f, u) max∣∣uZpϵLpout(f,u)

  • 在本文中,我们总是使用p = ∞。注意,如果分布pout和pin具有联合支持,则(5)中的最大值可以在真实分布的支持点处获得。然而,如果pout是类似均匀噪声或其平滑版本的一般噪声分布,那么在pout下发生这种情况的数量具有接近于零的概率质量,因此不会负面影响(4)中真实分布上的损失LCE。(4)中ACET的优化可以使用[Towards deep learning models resistant to adversarial attacks]中PGD方法的改编版本进行对抗训练,其中执行投影梯度下降(可能需要重新启动几次),并使用u实现计算梯度的最坏损失。

  • 所得样本的信息量更大,因此可以更快、更显著地减少远离训练数据的高置信度预测。我们对所有数据集使用=0.3。我们在图2和图3中展示了MNIST和CIFAR-10的一些噪声图像,以及通过应用PGD求解而生成的对抗性修改u(5)。可以观察到,生成的图像没有类似于分布中图像的结构。

    • 在这里插入图片描述

    • 图2:顶行:我们基于均匀噪声响应生成的噪声图像。置换MNIST连同高斯滤波器和对比度重新调整。底行:对于上面的每个噪声图像,我们使用PGD生成相应的敌对噪声图像,其中40次迭代最大化了普通模型的ACET中的第二部分损失。注意,无论是在噪声图像中还是在对抗修改的图像中,都不存在类似于MNIST图像的结构。对于ACET和CEDA,很难为完全训练的模型生成对立的噪声图像,因此我们省略它们。

    • 在这里插入图片描述

    • 图3:顶行:我们基于均匀噪声响应生成的噪声图像。置换MNIST连同高斯滤波器和对比度重新调整(类似于图2)。底行:plain、CEDA和ACET模型的相应对比图像。噪声和敌对噪声图像都没有显示出与CIFAR-10图像的相似性。

Experiments

  • 在评估中,我们对一个数据集进行训练,并对其他分布外数据集和噪声图像的置信度进行评估。我们既不为每个测试数据集使用不同的参数集,也不在训练期间使用测试数据集之一。更准确地说,我们在MNIST、SVHN、CIFAR-10和CIFAR100上进行训练,其中我们在MNIST上使用取自[Towards deep learning models resistant to adversarial attacks]的LeNet架构,在其他数据集上使用ResNet架构。我们还使用标准数据扩充,包括针对所有数据集的随机裁剪以及针对CIFAR-10和CIFAR-100的随机镜像。对于从pout生成非分布图像,我们进行如下:一半的图像是通过随机置换来自训练集的图像像素而生成的,一半的图像是均匀随机生成的。然后,我们对这些图像应用具有标准偏差σ ∈ [1.0,2.5]的高斯滤波器作为低通滤波器,以在噪声中具有更多低频结构。由于高斯滤波器导致对比度降低,我们随后应用全局重新缩放,使得图像的最大范围再次在[0,1]中

  • 在 MNIST、SVHN、CIFAR-10 和 CIFAR-100 上进行了测试,比较了普通训练、CEDA 和 ACET 的效果。需要分析超参数的选择,比如 λ、ε、PGD 的迭代次数和步长,以及这些参数如何影响结果。例如,λ=1 意味着训练数据和噪声数据各占一半,ε=0.3 控制对抗扰动的范围。

  • 训练:我们正常训练每个模型(普通),使用增强信心数据增强(CEDA)和对抗性增强信心训练(ACET)。众所周知,仅体重下降就可以减少过度自信的预测。因此,我们对所有导致强基线(普通)的模型使用具有正则化参数5·10−4的权重衰减。对于CEDA(1)和ACET(4),我们使用λ=1,这意味着每批中50%的样本来自原始训练集,50%是噪声样本,如前所述。对于ACET,我们使用 p=∞ 和 ϵ=0.3,并使用 PGD 对所有数据集进行优化,使用40次迭代和0.0075的步长。所有模型都在MNIST上使用 ADAM 进行了100个 epoch 的训练,并在SVHN/CIFAR-10/CIFAR100上使用SGD+动量进行了训练。MNIST的初始学习率为10−3,SVHN/CIFAR-10为0.1,在总共100个迭代周期的第50、75和90个迭代周期中,初始学习率降低了10倍。该代码可在以下网址获得 GitHub - max-andr/relu_networks_overconfident: Why ReLU networks yield high-confidence predictions far away from the training data and how to mitigate the problem CVPR 2019, oral]

  • 评估:我们在测试集上报告了每个模型(普通、CEDA、ACET)的测试误差和平均最大置信度(对于每个点,最大置信度为 m a x k = 1 , … , K e f k ( x ) ∑ l = 1 K e f l ( x ) max_{k=1,…,K} \frac {e fk(x)}{\sum ^K_{l=1} {e fl(x)}} maxk=1Kl=1Keflxefkx) ,表示为MMC。为了评估我们降低外分布置信度的程度,我们在CIFAR-10 和 SVHN 上使用了四个数据集(即CIFAR-10、CIFAR100、SVHN、ImageNet-,这是ImageNet的一个子集,我们删除了与CIFAR-10类似的类,LSUN的 class 子集我们使用了我们没有训练过的类),对于MNIST,我们在 EMNIST 上进行了评估,EMNIST 是 CIFAR10 和 Fashion MNIST 的灰度版本。此外,我们还展示了对噪声、对抗噪声和对抗样本的评估。噪声的产生方式与我们用于训练的噪声相同。

  • 对于对抗性噪声,我们在所有类别上最大化最大置信度(见(3)中的Lpout(f,z)),我们使用200次迭代和步长为0.0075的PGD,在球中使用||·||∞范数,ϵ=0.3(与训练中相同)。请注意,对于训练,我们只使用40次迭代,因此测试时的攻击明显更强。最后,我们还使用80次PGD迭代来检查分布内数据集测试集计算的对抗样本的置信度,MNIST的PGD迭代次数为0.3,步长为0.0075,其他数据集的PGD为0.1,步长为0.0025。后两种评估方式是新颖的。对抗性噪声很有趣,因为它主动搜索在噪声图像附近仍然具有高置信度的图像,因此比单纯的噪声评估更具挑战性。此外,它可能会检测到对训练期间使用的噪声模型的过度适应,特别是在CEDA中。

  • 对抗样本的评估很有趣,因为人们可以希望,分布外图像的置信度降低也会降低对抗样本的置信度,因为通常对抗样本不在数据流形上,因此也是分布外样本(即使它们与真实分布的距离很小)。请注意,我们的模型在训练过程中从未见过对抗性样本,它们只是使用对抗性噪声进行训练的。然而,我们的ACET模型可能会降低对抗样本的置信度。作为评估标准,我们使用平均最大置信度、ROC曲线下面积(AUC)作为检测问题的阈值(内分布与外分布)。此外,我们在相同的设置中报告了当真阳性率(TPR)固定为95%时的假阳性率(FPR)。所有结果见表1。

    • 在这里插入图片描述

    • 表1:在四个数据集MNIST、SVHN、CIFAR-10和CIFAR-100上,我们训练了三个模型:Plain、CEDA和ACET。我们在分布外样本(其他图像数据集、噪声、对抗性噪声和从训练的测试集构建的对抗性样本)上对它们进行评估。我们报告了所有模型的测试误差,并显示了输入和输出分布样本的平均最大置信度(MMC)(输出分布样本越低越好),基于置信度值区分输入和输出分配的ROC曲线的AUROC(AUROC)(越高越好),以及同一问题在95%真阳性率下的FPR(越小越好)。

  • 主要结果:在表1中,我们显示了 plain (正常训练),CEDA和ACET的结果。首先,我们观察到三种方法的测试误差几乎没有区别。因此,提高远离训练数据的置信度不会损害泛化性能。我们还看到,简单模型总是在噪声图像上产生相对高的置信度预测,而在敌对噪声上完全失败。CEDA在噪声图像上产生低置信度,但是在敌对噪声上几乎失败(除了MNIST ),这是可以预料的,因为在敌对样本的创建上已经有了类似的发现。只有ACET始终对敌对噪声产生低置信度预测,并具有高AUROC。对于分布外数据集,CEDA和ACET在大多数情况下提高了最大置信度和AUROC,有时提高非常明显,如在FMNIST上评估的MNIST或在LSUN上评估的SVHN。然而,我们观察到降低相关任务的置信度更加困难,例如在EMNIST上评估的MNIST或在LSUN上评估的CIFAR-10,其中图像结构更加相似。

  • 最后,一个有趣的结果是,ACET降低了对立示例的置信度,参见图4中MNIST的说明,并在所有数据集上实现了改进的AUROC值,因此与 plain 和 CEDA 模型相比,通过设定置信度阈值,可以检测到更多的对立示例。ACET的改进性能在某种程度上是出乎意料的,因为我们只是在远离训练数据的所有类别上使模型偏向一致的置信度,但是对立的例子仍然接近原始图像。总之,与普通模型相比以及与CEDA相比,ACET确实显著提高了置信度估计,特别是在对立噪声和对立例子上。ACET对对立的例子也有有益的影响,这是一个有趣的副作用,在我们看来,模型变得更加可靠

  • 远离高置信度预测:定理3.1陈述了 ReLU 网络总是在远离训练数据的地方获得高置信度预测。本文中使用的两种网络体系结构是ReLU网络。因此,调查增强信心的训练(ACET)是否比简单模型更难达到高信心是很有趣的。我们进行以下实验:我们获取均匀随机噪声图像x,然后搜索最小的α,使得分类器对αx达到99.9%的置信度。这正是从定理3.1构造的,结果可以在表2中找到。我们观察到,实际上ACET所需的放大因子α明显高于普通模型,这意味着我们的方法也影响远离训练数据的网络。这也表明,即使训练方法明确地旨在抵消远离训练数据的高置信度预测的现象,也不能防止这种情况。我们还在附录中讨论了一个类似的实验,但把它投影到[0,1]d。

Conclusion

  • 我们在本文中已经表明,即使进行了温度重新标度等修改,也无法避免远离训练数据的ReLU网络的任意高置信度预测问题。这是神经网络结构的固有问题,因此只能通过改变结构来解决。另一方面,我们已经表明,CEDA,特别是ACET是一个很好的方式来达到更好的图像数据的信心估计。CEDA和ACET可以直接用于任何模型,实现开销很小。对于未来,希望有这样的网络体系结构,其具有可证明的属性,即远离训练数据,置信度在类上是一致的:当网络不知道时,它知道。

  • 现有方法的局限性后处理方法(如温度缩放、集成学习)无法解决 ReLU 网络的结构性缺陷;生成模型(如 VAE、GAN)可能对 OOD 数据分配高置信度;对抗训练虽增强鲁棒性,但未直接针对置信度校准。

  • ReLU 网络的分段线性特性:ReLU 网络的输出函数是分段线性的,每个线性区域由隐藏单元的激活状态决定(定义 2.1)。当输入远离训练数据时,线性区域的扩张导致某一类的 logit 值显著超过其他类,从而产生高置信度预测(定理 3.1)。

  • RBF 网络的对比:与 ReLU 不同,RBF 网络在远离训练数据时输出均匀置信度(定理 3.2),表明存在满足不确定性感知的模型结构。

  • ReLU 网络的高置信度问题源于其分段线性结构,后处理方法无法根治;ACET 通过对抗噪声优化,为 OOD 置信度校准提供了普适框架,无需特定任务适配。

Logo

脑启社区是一个专注类脑智能领域的开发者社区。欢迎加入社区,共建类脑智能生态。社区为开发者提供了丰富的开源类脑工具软件、类脑算法模型及数据集、类脑知识库、类脑技术培训课程以及类脑应用案例等资源。

更多推荐