跳转至

8 Visualizing and Understanding

文本统计:约 4251 个字

现在卷积神经网络对我们来说就像一个小黑屋,扔进去输入,出来的是输出,中间的过程我们完全不了解,这一讲的内容就尝试去理解和可视化卷积神经网络中间到底发生了什么?

我们可以将训练之后每一层的卷积核拿出来可视化

对于第一层的可视化结果还能看出个大概,但是后面几层的内容就有些难以理解了。

而对于最后一层特征,可以说是高度总结的特征。回顾一下这门课开始几节所讲的 KNN (Nearest neighbors in pixel space) 是在像素层面做的最近邻操作。我们现在对最后一层做相应的操作,得到的结果还不错。说明我们的最后一层确实提取了一些信息

对最后一层的向量进行降维得到的结果更加清晰

降维的方法有 PCA(simple), t-SNE(complex)


Visualizing Activations

对中间层的可视化,展示神经网络在处理输入数据时各个神经元的响应情况。

我们输入一张图,可以看到在 conv3 层的某一个 channel 上提取到了类似人脸的信息。

Maximally Activating Patches

我们还可以寻找能够最大程度激活特定神经元或通道的图像区域,以帮助我们理解每个神经元或通道对输入图像中的哪些特征最为敏感。

右图中每一行都代表了一个神经元在不同的图中所着重观察的地方,具体的方法大致如下

  1. 选择目标层和通道:确定要分析的卷积层和通道,例如 conv5 的第 17 个通道。
  2. 输入大量图像:将许多不同的图像输入到网络中,计算每个图像在选定通道上的激活值。
  3. 记录和排序激活值:记录所有图像在该通道上的激活值,并按降序排列。
  4. 提取最大激活的图像:找出激活值最大的那些图像区域,并将它们可视化出来。
  5. 分析和解释结果:观察这些补丁的共同特征和模式,理解该通道对哪些特征最为敏感。

Occlusion Experiments

通过在输入图像上进行局部遮挡,并观察网络预测结果的变化,来确定网络对图像中哪些区域最为敏感。

遮挡部分图像

  • 选择遮挡区域:将输入图像分成多个小块(patch),每次只遮挡其中一个小块。
  • 生成遮挡图像:用灰色或其他颜色填充选定的小块,生成一个新的遮挡图像。
  • 输入到 CNN:将遮挡图像输入到 CNN 中,得到网络的预测结果(如分类概率)。

绘制热力图

  • 记录预测概率:对于每个遮挡位置,记录下网络输出的预测概率。
  • 绘制热力图:根据遮挡位置和对应的预测概率,绘制出一个热力图(heatmap)。热力图中的颜色表示了该位置对网络预测结果的影响程度:
  • 红色表示遮挡该区域时,网络的预测概率显著下降,说明该区域对网络的决策非常重要。
  • 蓝色表示遮挡该区域时,网络的预测概率变化不大,说明该区域对网络的决策影响较小。

Saliency Maps

我们也可以针对到像素层面,比如说对于一个狗的图像,图像中每个像素是怎么影响到狗这个分类标签的?讲每个像素对于这个分数的梯度用灰度图展示出来,就可以得到 Saliency Maps,从而清晰地展示我们的神经网络到底关注了哪些地方

利用 Saliency Maps 我们也可以进行一个无监督的物体分割的操作(结合 GrabCut 算法)

Intermediate Features via (guided) backprop

与上述 Saliency Maps 的思想类似,我们不仅可以看原始图像对于每一类分数的影响,也可以看其对中间神经元的影响。选择某层特征图的某个值求原图的梯度。

对于之前得到的 Maximally Activating Patches,我们可以利用这个方法得到这个神经元到底在关注哪些地方。

ReLU trick

Visualizing CNN features: Gradient Ascent

给定一个神经网络和一个特定的神经元,我们的目标是找到一个图像 I∗I∗,使得该神经元的激活值最大化。这可以通过以下优化问题来表示:

\[ I^* = \arg \max_I f(I) + R(I) \]

其中:

  • \(f(I)\) 表示神经元对图像 \(I\) 的响应值(即神经元的激活值)。
  • \(R(I)\) 是一个正则化项,用于确保生成的图像看起来像自然图像,而不是随机噪声。

大致的基本流程如下所示:

得到的图就像下图所示的那样

Some Regularizer

Better regularizer: Penalize L2 norm of image; also during optimization periodically

(1) Gaussian blur image

(2) Clip pixels with small values to 0

(3) Clip pixels with small gradients to 0

我们也可以对中间神经元的一些特征做相同的事情

为了获得更好的结果,采用 “multi-faceted” 的方法可以得到更好的结果。我们将图片初始化为同一标签下的不同类型图片(如 “杂货店“ 标签下可以有不同视觉的图)然后在这些图片下做梯度上升,让不同类型的图片都获得较好地结果。

Fooling Images / Adversarial Examples

我们可以通过下述方式得到对抗网络的图片

(1) Start from an arbitrary image

(2) Pick an arbitrary class

(3) Modify the image to maximize the class

(4) Repeat until network is fooled

Question

这里我们看到两者的图片并没有显著的差异,但是标签却发生了变化。这是为什么呢?

这种现象的发生主要是由于深度神经网络在高维空间中的复杂性和脆弱性。具体来说:

  1. 高维空间的稀疏性:在高维空间中,数据点之间往往相距甚远,这使得模型在某些区域的决策边界变得非常敏感。即使是很小的扰动,也可能导致输入数据跨越决策边界,从而改变模型的预测结果。
  2. 梯度方向的利用:攻击者可以通过计算损失函数关于输入图像的梯度,找到使模型预测错误的方向,并沿着该方向添加微小扰动。这种方法被称为快速梯度符号方法(Fast Gradient Sign Method, FGSM),正是由Ian Goodfellow等人提出的。

为了提高模型对对抗样本的鲁棒性,研究人员提出了多种防御策略,包括对抗训练:在训练过程中加入对抗样本,使模型能够学习到更加鲁棒的特征表示。这在后面讲解生成模型时会详细阐述

DeepDream: Amplify existing features

DeepDream 是一种用于可视化和增强图像中已存在的特征的技术,它通过放大神经网络某一层的神经元激活来实现。

具体步骤如下:

  1. 选择图像和层

首先,你需要选择一个输入图像和卷积神经网络(CNN)中的某一层作为目标层。这个目标层通常是一个中间层,因为它包含了丰富的特征表示。

  1. 前向传播:计算选定层的激活值

将输入图像前向传递到 CNN 中,计算目标层上每个神经元的激活值。这一步骤可以理解为让网络“看到”这张图像,并记录下它在目标层上的反应。

  1. 设置梯度等于激活值

接下来,将目标层的梯度设置为其自身的激活值。这意味着我们希望在反向传播过程中,能够增强那些已经在目标层上被激活的特征。

为什么要这样做?

因为实际上我们希望得到的是

\[ I^* = \arg\max_I \sum_i f_i(I)^2 \]

目标函数是 \(L = \sum_i f_i(I)^2\)

相应的梯度是

\[ \nabla_I L = 2 \sum_i f_i(I) \cdot \nabla_I f_i(I) \]

也就是说我们把上游梯度设置为相应的激活值即可

  1. 反向传播:计算图像上的梯度

进行反向传播,计算输入图像上的梯度。这一步骤会告诉我们如何修改输入图像,才能进一步增强目标层上的神经元激活。

  1. 更新图像

根据计算得到的梯度更新输入图像。通常,我们会使用梯度上升的方法,即沿着梯度的方向调整像素值,以增加目标层的激活值。

这样我们得到的图像就非常的梦幻(虽然我觉得有点恶心

Feature Inversion

Given a CNN feature vector for an image, find a new image that:

  • Matches the given feature vector

  • “looks natural” (image prior regularization)

Reconstructing from different layers of VGG-16 从 VGG-16 网络中的不同层重建图片

我们可以发现不同层保留的信息是不同的,重构的效果也有很大差异

  • relu2_2:这一层较浅,因此重构出的图像保留了较多的低级特征,如边缘和纹理。可以看到,大象和水果的基本形状和颜色都被较好地保留下来。
  • relu3_3:随着网络深度增加,这一层开始捕捉更复杂的特征。重构图像仍然保持了物体的大致轮廓和颜色,但细节有所丢失,背景变得模糊。
  • relu4_3:这一层进一步深入,重构图像开始出现一些抽象化的效果。虽然物体的轮廓依然存在,但细节变得更加简化,背景也更加不清晰。
  • relu5_1relu5_3:这两层位于网络的深层,主要捕捉高级语义特征。重构图像已经变得相当抽象,物体的轮廓和颜色都发生了显著变化,甚至出现了色彩斑斓的视觉效果。这表明深层特征更多关注于整体结构和类别信息,而非具体的细节。

Texture Synthesis

如何将一部分纹理进行扩充?这是一个图形学上的问题

有一些传统的图形学方法,比如最近邻算法(可以参考19. 纹理合成再谈 - 一种非参数的方法 - 知乎

利用 CNN,我们也可以解决这个问题

Gram Matrix

Each layer of CNN gives \(C \times H \times W\) tensor of features; H x W grid of C-dimensional vectors

Outer product of two C-dimensional vectors gives \(C \times C\) matrix measuring co-occurrence

Average over all HW pairs of vectors, giving Gram matrix of shape \(C \times C\)

Efficient to compute; reshape features from \(C \times H \times W\) to =\(C \times HW\)。then compute \(G = FF^T\)【自行矩阵推导一下即可】

  1. 预训练一个CNN(VGG-19) 首先,使用ImageNet数据集预训练一个VGG-19模型。这个预训练模型将作为特征提取器,用于捕捉输入图像的高级特征。

  2. 将输入纹理前向传播通过CNN 将目标纹理图像输入到预训练的VGG-19网络中,记录每一层的激活值(即特征图)。假设第i层的特征图形状为 \(C_i \times H_i \times W_i\),其中 \(C_i\) 表示通道数,\(H_i\)\(W_i\) 分别表示特征图的高度和宽度。

  3. 在每一层计算Gram矩阵 对于每一层的特征图,计算其Gram矩阵,该矩阵描述了不同特征通道之间的相关性。具体计算公式如下:

\[ G_{ij}^l = \sum_k F_{ik}^l F_{jk}^l \]

其中,\(F_{ik}^l\)\(F_{jk}^l\) 分别表示第 \(l\) 层特征图在位置 \(k\) 处的第 \(i\) 个和第 \(j\) 个通道的值。Gram矩阵的形状为 \(C_i \times C_i\)

  1. 使用随机噪声初始化生成图像 为了生成新的纹理图像,从随机噪声开始初始化一张与目标纹理图像大小相同的图像。

  2. 将生成图像通过CNN 将初始化的生成图像输入到VGG-19网络中,计算每一层的特征图,并进一步计算对应的Gram矩阵。

  3. 计算损失:加权L2距离 定义损失函数为生成图像和目标纹理图像在各层Gram矩阵之间的加权L2距离之和:

\[ E_l = \frac{1}{4N_i^2M_i^2}\sum_{i,j}(G_{ij}^l - \hat{G}_{ij}^l)^2 \]
\[ \mathcal{L}(\vec{x}, \hat{\vec{x}}) = \sum_{l=0}^{L} w_lE_l \]

其中,\(G_{ij}^l\)\(\hat{G}_{ij}^l\) 分别表示生成图像和目标纹理图像在第 \(l\) 层的Gram矩阵元素,\(w_l\) 是权重系数。

  1. 反向传播以获取图像梯度 根据损失函数对生成图像进行反向传播,计算损失关于生成图像的梯度。

  2. 对图像进行梯度下降更新 利用计算得到的梯度,通过梯度下降法更新生成图像的像素值,使其逐步接近目标纹理图像的特征。

  3. 跳转至步骤5 重复步骤5至8,直到生成图像的特征与目标纹理图像的特征足够接近,或者达到预定的迭代次数。

Neural Style Transfer

原始的图片加上一张有风格的画,实现风格的转移。基本的思路从 Style Image 中取每一层的Gram矩阵来表示风格特征。从 Content Image 中只取一个深层的特征向量来表示内容特征。

Question

为什么 Style Target 需要每一层的 Gram 矩阵?

原因一:多尺度风格信息

  • 不同层捕获不同尺度的信息:浅层网络(如relu1_2)主要捕捉低级特征(如边缘和局部纹理),而深层网络(如relu4_3)则捕捉更高级的语义信息(如整体结构和布局)。为了全面地表示风格特征,需要从多个层次提取信息。
  • 全局和局部风格:通过结合不同层的Gram矩阵,可以同时考虑全局风格(如整体色调和构图)和局部风格(如细节纹理和笔触)。

原因二:Gram 矩阵描述特征相关性

  • 特征通道之间的关系:Gram矩阵计算的是特征图中不同通道之间的外积,能够反映特征通道之间的相关性和相互作用。这种相关性对于捕捉风格特征非常重要,因为它描述了图像中的纹理和图案是如何组合在一起的。
  • 统计特性:Gram矩阵本质上是对特征图的统计描述,它不关心特征的具体位置,而是关注特征之间的相对关系,这正好符合风格特征的特点。

为什么 Content Target 只取一个深的特征向量?

原因一:高层特征包含丰富的语义信息

  • 深层网络的语义理解:深层网络(如relu3_3)已经经过多次卷积和池化操作,能够捕捉到图像的高层次语义信息,如物体的形状和结构。这些信息对于保留图像的内容至关重要。
  • 避免过细的细节干扰:如果在浅层提取内容特征,可能会过多地保留一些不必要的细节,导致生成图像过于复杂或失真。而深层特征更加抽象和概括,有助于保持图像的整体结构和意义。

原因二:内容特征的位置敏感性

  • 特征图的位置信息:与风格特征不同,内容特征对位置非常敏感。例如,一栋房子应该出现在图像的某个特定位置,而不是随意移动。因此,直接使用特征向量(而不是Gram矩阵)可以更好地保留这种位置信息。
  • 单一层次的描述:由于内容特征主要关注图像的结构和布局,通常只需要一个层次的描述就足够了。选择一个合适的深层特征向量即可较好地表示图像的内容信息。

对于这个 Multi-task 的 Loss 计算,可以通过调整权重来调整最终输出的结果

但是这个方法非常的慢,因为每次一迭代我们的输出图像都需要经过一次神经网络,以计算相应的 Gram 矩阵与相应的特征向量。对此我们的改进是训练一个网络以直接生成相应的迁移图像,后面的网络在这里只是用来计算损失的。这样我们只需要训练一次,将前面这个网络训练好即可,虽然也需要很长的时间,但是后续使用的时候就可以很快地进行生成了

评论区

对你有帮助的话请给我个赞和 star => GitHub stars
欢迎跟我探讨!!!