卷积神经网络 + 机器视觉: L12_Visualization 神经网络可视化 (斯坦福CS231n)

完整的视频课堂链接如下

完整的视频课堂投影片连接

 

To Visualize what?

经过一系列在神经网络上的探索与实践,我们知道设定一些 Hyperparameters,训练权重与偏值直到损失函数为最小值的状态,但是他们实际上在每一层训练出来的结果是什么正是解开神经网络黑箱的重要关键所在。

探讨权重的长相可以很大程度的帮助我们了解卷积核在图像数据中寻找什么用来分类的有用特征,这些特征可能是一条线,一种花纹,或是一个直角等,如下图分别是不同神经网络截取出来的第一层权重:

有趣的是,不论是哪一种框架类型,第一层圣经网络提取出来的内容大致都会相同,因此这些权重也可以被我们理解为一系列泛化的图像特征,是一种神经网络用来评判事情的底层「概念」,不过只有一个概念是不可能描绘出完整的分类问题全貌的,通常同一类问题的概念会有非常多个,每一层之间也会有不同深度的概念,用这些非常基本的概念作为基础,建立起一套机器自己学习得来的「知识体系」。

From Shellow to Deep

机器学习的过程就好比人类一般,是建构了基础的知识后,不断基于既有的内容堆叠上去新的视野,就像是牛顿说的「站在巨人的肩膀上」,神经网络的权重学习也是同样的逻辑,下一层的权重分配是根据上一层传递下来的数据内容经过新一轮卷积核扫描后的结果,因此上一层中被判断为比较重要的内容会进一步被剥离出来成为更高级的「概念」。

神经网络虽然随着层数的增加,每次深一层神经的输出也会增大深度,但是总体而言深一层的总参数量是在不断缩减的,一开始剥离出来的图像底层特征是基础,以此基础构建一个类金字塔参数结构,随着深度的增加,参数总量只会不断趋近顶层的总分类个数。

最后,如果像 ImageNet 有 1k 个类别要分,那最终我们就要让原本是三位数据结构的神经网络转变成一维的长条数据,并以全联接层的方法,逐层的收敛参数总量,直到最后面完全收合到类的个数上才算完成。

Dimensionality Reduction

不过即便如此,每一个类如果单独作为一个维度来看待,最终的输出层还是有非常高维度的特性,并不适合我们肉眼观察每个类在坐标轴上面的特征分布,因此下面提供两个方法:

  1. PCA: Principle Component Analysis
  2. t-SNE: t-distributed Stochastic Neighbor Embedding

主要目的就是对高维的数据降维,降到可以被呈现在我们指定的坐标轴上为止,其中第一个方法的难度和运算资源消耗远小于第二个方法,但是同样的呈现出来的结果也没有第二个方法来的优良和清晰,而具体的细节比较复杂,将不在课程中讨论。

python 语言有一个模块专门提供上述两函数的调用方法,运算环节也已经打包到了函数中去,可以让我们很方便的在不用知道细节的情况下应用,并使用别的绘图模块观察数据的分布。此模块就是 scikit-learn,调用方法如下代码:

from sklearn.decomposition import PCA
from sklearn.manifold import TSNE

具体操作环节将在 Tensorflow 系列的文章内容展开。

可视化的方法有很多种,种类变化的方向主要根据几个维度展开:

  1. 重点局部探测
  2. 神经层深度对输出的观察
  3. 激励与不被激励之间的差异

p.s. 这些方法中,学会了并不会帮助训练的结果产生更好的准确率,而是帮助我们能够反过头来检查训练的过程里,哪些地方是可以改善的部分。

Visualizing Activation

一张图片有非常多的像素格,我们利用神经网络的方式使其归类,这个方法让我们能够一定程度的还原归类的过程,发现到底是像素格中的那个像素占的影响因子最大,成为了那个压倒性评判该图片是所属种类的要素。

Occlusion Experiments

这个方法应用中,只使用了整张图片的一个随机部分,来检测该部分对整个判断的影响程度是多少,并用类似红外线热成像的方式,把决定该张图片是不是该种类的越重要的区域使用越深的颜色呈现出来,如下图:

Saliency Maps

这是另一个类似的检测手段,用来判断一张图片中的那么多个像素格里,对最终决策结果的影响有多少,同时这方面有许多优秀的论文值得参考,是这次课堂中留给大家实做的项目之一。类似的结果如下图:

从这些方法中我们可以发现呈现的结果如同上一章中提到的 Segmentation 效果,但是人工标签这些单一的像素点是非常低效率且高成本的,因此有一个提到的算法: grab cut segmentation algorithm,它可以让我们在 unsupervised 的状态下完成标签的工作。

Guided Backprop

上面几个方法都是对像素格和结果动手脚,从中试图找到规律,而这个方法则是从计算过程动手脚,来观察过程对结果的影响是什么,原本的 ReLU 激励函数是把负数部分全部一致化成 0,而反向传播的时候再经过前面传回来的梯度下降步伐更新这一轮参数。

这个方法提出了只更新正数,而原本负的部分一样抹平成 0,如下图:使用这个方法后反而发现图像的特征值凸显更明显了,是一个好的尝试。


上述说的都是给定一个固定的输入图像,然后根据设定好的特定参数和算法,最终得出一个归类结果,但是有没有什么参数和算法设定好后,可以套用到所有的图像数据中,就得到一个好的结果,达到不需要为特定种类的物体提供一个特定种类的特征的状态?下面是一个方法的尝试。

Gradient Ascent

这个方法从另一个角度出发,一般我们看神经网络的训练过程都是给定一个输入图像,然后看什么样的权重能够顺利让图像归类到正确的地方去;而这个方法不同之处在于我们希望了解什么图像能够顺利激发对应的神经元,因此这个方法中,我们不经过反向传播改变权重的值,而是改变图像中的像素本身。

这个被改变的图像本身需要达成两个特征:

  1. 数据必须在被改动后,还看起来像是个自然的图片
  2. 数据需要在改动的允许范围内最大化的激励神经元

而实际执行的时候就如同下面公式一般,需要附带一个正则项,避免数据在反向传播的时候被改成了不自然的样子,也就是过拟合的模样,如下图:

实际做法中,初始化的方法不再是从零或是高斯分布开始,而是根据一定已知的数据,从一个有高度的位置开始训练的,借由不断更新数据本身的样貌,达到神经元的最大激励程度,下面是经过多次重复训练更新后的数据样子:

DeepDream

这是一个在约 2016 年 Google 提出来的一个想法,既然神经网络可以剥离出输入图像的特征,那么我们在每次训练更新的时候,就把被找出来的特征在图像上进一步放大,逐渐的让修正过后的图像产生一种超现实的画风感受,其中为了不然呢图像被更新到不像个原本的样子,我们在算法后面添加了正则项,预防现象发生,如下代码:

def objective_L2(dst):
    dst.diff[:] = dst.data
    
def make_step(net, step_size=1.5, end='inception_4c/output',
              jitter=32, clip=True, objective=objective_L2):
    '''Basic gradient ascent step.'''
    
    # Input image is stroed in Net's 'data' blob
    src = net.blobs['data']
    dst = net.blobs[end]
    
    # To jitter images
    ox, oy = np.random.randint(-jitter, jitter+1, 2)
    # Apply jitter shift
    src.data[0] = np.roll(np.roll(src.data[0], ox, -1), oy, -2)
    
    net.forward(end=end)
    objective(dst)
    net.backward(start=end)
    q = src.diff[0]
    # Apply normalized ascent step to the input image
    src.data[:] += step_size / np.abs(g).mean() * g
    
    # Apply jitter shift
    src.data[0] = np.roll(np.roll(src.data[0], -ox, -1), -oy, -2)
    
    if clip:
        bias = net.transformer.mean['data']
        src.data[:] = np.clip(src.data, -bias, 255-bias)

DeepDream 产生出来的结果如下图显示:

Google 已经开放这方面的源代码,非常适合作为练习尝试。

Feature Inversion

这个方法有点类似上面提及的 DeepDream 原理,过程是让神经网络接受一个输入图像数据,然后经过一系列的流程训练并优化参数后,提取出了根据该图像获取到的特征,最后我们尝试使用这些搜集到的特征重构整张图片,而不是基于原本的图片修改内容。

最后结果我们希望它和原始的图像越接近越好,这个行为有点类似 GAN 的原理,我们可以利用此方法来观察每一个模型抽离原始数据特征的能力和特征本身的状态,下面是根据 VGGNet 架构在不同层抽离出来的特征重新拼凑出来的图像结果:

从图上可以观察到越深的层,其抽取出来的所谓概念就会越抽象,越来越跟原始数据有距离。

 

Texture Synthesis

此方法根据一个带有重复性的图片,试图创建出一个自然的重复性图片的拼接图片,不过这个问题已经是一个非常久的问题了,前人使用 Nearest Neighbor 方法已经可以非常好的解决了,下面是图像拼接的展示:

不过随着需要被重复的数据复杂度的提升,逐渐的也需要使用神经网络才可以解决问题:Gram Matrix。

同样是使用神经网络提取出特征,再根据这些特征进一步做排列组合,具体的细节和神经网络框架需要深入研读论文的内容,点击 链接 前往论文所在页面。最后呈现出来的结果将可以根据输入的数据,不断的在一个新的数据中呈现出不断重复的形状和颜色分布,如下图:

Neural Style Transfer

最后,结合上述的所有特征抽离方法,我们可以尝试选择两张不同画风的图片,抽离出其中一个画风的特征,保留第二个画风的形状,融合起来就会成为 Style Transfer 的应用方法。方法里面有两个神经网络分别目标是降低两个损失函数的值到最小,名字分别如下:

  • 图像的形状:feature reconstruction loss of the content image 
  • 图像的风格:grand matrix reconstruction loss of the sytle image

训练神经网络初始化的权重是共享的,他们必须根据数据的 Style 经过训练调整自己,但是其过程非常耗费运算资源,一张图片的产出耗时会根据图片本身大小决定,好的清晰图片在高性能的 GPU 上训练甚至都要花上几十分钟的时间才能完成。解决方法是分开执行不同的任务,提炼特征的网络,事先把特征处理好之后,直接融入到处理图像的另一个神经网络中去,那么就能够达到实时显示的速度。

相比于 DeepDream,Style Transfer 能够更好的控制风格的套用,是一种针对性的实践。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值