如何入门 PyTorch机器学习,学了知识点不会用怎么办(个人红温记录/CNN部分)

目录

1:以CNN和LSTM为例

CNN:

LSTM: 

常见应用场景:

如何应用:

2:以上废话如何应用 

1:概要:

2:CNN数据预处理

2.1:图像数据预处理通常包括以下几个步骤:

2.1示例:图像数据集的预处理(使用 torchvision)

3:设计模型 

3.1:CNN模型

3.2基本设计理念

4:编写训练过程

4.1:CNN示例

这个训练函数的 框架是通用的,适用于大多数图像分类任务,但在不同的数据集上可能需要 修改 部分内容。以下是几种可能需要调整的情况,具体的修改方式取决于数据集的特征。 

5:测试代码 (复用率很高)

5.1:CNN示例(有需要再补充)


1:以CNN和LSTM为例

CNN:

CNN 主要用于处理图像和视频等二维数据,但也可以用于一些其他类型的输入,如时间序列、音频数据等。CNN 的主要特点是它的卷积层可以有效提取输入数据中的空间特征,这对于图像分析尤其重要。

常见应用场景:

  • 图像分类:将图片分到不同类别中。例如:给定一个包含猫、狗、鸟等图像的数据集,训练一个 CNN 模型来进行分类。
  • 目标检测:识别图像中的多个物体并给出它们的位置(例如在图像中标记出车、行人等物体)。
  • 语义分割:不仅要识别图像中的物体,还要区分出每个像素属于哪个类别。
  • 风格迁移:使用 CNN 将一张图像的风格转移到另一张图像上。

如何应用:

  • 步骤 1:选择数据集。例如,你可以使用经典的 CIFAR-10 数据集,或者从 Kaggle 上下载一个新的图像数据集。
  • 步骤 2:数据预处理。这通常包括图像的归一化、裁剪、翻转、旋转等操作,以增加数据的多样性。
  • 步骤 3:设计模型。创建一个由多个卷积层(Conv2d)和池化层(MaxPool2d)组成的网络。通常还会使用 ReLU 激活函数,最后接一个全连接层(Linear)。
  • 步骤 4:训练模型。使用 PyTorch 中的 DataLoader 来加载数据,选择合适的损失函数(如交叉熵损失)和优化器(如 Adam 或 SGD),然后训练网络。
  • 步骤 5:评估和调优。在测试集上评估模型性能,调整网络结构、学习率等超参数来提升准确率。
LSTM: 

LSTM 是一种特殊类型的循环神经网络(RNN),它特别擅长处理和预测时间序列数据或序列数据中的长期依赖关系。LSTM 在处理语音、文本等时间依赖性强的数据时非常有效。

常见应用场景:
  • 自然语言处理(NLP):文本分类、情感分析、命名实体识别、机器翻译等。
  • 时间序列预测:如股票预测、气象预测等。
  • 语音识别:将语音转换为文本。
  • 视频分析:对视频帧进行分析时,LSTM 可以帮助处理帧之间的时间关系。
如何应用:
  • 步骤 1:选择数据集。对于 NLP 任务,你可以选择经典的文本分类数据集(如 IMDB 电影评论数据集),对于时间序列任务,你可以使用股票数据等。
  • 步骤 2:数据预处理。对于文本数据,你需要进行分词、去停用词、转换为词嵌入(如使用 Word2Vec 或 GloVe)。对于时间序列数据,你通常需要将数据标准化并分割成训练集和测试集。
  • 步骤 3:设计模型。LSTM 网络通常由多个 LSTM 层(nn.LSTM)和全连接层组成。LSTM 可以处理序列中的长期依赖关系。
  • 步骤 4:训练模型。和 CNN 一样,你需要选择合适的损失函数和优化器来训练 LSTM 网络。
  • 步骤 5:评估和调优。在测试集上评估模型的表现,调整模型架构(如层数、隐藏单元数等)和超参数(如学习率、批量大小等)。

2:以上废话如何应用 

1:概要:

数据预处理设计模型训练模型 的过程是机器学习中至关重要的一步。幸运的是,PyTorch 提供了一些非常清晰的 API 和模块,可以帮助我们实现这些步骤,并且这些步骤并不需要“背诵”代码,而是理解如何使用 PyTorch 提供的工具来解决实际问题。

2:CNN数据预处理

预处理的目标是将原始数据转换为可以被模型接受的形式。

2.1:图像数据预处理通常包括以下几个步骤:
  • 调整大小(Resizing):将图像统一调整为相同的尺寸,以便输入到模型。
  • 标准化(Normalization):将像素值缩放到一个标准范围(通常是 [0, 1] 或 [-1, 1]),有助于模型训练时的稳定性。
  • 数据增强(Data Augmentation):通过对图像的旋转、翻转、裁剪等方式增加数据的多样性,从而提高模型的泛化能力。
2.1示例:图像数据集的预处理(使用 torchvision
import torch
from torchvision import datasets, transforms
from torch.utils.data import DataLoader

# 1. 定义数据预处理的转换操作
transform = transforms.Compose([
    transforms.Resize(128),                      # 调整图像大小
    transforms.ToTensor(),                        # 转换为Tensor
    transforms.Normalize(mean=[0.5, 0.5, 0.5],   # 标准化
                         std=[0.5, 0.5, 0.5])   # 标准化
])

# 2. 加载数据集并应用预处理
trainset = datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
trainloader = DataLoader(trainset, batch_size=64, shuffle=True)

# 3. 可选:使用数据增强(如果需要)
augmentation_transform = transforms.Compose([
    transforms.RandomHorizontalFlip(),            # 随机水平翻转
    transforms.RandomRotation(20),                # 随机旋转20度
    transforms.ToTensor(),                        # 转换为Tensor
    transforms.Normalize(mean=[0.5, 0.5, 0.5],   # 标准化
                         std=[0.5, 0.5, 0.5])   # 标准化
])

trainset_with_augmentation = datasets.CIFAR10(root='./data', train=True, download=True, transform=augmentation_transform)
trainloader_with_augmentation = DataLoader(trainset_with_augmentation, batch_size=64, shuffle=True)

以上废话内容概要:

1:图像大小如何处理?transforms.Resize()

目的:调整所有图像固定大小,以适配网络输入层,大多数模型要求输入图像尺寸一致

通用参数:图像尺寸通常会选择为 224x224 或 128x128 这样的常见尺寸,这些尺寸适用于大多数任务(如图像分类、目标检测等);如果是别人训练好的模型,去查他要多大尺寸;如果你就要自己设置,那选一个较小的尺寸可以加快训练速度。

2:标准化transforms.Normalize()

目的:meanstd 分别代表 均值(mean)标准差(standard deviation)。这两个参数的作用是将图像的像素值调整到一个标准的范围,以提高模型训练的稳定性和效果。

概要mean 是每个颜色通道(红色、绿色、蓝色)的像素值的 均值它表示该通道的平均亮度水平。std 是每个颜色通道的像素值的 标准差它表示图像中该通道的亮度波动程度,或者说图像的对比度。

示例中的[0.5, 0.5, 0.5] 是一个* 默认值,仅供简单的示例使用*

通用参数

在许多常见的图像分类任务(特别是使用预训练网络如 ResNet、VGG 等)中,数据集(例如 ImageNet)的每个颜色通道的均值和标准差通常已经被计算过了。对于 ImageNet 数据集,RGB 三个通道的均值和标准差是:

mean=[0.485, 0.456, 0.406]

std=[0.229, 0.224, 0.225]

ImageNet 是一个大规模图像分类数据集,许多预训练模型(如 ResNet、VGG、Inception 等)是在这个数据集上训练的。因此,如果你使用这些预训练模型,通常会使用 ImageNet 上计算的均值和标准差进行标准化。

3:有点理想:如何根据数据集调整 meanstd

你可以先加载数据集,然后计算其每个颜色通道的均值和标准差。

import torch
from torchvision import datasets, transforms
from torch.utils.data import DataLoader

# 假设我们使用 CIFAR-10 数据集进行示范
transform = transforms.Compose([
    transforms.ToTensor(),  # 将图像转换为 Tensor([0, 1] 范围)
])

# 加载 CIFAR-10 数据集
trainset = datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
trainloader = DataLoader(trainset, batch_size=64, shuffle=True)

# 初始化均值和标准差
mean = 0.0
std = 0.0
total_images = 0

# 遍历训练数据集,计算均值和标准差
for images, _ in trainloader:
    # 累加每个batch的均值和标准差
    mean += images.mean([0, 2, 3])  # 对每个通道求均值
    std += images.std([0, 2, 3])    # 对每个通道求标准差
    total_images += 1

# 求平均值
mean /= total_images
std /= total_images

print("Mean:", mean)
print("Std:", std)

这些计算出来的 meanstd 可以用于标准化操作,以使得你的数据集的像素值分布更加合理。 

3:数据增强根据数据集的大小和多样性来选择是否应用数据增强。对于较小的数据集,增强可能会帮助模型更好地泛化。(有需要再补充)

4:裁剪与填充如果图像的尺寸或比例不一致,可以进行裁剪或填充操作,确保输入一致。(有需要再补充)

3:设计模型 
3.1:CNN模型

输入层->卷积层->激活层->池化层->全连接层->输出层(Input layer ->Convolutional layer ->Activation layer ->Pooling layer ->Fully connected layer ->Output layer)

以下假设输入图像尺寸为 32×32×3 的 RGB 图像(即 3 个通道)

class SimpleCNN(nn.Module):
    def __init__(self):
        super(SimpleCNN, self).__init__()
        
        # 卷积块 1
        self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1)  # 输入 3 个通道,输出 32 个通道
        self.pool1 = nn.MaxPool2d(2, 2)  # 最大池化 2x2
        
        # 卷积块 2
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)  # 输入 32 个通道,输出 64 个通道
        self.pool2 = nn.MaxPool2d(2, 2)  # 最大池化 2x2
        
        # 全连接层
        self.fc1 = nn.Linear(64 * 8 * 8, 128)  # 展平特征图后,输入到全连接层
        self.fc2 = nn.Linear(128, 10)  # 输出 10 个类别
    
    def forward(self, x):
        # 卷积块 1
        x = self.pool1(torch.relu(self.conv1(x)))  # 卷积 + 激活 + 池化
        
        # 卷积块 2
        x = self.pool2(torch.relu(self.conv2(x)))  # 卷积 + 激活 + 池化
        
        # 展平
        x = x.view(-1, 64 * 8 * 8)  # 展平特征图为一维向量
        
        # 全连接层
        x = torch.relu(self.fc1(x))  # 第一个全连接层
        x = self.fc2(x)  # 第二个全连接层(输出层)
        
        return x

卷积层: 它通过滑动滤波器(卷积核)对图像进行卷积操作,学习特征信息

通用参数:常见的卷积核大小有 3×3,5×5 等,卷积层的深度(即卷积核的数量)决定了网络能够学习的特征数量。多层堆叠的卷积层比使用大卷积核更有效。

#八层组成,五个卷积层,两个全连接隐藏层和一个全连接输出层
#使用ReLu激活函数,最大池化
#输入227*227*3,第一个卷积核11*11*3*96 stride=4,输出为55*55*96
#公式 输出高=((输入高+2*填充-卷积核高)/步长stride ) +1 =55
#输出宽=((输入宽+2*填充-卷积核宽)/步长stride )+1 =55
#使用了 11*11的卷积核 3为输入通道,96为输出通道 ,所以输出为55*55*96
#最大池化 3*3 stride=2
#计算同上 输出高=((输入高+2*填充-池化核高)/步长stride )+1 =27
#输出宽=((输入宽+2*填充-池化核宽)/步长stride )+1 =27
#最大池化对每个 通道独立进行,所以还是输出96给通道,输出为27*27*96
  • 卷积核大小:常见的卷积核大小是 3×3 或 5×5,一般选择较小的卷积核(例如 3×3),多层堆叠的卷积层比使用大卷积核更有效。
  • 卷积层深度:通常卷积层的深度随着网络的深度增加而增大。例如,初期卷积层通常使用较少的卷积核(如 32 个),而后面的卷积层可以增加到 128、256 等。
  • 代码内容self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1) 3:3个颜色通道红绿蓝32:生成32个输出通道;kernel_size=3:卷积核大小为 3×3;填充(padding):是指在输入图像的边缘加上额外的像素,以保持输出图像的空间尺寸。填充可以帮助避免卷积操作中图像尺寸的过度压缩,=1为在每一边加上一个像素填充。

池化层: 减少空间尺寸,降低计算复杂度,保持重要特征,一般使用Max Pooling,即从每个池化窗口选择最大的值。

通用参数:常见的池化窗口大小为 2×2,步幅(stride)为 2;池化层通常放置在卷积层后面,以减少特征图的尺寸,同时保留最重要的特征。

代码内容:

# 卷积块 1 self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1) 

self.pool1 = nn.MaxPool2d(2, 2) # 最大池化 2x2

全连接层: 用于将卷积层提取到的特征图(feature map)转换为最终的输出。全连接层的作用是通过线性变换对这些特征进行组合,从而进行分类、回归等任务。

代码内容:

self.fc1 = nn.Linear(64 * 8 * 8, 128)  # 展平特征图后,输入到全连接层
self.fc2 = nn.Linear(128, 10)  # 输出 10 个类别

参数含义:参数继承自卷积层

  1. 卷积层(conv1)
    输入图像尺寸为 32×32,由于卷积核大小为 3×3,填充为 1,步幅为 1,经过卷积后输出的图像尺寸是 32×32(空间尺寸不变)。

  2. 池化层(pool1)
    使用最大池化层,池化窗口为 2×2,步幅为 2。池化操作会将每个 2×2 区域的像素取最大值,因此池化后图像的尺寸会减半,从 32×32 变为 16×16。

所以,经过第一个卷积块后,图像尺寸变为 16 × 16,并且有 32 个通道

  1. 卷积层(conv2)
    输入图像的尺寸为 16×16,经过 3×3 的卷积操作后,输出的空间尺寸仍然是 16×16,因为卷积核的填充为 1,步幅为 1,所以尺寸不变。

  2. 池化层(pool2)
    使用最大池化,池化窗口为 2×2,步幅为 2,池化后图像的尺寸从 16×16 减半,变为 8×8。

所以,经过第二个卷积块后,图像尺寸变为 8 × 8,并且有 64 个通道

全连接层需要将输入的特征图展平(flatten),即将 8×8 的二维特征图展平为一维向量。然后,这个一维向量将被输入到全连接层

如代码内容所示,64 * 8 * 8个输入, 128通道,输出为10个类型

3.2基本设计理念

forward函数

forward 函数涵盖了卷积神经网络中最常见的几个操作:卷积、激活、池化、展平和全连接层。下面逐步解释各个部分的功能:

1. 卷积层 + 激活函数 + 池化层

x = self.pool1(F.relu(self.conv1(x))) # 卷积 + 激活 + 池化

  • self.conv1(x)将输入数据传入卷积层 conv1,生成新的特征图(feature map)。
  • F.relu(...)通过 ReLU 激活函数进行非线性处理,ReLU 将所有负值设置为 0,保持正值不变。
  • self.pool1(...)使用最大池化层 pool1 进行下采样,减少特征图的空间尺寸,同时保留重要的特征信息。

2. 第二个卷积块

x = self.pool2(F.relu(self.conv2(x))) # 卷积 + 激活 + 池化

  • 这里的操作与第一个卷积块相同,只不过输入数据来自上一层的输出,卷积层和池化层的通道数和空间尺寸会发生变化。

3. 展平特征图

x = x.view(-1, 64 * 8 * 8) # 展平特征图为一维向量

  • x.view(-1, 64 * 8 * 8)view 操作用于将多维张量展平为一维。-1 表示 PyTorch 会自动计算批次的大小(batch_size),而 64 * 8 * 8 表示每张图像的展平后的特征长度(假设经过卷积和池化后的特征图的尺寸为 8×8,并且有 64 个通道)。

4. 全连接层

x = F.relu(self.fc1(x)) # 第一个全连接层 x = self.fc2(x) # 输出层

  • self.fc1(x):将展平后的特征图输入到第一个全连接层 fc1,通常该层用来捕获全局的特征信息。全连接层的输出维度是 128(可以根据需要调整)。
  • F.relu(...):使用 ReLU 激活函数进行非线性处理。
  • self.fc2(x):最后一个全连接层,将数据映射到目标输出空间,这里是 10 类(假设是 10 类分类问题)。

4:编写训练过程
4.1:CNN示例

在机器学习和深度学习中,训练过程的核心步骤是相似的,通常包括:

  • 前向传播:输入数据经过模型计算输出。
  • 损失函数:用来衡量模型输出与真实标签之间的差异。
  • 反向传播:计算梯度,并更新模型参数。
  • 优化器:通过反向传播计算的梯度来更新模型参数。

这个框架几乎适用于所有的深度学习模型(CNN、RNN、Transformer 等)。因此,训练过程的代码 不需要背诵,你只需要理解每个步骤的作用,并根据具体情况进行调整。

# 数据预处理(如归一化、转换为Tensor等)
transform = transforms.Compose([
    transforms.ToTensor(),  # 将图像转换为 Tensor 格式
    transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])  # 对图像进行标准化
])

# 加载 CIFAR-10 数据集(训练集和测试集)
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)

# 创建 DataLoader(自动批处理数据、打乱数据等)
trainloader = DataLoader(trainset, batch_size=32, shuffle=True)
testloader = DataLoader(testset, batch_size=32, shuffle=False)


# 定义损失函数和优化器
model = SimpleCNN().cuda()  # 将模型移动到GPU(如果可用)
criterion = nn.CrossEntropyLoss()  # 使用交叉熵损失函数用于分类任务
optimizer = optim.Adam(model.parameters(), lr=0.001)  # 使用Adam优化器


# 训练函数
def train(model, trainloader, criterion, optimizer, num_epochs=10):
    """
    模型训练函数
    :param model: 要训练的模型
    :param trainloader: 训练数据的 DataLoader
    :param criterion: 损失函数
    :param optimizer: 优化器
    :param num_epochs: 训练的轮次(epochs)
    """
    model.train()  # 设置模型为训练模式(启用 dropout 等)
    
    for epoch in range(num_epochs):
        running_loss = 0.0  # 用于记录每个batch的总损失
        correct = 0
        total = 0
        
        for inputs, labels in trainloader:
            # 将输入数据和标签转移到GPU(如果可用)
            inputs, labels = inputs.cuda(), labels.cuda()

            # 清空之前计算的梯度
            optimizer.zero_grad()

            # 前向传播:将输入传入模型
            outputs = model(inputs)

            # 计算损失
            loss = criterion(outputs, labels)

            # 反向传播:计算梯度
            loss.backward()

            # 更新模型参数
            optimizer.step()

            # 记录损失
            running_loss += loss.item()

            # 计算当前batch的预测准确率
            _, predicted = torch.max(outputs, 1)  # 选取概率最大的类别
            total += labels.size(0)
            correct += (predicted == labels).sum().item()

        # 每个epoch输出一次训练损失和准确率
        print(f"Epoch [{epoch+1}/{num_epochs}], Loss: {running_loss/len(trainloader):.4f}, Accuracy: {100 * correct / total:.2f}%")
这个训练函数的 框架是通用的,适用于大多数图像分类任务,但在不同的数据集上可能需要 修改 部分内容。以下是几种可能需要调整的情况,具体的修改方式取决于数据集的特征。 

1:修改数据加载:CIFAR-10 数据集包含 10个类别 的图像,每张图像有 3个颜色通道(RGB)

如果使用灰度单通道,则修改卷积中的通道数

self.conv1 = nn.Conv2d(1, 32, kernel_size=3, padding=1)

如果数据集类别有区别,则修改输出类别数

self.fc2 = nn.Linear(128, 5)  # 输出 5 个类别
 

2:修改如前文提到的预处理像素范围,均值和标准差。

3:训练过程调整,对于 CIFAR-10,通常选择较小的 batch size(例如 32 或 64)。但对于其他数据集,可能需要调整 batch_size

更大的数据集(如 ImageNet),通常选择更大的 batch_size(如 128 或 256)来加速训练。

小的数据集,可能使用更小的 batch_size,例如 16。

4:损失函数

在分类任务中,CrossEntropyLoss 是最常见的损失函数,适用于大多数情况。

如果数据集是多标签分类(而不是单标签分类),你可能需要使用 BCEWithLogitsLoss 损失函数,它适用于多标签二分类任务。

5:调整学习率和优化器

学习率(Learning Rate):不同的数据集可能需要不同的学习率。如果你在训练过程中发现模型训练不稳定,可以尝试调小学习率。

优化器Adam 优化器是一个比较通用的优化器,适用于大多数任务。但你可以根据数据集和任务的不同,尝试使用其他优化器,如 SGDRMSprop

5:测试代码 (复用率很高)
5.1:CNN示例(有需要再补充)

在 PyTorch 中,测试过程通常会包括以下步骤:

  1. 设置模型为评估模式:这会影响到一些特殊层(如 dropout、batch norm)在测试时的行为。
  2. 禁用梯度计算:在测试阶段,不需要计算梯度(即不做反向传播),因此可以通过 torch.no_grad() 来禁用。
  3. 计算损失和评估指标:根据模型的输出和真实标签,计算损失和其他性能指标(例如准确率、F1 分数等)。
def test(model, testloader, criterion):
    """
    模型测试函数
    :param model: 已训练好的模型
    :param testloader: 测试数据的 DataLoader
    :param criterion: 损失函数
    """
    model.eval()  # 设置模型为评估模式(禁用 dropout 和 batchnorm)
    
    running_loss = 0.0
    correct = 0
    total = 0
    
    # 在测试时禁用梯度计算,提高效率
    with torch.no_grad():
        for inputs, labels in testloader:
            # 将数据移到GPU(如果可用)
            inputs, labels = inputs.cuda(), labels.cuda()

            # 前向传播:得到预测值
            outputs = model(inputs)

            # 计算损失
            loss = criterion(outputs, labels)
            running_loss += loss.item()

            # 计算准确率
            _, predicted = torch.max(outputs, 1)  # 选取概率最大的类别
            total += labels.size(0)
            correct += (predicted == labels).sum().item()

    # 输出测试集的总损失和准确率
    avg_loss = running_loss / len(testloader)
    accuracy = 100 * correct / total
    print(f"Test Loss: {avg_loss:.4f}, Test Accuracy: {accuracy:.2f}%")

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值