从0搭建卷积神经网络(CNN)--详细教学

目录

一、卷积神经网络介绍

1、简介

经典CNN架构

2、与传统神经网络区别

3、卷积神经网络的结构

(1) 卷积层(Convolutional Layer)

(2) 激活函数(Activation Function)

(3) 池化层(Pooling Layer)

(4) 全连接层(Fully Connected Layer)

二、卷积神经网络的原理

1、卷积层(Convolutional Layer)

2、激活函数层(Activation Function Layer)

3、池化层(Pooling Layer)

4、全连接层(Fully Connected Layer)

5、反向传播(Backpropagation)

三、卷积神经网络的搭建过程

1、卷积层的构建方法

2、激活层的构建方法

3、池化层的构建方法

4、全连接层的构建方法 

四、卷积神经网络代码实践

1、导入相应的库

2、数据集加载

3、选择训练工具(这里是GPU)

4、构建卷积神经网络

5、将模型传入GPU、打印检查是否有误

6、构建优化器和损失函数

7、定义训练和测试函数

 8、调用训练和测试函数

9、完整代码展示

 10、结果展示


一、卷积神经网络介绍

1、简介

卷积神经网络(CNN)是一种专门用于处理网格状数据(如图像、视频、音频)的深度学习模型。其核心思想是通过卷积操作自动提取数据的空间或时序特征,广泛应用于计算机视觉、自然语言处理等领域。

经典CNN架构
模型提出时间主要贡献应用场景
LeNet-51998首个成功的手写数字识别CNNMNIST 分类
AlexNet2012引入ReLU、Dropout,赢得ImageNet竞赛图像分类
VGGNet2014深层的3x3卷积堆叠,结构简洁通用视觉任务
ResNet2015残差连接解决深层网络梯度消失问题图像分类/检测
YOLO2016单阶段目标检测,实时性高目标检测

2、与传统神经网络区别

  • 传统神经网络:传统神经网络对输入数据的处理是基于全连接的方式,神经元与输入数据的每个元素都有连接。这意味着输入数据中目标的位置发生变化时,网络需要重新学习该目标的特征。因为对于传统神经网络而言,不同位置的相同特征在输入层对应的神经元是不同的,所以不具备画面不变性。

  • 卷积神经网络:卷积神经网络通过卷积层中的卷积核在输入图像上滑动进行卷积操作,提取特征。由于卷积核的参数共享机制,无论目标在图像中的哪个位置,只要其特征模式与卷积核匹配,就能够被检测到。因此,卷积神经网络天然具有画面不变性。

3、卷积神经网络的结构

(1) 卷积层(Convolutional Layer)
  • 功能:通过滑动窗口(卷积核)在输入数据上提取局部特征。

  • 关键参数

    • 卷积核(Filter):权重矩阵,用于捕捉特征(如边缘、纹理)。

    • 步长(Stride):卷积核每次滑动的距离。

    • 填充(Padding):在输入边缘补零,控制输出尺寸。

  • 输出:生成特征图(Feature Map)

(2) 激活函数(Activation Function)
  • 作用:引入非线性,增强模型表达能力。

  • 常用函数:ReLU(修正线性单元)、Sigmoid、Leaky ReLU。

(3) 池化层(Pooling Layer)
  • 功能:降低特征图的空间维度,减少计算量并增强平移不变性。一种降采样,减小数据的空间大小,因此参数的数量和计算量也会下降,这在一定程度上也控制了过拟合。

  • 类型

    • 最大池化(Max Pooling):取窗口内最大值。

    • 平均池化(Average Pooling):取窗口内平均值。

(4) 全连接层(Fully Connected Layer)
  • 功能:将提取的特征映射到最终输出(如分类结果)。

  • 位置:通常位于网络末端。

二、卷积神经网络的原理

1、卷积层(Convolutional Layer)

  • 卷积操作:这是 CNN 的核心操作。卷积层通过卷积核(也叫滤波器)在输入数据(如图像)上滑动,对每个位置进行局部的加权求和运算。例如,对于一个二维图像,卷积核是一个小的二维矩阵,在图像上按照一定的步长(stride)滑动,每次滑动时,卷积核与图像上对应的局部区域进行元素相乘并求和,得到一个输出值。

  • 特征提取:不同的卷积核可以提取不同的特征。例如,一些卷积核可能提取图像中的边缘信息,另一些可能提取纹理信息。通过多个不同的卷积核,可以从输入数据中提取丰富多样的特征。

  • 参数共享:卷积核在滑动过程中,其参数是固定不变的。这意味着无论卷积核在图像的哪个位置,它对局部区域的处理方式都是相同的。这种参数共享机制大大减少了网络的参数数量,降低了计算复杂度,同时也使得网络能够更有效地学习到图像的平移不变性特征。

2、激活函数层(Activation Function Layer)

  • 常见的激活函数有 ReLU(Rectified Linear Unit,修正线性单元)、Sigmoid、Tanh 等。激活函数的作用是为神经网络引入非线性因素。因为如果没有激活函数,神经网络只是线性的组合,其表达能力有限,只能处理线性可分的问题。而引入激活函数后,神经网络可以学习和表示更复杂的非线性关系。例如,ReLU 函数在输入大于 0 时直接输出输入值,在输入小于 0 时输出 0,它能够有效地解决梯度消失问题,并且计算速度快,在 CNN 中被广泛使用。

3、池化层(Pooling Layer)

  • 下采样操作:池化层主要用于对卷积层输出的特征图进行下采样,降低特征图的尺寸。常见的池化方法有最大池化(Max Pooling)和平均池化(Average Pooling)。最大池化是在每个池化窗口中取最大值作为输出,平均池化则是计算池化窗口内的平均值作为输出。

  • 作用:通过池化操作,一方面可以减少网络的计算量和参数数量,提高计算效率;另一方面可以在一定程度上增强网络对输入数据的平移、旋转和尺度变化的鲁棒性,使网络学习到更具代表性的特征。

4、全连接层(Fully Connected Layer)

  • 经过多层卷积和池化操作后,将提取到的特征图展平成一维向量,然后输入到全连接层。全连接层中每个神经元与上一层的所有神经元都有连接,其作用是对前面提取到的特征进行综合和分类。例如,在图像分类任务中,全连接层可以根据前面提取的特征判断输入图像属于哪个类别。

  • 通常,全连接层的最后一层会使用合适的激活函数(如 Softmax 用于多分类问题)来输出分类结果,Softmax 函数可以将输出值转换为概率分布,每个值表示输入数据属于相应类别的概率。

5、反向传播(Backpropagation)

  • 在训练 CNN 时,使用反向传播算法来更新网络的参数(卷积核的权重和偏置等)。首先,根据网络的预测结果和真实标签计算损失函数(如交叉熵损失函数),衡量预测结果与真实值之间的差异。然后,通过反向传播算法,从输出层开始,将损失函数关于每个参数的梯度逐层反向传播到网络的输入层。最后,根据计算得到的梯度,使用优化算法(如随机梯度下降、Adam 等)更新网络的参数,使得损失函数逐渐减小,从而提高网络的性能。

三、卷积神经网络的搭建过程

在搭建网络只之前要先设计和模型的形状结构,多少层网络、使用什么激活函数、在哪里添加池化层等。

1、卷积层的构建方法

nn.Conv2d(in_channels=1, # 输入图片的通道数
out_channels=32, # 卷积核的个数
kernel_size=5, # 卷积核的大小
stride=1, # 移动步长
padding=2) # 边缘填充层数

2、激活层的构建方法

nn.ReLU()

3、池化层的构建方法

nn.MaxPool2d(2)

4、全连接层的构建方法 

nn.Linear(64*7*7,out_features=10)

四、卷积神经网络代码实践

举例描述:以手写数字数据集作为例子,用卷积神经网络进行训练。

1、导入相应的库

import  torch
print(torch.__version__)
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor

2、数据集加载

# 训练集
training_data = datasets.MNIST(
    root='data', # 路径
    train=True, # True为训练集False为测试集
    download=True, # 下载后就不重复下载
    transform=ToTensor() # 转换为张量
)

# 测试集
test_data = datasets.MNIST(
    root='data',
    train=False,
    download=True,
    transform=ToTensor()
)
print(len(training_data))


train_dataloader = DataLoader(training_data, batch_size=32)
test_dataloader = DataLoader(test_data, batch_size=32)
for X, y in test_dataloader:
    print(f'Shape of X [N,C,H,W]:{X.shape}')
    print(f'Shape of y:{y.shape},{y.dtype}')
    break

3、选择训练工具(这里是GPU)

device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
print(f"Using {device} device")

4、构建卷积神经网络

class CNN(nn.Module):
    def __init__(self):
        super(CNN,self).__init__()
        self.conv1 = nn.Sequential(
            nn.Conv2d(in_channels=1,out_channels=32,kernel_size=5,stride=1,padding=2),
            nn.ReLU(),
            nn.Conv2d(32,16,5,1,2),
            nn.ReLU(),
            nn.MaxPool2d(2) # 14*14
        )
        self.conv2 = nn.Sequential(
            nn.Conv2d(16,32,5,1,2),
            nn.ReLU()

        )
        self.conv3 = nn.Sequential(
            nn.Conv2d(32,16,5,1,2),
            nn.ReLU(),
            nn.Conv2d(16,28,5,1,2),
            nn.ReLU(),

        )
        self.conv4 = nn.Sequential(
            nn.Conv2d(28,64,5,1,2),
            nn.ReLU(),
            nn.MaxPool2d(2)  # 7*7
        )
        self.out = nn.Linear(64*7*7,out_features=10)

    def forward(self,x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = self.conv3(x)
        x = self.conv4(x)
        x = x.view(x.size(0),-1)
        output = self.out(x)
        return output

5、将模型传入GPU、打印检查是否有误

model = CNN().to(device)
print(model)

6、构建优化器和损失函数

loss_fn = nn.CrossEntropyLoss()  # 交叉熵损失函数
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)  # 优化器,lr为步长学习率

7、定义训练和测试函数

# 训练
def train(dataloader, model, loss_fn, optimizer):
    model.train()  # 开始训练,w可以改变,与测试中的model.eval()相对应
    batch_size_num = 1
    for X, y in dataloader:
        X, y = X.to(device), y.to(device)  # 将数据传入Gpu
        pred = model.forward(X)  # 前向传输,model的数据来自模型的out
        loss = loss_fn(pred, y)  # 通过交叉熵损失函数计算loss,pred为预测值,y为真实值
        optimizer.zero_grad()  # 优化,梯度值清零
        loss.backward()  # 反向传播计算每个参数的梯度值W
        optimizer.step()  # 根据梯度更新W
        loss_value = loss.item()  # 从tensor数据中提取数据出来,转换成对应的整数或者浮点数
        if batch_size_num % 200 == 0:
            print(f"loss: {loss_value:>7f} [number:{batch_size_num}]")
        batch_size_num += 1


# 测试集
def test(dataloader, model, loss_fn):
    size = len(dataloader.dataset)
    num_batches = len(dataloader)
    model.eval()  # 测试,w不可更新
    test_loss, correct = 0, 0  # 初始化损失值以及正确率
    with torch.no_grad():  # 一个上下文管理器,关闭梯度计算
        for X, y in dataloader:  # 提取测试集的数据
            X, y = X.to(device), y.to(device)
            pred = model.forward(X)  # 预测结果
            test_loss += loss_fn(pred, y).item()  # test_loss会自动累加每一批次的损失值
            correct += (pred.argmax(1) == y).type(torch.float).sum().item()  # pred.argmax(1)返回每一行中最大值对应的索引号
            a = (pred.argmax(1) == y)  # 比较预测值与正确标签是否相同,返回True或者False
            b = (pred.argmax(1) == y).type(torch.float)  # 将True-->1,False-->0,便于统计正确率
    test_loss /= num_batches
    correct /= size
    print(f"Test result: \n Accuracy: {(100 * correct)}%,Avg loss:{test_loss}")

 8、调用训练和测试函数

这里训练10轮测试一次

epoch = 10
for i in range(epoch):
    print('第{}轮训练'.format(i))
    train(train_dataloader, model, loss_fn, optimizer)
test(test_dataloader, model, loss_fn)

9、完整代码展示

import  torch
print(torch.__version__)
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor

# 训练集
training_data = datasets.MNIST(
    root='data', # 路径
    train=True, # True为训练集False为测试集
    download=True, # 下载后就不重复下载
    transform=ToTensor() # 转换为张量
)

# 测试集
test_data = datasets.MNIST(
    root='data',
    train=False,
    download=True,
    transform=ToTensor()
)
print(len(training_data))


train_dataloader = DataLoader(training_data, batch_size=32)
test_dataloader = DataLoader(test_data, batch_size=32)
for X, y in test_dataloader:
    print(f'Shape of X [N,C,H,W]:{X.shape}')
    print(f'Shape of y:{y.shape},{y.dtype}')
    break
device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
print(f"Using {device} device")

class CNN(nn.Module):
    def __init__(self):
        super(CNN,self).__init__()
        self.conv1 = nn.Sequential(
            nn.Conv2d(in_channels=1,out_channels=32,kernel_size=5,stride=1,padding=2),
            nn.ReLU(),
            nn.Conv2d(32,16,5,1,2),
            nn.ReLU(),
            nn.MaxPool2d(2) # 14*14
        )
        self.conv2 = nn.Sequential(
            nn.Conv2d(16,32,5,1,2),
            nn.ReLU()

        )
        self.conv3 = nn.Sequential(
            nn.Conv2d(32,16,5,1,2),
            nn.ReLU(),
            nn.Conv2d(16,28,5,1,2),
            nn.ReLU(),

        )
        self.conv4 = nn.Sequential(
            nn.Conv2d(28,64,5,1,2),
            nn.ReLU(),
            nn.MaxPool2d(2)  # 7*7
        )
        self.out = nn.Linear(64*7*7,out_features=10)

    def forward(self,x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = self.conv3(x)
        x = self.conv4(x)
        x = x.view(x.size(0),-1)
        output = self.out(x)
        return output

model = CNN().to(device)
print(model)

loss_fn = nn.CrossEntropyLoss()  # 交叉熵损失函数
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)  # 优化器,lr为步长学习率

# 训练
def train(dataloader, model, loss_fn, optimizer):
    model.train()  # 开始训练,w可以改变,与测试中的model.eval()相对应
    batch_size_num = 1
    for X, y in dataloader:
        X, y = X.to(device), y.to(device)  # 将数据传入Gpu
        pred = model.forward(X)  # 前向传输,model的数据来自模型的out
        loss = loss_fn(pred, y)  # 通过交叉熵损失函数计算loss,pred为预测值,y为真实值
        optimizer.zero_grad()  # 优化,梯度值清零
        loss.backward()  # 反向传播计算每个参数的梯度值W
        optimizer.step()  # 根据梯度更新W
        loss_value = loss.item()  # 从tensor数据中提取数据出来,转换成对应的整数或者浮点数
        if batch_size_num % 200 == 0:
            print(f"loss: {loss_value:>7f} [number:{batch_size_num}]")
        batch_size_num += 1


# 测试集
def test(dataloader, model, loss_fn):
    size = len(dataloader.dataset)
    num_batches = len(dataloader)
    model.eval()  # 测试,w不可更新
    test_loss, correct = 0, 0  # 初始化损失值以及正确率
    with torch.no_grad():  # 一个上下文管理器,关闭梯度计算
        for X, y in dataloader:  # 提取测试集的数据
            X, y = X.to(device), y.to(device)
            pred = model.forward(X)  # 预测结果
            test_loss += loss_fn(pred, y).item()  # test_loss会自动累加每一批次的损失值
            correct += (pred.argmax(1) == y).type(torch.float).sum().item()  # pred.argmax(1)返回每一行中最大值对应的索引号
            a = (pred.argmax(1) == y)  # 比较预测值与正确标签是否相同,返回True或者False
            b = (pred.argmax(1) == y).type(torch.float)  # 将True-->1,False-->0,便于统计正确率
    test_loss /= num_batches
    correct /= size
    print(f"Test result: \n Accuracy: {(100 * correct)}%,Avg loss:{test_loss}")


epoch = 10
for i in range(epoch):
    print('第{}轮训练'.format(i))
    train(train_dataloader, model, loss_fn, optimizer)
test(test_dataloader, model, loss_fn)


 10、结果展示

正确率达到了99.21%,还是很可观的。

 

 

为了搭建一个基于一维CNN卷积神经网络)的时间序列预测模型,首先需要准备时间序列数据和建立合适的数据集。时间序列数据通常包括连续的时间点和对应的数值,可以是股票价格、气温变化等。接着,我们需要将数据进行预处理,包括归一化、平滑处理或者填充缺失值等操作,确保数据的稳定性和一致性。 在搭建模型之前,需要确定CNN的结构和超参数。CNN包括卷积层、池化层和全连接层等组件,可以通过叠加这些层构建模型。在选择卷积层的深度、滤波器的大小、池化的类型等超参数时,可以根据实际数据的特点和问题的要求进行调整和优化。 接下来,将数据集划分为训练集和测试集,并通过训练集对模型进行训练,通过反向传播算法不断调整模型参数,使得模型逐渐收敛并学习到数据的特征。同时,可以通过交叉验证等方法来评估模型的性能,确保模型的泛化能力和预测准确性。 最后,可以使用训练好的模型对未来时间序列进行预测,得到预测结果并进行进一步的分析和应用。在实际应用中,可能还需要考虑模型的部署和优化,例如模型压缩、加速等方法,以适应不同的场景和需求。总之,搭建一维CNN的时间序列预测模型需要对数据进行充分的了解和预处理,选择合适的模型结构和参数,并通过训练和评估来不断优化模型,以实现准确的时间序列预测。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值