卷积神经网络(一)——基础知识

為{幸葍}努か 提交于 2020-02-15 06:04:38

(一)卷积神经网络基础知识

(1) 卷积神经网络基本结构

卷积神经网络(Convolutional Neural Networks,CNN)是一类特殊的人工神经网络,其最主要的特点就是卷积运算。卷积其实就是一种效果的叠加。CNN 目前在图像相关任务上有很好的效果。如图像分类、语音分割、图像检索、目标检测等计算机视觉问题。
卷积神经网络是一种层次模型,其输入是原始数据,如RGB图像、音频等数据,通过卷积操作、池化操作、非线性激活函数等一系列操作的层层堆叠。目的是将高层语义信息逐层抽象出来,这一过程就是前向传播的过程。

卷积神经网络的组成部分
CNN层次结构 作用
输入层 网络原始输入,可以是原始或预处理后的像素矩阵
卷积层 参数共享、局部连接,利用平移不变性从全局特征图提取局部特征
激活层 将卷积层的输出结果进行非线性映射
池化层 进一步对特征进行筛选,可有效的减少网络所需的参数量
全连接层 将多维特征展平为2维特征,通常低维度特征对应任务的学习目标
1、输入层

输入的图片一般包含RGB三个通道,是一个由长宽分别为H和W组成的3维像素值矩阵HW3(图片默认的是通道是H W C,在处理的时候一般要将通道转换为C H W ),卷积网络会将输入层的数据传递到一系列卷积、池化等曹操做进行特征提取和转化,最终由全连接层对特征进行汇总和结果输出。若指定输入层接收到的图像个数为N,则输入层的输出数据为NHW*3.这里是引用

2、卷积层

卷积操作的原理上其实是对两张像素矩阵进行点乘求和的数学操作,其中一个矩阵为输入的数据矩阵,另一个矩阵则是卷积核(滤波器或特征矩阵),求得的结果表示为原始图像中提取的特定局部特征。

卷积提取的特征类型
卷积层次 特征类型
浅层卷积 边缘特征
中层卷积 局部特征
深层卷积 全局特征
卷积层的基本参数
参数名称 作用 常见设置
卷积核(Kernel Size) 卷积核大小定义了卷积的感受野 目前多设置为3*3的卷积核,通过堆叠卷积核达到更大的感受域。
卷积核步长(Stride) 定义了卷积核在卷积过程中移动距离 常见设置为1,当设置为更大值时相当于对特征组合降采样
填充方式(Padding) 在卷积核尺寸不能完美的匹配输入图像矩阵时,需要进行一定的填充策略 一种策略是用0填充,另一种是丢弃一部分特征信息
输入通道数(In Channels) 指定卷积操作时卷积核的深度 默认与输入的特征矩阵通道数(深度)一致,在某些压缩模型中会采用通道分离的卷积方式
输出通道数(out Channels) 指定卷积核的个数 若采用比输入通道更小的值,则可以减少整体网络的参数量
输出特征图大小的计算公式:

Out = (输入图片大小-卷积核大小 + 2 *padding)/步长 + 1

卷积操作示意图:

在这里插入图片描述
在这里插入图片描述

3、激活层

激活层负责对卷积层抽取的特征进行激活,由于卷积操作是由输入矩阵与卷积核矩阵进行相差的线性变化关系,需要激活层对其进行非线性映射,让输出的特征具有非线性关系,卷积网络中通常采用ReLu来充当激活函数。

4、池化层

池化层又称为降采样层,作用是对感受野中的特征进行筛选,提取区域内最具代表性的特征,能够有效的降低输出特征尺度,进而减少模型所需要的参数来嗯。
分类: 最大池化、平均池化、求和池化。常用的是前两种池化方式。

在这里插入图片描述

5、全连接层

全连接层负责对卷积神经网络学习提取到的特征进行汇总,将多维的特征输入映射为二维的特征输出。

(2) 感受野、局部连接、权值共享

1、感受野

感受野:即每个神经元仅与输入神经元相连接的一块区域。点击这篇博客有详细的介绍.

2、局部连接

在图像卷积操作中,神经元在空间维度上是局部连接,但在深度上是全连接。局部连接的思想是受启发于生物学里的视觉系统结构,视觉皮层的神经元就是仅用局部接受信息。对于二维图像,局部像素关联性较强,这种局部连接保证了训练后的滤波器能够对局部特征有最强的响应,使神经网络可以提取数据的局部特征。
对于一张10001000的输入图像,如果下一个隐藏层的神经元数目为10^6个,采用全连接则有1000100010 ^6 = 10 ^12 个权值参数。参数量如此巨大训练几乎很难,如果采用局部连接,隐藏层的每个神经元仅仅与图像中1010的局部图像相连接,那么此时的权值参数量为101010 ^6 = 10 ^8 ,直接减少了四个数量级。

3、权值共享

权值共享,即计算同一深度的神经元时采用的卷积核参数时共享的。简单的说,给一张输入图片,用一个滤波器去扫这张图片,滤波器里面的值叫权重,这张图片每个位置被相同的滤波器进行卷积,所以权重是一样的,也就是共享。需要注意,权重只是对同一深度切片的神经元时共享的。权值共享大大的降低了网络的训练难度。

(4) 卷积神经网络前向传播

用代码实现卷积神经网络的前向传播过程,更好的来理解卷积神经网络的工作。
""" 卷积神经网络前向运算就是计算最后的特征图,所以先根据特征图计算公式,计算出特征图的大小,作一个0矩阵。然后从通道层面切片分离出每个通道的权重和输入值,相乘并相加的结果填充到0矩阵的相应的位置。"""
# 首先步长为1时,stride = 1, padding=0    
import torch
import torch.nn as nn


def forward(x_input):
    weight = next(params)
    bias = next(params)
    # input_size
    n = x_input.shape[2]
    # kernel_size
    k = conv.kernel_size[0]  # (3, 3)
    # padding
    p = conv.padding[0]
    # stride
    s = conv.stride[0]
    # out_h = out_w (6-3+2*0)/1+1=4
    out_w = out_h = (n - k + 2 * p)//s + 1
    feature_map = torch.zeros(out_h, out_w)
    # print(feature_map)
    #  out = w*x + b
    for h in range(out_h): # 最后输出特征图矩阵的行
        # print("h=%s"%h)
        for w in range(out_w): # 特征图矩阵的列
            feature_map[h, w] = (weight[0, :] * x_input[0, :, h: h+k, w:w+k]).sum()
    feature_map += bias
    return feature_map


if __name__ == '__main__':
    x = torch.randn(1, 3, 6, 6)
    conv = nn.Conv2d(3, 1, 3, 1)
    params = conv.parameters()
    a = forward(x)
    print("系统计算结果", a)
    print("手动计算结果", conv(x))  # 这两个结果主要是为进行对比,看手动计算结果是否正确
# 步长为n时, stride = n ,padding = 0
import torch
import torch.nn as nn


def forward(x_input):
    weight = next(params)
    bias = next(params)
    # input_size
    n = x_input.shape[2]
    # kernel_size
    k = conv.kernel_size[0]  # (3, 3)
    # padding
    p = conv.padding[0]
    # stride
    s = conv.stride[0]
    # out_h = out_w (6-3+2*0)/2+1=2
    out_w = out_h = (n - k + 2 * p)//s + 1
    feature_map = torch.zeros(out_h, out_w)
    # print(feature_map)
    #  out = w*x + b
    in_h, in_w = x_input.shape[2], x_input.shape[3] 
    for i, h in enumerate(range(0, in_h, s)): # hang
        if h + k > in_h: # 卷积核在图片上面扫不能越界。网络默认将padding设为0.
            break
        for j, w in enumerate(range(0, in_w, s)): # lie
            if w + k > in_w:
                break
            feature_map[i, j] = (weight[0, :] * x_input[0, :, h: h+k, w:w+k]).sum()
    feature_map += bias
    return feature_map


if __name__ == '__main__':
    x = torch.randn(1, 3, 6, 6)
    conv = nn.Conv2d(3, 1, 3, 2)
    params = conv.parameters()
    a = forward(x)
    print("out1", a)
    print("out2", conv(x))

(5) 卷积神经网络反向传播

具体的理论知识请查看这篇博客,这里交代了前向和反向传播的数学过程。https://www.jianshu.com/p/2eb6116f62bb

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!