Pytorch深度学习实践 10 卷积神经网络(基础)

10.卷积神经网络(基础篇)_哔哩哔哩_bilibili

最近在 B站 刘二大人 学习PyTorch ,上传一些学习用的代码,仅供参考和交流。

目录

1、卷积层

2、池化层

3、ReLU函数

4、卷积神经网络


1、卷积层

        卷积神经网络中每层卷积层(Convolutional layer)由若干卷积单元组成,每个卷积单元的参数都是反向传播算法最佳化得到的。卷积运算的目的是提取输入的不同特征,第一层卷积层可能只能提取一些低级的特征如边缘、线条和角等层级,更多层的网路能从低级特征中迭代提取更复杂的特征,主要作用包括:

  • 特征提取:卷积层通过卷积操作可以有效地提取图像中的特征,如边缘、角点、纹理等。

  • 局部感受野:每个卷积核只关注输入数据的一个小区域,即局部感受野,有助于模型捕捉局部特征。在多个卷积层叠加下,网络能够逐渐整合这些局部特征以识别更复杂的模式。

  • 参数共享:在卷积层中,同一个过滤器的权重在整个输入图像上共享。权重共享大大减少了模型的参数数量,从而降低了过拟合的风险。

  • 平移不变性:由于参数共享的存在,卷积网络对输入图像的小幅平移具有一定的不变性。换句话说,即使图像中的对象稍微移动,卷积网络也可以有效地识别它。

  • 降低维度:通过使用步长(Stride)和池化层,卷积层可以降低数据的空间维度。

        那么,卷积层是如何计算的呢?

        卷积层作为一个3x3的窗口在输入层上面滑动,每个单元进行乘法运算,相当于矩阵运算中的点乘操作,最后相加得到处理后的结果,如图所示:

​        运算的结果为:

        上述是单个通道的卷积计算,在实际应用中,一般为彩色图片,具有R、G、B三个通道,需要将单个通道计算结果进行再次相加,如下图所示:

        那么经过卷积层后输出尺寸如何计算呢?

O=\frac{W-K+2P}{S}+1

        其中,W为输入的大小(宽度或者高度),K为卷积核的大小,P为填充的大小,S为步长。S表示卷积窗口移动的步长,P表示填充,常见的填充有三种:

  • 有效(Valid)或零填充(Zero-padding):P=0,不在输入图像周围添加额外的零值像素,最终会导致输出尺寸减小。

  • 相同(Same)填充: 通过设置P,使得卷积操作后输出的尺寸与输入尺寸相同。对于奇数大小的卷积核,可以通过P=(K-1)/2计算相同填充的大小:

  • 全填充(Full padding): 通过设置 P,使得卷积操作后输出的每个像素都由输入的所有像素参与计算。全填充会导致输出尺寸增加。

在程序中,通过torch.nn.Conv2d创建卷积层,代码如下:

# 创建 Conv2d 层
conv_layer = torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride)

  in_channels 表示输入通道的数量,out_channels 表示输出通道的数量,kernel_size 表示卷积核的大小,stride 表示卷积操作的步幅。

        在下图中,输入通道为n,输出通道为m,输出的尺寸可以根据公式计算,而这需要m组n通道的卷积核实现,假设卷积核为正方形,卷积核大小为k,卷积核表示为一个m✖n✖k✖k的张量。

2、池化层

        池化层用于降采样和减少特征映射的空间维度。最大池化和平均池化是两种常见的池化操作,它们分别选取池化窗口中的最大值或平均值,从而减小数据的空间尺寸。池化与卷积层类似,计算时只选取池化窗口中的最大值或平均值,而无须进行点乘相加操作。

        当窗口移动步长为stride=2时,最大池化计算如图所示:

        计算结果如下:

3、ReLU函数

        ReLU(Rectified Linear Unit)是深度学习中常用的激活函数之一。它是一种非线性函数,通常应用于神经网络的隐藏层,以引入非线性特性。

f(x)=max(0,x)

        即当输入x>0时,输出保持不变,否则,输出为0。

4、卷积神经网络

        卷积神经网络(Convolutional Neural Network,CNN)是一种专门用于处理具有网格状结构数据(如图像、语音)的深度学习模型,由一个或多个卷积层和顶端的全连通层组成,同时也包括关联权重核池化层(pooling layer)。本次学习所用数据集为MNIST数据集,可参考:PyTorch深度学习实践 09.多分类问题-优快云博客

        先使用两层卷积层、池化层进行特征提取,最后将输出的二维张量平铺为一维向量,使用全连接神经网络进行分类操作。在卷积层核池化层之间一般有激活函数,如sigmoid函数、ReLU函数,本次使用ReLU函数。

        完整代码如下:

import torch
import torch.nn as nn
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
import matplotlib.pyplot as plt

#加载数据集
batch_size=64
transform=transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.1307,),(0.3081,))
])

train_dataset=datasets.MNIST(root='../dataset/mnist/',
    train=True,
    download=False,
    transform=transform)
train_loader = DataLoader(train_dataset,
    shuffle=True,
    batch_size=batch_size)
test_dataset = datasets.MNIST(root='../dataset/mnist/',
    train=False,
    download=False,
    transform=transform)
test_loader = DataLoader(test_dataset,
    shuffle=False,
    batch_size=batch_size)

#构造模型
class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = torch.nn.Conv2d(1, 10, kernel_size=5)
        self.conv2 = torch.nn.Conv2d(10, 20, kernel_size=5)
        self.pooling = torch.nn.MaxPool2d(2)
        self.fc = torch.nn.Linear(320, 10)

    def forward(self, x):
        # flatten data from (n,1,28,28) to (n, 784)
        batch_size = x.size(0)#[batch_size,channels,height,width]]
        x = F.relu(self.pooling(self.conv1(x)))
        x = F.relu(self.pooling(self.conv2(x)))
        x = x.view(batch_size, -1)  # -1 此处自动算出的是320
        # print(x.shape)
        #x = x.view(batch_size, -1):将多维的特征图展平为一维向量。view函数是PyTorch中用于重塑张量的函数。batch_size参数保持不变,
        # 意味着每个样本在展平后仍然是独立的。-1表示让PyTorch自动计算这个维度应该有多少元素,以确保所有元素都包含在内且保持原来的批量大小不变。
        x = self.fc(x)

        return x

model=Net()

#定义损失函数
criterion=torch.nn.CrossEntropyLoss()#损失函数,不求均值
#定义优化器
optimizer=torch.optim.SGD(model.parameters(),lr=0.01,momentum=0.6)#SGD优化器,带动量

losses=[]
accs=[]
def train(epoch):
    running_loss=0.0
    for batch_idx,data in enumerate(train_loader,0):
        inputs,target=data
        optimizer.zero_grad()

        #forward+backward+update
        outputs=model(inputs)
        loss=criterion(outputs,target)
        loss.backward()
        optimizer.step()

        running_loss+=loss.item()
        if batch_idx%300==299:
            print('[%d %5d] loss:%.3f'%(epoch + 1, batch_idx + 1, running_loss / 300))
            losses.append(running_loss / 300)
            running_loss=0

def test():
    correct=0
    total=0
    with torch.no_grad():
        for data in test_loader:
            images,labels=data
            outputs=model(images)
            _,predicted=torch.max(outputs.data,dim=1)
            total+=labels.size(0)
            correct+=(predicted==labels).sum().item()
    acc=100*correct/total
    print('Accuracy on test set:%0.3f'%(acc))
    accs.append(acc)

if __name__=='__main__':
    for epoch in range(15):
        train(epoch)
        test()

    plt.figure(12)
    plt.plot(losses, label='loss')
    plt.xlabel('epoch')
    plt.ylabel('loss')
    plt.title('Variation of Cross-Entropy Loss')

    plt.figure(2)
    plt.plot(accs, label='acc')
    plt.xlabel('epoch')
    plt.ylabel('acc')
    plt.title('Accuracy Evolution')
    plt.show()

训练过程中损失函数值变化如下:

最终测试集准确率为98.8%,测试集准确率变化如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值