卷积神经网络(CNN)学习笔记

卷积神经网络(CNN)

1.神经网络结构示意图如下

enter description here

相比于普通的神经网络,卷积神经网络多了卷积层以及池化层,还增加了许多特有名词,例如:填充、步幅、通道等。此外,各层中传输的数据是有形状的数据(比如三维数据)。下面开始介绍卷积层和池化层。

2.卷积层

首先,我们知道,全连接层存在一些问题,在处理三维数据时,向全连接层输入数据时,需要将三维数据拉成一维数据。这就导致了数据的形状被“忽视”了。全连接层会将全部的输入数据作为相同的神经元(同一维度的神经元)处理,所以无法利用与形状相关的信息。
而卷积层可以保持形状不变。当输入数据是图像时,卷积层会以3维 数据的形式接收输入数据,并同样以3维数据的形式输出至下一层。因此, 在CNN中,可以(有可能)正确理解图像等具有形状的数据。另外,CNN中,有时将卷积层的输入输出数据称为特征图(feature map)。其中,卷积层的输入数据称为输入特征图(input feature map),输出数据称为输出特征图(output feature map)。

2.1卷积运算

卷积层进行的处理就是卷积运算。下面举个例子:

enter description here

本例中,输入大小是 (4, 4),滤波器大小是(3, 3),输出大小是(2, 2),滤波器在有的例子中也被成为卷积核。
对于输入数据,卷积运算以一定间隔滑动滤波器的窗口并应用。这里所 说的窗口是指图中灰色的3×3的部分。

第一步
第二步
最后一步
enter description here

在上述图中,滤波器中的参数对应于全连接层的参数,CNN中也有偏置,但偏置通常只有一个。

2.2填充

在进行卷积层的处理之前,有时要向输入数据的周围填入固定的数据(比 如0等),这称为填充(padding),是卷积运算中经常会用到的处理。

enter description here

为什么要使用填充呢?使用填充主要是为了调整输出的大小。我们在每次进行卷积运算都会缩小空间,那么在某个时刻输出大小就有可能变为1,导致无法再应用卷积运算。为了避免出现这样的情况,就要使用填充。在刚才的例子中,将填充的幅度设为1,那么相对于输入大小(4, 4),输出大小也保持为原来的(4,4)。因此,卷积运算就可以在保持空间大小不变的情况下将数据传给下一层。

2.3步幅

应用滤波器的位置间隔称为步幅(stride)。下面是步幅为1和步幅为2的情况。

enter description here
enter description here

由2.2节和2.3节可知,增大步幅输出大小会变小,添加填充输出大小会变大。我们可以根据步幅和填充来计算输出大小。
假设输入大小为(H,W),滤波器大小为(FH,FW),输出大小为(OH,OW),填充为P,步幅为S。那么我们可以得到下面这个式子:

enter description here

2.4三维数据的卷积运算

对于图像来说,图像是三维数据,除了高、长方向之外,还需要处理通道方向。在进行卷积运算时候,当通道方向上有多个特征图时,会按通道 进行输入数据和滤波器的卷积运算,并将结果相加,从而得到输出。

enter description here
enter description here
enter description here
enter description here

我们需要注意的是,在三维的卷积运算中,输入数据和过滤器的通道数要保持一致。

我们可以把上述例子中的输入数据和过滤器当成长方体方块来考虑。把3维数据表示为多维数组时,书写顺序为(channel,height,width)。比如,通道数为C、高度为H、长度为W的数据的形状可以写成(C, H,W)。滤波器也一样,要按(channel,height,width)的顺序书写。比如,通道数为C、滤波器高度为FH(Filter Height)、长度为FW(Filter Width)时,可以写成(C,FH,FW)。

enter description here

如果我们要在通道方向上有多个卷积运算的输出,我们应该这样做,即用到多个滤波器。用图片表示如下:

enter description here

当考虑到滤波器的数量时,那么数据就变成了4维数据,滤波器的权重数据要按(output_channel,input_channel,height,width)的顺序书写。
在上图中,每个通道只有一个偏置。这里,偏置的形状是(FN,1,1), 滤波器的输出结果的形状是(FN,OH,OW)。这两个方块相加时,要对滤波 器的输出结果(FN,OH,OW)按通道加上相同的偏置值。另外,不同形状的 方块相加时,可以基于NumPy的广播功能轻松实现。

2.5卷积运算中的批处理

我们在卷积层进行批处理时,需要将在各层间传递的数据保存为4维数据。具体地讲,就是按(batch_num,channel,height,width)的顺序保存数据。

enter description here

上图批处理版的数据流中,在各个数据的开头添加了批用的维度。数据作为4维的形状在各层间传递。批处理中网络间传递的是4维数据,将N个数据进行打包处理,将N卷积运算汇成了一次卷积运算。

3.池化层

池化层是缩小高、长方向上的运算。下面是Max池化运算的示例:

enter description here

除了,Max池化外,还有Average池化。相对于Max池化是从目标区域中取出最大值,Average池化则是计算目标区域的平均值。 在图像识别领域,主要使用Max池化。

3.1池化层的特征

1.没有要学习的参数,池化只是从目标区域中取最大值(或者平均值),所以不存在要学习的参数。
2.通道数不发生变化,计算是按通道独立进行的。
3.对微小的数值变化具有鲁棒性(健壮),输入数据发生微小偏差时,池化仍会返回相同的结果

4.卷积层和池化层的实现

在这里我们使用了一个im2col函数。

enter description here

它能将一个包含批处理的四维数据转换成二维数据。
在滤波器的应用区域重叠的情况下,使用im2col展开后,展开后的元素个数会多于原方块的元素个数。因此,使用im2col的实现存在比普通的实现消耗更多内存的缺点。但是,汇总成一个大的矩阵进行计算,对计算机的计算颇有益处。

enter description here

上图是卷积运算的滤波器处理的细节:将滤波器纵向展开为1列,并计算和im2col展开 的数据的矩阵乘积,最后转换(reshape)为输出数据的大小。

4.1卷积层的实现

下面我们使用im2col来实现卷积层

class Convolution:
    # 初始化
    def __init__(self, W, b, stride = 1, pad = 0):
        self.W = W
        self.b = b
        self.stride = stride
        self.pad = pad
    
    def forward(self, x):
        (FN, C, FH, FW) = self.W.shape
        (N, C, H, W) = x.shape
        out_h = int(1 + (H + 2*self.pad - FH) / self.stride)
        out_w = int(1 + (W + 2*self.pad - FW) / self.stride)
        
        col = im2col(x, FH, FW, self.stride, self.pad)
        col_W = self.W.reshape(FN, -1) 
        #reshape函数会自动计算-1维度上的元素个数,以使多维数组的元素个数前后一致
        out = np.dot(col, col_W) + self.b
        
        out = out.reshape(N, out_h,out_w,-1).transpose(0, 3, 1, 2)
        # transpose会更改多维数组的轴的顺序。
        self.x = x
        self.col = col
        self.col_W = col_W
        
        return out
        
    def backword(self,dout):
        (FN,C,FH,FW) = self.W.shape
        dout = dout.transpose(0,2,3,1).reshape(-1,FN)
        # 改变损失中数组的轴的顺序,再用reshape转为二维数组
        
        self.db = np.sum(dout, axis=0)
        self.dW = np.dot(self.col.T, dout)
        self.dW = self.dW.transpose(1,0).reshape(FN,C,FH,FW)
        # 用reshape转为二维数组,再改变损失中数组的轴的顺序
        
        dcol = np.dot(dout,self.col_W.T)
        dx = col2im(dcol, self.x.shape, FH, FW, self.stride, self.pad)
        return dx

4.2池化层的实现

class Pooling:
    def __init__(self, pool_h, pool_w,stride=1,pad=0):
        self.pool_h = pool_h
        self.pool_w = pool_w
        self.stride = stride
        self.pad = pad
        
    def forward(self, x):
        (N, C, H, W) = x.shape
        out_h = int(1 + (H - self.pool_h) / self.stride)
        out_w = int(1 + (W - self.pool_w) / self.stride)
        col = im2col(x, self.pool_h, self.pool_w, self.stride, self.pad)
        col = col.reshape(-1, self.pool_h*self.pool_w)
        
        arg_max = np.argmax(col, axis = 1)
        out = np.max(col, axis = 1)
        out = out.reshape(N, out_h, out_w, C).reshape(0, 3, 2, 1)
        
        self.x = x
        self.arg_max = arg_max
        
        return out
        
    def backward(self, dout):
        dout = dout.transpose(0,2,3,1)
        
        pool_size = self.pool_h * self.pool_w
        dmax = np.zeros(dout_size, pool_size)
        dmax[np.arange(self.arg_max.size),self.arg_max.flatten()] = dout.flatten()
        dmax = dmax.reshape(dout.shape + (pool_size,))
        
        dcol = dmax.reshape(dmax.shape[0] * dmax.shape[1] * dmax.shape[2], -1)
        dx = col2im(dcol, self.x.shape,self.pool_h, self.pool_w,self.stride,self.pad)
        
        return dx

5.参数减少的原因

卷积神经网络参数映射参数比全连接层少的原因有两个:

5.1权重共享

enter description here

观察发现,特征检测如垂直边缘检测如果适用于图片的某个区域,那么它也可能适用于图片的其他区域。也就是说,如果你用一个 3×3 的过滤器检测垂直边缘,那么图片的左上角区域,以及旁边的各个区域(左边矩阵中蓝色方框标记的部分)都可以使用这个3×3的过滤器。每个特征检测器以及输出都可以在输入图片的不同区域中使用同样的
参数,以便提取垂直边缘或其它特征。它不仅适用于边缘特征这样的低阶特征,同样适用于高阶特征,例如提取脸上的眼睛,猫或者其他特征对象。

5.2稀疏连接

enter description here

结合图解释下这个概念,图中标记的0是通过3×3的卷积计算得到的,它只依赖于这个3×3的输入的单元格,右边这个输出单元(元素 0)仅与36个输入特征中9个相连接。而且其它像素值都不会对输出产生任影响,这就是稀疏连接的概念。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容