0%

DL笔记(6)Convolutional Neural Network(CNN)

1.Why CNN for Image?

1.1. CNN vs DNN

Convolutional Neural Network,CNN(卷积神经网络)常常被用在影像辨识领域。当然也可以用一般的neural network来做影像处理,不一定要用CNN,比如做图像的分类,就可以去train一个neural network,它的input是一张图片,用pixel来表示这张图片,即一个很长的vector,而output则是由图像类别组成的vector,假设你有1000个类别,那output就有1000个dimension。

但是我们会遇到这样的问题:实际上,在train neural network的时候,我们会有一种期待:在这个network structure里面的每一个neuron,都应该代表了一个最基本的classifier;事实上,在文献中,根据训练的结果,也有很多人得到这样的结论,举例来说,下图中:

  • 第一层layer的neuron,它就是最简单的classifier,它做的事情就是detect有没有绿色出现、有没有黄色出现、有没有斜的条纹出现等等;
  • 第二层layer,它detect更复杂的东西,根据第一个layer的output,它如果看到直线横线,就是窗框的一部分;如果看到棕色的直条纹就是木纹;看到斜条纹加灰色的,这个有可能是轮胎的一部分等等;
  • 第三层hidden layer再根据第二层hidden layer的output,会做更复杂的事情,比如当某一个neuron看到蜂巢,它就会被activate;当某一个neuron看到车子,它就会被activate;当某一个neuron看到人的上半身,它就会被activate等等。

但如果直接用一般的fully connected feedforward network来做图像处理的时候,往往会需要太多的参数。举例来说,假设我们的网络需要辨识的是100*100 pixel的彩色图片,它的分辨率是100*100,那这其实是很小张的image了。然后需要把他转换成一个vector,总共有100*100*3个pixel(如果是彩色的图的话,每个pixel其实需要3个value,即RGB值来描述它的),那input vector就是30000维;如果input vector是三万维,又假设hidden layer有1000个neuron,那仅仅是第一层hidden layer的参数就已经有30000*1000个了,这样参数就太多了,train network的成本太高。

CNN做的事情其实是,来简化这个neural network的架构,我们可以根据自己的知识和对图像处理的理解,一开始就把某些实际上用不到的参数给过滤掉。虽然CNN看起来它的运作比较复杂,但事实上,它的模型比DNN还要更简单,我们就是用prior knowledge,去把原来fully connected的layer里面的一些参数拿掉,就变成CNN。

1.2. Three Property for CNN theory base

为什么我们有可能把一些参数拿掉?为什么我们有可能只用比较少的参数就可以来做图像处理这件事情?下面列出三个对影像处理的观察:(这也是CNN架构提出的基础所在)

  • Some patterns are much smaller than the whole image

在影像处理中,如果network的第一层hidden layer中的neuron要做的事情是侦测有没有一种东西、一种pattern(图案样式)出现,那大部分的pattern其实是比整张image要小的(比如鸟会出现而图片的中央,而其他地方是背景),所以对一个neuron来说,想要侦测有没有某一个pattern出现,它其实并不需要看整张image,只需要看这张image的一小部分。

比如现在有一张鸟的图片,那第一层hidden layer的某一个neuron的工作是,检测有没有鸟嘴的存在(可能还有一些neuron侦测有没有鸟嘴的存在、有一些neuron侦测有没有爪子的存在、有一些neuron侦测有没有翅膀的存在、有没有尾巴的存在,之后合起来,就可以辨识图片中有没有一只鸟),那它其实并不需要看整张图,只要给neuron看这个小的红色杠杠里面的区域,它就可以知道这是不是一个鸟嘴。所以,每一个neuron其实只要连接到一个小块的区域就好,它不需要连接到整张完整的图,因此也对应着更少的参数

  • The same patterns appear in different regions

同样的pattern,可能会出现在image的不同部分,但是它们有同样的形状、代表的是同样的含义,因此它们也可以用同样的neuron、同样的参数,被同一个detector检测出来。

比如上面两张图中分别有一个处于左上角的鸟嘴和一个处于中央的鸟嘴,但我们并不需要训练两个不同的detector去专门侦测左上角有没有鸟嘴和中央有没有鸟嘴这两件事情,这样做太冗余了,我们要cost down(降低成本),我们并不需要有两个neuron、两组不同的参数来做duplicate(重复一样)的事情,所以我们可以要求这些功能几乎一致的neuron共用一组参数,它们share同一组参数就可以帮助减少总参数的量

  • Subsampling the pixels will not change the object

我们可以对一张image做subsampling(二次抽样),假如你把它奇数行、偶数列的pixel拿掉,image就可以变成原来的四分之一大小,而且并不会影响人对这张image的理解。所以,可以利用subsampling把image变小,从而减少需要的参数量

2. The whole CNN structure

CNN的结构可以这样理解:首先,input data以后,它会先通过Convolution的layer,接下来做Max Pooling,然后再去做Convolution,再做Maxi Pooling…,这个process可以反复进行多次(重复次数需要事先决定),这就是network的架构。当做完先前决定的convolution和max pooling的次数后,接着做Flatten(将矩阵展开成vector),最后把Flatten output放到一般的Fully connected network里面去,最终得到输出的结果。

我们基于之前提到的三个对影像处理的观察,设计了CNN这样的架构,第一个是要侦测一个pattern,不需要看整张image,只要看image的一个小部分;第二个是同样的pattern会出现在一张图片的不同区域;第三个是我们可以对整张image做subsampling。那前面这两个property,是用convolution的layer来处理的;而第三个property,是用max pooling来处理的

2.1. Convolution

假设现在我们的network的input是一张6*6的image,图像是黑白的,因此每个pixel只需要用一个value来表示,而在convolution layer里面,有很多Filter,每一个Filter,其实就相当于是Fully connected layer里的一个neuron。

  • Property 1

每一个Filter其实就是一个matrix,这个matrix里面每一个element的值,就跟那些neuron的weight和bias一样,是network的parameter,它们具体的值都是通过Training data学出来的,而不是人去设计的。上图中每一个Filter是3*3的size,意味着它就是在侦测一个3*3的pattern,当它侦测的时候,并不会去看整张image,它只看一个3*3范围内的pixel,就可以判断某一个pattern有没有出现,这就实现了property 1。

  • Property 2

这个Filter是从image的左上角开始,做一个slide window,每次向右挪动一定的距离这个距离就叫做stride,由你自己设定,每次filter停下的时候就跟image中对应的3*3的matrix做一个内积(相当于展开成vector再作内积,其实就是相同位置的值相乘并累计求和)。

这里假设stride=1,那么我们的Filter每次移动一格,当它碰到image最右边的时候,就从下一行的最左边开始重复进行上述操作,经过一整个convolution的process,最终得到下图所示的红色的4*4 matrix。

观察上图中的Filter1,它斜对角的地方是1,1,1,所以它的工作就是detect有没有连续的从左上角到右下角的1,1,1出现在这个image里面,检测到的结果已在上图中用蓝线标识出来,此时Filter得到的卷积结果的左上和左下得到了最大的值,这就代表说,该Filter所要侦测的pattern出现在image的左上角和左下角。同一个pattern出现在image左上角的位置和左下角的位置,并不需要用到不同的Filter,我们用Filter1就可以侦测出来,这就实现了property 2。

Feature Map

在一个convolution的layer里面,它会有很多的filter,不一样的filter会有不一样的参数,但是这些filter做卷积的过程都是一模一样的,把filter2和image做完convolution以后,就会得到另外一个的4*4 matrix,那这个蓝色的4*4 matrix跟之前红色的4*4matrix合起来,就叫做Feature Map(特征映射),有多少个filter,对应就有多少个映射后的image。

CNN对不同scale的相同pattern的处理上存在一定的困难,由于现在每一个filter size都是一样的,这意味着,如果你今天有同一个pattern,它有不同的size,有大的鸟嘴,也有小的鸟嘴,CNN并不能够自动处理这个问题;DeepMind曾经发过一篇paper,上面提到了当你input一张image的时候,它在CNN前面,再接另外一个network,这个network做的事情是,它会output一些scalar,告诉你说,它要把这个image的里面的哪些位置做旋转、缩放,然后,再丢到CNN里面,这样你其实会得到比较好的performance。

Colorful image

刚才举的例子是黑白的image,input的是一个2维的matrix。彩色的image的每一个pixel就是由RGB组成的,相当于3个matrix叠在一起,可以理解是多了一维“深度”。这时Filter也会跟着input作相应的变化,假如上面的例子中输入的是彩色图片,input就是3*6*6的,Filter相应就是3*3*3。在做convolution的时候,就是把这个Filter的27个值跟image里对应区块的27个值做内积,即三个channel是一起处理的,经过convolution之后仍然得到一个$4*4$的matrix(注意不是$443$),这样在做完这一层的convolution之后,有多少个Filter,得到的Feature Map就有多少“层”,和处理黑白image是一样的。

2.2. Convolution V.s. Fully connected

filter是特殊的”neuron“

接下来要讲的是,convolution跟fully connected有什么关系。你可能觉得会觉得它是一个很特别的operation,感觉跟neural network没半毛钱关系┐(゚~゚)┌ ,但其实它就是一个neural network。

convolution其实就相当于是fully connected的layer把一些weight删掉,下图中绿色方框标识出的feature map的output,其实就是hidden layer的neuron的output。

那为什么是这样的呢(。-`ω´-)?如下图,我们在做convolution的时候,把Filter放在image的左上角,然后再去做inner product,得到一个值3;这件事情等同于,我们现在把这个image的6*6的matrix拉直变成右边这个用于input的vector(竖着的一长条),然后有一个红色的neuron,这些input经过这个neuron之后,得到的output是3。

每个“neuron”只检测image的部分区域

那这个neuron的output怎么来的呢?这个neuron实际上就是由Filter转化而来的,我们把filter放在image的左上角,此时filter考虑的就是和它重合的9个pixel,假设你把这一个6*6的image的36个pixel拉成直的vector作为input,那这9个pixel分别就对应着右侧编号1,2,3的pixel,编号7,8,9的pixel跟编号13,14,15的pixel。

如果我们说这个filter和image matrix做inner product以后得到的output 3,就是input vector经过某个neuron得到的output 3的话,这就代表说存在这样一个neuron,这个neuron带weight的连线,就只连接到编号为1,2,3,7,8,9,13,14,15的这9个pixel而已,而这个neuron和这9个pixel连线上所标注的的weight就是filter matrix里面的这9个数值。

作为对比,Fully connected的neuron是必须连接到所有36个input上的,但是,我们现在只用连接9个input,因为我们知道要detect一个pattern,不需要看整张image,看9个input pixel就够了,所以当我们这么做的时候,就用了比较少的参数

“neuron”之间共享参数

当我们把filter做stride = 1的移动后,通过filter和image matrix的内积得到另外一个output值-1,我们假设这个-1是另外一个neuron的output,那这个neuron会连接到哪些input呢?下图中这个框起来的地方正好就对应到pixel 2,3,4,pixel 8,9,10跟pixel 14,15,16

你会发现output为3和-1的这两个neuron,它们的作用是分别去检测在image的两个不同位置上是否存在某个相同pattern,它们的weight是一样的。但在Fully connected layer里它们通常做的是两件不同的事情,每一个neuron应该有自己独立的weight。

来看我们的convolution,首先是把每一个neuron前面连接的weight减少了,然后我们强迫某些neuron(比如上图中output为3和-1的两个neuron),它们一定要共享一组weight,虽然这两个neuron连接到的pixel对象各不相同,但它们用的weight都必须是一样的(9=3*3对应着filter的元素个数,这些weight也就是filter内部的元素值,上图中圆圈的颜色与连线的颜色一一对应,PS:李老师讲课真的很用心),等于filter里面的元素值,这件事情就叫做weight share。这样的两个方法就会让convolution里的参数数量相比于fully connected layer的大大减少。可以说CNN的本质,就是减少参数的过程。

看到这里你可能会问(´ω`),这样的network该怎么搭建,又该怎么去train呢?其实现在这些都是用toolkit(Tensorflow, Pytorch等等)来完成的,所以你大概不会自己去写;如果要自己写的话,它其实就是跟原来的Backpropagation用一模一样的做法,只是有一些weight就永远是0,你就不用去train它,它就永远是0。然后,怎么让某些neuron的weight值永远都是一样呢?就可以先用一般的Backpropagation的方法,对每个weight都去算出gradient,再把本来要tight在一起、要share weight的那些weight的gradient取平均,然后让这些weight用这个相同的平均值取update就好了。

2.3. Max Pooling

Operation of max pooling

相较于convolution,max pooling是比较简单的,它相当于实现了property3,即subsampling,由Filter 1得到一个4*4的matrix,由Filter 2得到另外一个4*4的matrix。接下来,我们把output四个分为一组,每一组里面通过选取平均值或最大值的方式,把原来4个value合成一个 value,这种subsampling的方式就可以让你的“image”缩小。

但是如果取Maximum放到network里面,不就没法微分了吗?其实是可以的,后面的章节会讲到Maxout network,会告诉你怎么用微分的方式来处理它。

Convolution + Max Pooling

做完一次convolution加一次max pooling,我们就把原来6*6的image,变成了一个 Filter个数2\2 的image;如下图中是两个Filter,那经过一次convolution+max pooling得到的image就是$222$维的。这是一个新的比较小的image,它表示的是不同区域上提取到的特征,不同的Filter检测的是该image同一区域上的不同特征属性。

Convolution + Max Pooling可以repeat很多次,你可以把得到的这个比较小的image,再次进行convolution和max pooling的操作,得到一个更小的image,依次类推。

你可能会问:假设我第一个convolution有25个filter,通过这些filter得到25个feature map,然后repeat的时候第二个convolution也有25个filter,那这样做完,我是不是会得到25*25个feature map呢?

其实不是这样的,convolution的input是会考虑“深度”的,比如在第一次convolution+max pooling后得到的是$2566$的matrix,那么第二层convolution的FIlter就可以是$2533$了,这样第二次得到的feature map也是25个。所以每次convolution+max pooling得到的matrix的“层数”或者说“深度”,只和这一层的convolution中的Filter数有关,即等于这一层的convolution中的Filter数

2.4. Flatten

做完convolution和max pooling之后,就是FLatten和Fully connected Feedforward network的部分。Flatten的意思是,把左边的feature map“拉直”成一个vector。然后把这个vector丢进一个Fully connected Feedforward network,最后得到输出的结果。

也就是说,我们之前通过CNN提取出了image的feature,它相较于原先一整个image的vetor,少了很大一部分内容,因此需要的参数也大幅度地减少了,但最终也还是要丢到一个Fully connected的network中去做最后的分类工作。

2.5. Example: CNN in Keras

过程可以概括为:

  • 假设我们input是一个1*28*28的image;
  • 通过25个Filter的convolution layer,每个Filter的size是33,如果不考虑image边缘处的处理的话,得到的每个channel会是26\26的,因此通过第一个convolution得到25*26*26的“cubic image”;
  • 接着做Max pooling,把2*2的pixel分为一组,然后从里面选一个最大的组成新的image,得到25*13*13的image;
  • 再做一次convolution,假设这次选择50个filter,每个filter size是253\3,output得到50*11*11的image;
  • 再做一次Max Pooling,也是把2*2的pixel分为一组,然后从里面选最大值,output得到50*5*5的image;
  • 最后用Flatten将这个image“拉直”成一个1250维的vector,把这个vector作为一个Fully Connected Feedforward network的输入,这样我们的CNN的structure就搭建完成了。

3. What does CNN learn?

很多人会说Deep Learning就是一个黑盒子,你learn出来以后,根本就不知道为什么是这样子,于是你会感觉它很intelligent⊙(・◇・)?,但其实我们可以从CNN设计的思路出发来分析它在learn的过程中学到了什么。

3.1. what does filter do

还是用上面的例子,第一层convolution的Filter比较容易理解,每一个Filter是一个3*3的matrix,它对应到image中3*3范围内的9个pixel,所以这个Filter的值就反映着它在detect什么东西。

但第二层convolution中的Filter的作用就比较难理解了,每个Filter的size是$2533$,这些Filter的input并不是pixel,而是做完一次convolution+max pooling的结果,因此Filter考虑的范围并不是3*3=9个pixel,而是一个长宽为3*3,高为25的“cubic”,filter实际在image上看到的范围是远大于9个pixel的,就算把它的weight拿出来看,也不知道它在做什么。

那我们可以通过下面的方法来分析一个Filter它做的事情是什么:

第二层convolution里面的50个Filter,每一个Filter的output是一个11*11的matrix,假设现在把第k个filter的output拿出来,如下图所示,这个matrix里的每一个element,记为$a^k_{ij}$,上标$k$表示这是第$k$个filter,下标$ij$表示它在这个matrix里的第$i$行,第$j$列。

定义$a^k$为Degree of the activation of the k-th filter,这个值表示现在的第k个filter,它有多被activate,直观来讲就是描述现在input的东西跟第k个filter有多接近,它对filter的“激活程度”有多少。$a^k$等于,第k个filter与input进行卷积所输出的output里所有element的summation,以上图为例,就是这11*11的output matrix里所有元素之和:

接下来我们想要知道第k个filter的作用是什么,那就找一张image这张image可以让第k个filter被activate的程度最大;即找一个image x*,它可以让我们定义的activation的degree $a^k$最大:

之前我们求minimize用的是gradient descent,那现在我们求Maximum用gradient ascent(梯度上升法)。

这个方法还是颇为神妙的(๑´ㅂ`๑) ,现在是把input x作为要找的参数,对它去用gradient descent或ascent进行update,在这个task里面model的参数是固定的,要用gradient ascent去update这个x,让它可以使degree of activation最大。

上图就是得到的结果,50个filter理论上可以分别找50张image使对应的activation最大,这里仅挑选了其中的12张image作为展示,这些image有一个共同的特征,它们里面都是一些反复出现的某种texture(纹路)比如说第三张image上布满了小小的斜条纹,这意味着第三个filter的工作就可以理解为是在detect图上有没有斜条纹,要知道现在每个filter检测的都只是图上一个小小的范围而已,所以图中一旦出现一个小小的斜条纹,这个filter就会被activate,相应的output也会比较大,所以如果整张image上布满这种斜条纹的话,这个filter的activation程度是最大的,相应的output值也会达到最大。

因此我们可以用这种方法去研究CNN中的每个filter的作用是去detect怎样的pattern,或者说texture。

3.2. what does neuron do

做完convolution和max pooling之后,会将结果用Flatten展开,然后丢到Fully connected neural network里面去,之前已经搞清楚了filter是做什么的,那我们也想要知道在这个neural network里的每一个neuron是做什么的,那就可以对刚才的做法如法炮制。

我们定义第$j$个neuron的output就是$a_j$,接下来就用gradient ascent的方法去找一张image $x$,这个$x$作为输入可以使$a_j$的值最大,即:

找到的结果如上图所示,同理这里仅取出其中的9张image作为展示,你会发现这9张图跟之前filter所观察到的情形是很不一样的,刚才我们观察到的是类似纹路的东西,那是因为每个filter考虑的只是图上一部分的vision,所以它detect的是一种texture;但是在做完Flatten以后,每一个neuron不再是只看整张图的一小部分,它现在的工作是看整张图。

3.3. what about output

接下来考虑CNN的output,由于是手写数字识别的demo,因此这里的output就是10维。同样地,我们把某一维拿出来,然后同样去找一张image x,使这个维度的output值最大,即

可以想象说既然现在每一个output的每一个dimension就对应到一个数字,那如果我们去找一张image x,它可以让对应到数字1的那个output layer的neuron的output值最大,那这张image显然应该看起来会像是数字1,你甚至可以期待搞不好用这个方法就可以让machine自动画出数字⊙(・◇・)?

但实际上得到的结果却是如下图所示:

上面的每一张图分别对应着数字0-8,发现可以让数字1对应neuron的output值最大的image看起来一点也不像1;为了验证程序有没有bug,把上述得到的image作为testing data丢到CNN里面,结果classify的结果确实对应着的数字0-8。看来这个CNN所学到的东西跟人类一般的想象认知还是有差别的。

那有没有办法让上面这个图看起来更像数字呢?想法是这样的:一张图是不是一个数字,它会有一些基本的假设,比如这些image,显然人类手写出来的东西就不是长这个样子的。所以要对x做一些regularization,做一些constraint(限制约束),我们应该告诉machine说,虽然有一些x可以让y很大,但是它们不是数字。

最简单的加constraint的想法是:image中白色代表的是有墨水、有笔画的地方,而对于一个digit来说,整张image上涂白的区域是有限的,像上面这些整张图都是白白的,它一定不会是数字。假设image里的每一个pixel都用$x_{ij}$表示,我们把所有pixel值取绝对值并求和$\sum\limits_{i,j}|x_{ij}|$,这一项其实就是之前提到过的L1的regularization,再用$y^i$减去这一项,得到:

这样我们找出的让上式最大的$x*$,它可以让$y^i$很大的同时,也是让$|x_ij|$的summation越小越好,那我们希望找出来的image,大部分的地方是没有涂颜色的,只有少数数字笔画在的地方才有颜色出现。加上这个constraint以后,得到的结果会像下图右侧所示一样,已经隐约有些可以看出来是数字的形状了

如果再加上一些额外的constraint,比如希望相邻的pixel是同样的颜色等等,应该可以得到更好的结果。

3.4. Deep Dream

那上面讲到的有点“逆向”的思路,我们就可以实现这一一件事:如果你给network一张image,它会在这个image里面加上它看到的东西,做法就是:找一张image输入到CNN训练,然后把某一个convolution layer里面的filter或是fully connected layer里的某一个hidden layer的output拿出来;接下来把本来是positive的dimension值调大,negative的dimension值调小,即让绝对值更大,将它作为我们要找的image的target。

然后用gradient descent的方法找一张image x,让它通过这个hidden layer后的output就是你调整后的target,这么做的目的是让CNN夸大化它看到的东西——make CNN exaggerates what is sees。也就是说,如果某个filter有被activate,那你让它被activate的更剧烈,CNN可能本来看到了某一样东西的“端倪”,那现在你就让它更“具象化”,或者说“夸大化”。如果把上面这张image拿去做Deep Dream的话,看到的结果就会像下面这个样子(着实是有点吓人`Д´|):

3.5. Deep Style

Deep Dream还有一个进阶的版本,叫做Deep Style,或者叫Neural Style图片风格迁移。我们input一张image,Deep Style做的事情就是让machine去修改这张图,让它有另外一张图的风格,如下所示:

实际上机器做出来的效果惊人的好,具体的做法参考reference:A Neural Algorithm of Artistic Style

Deep Style的大致思路是,把原本的image输入到CNN,得到CNN filter的output,代表这张image里面有什么样的content。然后你把呐喊这张图也丢到CNN里面得到filter的output,这时我们在意的是,filter和filter的output之间的correlation,这个correlation代表了这张image的style。

接下来就用一个CNN去找一张image,这张image的content像左边的图片,比如使这张image的filter output的value接近左边的图片的value;同时让这张image的style像右边的图片,比如使这张image output的filter之间的correlation像右边这张图片。最终用gradient descent找到一张image,同时可以maximize左边的content和右边的style,它的样子就像上图左下角所示:

4. More Application

4.1. Playing Go

除了图像处理,CNN可以被运用到不同的领域,比如广为人知的alphaGo。想要让machine来下围棋,其实一般的neural network也可以帮我们做到这件事情,但采用CNN的话会得到更好的performance。

之前举的例子都是把CNN用在图像上面,input是一个matrix,而棋盘就可以表示成一个19*19的matrix,那对CNN来说,就是直接把它当成一个image来看待,然后再output下一步要落子的位置,training process可以通过搜集很多棋谱来train CNN,看到这样的棋局应该有什么样的output,即下一步应该在哪里落子。其实这时supervised的部分,AlphaGo还有reinforcement learning的部分,后面的章节会讲到。

回想之前讲过的设计在图像识别中,设计CNN的结构时考虑的三个property:

  • Some patterns are much smaller than the whole image
  • The same patterns appear in different regions
  • Subsampling the pixels will not change the object

CNN能够应用在Alpha-Go上,是因为围棋有一些特性和图像处理是很相似的。对于property 1,有一些pattern是比整张image要小得多,在围棋中也有同样的现象。在AlphaGo里面,它第一层convolution是用5*5的filter,显然做设计的人了解围棋上最基本的pattern可能都是在5*5的范围内就可以被侦测出来。对于property 2,同样的pattern可能会出现在不同的region,这在围棋中也是存在的,所以可以用同一个detector,来处理这些在不同位置的同样的pattern。

但是对于property3,对棋谱做subsampling之后,其所表达的内容明显就和之前的不同的,通过阅读Alpha-go的论文,我们可以知道AlphaGo的network structure中并没有Max pooling层,即没有做subampling。可见根据围棋的特性,并不需要在围棋的CNN里面使用用Max pooling这样的构架。

4.2. Speech

CNN也可以用在语音处理上,我们可以把一段声音表示成spectrogram,spectrogram的横轴是时间,纵轴则是这一段时间里声音的频率,如下图中是一段“你好”的音频,偏红色代表这段时间里该频率的energy是比较大的,也就对应着“你”和“好”这两个字,spectrogram用颜色来描述某一个时刻不同频率的能量。我们可以把这个spectrogram当作一张image,然后用CNN来判断input的这张image对应着什么样的声音信号,通常用来判断结果的单位可以用phoneme(类似音标)。

用CNN处理语言的一个比较特别的点是:在convolution中通常只考虑在frequency(频率)方向上移动Filter,而不在时间的序列上移动。

这是因为在语音里面,CNN的output后面都还会再接别的东西,比如接LSTM之类,它们都已经有考虑时间有关的信息。那在频率上的filter有帮助的原因是,在声音讯号上,比如虽然男生和女生说同样的话看起来这个spectrogram是非常不一样的,但实际上他们的不同只是表现在一个频率的shift而已(整体在频率上的位移),男生说的“你好”跟女生说的“你好”,它们的pattern其实是一样的,它们的差别可能只是所在的频率范围不同而已,所以filter在frequency的direction上移动是有效的。

4.3. Text

CNN也可以用在文字处理上,假设input是一个word sequence,你要做的事情是让machine侦测这个word sequence代表的意思是positive的还是negative的。

首先把这个word sequence里面的每一个word都用一个vector来表示,vector代表的这个word本身的semantic (语义),那如果两个word本身含义越接近的话,它们的vector在高维的空间上就越接近,这叫做word embedding

把一个sentence里面所有word的vector排在一起,它就变成了一张image(一个matrxi),然后把CNN套用到这个image上,但是这时Filter的“高”和image的高是一样的,然后把Filter沿着句子里词汇的顺序来移动,每个filter移动完成之后都会得到一个由内积结果组成的vector,不同的filter就会得到不同的vector,接下来做Max pooling,然后把Max pooling的结果丢到fully connected layer里面,得到最后的output。

与语音处理不同的是,在文字处理上,filter只在时间的序列(按照word的顺序)上移动,而不在embedding的dimension上移动;因为在word embedding里面,不同dimension是independent的,它们是相互独立的,不会出现有两个相同的pattern的情况,所以在这个方向上面移动filter,是没有意义的。

——————

这一章举这三个例子是为了说明,虽然CNN很powerful,但在设计network structure去解决新的task的时候,都要根据所要解决的问题的特性,设计出合理合适的strcuture,包括Filter的尺寸,移动的方向,stride的大小;有无Max pooling等等很多因素,而不是生搬硬套已有的模式。所谓应用之道,存乎一心