震惊!史上最详细深度学习与神经网络讲解(二)

卷积神经网络

为什么BP神经网络没有继续发展下去,总的来说有以下几个原因:

  • 全连接网络算的慢,难收敛
  • 可能进入局部极小值,也容易产生过拟合问题。
  • 参数量极高

因此随着目标检测,图像分类,语义分割的发展,卷积神经网络得到了进一步发展。

深度学习平台简介

在这里插入图片描述
在这里插入图片描述
目前,最主流的平台就是这些,其中最被大家熟知的就是TensorFlow和Pytorch,而目前使用最广泛的就是pytorch,所以如果大家想入手深度学习,那么就可以从Pytorch入手了。

pytorch简介

Pytorch 是一个Python的深度学习库。最初由Facebook人工智能研究小组开发,除了Facebook之外,Twitter、GWU和Sslesforce等机构都采用了Pytorch。到目前,据统计已有80%的研究采用PyTorch,包括Google.
Pytorch 与 TensorFlow2的的对比
在这里插入图片描述
PyTorch资源:

卷积神经网络进化史

卷积神经网络发展历史
大家看到这些网络结构的时候,一开始可能会有点蒙。但完全没必要,因为完全就是搭积木,一点一点搭建起来的。这不过在新的模型中会出现一些新的算法,例如残差网络,洗牌操作,多通道卷积,上采样特征融合等等。这张图片有点老,还应该加入YOLO,GPT等等。

卷积神经网络基础

卷积

在这里插入图片描述
卷积其实很好理解,就是一个卷积核在输入数据上进行移动,每移动一次,计算一次,最终生成一个新的数据。在创建神经网络时,能够进行设定的就是卷积核的大小,例如1*1,3*3,5*5,7*7。
在这里所涉及的一个就是卷积核的计算,基本上每初学者都会遇到这个问题,以输入数据的尺寸为64*256*256,输出为128*256*256,卷积核大小为3*3为例:

  • 首先可以看到输入输出的形状没变,这里就需要进行padding操作,接下来会讲解,先不急!
  • 可以看到输入的通道数是64,输出的通道数是128,那么卷积核的尺寸就是128*64*3*3,这种是标准卷积下对于卷积核的计算。
  • 还用一种卷积方法就是Depthwise,为了防止大家造成混乱,这里就先不讲解了,其实也不难,后续会陆续讲解。

池化

池化操作主要分成两种:最大值池化和均值池化。池化层也叫下采样层(Upsampling)均值池化就是对指定区域求均值作为说出,最大值池化就是对指定区域取最大值操作。同样,在搭建模型的时候,也可以使用下面步长公式进行计算,原理相同。
在这里插入图片描述
在这里插入图片描述

padding

在这里插入图片描述
好了,到了刚才提到的padding了。这个操作就是对输入数据的一周进行填充,当输入数据的形状是5*5,卷积核大小为3*3,为了让输出的形状是5*5,我们就需要对输入数据进行填充,这样就可以保证输出的形状不变,这是如何计算的呢,请接着看!

stride

这部分其实没啥可讲的,就是卷积核移动的步长,在建立模型的时候,需要通过设定stride,来获得不同尺寸输出,在这里只要记住一个公式就行:
H o u t = ⌊ H i n − K + 2 P S ⌋ + 1 H_{out}=\left\lfloor\frac{H_{in}-K+2P}S\right\rfloor+1 Hout=SHinK+2P+1
W o u t = ⌊ W i n − K + 2 P S ⌋ + 1 W_{out}=\left\lfloor\frac{W_{in}-K+2P}S\right\rfloor+1 Wout=SWinK+2P+1
其中 H i n H_{in} Hin代表输入数据的长, K K K代表卷积核的大小, P P P代表padding设置的值, S S S代表步长, H o u t H_{out} Hout代表输出数据的的长,下一个公式也是同样的。

前向计算

结合之前的图,前向传播定义为:
z [ l ] ( x , y ) = ∑ u = 0 p ∑ v = 0 q a [ l − 1 ] ( x + u , y + v ) w [ l ] , k ( u , v ) a [ l ] ( x , y ) = f ( z [ l ] ( x , y ) ) \begin{gathered}z^{[l]}(x,y)=\sum_{u=0}^p\sum_{v=0}^qa^{[l-1]}(x+u,y+v)w^{[l],k}(u,v)\\a^{[l]}(x,y)=f\left(z^{[l]}(x,y)\right)\end{gathered} z[l](x,y)=u=0pv=0qa[l1](x+u,y+v)w[l],k(u,v)a[l](x,y)=f(z[l](x,y))
这其实就是对filter内进行计算。
如果第L层是卷积+池化层,则:
a [ l ] ( x , y ) = downsample ( ∑ u = 0 p ∑ v = 0 q a [ l − 1 ] ( x + u , y + v ) w s ( u , v ) ) \begin{aligned}&a^{[l]}(x,y)=\text{downsample}\left(\sum_{u=0}^p\sum_{v=0}^qa^{[l-1]}(x+u,y+v)w_s(u,v)\right)\end{aligned} a[l](x,y)=downsample(u=0pv=0qa[l1](x+u,y+v)ws(u,v))

误差方向传播

对于卷积神经网络的误差反向传播,其实很好理解。首先需要结合上一篇文章讲解的BP算法的误差反向传播。
在这里插入图片描述
从这张图中可以看出,卷积神经网络的计算过程,其实就是一种局部连接计算,也是一种类似BP神经网络的计算过程。所以它的误差反向传播算法如下所示:

  • 如果当前是卷积层,下一层为下采样层:
    在这里插入图片描述
  • 如果当前是下采样层,下一层是卷积层:
    在这里插入图片描述
  • 卷积层+卷积层
    a [ l ] ( x 1 , y 1 ) = f ( ∑ u = 0 p ∑ v = 0 q a [ l − 1 ] ( x 1 + u , y 1 + v ) w [ l ] , k ( u , v ) ) . . . . . . . a [ l + 1 ] ( x i , y i ) = f ( ∑ u = 0 p ∑ v = 0 q a [ l ] ( x i + u , y i + v ) w [ l + 1 ] , k ( u , v ) ) \begin{gathered} a^{[l]}(x_1,y_1)=f\left(\sum_{u=0}^p\sum_{v=0}^qa^{[l-1]}(x_1+u,y_1+v)w^{[l],k}(u,v)\right) \\.......\\ \begin{aligned}a^{[l+1]}(x_i,y_i)&=f\left(\sum_{u=0}^p\sum_{v=0}^qa^{[l]}(x_i+u,y_i+v)w^{[l+1],k}(u,v)\right)\end{aligned} \end{gathered} a[l](x1,y1)=f(u=0pv=0qa[l1](x1+u,y1+v)w[l],k(u,v)).......a[l+1](xi,yi)=f(u=0pv=0qa[l](xi+u,yi+v)w[l+1],k(u,v))
    因此有:
    ∂ a [ l + 1 ] ( x i , y i ) ∂ w [ l ] , k = ∑ u = 0 p ∑ v = 0 q ∂ a [ l + 1 ] ( x i , y i ) ∂ a [ l ] ( x i + u , y i + v ) ⋅ ∂ a [ l ] ( x i + u , y i + v ) ∂ w [ l ] , k \frac{\partial a^{[l+1]}(x_i,y_i)}{\partial w^{[l],k}}=\sum_{u=0}^{p}\sum_{v=0}^{q}\frac{\partial a^{[l+1]}(x_i,y_i)}{\partial a^{[l]}(x_i+u,y_i+v)}\cdot\frac{\partial a^{[l]}(x_i+u,y_i+v)}{\partial w^{[l],k}} w[l],ka[l+1](xi,yi)=u=0pv=0qa[l](xi+u,yi+v)a[l+1](xi,yi)w[l],ka[l](xi+u,yi+v)
  • 卷积层+全连接层:
    卷积层:
    a [ l ] ( x 1 , y 1 ) = f ( ∑ u = 0 p ∑ v = 0 q a [ l − 1 ] ( x 1 + u , y 1 + v ) w [ l ] , k ( u , v ) ) . . . . . . a^{[l]}(x_1,y_1)=f\left(\sum_{u=0}^p\sum_{v=0}^qa^{[l-1]}(x_1+u,y_1+v)w^{[l],k}(u,v)\right)\\...... a[l](x1,y1)=f(u=0pv=0qa[l1](x1+u,y1+v)w[l],k(u,v))......
    全连接层:
    a [ l + 1 ] ( x i , y i ) = f ( ∑ u = 0 n ∑ v = 0 n a [ l ] ( x i + u , y i + v ) w [ l + 1 ] , k ( u , v ) ) a^{[l+1]}(x_i,y_i)=f\left(\sum_{u=0}^n\sum_{v=0}^na^{[l]}(x_i+u,y_i+v)w^{[l+1],k}(u,v)\right) a[l+1](xi,yi)=f(u=0nv=0na[l](xi+u,yi+v)w[l+1],k(u,v))
    因此有:
    ∂ a [ l + 1 ] ( x i , y i ) ∂ w [ l ] , k = ∑ u = 0 n ∑ v = 0 n ∂ a [ l + 1 ] ( x i , y i ) ∂ a [ l ] ( x i + u , y i + v ) ⋅ ∂ a [ l ] ( x i + u , y i + v ) ∂ w [ l ] , k \frac{\partial a^{[l+1]}(x_i,y_i)}{\partial w^{[l],k}}=\sum_{u=0}^n\sum_{v=0}^n\frac{\partial a^{[l+1]}(x_i,y_i)}{\partial a^{[l]}(x_i+u,y_i+v)}\cdot\frac{\partial a^{[l]}(x_i+u,y_i+v)}{\partial w^{[l],k}} w[l],ka[l+1](xi,yi)=u=0nv=0na[l](xi+u,yi+v)a[l+1](xi,yi)w[l],ka[l](xi+u,yi+v)

LeNet - 5网络

在这里插入图片描述
这其实是一个非常简单的网络模型,但也是非常经典的网络模型。
首先对输入数据做卷积->池化->卷积->池化->全连接->全连接层->输出层
与现在网络的区别:

  • 卷积时不进行填充
  • 池化层选用平均池化而非最大值池化
  • 选用Sigmoid或tanh而非ReLU作为非线性环节激活函数
  • 层数较浅,参数数量小

用PyTorch生成的LeNet网络模型:

import torch
import torch.nn as nn
import torch.nn.functional as F

class LeNet(nn.Module):
    def __init__(self):
        super(LeNet, self).__init__()
        # 定义LeNet的各个层
        self.conv1 = nn.Conv2d(1, 6, kernel_size=5)
        self.conv2 = nn.Conv2d(6, 16, kernel_size=5)
        self.fc1 = nn.Linear(16*4*4, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)  # 10类输出,对应10个数字
        
    def forward(self, x):
        # 定义数据流向
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
        x = F.max_pool2d(F.relu(self.conv2(x)), (2, 2))
        x = x.view(-1, self.num_flat_features(x))
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x
    
    def num_flat_features(self, x):
        size = x.size()[1:]  # 所有维度除了batch维度之外的维度
        num_features = 1
        for s in size:
            num_features *= s
        return num_features

# 创建LeNet模型实例
net = LeNet()
print(net)

基本卷积神经网络

AlexNet

在这里插入图片描述
改进:

  • 池化层均采用最大池化
  • 选用ReLU作为非线性环节激活函数
  • 网络规模扩大,参数数量接近6000万
  • 出现“多个卷积层+一个池化层”的结构

用PyTorch实现AlexNet网络模型:

import torch
import torch.nn as nn

class AlexNet(nn.Module):
    def __init__(self, num_classes=1000):
        super(AlexNet, self).__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
            nn.Conv2d(64, 192, kernel_size=5, padding=2),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
            nn.Conv2d(192, 384, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(384, 256, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
        )
        self.avgpool = nn.AdaptiveAvgPool2d((6, 6))
        self.classifier = nn.Sequential(
            nn.Dropout(),
            nn.Linear(256 * 6 * 6, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(4096, 4096),
            nn.ReLU(inplace=True),
            nn.Linear(4096, num_classes),
        )

    def forward(self, x):
        x = self.features(x)
        x = self.avgpool(x)
        x = torch.flatten(x, 1)
        x = self.classifier(x)
        return x

# 创建AlexNet模型实例
net = AlexNet()
print(net)

VGG16

在这里插入图片描述
改进

  • 网络规模进一步增大,参数数量为1.38亿
  • 卷积层、池化层的超参数基本相同,整体结构呈现出规整的特点
import torch
import torch.nn as nn

# 定义VGG16网络结构
class VGG16(nn.Module):
    def __init__(self, num_classes=1000):
        super(VGG16, self).__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(64, 64, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Conv2d(64, 128, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(128, 128, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Conv2d(128, 256, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Conv2d(256, 512, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Conv2d(512, 512, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),
        )
        self.avgpool = nn.AdaptiveAvgPool2d((7, 7))
        self.classifier = nn.Sequential(
            nn.Linear(512 * 7 * 7, 4096),
            nn.ReLU(True),
            nn.Dropout(),
            nn.Linear(4096, 4096),
            nn.ReLU(True),
            nn.Dropout(),
            nn.Linear(4096, num_classes),
        )

    def forward(self, x):
        x = self.features(x)
        x = self.avgpool(x)
        x = torch.flatten(x, 1)
        x = self.classifier(x)
        return x

# 实例化VGG16网络
vgg16 = VGG16()

# 打印网络结构
print(vgg16)

残差网络

梯度消失问题是指在深层神经网络中,梯度在反向传播过程中逐渐变小,最终接近零,导致深层层次的权重更新变得非常缓慢,甚至无法进行有效的学习。这通常发生在网络层数较深、激活函数导数接近于0的情况下。解决梯度消失问题,最好的方法莫过于残差连接。
在这里插入图片描述
传统连接方式的计算过程:
z [ l + 1 ] = w [ l + 1 ] a [ l ] + b [ l + 1 ] , a [ l + 1 ] = g [ l + 1 ] ( z [ l + 1 ] ) , z [ l + 2 ] = w [ l + 2 ] a [ l + 1 ] + b [ l + 2 ] , a [ l + 2 ] = g [ l + 2 ] ( z [ l + 2 ] ) z^{[l+1]}=w^{[l+1]}a^{[l]}+b^{[l+1]},a^{[l+1]}=g^{[l+1]}(z^{[l+1]}),z^{[l+2]}=w^{[l+2]}a^{[l+1]}+b^{[l+2]},a^{[l+2]}=g^{[l+2]}(z^{[l+2]}) z[l+1]=w[l+1]a[l]+b[l+1],a[l+1]=g[l+1](z[l+1]),z[l+2]=w[l+2]a[l+1]+b[l+2],a[l+2]=g[l+2](z[l+2])
残差连接方式的计算过程:
z [ l + 1 ] = w [ l + 1 ] a [ l ] + b [ l + 1 ] , a [ l + 1 ] = g [ l + 1 ] ( z [ l + 1 ] ) , z [ l + 2 ] = w [ l + 2 ] a [ l + 1 ] + b [ l + 2 ] , a [ l + 2 ] = g [ l + 2 ] ( a [ l ] + z [ l + 2 ] ) z^{[l+1]}=w^{[l+1]}a^{[l]}+b^{[l+1]},a^{[l+1]}=g^{[l+1]}(z^{[l+1]}),z^{[l+2]}=w^{[l+2]}a^{[l+1]}+b^{[l+2]},a^{[l+2]}=g^{[l+2]}(a^{[l]}+z^{[l+2]}) z[l+1]=w[l+1]a[l]+b[l+1],a[l+1]=g[l+1](z[l+1]),z[l+2]=w[l+2]a[l+1]+b[l+2],a[l+2]=g[l+2](a[l]+z[l+2])
残差连接可以通过跨层的信息流动来缓解梯度消失问题,使得深层网络的训练更加稳定。

  • 37
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值