瞎谈CNN:通过优化求解输入图像

瞎谈CNN:通过优化求解输入图像

机器学习和优化问题

很多机器学习方法可以归结为优化问题,对于一个参数模型,比如神经网络,用y=f(x;\theta)来表示的话,训练模型其实就是下面的参数优化问题:
\hat \theta= \arg \min_\theta L(\theta;x,y)

其中L是loss function,比如神经网络中分类常用的cross-entropy。

CNN学到了什么?

特征(Representation)。把原始图像看做一个维度是像素×通道的向量,经过各种复杂的CNN结构,其实只不过成了另一个向量。这个向量所在的空间也许有更好的线性可分性,也许是相似样本的“距离”更近,原始的数据经过变换到了这里之后,就是特征。


可视化CNN

那么有个问题来了,如何可视化一个CNN结构学到的特征呢?答案有很多,其中一种就是本文的主题:不再通过优化求解网络的参数,而是求解输入图像

优化网络的输入,是相对于“正统”的机器学习优化参数而言的。当一个CNN训练完全后,我们可以固定好参数,把输入作为可训练的量,根据目的给定一个新的目标函数。

把这种方法最早用在深度学习里大概是Bengio组在2009年的一个Tech report:《Visualizing Higher-Layer Features of a Deep Network》。文章里提出了下面的优化问题

\hat x = \arg \max_{x} \left( h_{ij}(x;\theta) \right)
\text {subject to}  \left| \left| x \right| \right|=\rho

其中h_{ij}代表第j层中的第i个神经元的响应。很直观的,这是要寻找什么样的图像可以最大程度地激活这个神经元,这种方法就叫做activation maximization。利用这种办法,原文中得到了类似下面的可视化,从左至右依次是一个DBN中从低到高的三层:

也许很多人一提起特征可视化首先想到的是可视化特征图或是直接把卷积核画出来,就像Caffe的Tutorial(Image Classification and Filter Visualization)中一样。这样的可视化其实是很不直观的,尤其是卷积核的可视化,第一层之后的卷积核到底学到了什么内容只能靠脑补。基于这个思路,Cornell的Jason Yosinski把公式改了改

\hat x = \arg \max_x \left( h_{ij}(x;\theta)-R(x) \right)

其实就是Regularization项R(x)放到了目标函数里。然后他把这种可视化作为功能之一,基于Caffe制作了一个年久失修的用于CNN可视化的工具包:yosinski/deep-visualization-toolbox。用在AlexNet上的效果是下面样子:

注意到这个可视化结果还考虑到了感受野,也就是实际优化的目标是响应图中心的点,所以越高层的可视化图像越大。

直接把某一类别的分数作为优化值可以得到关于该类别更直观的可视化结果,比如下图是这个工具包对几个类别的可视化:

每个类别学到的视觉上的特征一目了然。另外注意到这种方法因为是基于优化,所以每次优化的结果会有不同。

借助这种可视化,我们能够分析出网络是不是真的学习到了我们希望其所学的特征,比如Google的Research Blog中提到过哑铃的例子:

可视化的类别是哑铃,可是结果里包含了一些我们不希望出现的元素:胳膊。这是因为用于训练的哑铃图片中,大都有握着哑铃的胳膊。

可视化网络的方法有很多,以简单粗暴为最大特点的大概只是activation maximization。


对抗样本(Adversarial Examples)

对抗样本也是机器学习中的一种常用概念,通常指人为制造的,让一个机器学习模型发生错误的样本。Anh Nguyen的论文《Deep Neural Networks are Easily Fooled: High Confidence Predictions for Unrecognizable Images》中有个比较形象的示意:

要理解这个图,还要提一句机器学习的一个基本问题:学习数据的分布。具体到方法就是从训练数据中进行学习,如果学习成功,则可以泛化到所有数据,包含没见过的测试数据。回到这个图,数据的分布就是最上边那三坨。一种造对抗样本的方法就是从一个类别的样本出发,做一些小修改,让模型将修改后的样本判断为另一个类别,而实际上(或是人的,显然的判断)该样本仍为原来类别,这就是图中从蓝色原点到白色小方块的方法。

当然更容易的方法是利用分类边界的不可确定性。比如上图中除了最上面部分的空间可以认为是数据存在概率极低的区域,从实际应用的角度甚至可以认为是我们完全不关心的区域。因为算法学习的样本只有实心的小圆点,所以远离小圆点的部分,分类边界是难以控制的。在这里面很容易轻松取到算法高概率认为是一个类别的样本,而实际上却难以辨认的对抗性样本。

所以大体来说,对抗性样本的存在是因为数据维度通常过高,即使考虑所在的子区域,往往还是过高,对整个(数据分布的)空间的搜索是不可行的。在训练样本没有覆盖的区域,无论该区域是否属于数据分布所在的区域,无论模型的capacity够不够,都有出现对抗性样本的可能。尽管深度学习中一直主张distributed representation已大幅优于局部泛化,维度的诅咒仍是一个无法摆脱的难题。

具体到CNN,下边这个例子可能不少人见过:

熊猫的图片上加上一个人眼难以察觉的噪音,对于人眼而言看上去还是熊猫,可是对于一个CNN而言,右边的图片以99%高概率被判断为了长臂猿。上句话其实已经很清楚地指出了得到右边图片的方法,还是一个优化输入图像的问题:加上一个尽量小的噪音,并通过优化这个噪音,让优化后的图像具有另一个类别的高概率:

\hat n = \arg \min_{n} \left( \alpha  \left| \left| n \right| \right| + L\left( x+n, c \right) \right)
\text {subject to} \ x+n \in [0,1]^m

其中n是要求的噪音,\alpha是相应的系数,L是x+n属于某个类别的loss,c是某个错误类别的标签。这大概是基于深度学习的计算机视觉中第一个讨论造对抗样本的方法,见于Christian Szegedy的论文《Intriguing properties of neural networks》。同样是在这篇论文中,Christian描述了一个比较令人担忧的发现:就是这种样本居然可以泛化,同一个对抗样本,对于不同的CNN结构,在不同数据子集下训练的模型,是可以达到一定程度的“通用”性的。也就是说对于一些涉及到安全的应用,攻击者即使不知道部署的模型是什么,通过某种手段猜测数据的分布,也是可以得到有效的攻击样本的。


语义信息和高层神经元

对于CNN,有个很基础的认识:低层的部分学习纹理等简单信息,高层部分学习语义信息。在《Intriguing properties of neural networks》中的另一个发现是,CNN中表示高层学习到的语义信息的,并不是某一个神经元,而是高层神经元构成的空间。这个看上去有些显然的结论的一种佐证方式又是对输入图像进行优化:

x'=\arg \max_{x \in \text{images}} <\phi(x), v>

其中\phi(x)是神经元激活值对应的向量,v是一个随机向量。另外这和前边的优化有些许不同,x的取值范围限定在已有的图片集里。其实就是在某个高层响应的空间里,沿着某个方向挑选了一些该方向上值最大的图片。最后的结论是,无论是沿着某个随机方向找到的图片,还是以某一个神经元响应最大找到的图片,都能看出一些语义上的共性,比如下图:

黑线以上是最大化某个神经元响应的样本,共性挺明显,黑线以下是最大化某层特征空间中某个方向响应的样本,共性也挺明显。

Deep Dream

很多人小时候都有这样的经历:抬头看天空的云彩,或是观察地面的纹路,甚至是凝视厕所里脏兮兮的墙面,这时候看到的却是各种机器人大战,武打画面,或是动画片中的人物和故事。

Deep Dream和这很像,输入任何一幅图像,都会得到在不同层的响应,前面已经提到过,低层的响应是纹理和细节的相应,高层的响应是语义信息的响应。所以Deep Dream的思想是:

对于某个高层的得到的语义信息响应,加强这些信息。这相当于让网络自己决定从输入图像中“看到”了什么,并把“看到”的东西加强,所以又是一个优化问题。

要优化的目标,就是最大化输入图像在某个高层已有的响应,优化的初始值就是输入图像,当然还有一些其他项,比如不同的包含不同尺度,或是抑制梯度及高频成分的约束,这些是否加上视情况而定。这并不是一个典型的优化问题,反而更像是一个单纯的梯度下降问题,所以梯度下降通常也不会进行到底,而是进行若干步直到输入图像中出现一个“梦境”。下面是TensorFlow的官方tutorial里,Inception模型在一幅图片上生成的梦境:


基于Inception的DeepDream有个特点,就是梦境里的狗很多,就像上面这幅图一样。

在电影《Inception》里,梦境是可以操控的,DeepDream也可以,按照可视化中的思路,把优化目标换成某一层响应图中的某个channel,这就是一个传统的优化问题了:

\hat x = \arg \max_x \left( h_{ij}(x;\theta)-R(x) \right)

和第一部分中的差别在于初始化的是一幅图像,并且优化不会进行到底。比如一个对花朵一样图案敏感的channel,对应的梦境里画面中就会开满了花:

其实那些隐藏在白云里和墙上的图案,长大后也是能看到的,只不过大多数人不看了。

Neural Art/Style

2016年,如果要评选一款和神经网络相关的最火爆的APP,一定非Prisma莫属。其背后的算法,也是对输入图像的优化。关于神经网络的艺术风格学习,首先要追溯到更早的一篇利用优化输入方法的论文《Understanding Deep Image Representations by Inverting Them》,里面讨论的问题之一是通过优化算法和神经网络中的特征重建一幅图像:

\hat x = \arg \min_x \ ||\phi(x)-\phi_0||^2+\lambda R(x)

其中\phi_0是某幅图像在网络中的特征,这个特征可以是部分层的响应,或者全部的响应。如果\phi_0取低层的特征,那么细节的还原度就会很好,如果\phi_0是高层的特征,则画面中的纹理和细节会丢失很多信息。比如下面的图像:

用Vgg16模型执行一遍前向计算,然后分别取relu1~relu5的特征作为\phi_0,重建的结果如下:

在基于神经网络的图像风格艺术化中,通常的输入是一幅原始图像,经过处理具有了其他画面,比如一幅油画的艺术风格。所以是原始图像的内容+其他图像的风格,那么上面讨论的部分就是内容的重建,所以接下来要讨论的是风格的重建。

图像风格其实是个很难定义的东西,不过在神经网络中,谈到风格,一般指的是纹理。纹理的特点是什么呢?又是一个很难定义的东西……不过纹理有个特点是和所在位置无关,基于这个特点,只要是和位置无关的统计信息,都可以试着来表示纹理的特征,Gram矩阵,就是在CNN中表示这种特征办法的一种:

G_{ij}^l=\sum_{k}{F_{ik}^lF_{jk}^l}

其中G^l代表第l层响应图对应的Gram矩阵,F_{i}^l代表该层第i个卷积核对应的响应图。通常一个响应图是二维的,这里把响应图展开为一个一维向量,其中F_{ik}^l代表该层第i个响应图的第k个元素。所以Gram矩阵的每一个元素就是求了个内积,把两个响应图之间,和位置无关的一种相关性给求了出来。

接下来的套路就和上一小节一样了,把每层Gram矩阵作为特征,让重建图像的Gram矩阵尽量接近原图的Gram矩阵,也是个优化问题:

\hat x = \arg \min_x \sum_l w_lE_l

其中E_l是每一层的loss,w_l是该层loss的权重。E_l的形式是考虑到每层响应图大小后的Gram矩阵差异:

E_l=\frac 1 {4N_l^2M_l^2} \sum_{i,j} \left( G_{ij}^l -G_{ij}^{l,\text {img}} \right)^2

同样是用Vgg16,用不同层的特征,对梵高的星空进行风格重建,结果如下:

至于Gram矩阵为什么能作为重建风格的依据,论文《Demystifying Neural Style Transfer》(感谢@Lyken 在评论中的分享)中给出了一个思路,是一个不错的参考。比起原文中相关性的解释,这篇论文更进一步把Gram矩阵转化成了squared Maximum Mean Discrepancy,这直接把图像和CNN中响应的分布联系了起来,并且可以通过替换计算MMD的方式尝试其他风格重建的目标计算方式。

总之,重建内容和风格的方法都已有,接下来就很自然了,把某个较高层的特征作为内容重建的目标,同时把每层响应的Gram矩阵以某个比例求和作为风格的重建目标,对输入图像进行优化:

\hat x = \arg \min_x  \ (\alpha L_{\text {content}}(x,x_{\text{content}})+\beta L_{\text {style}}(x,x_{\text{style}})+\lambda R(x))

这就是论文《A Neural Algorithm of Artistic Style》中的方法,也是Prisma背后的算法。

编辑于 2017-03-08

文章被以下专栏收录