欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

《三分钟了解》系列 一: CNN卷积神经网络

程序员文章站 2024-02-26 16:06:16
...

对于深度学习入门我至少尝试过2次了,每次都是连门在哪儿没找到就撤回来了。。。不过这次不一样,毕竟我.....要开始新课题了。昨天开始刷莫烦Python和吴恩达的教学视频,配合过去2年在OPTIMAL的“耳濡目染”(虽然我不做深度,但实验室全是搞深度的  (^-^)V),边学边感叹。。。原来是这个样子噢。

接下来,我会将自己在整个深度学习过程中遇到的问题,学习到的基本框架都记录下来,也希望看到的老师朋友们能顺手指点一下。。。


今天是第一个三分钟:《CNN卷积神经网络》(本系列将全部采用PyTorch框架在Linux服务器上来进行网络的搭建)

目录: 

  • 卷积 filter
  • **函数 activation function
  • 池化层 pooling layer
  • 全连接层 fully connection layer
  • 使用pytorch快速搭建一个简单的CNN

一、卷积运算

CNN(convolutional neural networks)的核心也就是这个convolution。它与数学上的卷积有着联系又有很大不同。

(1)一维卷积

在高等数学中我们都学过卷积运算,f(t)和g(t)在连续空间上的卷积是:

《三分钟了解》系列 一: CNN卷积神经网络

观察公式:先将g(t)做一个关于Y轴的翻转 g(-t),然后沿着X轴平移x得到g(x-t),之后再将其与f(t)对应相乘,然后再求积分。这是一维连续卷积。说人话就是:卷积就是两个变量在某一个范围上对应相乘然后再对其进行求和的过程。(注意有个翻转概念

离散卷积 把积分变成求和即可。

      (2)二维离散卷积

数学上二维离散卷积的定义是:

《三分钟了解》系列 一: CNN卷积神经网络

f 是一个m*n的矩阵(上面的*表示卷积运算,这里的*是乘号)

 《三分钟了解》系列 一: CNN卷积神经网络《三分钟了解》系列 一: CNN卷积神经网络

                              

 计算( f * g)(1,1),也就是以下两个矩阵做卷积:(注意下标的不同)

 《三分钟了解》系列 一: CNN卷积神经网络

结果: 

 《三分钟了解》系列 一: CNN卷积神经网络

也就是说卷积核在计算时,要先沿着中心旋转180度,然后再与框口内元素对应相乘后相加。 

(3) CNN中的卷积本质是一个图像的空间滤波

数字图像处理中,我们学过空间滤波操作:a) 平滑滤波     b)边缘提取。这类操作就是提前设计一个“卷积核”(也叫滤波算子)然后将其与像素矩阵元素对应相乘(不进行上述的翻转运算)。图像处理中 卷积的作用 ,就是提图像的特征(feature)。比如要提取图像的边缘,那就用边缘检测算子去跟原始图像做卷积。例如:sobel算子,Roberts算子等 

《三分钟了解》系列 一: CNN卷积神经网络

 两个卷积之间的联系和差别:

最直观的就是:是否进行翻转。本质上来说就是用途不一样。CNN就是为了提特征而产生的。

但他们都有一个共同的特点:“加权求和”。

学到这里我就迷惑了。在数学中卷积核都要自己给定,一定是提前设定好的。但是CNN中的卷积核,假如要预先给定的话,那可能人要累死啊,假如要做200个卷积核那也要自己设定???后来发现不是这样滴!!!CNN中的卷积核本就是要训练的参数,它是根据训练学习得到的。其中从这里也可以推翻前面说数学卷积和CNN卷积不同的所有论证:既然都是学习到的,那么在计算过程中翻转与否都是没有关系的。所以我觉得数学上的卷积和CNN中的卷积本质其实是一样的。(那我为什么写了这么多)


二、**函数 (activation function)

《三分钟了解》系列 一: CNN卷积神经网络《三分钟了解》系列 一: CNN卷积神经网络

假如有三个卷积核,那么经过卷积操作之后就可以得到3个feature map。 卷积运算也是一个线性的运算过程。

在CNN中,由于线性模型的表达能力不够,因此需要假如一个非线性的因素。

主要的**函数有:

 

《三分钟了解》系列 一: CNN卷积神经网络

 以ReLU为例,它将所有feature map中的所有负特征全部变为0。说人话就是,在CNN中, 卷积之后得到了很多特征,但是这些并不都是能为最终结果服务的特征,经过**函数后,将得到的线性特征扭曲做非线性操作。这也就是**函数的作用。


三、池化层 pooling layer

       pooling 其实就是一个下采样的过程。卷积之后得到的特征并不都是我们需要的,比如说要分辨猫和树,胳膊腿可能是比较重要的特征,而纹理边缘可能不是那么重要的。深度学习一般都会产生大量数据,因此下采样得到能为最终目的服务的重要特征,进一步减小数据量就是很关键了。

     一般来说,池化方式有三种:Max-pooling(最大值池化)、Average-pooling(均值池化)和Stochastic-pooling(随机池化)。

以Max-pooling举例:2X2的池化窗口滑动

 

《三分钟了解》系列 一: CNN卷积神经网络《三分钟了解》系列 一: CNN卷积神经网络

《三分钟了解》系列 一: CNN卷积神经网络

明显地减少了数据量。

CNN学习到这里我们可以了解到提取特征的三剑客组合,一般来说CNN这几个过程都是交替出现的:

                                                              conv+relu+pooling


 四、全连接层 fully connection layer

《三分钟了解》系列 一: CNN卷积神经网络

以分类为例,提取完图像的所有高级特征之后,将feature map通过一个全连接层映射到一个可分类的线性空间。全连接层的输入是多层feature map,输出是一个列向量。(将feature map reshape,然后送入输入层输出判别结果)

 

以上就是CNN的基本概念。下面是几个有名的CNN结构: 具体内容可以观看斯坦福李飞飞的CS231n课程。

LeNet:最古老的也是第一个成功的CNN应用

AlexNet:2012年提出的,应该是这个直接推进了CNN的发展,转到各个应用领域。使用了层叠的卷积层来提取特征(通常是一个conv下来是一个pooling)

ZF Net:增加了中间卷积层的尺寸,让第一层的stride 和filter size更小。

GoogLeNet :没有全连接层,用max pooling来代替了。减少了大量的网络参数

VGGNet:3x3的卷积层2x2的pooling层从头到尾堆叠

ResNet: 引入了跨层连接和batch normalization

DenseNet:跨层连接,从头至尾


五、快速搭建一个CNN

核心代码:

class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.conv1 = nn.Sequential(            # input shape (1, 28, 28)
            nn.Conv2d(
                in_channels=1,                  # input height or band RGB=3,GREY=1
                out_channels=16,                # n_filters
                kernel_size=5,                  # filter size
                stride=1,                       # filter movement/step
                padding=2                       # if want same width and length of this image afer Conv2d, padding=(kernel_size-1)/2 if stride
            ),                                  # output shape (16, 28, 28)
            nn.ReLU(),                          # activation
            nn.MaxPool2d(kernel_size=2),        # choose max value in 2x2 area, output shape (16, 14, 14)
        )
        self.conv2 = nn.Sequential(             # input shape (16, 14, 14)
            nn.Conv2d(16, 32, 5, 1, 2),         # output shape (32, 14, 14)
            nn.ReLU(),                          # activation
            nn.MaxPool2d(2),                    # output shape (32, 7, 7)
        )
        self.out = nn.Linear(32 * 7 * 7, 10)    # fully connected layer, output 10 classes

    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = x.view(x.size(0), -1)               # flatten the output of conv2 to (batch_size, 32 * 7 *7)
        output = self.out(x)
        return output                      # return x for visualization


cnn = CNN()
print(cnn)     # net architecture

optimizer = torch.optim.Adam(cnn.parameters(), lr=LR)      # optimize all cnn parameters
loss_func = nn.CrossEntropyLoss()