李宏毅ML笔记9:CNN

目录

为什么影像处理用CNN

一般的神经网络处理方式

如何减少参数

CNN架构

Convolution

Property 1

Property 2

特征映射

彩色图像

卷积与全连接对比

filter是特殊的neuron

基于“视野”概念产生的稀疏连接

“neuron”之间共享参数

CNN如何搭建, 如何训练

最大池化

最大池化操作

结果

Flatten

Keras实现CNN

卷积

池化

过程

卷积层中每一个filter的参数个数

CNN学到什么

分析filter

第k个filter被激活程度

分析神经元

分析输出

Deep Dream

Deep Style

应用

围棋

为什么围棋用CNN

property 1

property 2

最大池化?

Speech

Text

附录Appendix:CNN in Keras2.0


CNN的理论基础:

三个property

1. (局部感受野)Some patterns are much smaller than the whole image

2. (参数共享)The same patterns appear in different regions

3. (下采样)Subsampling the pixels will not change the object

两个架构

卷积:针对property 1, 2

池化:针对property 3

一个理念

应用之道,存乎一心.

为什么影像处理用CNN

一般的神经网络处理方式

输入用pixel来表示一张图片

即一个很长很长的vector,输出由图像类别组成的vector.

神经网络中每个neuron都代表classifier. 前面的层次对基础的信息识别分类, 后面的层次对整合的信息分类.

全连接前向传播网络做图像处理需要太多的参数:

如分辨率100*100的彩色图片,每个pixel其实需要3个value,即RGB值. 拉成一个vector,总共有100*100*3个pixel. 输入向量为三万维,假设第一层hidden layer有1000个neuron,参数有30000*1000个.

如何减少参数

1. 大部分的特征图像(pattern)比整张图片小很多, 一个神经元只需要连接到一小块区域.

2. 相同pattern会在不同区域出现, 但做的是同一件事, 侦测不需要定义两个分类器. 所以share同一组参数, 以减小参数量. (局部特征, 权值共享)

3. 图像可以做下采样(subsampling)以减少参数

如去除它奇数行、偶数列的pixel,变成十分之一大小,不影响人理解.

CNN架构

输入图片后,先经过卷积层(Convolution layer), 后最大池化(Max Pooling),再Convolution,再Max Pooling...反复数次(次数事先决定). 然后压平(Flatten),把Flatten的输出喂到全连接网络,得到影像辨识的结果.

CNN架构基于以上三个对影像处理的观察:

1. (局部感受野)侦测pattern,不需看整张图片,只要看图片的小部分;

2. (参数共享)同样的pattern会出现在图片的不同区域;

3. (下采样)可以对图片做下采样

property 1和2,用convolution layer处理;property 3,用max pooling处理.

Convolution

卷积层里,Filter(卷积核又名过滤器),等同Fully connected layer里的neuron.

input一张6*6的黑白图像,每个pixel对应一个value:

1

0

0

0

0

1

0

1

0

0

1

0

0

0

1

1

0

0

1

0

0

0

1

0

0

1

0

0

1

0

0

0

1

0

1

0

Property 1

Filter是矩阵,其中元素值类似于神经元的weight和bias,是网络的参数,Filter其值与其所做事情皆通过训练集学得.

filter是3*3的size,则侦测一个3*3 pixel的pattern,不看整张image,就可以判断某一个pattern有没有出现.

Property 2

filter与整张图片做卷积操作(operation).

filter从图像的左上角开始,做一个滑动窗口(slide window),每次向右挪动一定的距离stride(设stride=1), filter停下时跟图像中对应的3*3矩阵做内积(相同位置的值相乘并累计求和),到达图像右边缘时,从下一行的最左边开始重复进行上述操作,卷积完成得红色4*4 矩阵:

Filter1斜对角的地方是1,1,1,其目的为检测图像中从左上角到右下角的连续1,1,1,检测出现处(左上和左下)得到卷积结果最大值. 即该filter侦测的pattern出现在image的左上角和左下角. 内积值越大, 说明图像越相似

同一个pattern出现在image不同位置,不需要不同的filter,就可以侦测出来.

特征映射

卷积层中有很多filter,每个filter参数不同,但做卷积的过程都一样,做完卷积后,得到4*4矩阵, 称为Feature Map(特征映射),有多少个filter,对应就有多少个映射后的image.

CNN对不同scale的相同pattern的处理上存在困难,由于filter size相同,出现大的鸟嘴,小的鸟嘴,CNN不能自动处理;在CNN输入图像前,接另一个network,输出scalar,决定图像哪些位置做旋转、缩放,然后会得到比较好的结果.

彩色图像

黑白图像输入的是矩阵. 彩色图像由RGB组成(三个颜色表示一个pixel),几个matrix叠在一起的立方体, 输入是3*6*6.

彩色图像的filter也是立方体, filter就是3*3*3(高为3),卷积时把filter的3*9个值跟图像的3*9个值做内积. 每一个filter同时考虑不同颜色通道(channel).

参考: https://blog.csdn.net/qq_36537768/article/details/89648086

卷积与全连接对比

CNN的本质,就是减少参数的过程:

1. 卷积层检测图像的一部分, 即neuron只连接部分pixel,减少了对应连线weight参数;

2. 同一个filter检测不同位置,对卷积层是同一件事情,即不同的neuron连接到不同pixel对象,参数共享, 减少network的 weight参数.

filter是特殊的neuron

CNN就是一个神经网络, 卷积层是全连接层去除一些weight; 特征映射的输出是隐藏层神经元的输出(绿框):

卷积操作中, filter放在图片左上角做内积,得值3;等同于,图片的6*6矩阵拉直为输入向量,神经元输出3.

基于“视野”概念产生的稀疏连接

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

神经元算得输出值过程: filter放在图片左上角,考虑和它重合的9个pixel. 把6*6图像的36个pixel拉直为向量输入,9个pixel分别对应右侧编号1,2,3; 7,8,9; 13,14,15的pixel.

filter和图像矩阵做内积输出3,对应该神经元只连接到这9个pixel,连线的weight就是filter 矩阵里面9个数值. (圆圈的颜色与连线的颜色一一对应)

对比全连接神经元必须连接到所有36个input,CNN连接9个input(不需要看整张图片),此时参数更少.

“neuron”之间共享参数

filter做stride = 1的移动后, filter和图像矩阵内积得输出-1,设这个-1是另一个神经元的输出,该神经元连接到输入pixel 2,3,4; 8,9,10; 14,15,16.

输出为3和-1这两个神经元,分别检测图片不同位置上是否存在某pattern,在全连接层里做的是两件不同的事情,不同neuron有独立的weight.

卷积操作中,不仅每一个neuron前面连接的weight减少了,且output为3和-1的两个neuron共享同一组weight,虽然连接到的pixel对象不同,但weight等于filter里面的元素值,即weight share,减少了参数.

CNN如何搭建, 如何训练

一般用toolkit不会自己去写;如果自己写,与Backpropagation做法相同,只是有一些weight就永远是0,不去train它.

一些神经元共享weight值(永远一样), Backpropagation方法中对每个weight算梯度,再把需要share weight的weight梯度平均,让他们update同样值.

最大池化

最大池化操作

最大池化就是下采样(subsampling). 已根据filter 1,filter 2分别得到两个4*4矩阵.

把filter输出四个分为一组,每一组通过选取平均值或最大值,4个value合成一个value,相当于图像每相邻的四块区域内挑出一块来检测,让图像缩小.

取Maximum放到network里面后, 微分需要特殊的方法. (Maxout network)

结果

一次卷积加一次池化, 原6*6图像,变成2*2;其pixel的深度(每一个pixel用几个value表示),取决于有几个filter, 两个filter,则深度两维.

新的更小图像表示提取到的特征,不同filter检测同一区域上的不同特征属性,每一层channel(通道)代表一种属性,有几种属性,就有几层channel,有几个filter进行卷积操作. 该过程可重复多次, 卷积池化得到更更小的image.

设第一个卷积层有25个filter,得到25个feature map,第二个卷积层也有25个filter,得到feature map不是25^2个, 而是25个,因为卷积输入时考虑了深度,一次考虑所有的channel,即卷积多少个filter,输出多少个channel.

25个channel,经过含有25个filter卷积输出还是25个channel,但用的filter,都是cubic(立方体),高为25.

Flatten

卷积池化结束,接着Flatten和全连接前馈网络. Flatten指把左边的feature map拉直,然后输入全连接前馈网络.

CNN提取图像feature,相较于原图像vetor,小了很多且参数减少,但最终要全连接前馈网络做最后的分类工作.

Keras实现CNN

Keras实现CNN,在compile、training和fitting的部分同DNN,CNN需要改变的是network structure与输入格式(format).

DNN里输入为图像展开的向量,CNN考虑输入图像的几何空间,要输入tensor(高维vector),如三维vector,彩色图像长宽各是一维, RGB是第三维. 该高维矩阵为tensor.

卷积

model2.add( Convolution2D(25,3,3, input_shape=(28,28,1)) )

用model.add增加CNN的layer,将原先的Dense改成Convolution2D. 参数25,3,3中, 25代表有25个filter,3,3代表filter都是3*3矩阵. 参数input_shape为输入图像形状. input是28*28的image,pixel颜色单一,则值是(28,28,1),如果是RGB的话,1改成3.

池化

增加一层Max Pooling layer:

model2.add( MaxPooling2D(2,2) )

参数(2,2)指,把卷积得到的feature map,按2*2分割,选取最大值,组成新的小image,作为下采样结果.

过程

假设输入1*28*28的image. 通过25个filter的卷积层输出有25个channel, 当filter的size为 3*3,如果不考虑image边缘处的处理,得到channel为(28-2=)26*26,第一次卷积得到25*26*26的cubic image(image为长宽26,高25的cubic立方体).

相关知识: channel

https://www.bbsmax.com/A/pRdB7g6Pzn/

接下来就是做Max pooling,把2*2的pixel分为一组,然后从里面选一个最大的组成新的image,大小为25*13*13(cubic长宽各被砍掉一半)

再次convolution,假设这次用50个filter,size为3*3,输出的channel有50个,13*13的image,通过3*3的filter长宽会-2,变成11*11,得到50*11*11的image(长宽为11,高为50的cubic).

再次Max Pooling,变成50*50*5

卷积层中每一个filter的参数个数

第一个卷积层: 每一个filter是3*3矩阵, 有9个参数;

第二个卷积层: 每一个filter长宽3*3,由于输入是25*13*13的cubic含25个channel, filter高度同. filter为25*3*3的cubic,共225个参数.

两次卷积池化后,image size变成50*5*5,然后Flatten拉直为1250维的vector输入全连接前馈网络.

易混淆点:

第二次卷积输入是25*13*13的cubic,用50个3*3 filter,输出50个25*11*11的cubic?

真实情况:

用25*3*3的cubic filter对25*13*13的cubic input卷积,filter的每一层和input cubic中对应的每一层(channel),内积后,还要把25个channel的内积值累加最终得到标量scalar. 整个cubic filter对整个cubic input卷积操作后,得到一层scalar. 50个cubic filter,对应50层scalar,输出是50*11*11的cubic. 两个矩阵或者tensor做了卷积后,不管之前的维数如何,都会变为一个scalar,有50个filter,无论输入形状如何, 输出为50层.

CNN学到什么

DL是黑盒, 难以直观看出为什么得到该结果. 示范分析CNN学到什么.

第一个卷积层

filter为3*3矩阵,对应图像3*3=9个pixel,根据filter值,可知检测目标.

第二个卷积层

50个3*3的filter,其输入不是pixel,而是卷积池化结果,filter虽然长宽3*3高25的cubic,但视野范围远大于9个pixel,即使把weight拿出来,也不知道在做什么.

分析filter

第二个卷积层中50个filter,每个filter输出一个11*11矩阵,第k个filter的输出如下图所示,矩阵元素a^k_ij, 上标k表示第k个filter,下标ij表示矩阵i行j列:

第k个filter被激活程度

Degree of the activation of the k-th filter表示第k个filter,描述输入与第k个filter的接近程度,即对filter的激活程度. 定义: 该filter与input卷积的输出里所有元素累加.

输入一张图片, 把卷积输出的11*11个值全部加起来,即filter被激活的程度:

$$ a^{k} = {\sum_{i = 1}^{11}{\sum_{j = 1}^{11}a_{ij}^{k}}} $$

分析第k个filter的作用: 找一张image,使该filter被激活的程度最大;即 x使degree 最大:

$$ x^{*} = arg{\max\limits_{x}a^{k}} $$

求最小值用梯度下降,反之求最大值用gradient ascent(梯度上升法).

(原来训练CNN时,输入固定,模型参数用梯度下降找出)此时方向相反,用训练好的filter,模型固定参数,训练合适的input x,x为要找的参数,梯度上升进行更新, 使degree最大, 再把x可视化.

上图为得到结果的一部分,50个filter分别对应50张激活程度最大的图片. 图片共同特征为反复出现texture(纹路). 每个filter检测图上一个小范围,一旦出现小斜条纹,filter被激活,相应输出增大.

上图所示的filter检测不同角度的线条,filter找到激活程度最高的匹配对象,此时输出最大.

分析神经元

卷积池化后,将结果用Flatten展开,输入全连接神经网络,分析神经网络中神经元是做什么的,类似刚才的做法.

设第j个神经元输出a_j,梯度上升找image x,使其输入神经网络得到的值被最大化,即:

$$ x^{*} = arg{\max\limits_{x}a^{j}} $$

部分结果图:

与之前filter结果不同, 上次是纹路,因filter考虑图中一部分,只检测texture;Flatten后神经元看整张图,激活程度最大的图像是完整图形.

分析输出

手写数字识别的output有10维,找一张image x,使某维度的output值最大,即

$$ x^{*} = arg{\max\limits_{x}y^{i}} $$

输出的每一维对应一个数字,若使对应到数字1的那个输出层神经元输出值最大,则图片应该看起来像数字1.

但实际上,结果如下图:

上面图片分别对应数字0-8,image长得一点也不像1,像电视机坏掉的样子. 把上述得到的图片作为输入原CNN,分类结果确实对应数字0-8.

如何让图看起来更像数字?人类判断图片是不是数字,会有一些基本假设,对x正则化(regularization)加入constraint(限制约束), 不能再一味追求输出值大. constraint: 图片白色代表有笔画, 对于数字图像, 涂白区域有限,整张图白一定不会是数字. image中pixel用x_ij表示,把所有pixel值取绝对值并求和(L1的regularization),再用输出值减去这一项:

$$ x^{*} = arg{\max\limits_{x}\left( {y^{i} - {\sum_{i,j}\left| x_{ij} \right|}} \right)} $$

希望找的input x,让输出最大的同时,让x_ij之和越小越好,即图像大部分地方不涂颜色,只有数字笔画在的地方才有颜色出现.

加上constraint后,结果隐约有些数字形状:

还可加上其他constraint,如相邻pixel同样颜色.

Deep Dream

Deep Dream指给machine一张图片,它在图片里面加上它看到的东西.

将图片输入CNN,得某个卷积或全连接层的输出(vector);把本来值为正的维度中值调大,负的调小,(正的更正,负的更负),作为新的图像的target. 然后梯度下降法找x,使输出为调整后的target,让CNN夸大它看到的东西.

这样如果某个filter被激活,就能使其更剧烈,让它更像CNN看到的东西.

用该图片做Deep Dream得:

如右侧熊,原来是一个石头,机器看这石头有点像熊,强化让它真的变成熊.

Deep Style

风格迁移. 输入一张图, 让machine去修改这张图,让它有另外一张图的风格

具体的做法参考:https://arxiv.org/abs/1508.06576

图片输入CNN,得CNN filter的输出,代表图片内容,把'呐喊'图也输入CNN得filter输出. 此时重视filter和filter的输出之间的相关性(correlation), 这代表了图片的style.

再用CNN去找一张image,使content像左图,即filter 输出值像左图;同时使style像右图,即filter输出之间的correlation像右图.

梯度上升法同时maximize左边的content和右边的style得:

应用

围棋

CNN可以被运用到其他应用上,不只是影像处理,围棋(Playing Go)比如出名的alphaGo.

但下围棋,不一定用CNN,一般的神经网络也可以. 只需input棋盘当前局势,output是你下一步根据这个棋盘的盘势而应该落子的位置,全连接前馈网络也可. 设输入为19*19的vector,vector的dimension对应到棋盘上的位置,黑子1,白子-1,空位0,棋盘可描述成19*19的vector,输入神经网络,输出也是19*19个dimension , dimension棋盘上位置即可.

但CNN表现更好,图像input是矩阵,棋盘也可以表示19*19矩阵,就可以直接当成图片看待,再输出下一步落子位置.

训练过程:

搜集很多棋谱, 初手下在5之五,次手下在天元,然后再下在5之五,就告诉machine,看到落子在5之五,CNN的output就是天元的地方是1,其他是0.

以上是有监督部分, AlphaGo还有强化学习部分.

为什么围棋用CNN

自从AlphaGo用了CNN,都觉得CNN强,如果没有用CNN, 面试的人可能不知道CNN是什么 ,但是他就会问你为什么不用CNN呢,CNN不是比较强吗?知道什么时候用CNN,就可以怼回去.

适合用CNN情况: 有image特性如三个property,才设计CNN的network架构:

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小,在围棋类似,如一个白子被3个黑子围住叫做吃,下一个黑子落在白子下面,可以把白子提走;另一个白子接在下面,则不会被提走.

只需要看该范围,就可以侦测这个白子是不是属于被叫吃状态,不需要看整个棋盘. AlphaGo第一个layer用5*5的filter,设计者认为围棋基本pattern在5*5的范围可以被侦测.

property 2

同样的pattern可能会出现在不同的region,在围棋类似,叫吃pattern,可以在棋盘左上角,右下角,意义相同,可以用同一个filter检测处理.

最大池化?

可以图像下采样,拿掉奇数行、偶数列pixel,图像变小不会影响,才有了Max pooling layer;一个棋盘丢掉奇数行和偶数列,区别很大.

AlphaGo paper附录描述了其网络structure. 输入19*19*48图像,其中19*19是棋盘的格局,每个位置用48个value来描述(加上了domain knowledge观察其状态). 先用一个隐藏层做zero padding(图像外围补0),变成23*23, 然后k个5*5的filter卷积,stride设为1,激活函数ReLU,得输出为21*21 image;接着用k个3*3的filter,stride设为1,激活函数ReLU...

AlphaGo的网络架构一直卷积没有池化, 是根据围棋的特性,不需要在围棋的CNN里面,用Max pooling.

神经网络架构的设计,是应用之道,存乎一心

Speech

CNN也可以用在语音处理,把一段声音表示成语谱图(spectrogram),spectrogram横轴时间,纵轴声音频率.

下图中是一段“你好”的音频,红色代表该频率的energy较大,spectrogram用颜色来描述某一个时刻不同频率的能量.

可以让机器把这个spectrogram当作图片, 用CNN判断其对应声音信号如phoneme音标.

spectrogram输入CNN时,通常只在frequency(频率)方向上移动filter,如图为长方形,宽同image,filter只在Frequency即纵坐标方向移动,不在时间的序列上移动.

语音CNN的输出后还会再接别(LSTM)考虑时间, 但为什么要在频率上移动filter?

目的是同一个filter检测相同pattern,声音讯号中, 男生和女生说同样的话差别表现为整体在频率上的位移(shift).

应用时永远要想其特性是什么,根据特性设计网络架构.

Text

输入word sequence,让machine侦测其含义正面负面(positive, negative)

首先把word sequence里word都用vector表示,vector代表的word本身semantic (语义), word本身含义越接近, vector在高维的空间上越接近,即word embedding词嵌入.

把句子里所有词的vector排在一起,变成image,输入CNN,filter如图蓝色矩阵,高与image同,filter沿句子里词汇顺序移动,得到内积结果组成的vector,Max pooling结果输入全连接层得输出.

文字处理filter只在word的顺序上移动,而不在embedding上移动;因为word embedding不同dimension相互独立的,不会出现两个相同的pattern的情况移动没有意义.

CNN很强, 可以用在不同的地方,但是当应用到一个新的任务,要思考其架构.

附录Appendix:CNN in Keras2.0

写数字识别例子,DNN和加上CNN的对比

import numpy as np

from keras.models import Sequential

from keras.layers import Convolution2D, MaxPooling2D, Flatten, Conv2D

from keras.layers.core import Dense, Dropout, Activation

from keras.optimizers import SGD, Adam

from keras.utils import np_utils

from keras.datasets import mnist

# categorical_crossentropy

def load_mnist_data(number):

    # the data, shuffled and  split between train and test sets

    (x_train, y_train), (x_test, y_test) = mnist.load_data()

    x_train = x_train[0:number]

    y_train = y_train[0:number]

    x_train = x_train.reshape(number, 784)

    x_test = x_test.reshape(10000, 784)

    x_train = x_train.astype('float32')

    x_test = x_test.astype('float32')

    # convert class vectors to binary class matrices

    y_train = np_utils.to_categorical(y_train, 10)

    y_test = np_utils.to_categorical(y_test, 10)

    x_train = x_train / 255

    x_test = x_test / 255

    return (x_train, y_train), (x_test, y_test)

if __name__ == '__main__':

    (x_train, y_train), (x_test, y_test) = load_mnist_data(10000)

    # do DNN

    model = Sequential()

    model.add(Dense(input_dim=28 * 28, units=500, activation='relu'))

    model.add(Dense(units=500, activation='relu'))

    model.add(Dense(units=500, activation='relu'))

    model.add(Dense(units=10, activation='softmax'))

    model.summary()

    model.compile(loss='categorical_crossentropy',

                  optimizer='adam', metrics=['accuracy'])

    model.fit(x_train, y_train, batch_size=100, epochs=20)

    result_train = model.evaluate(x_train, y_train)

    print('\nTrain Acc:\n', result_train[1])

    result_test = model.evaluate(x_test, y_test)

    print('\nTest Acc:\n', result_test[1])

    # do CNN

    x_train = x_train.reshape(x_train.shape[0], 1, 28, 28)

    x_test = x_test.reshape(x_test.shape[0], 1, 28, 28)

    model2 = Sequential()

    model2.add(Conv2D(25, (3, 3), input_shape=(

        1, 28, 28), data_format='channels_first'))

    model2.add(MaxPooling2D((2, 2)))

    model2.add(Conv2D(50, (3, 3)))

    model2.add(MaxPooling2D((2, 2)))

    model2.add(Flatten())

    model2.add(Dense(units=100, activation='relu'))

    model2.add(Dense(units=10, activation='softmax'))

    model2.summary()

    model2.compile(loss='categorical_crossentropy',

                   optimizer='adam', metrics=['accuracy'])

    model2.fit(x_train, y_train, batch_size=100, epochs=20)

    result_train = model2.evaluate(x_train, y_train)

    print('\nTrain CNN Acc:\n', result_train[1])

    result_test = model2.evaluate(x_test, y_test)

    print('\nTest CNN Acc:\n', result_test[1])

 

 

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值