Py学习  »  机器学习算法

PyTorch深度学习实战(6)——神经网络性能优化技术(c)

GIS研发 • 1 周前 • 21 次点击  
为什么要缩放数据集?

3.缩放数据集

缩放数据集是确保变量被限制在给定范围内的过程,以确保数据不会分布在较大的区间。在本节中,我们通过将每个输入值除以数据集中的最大可能值,将自变量的值限制在。和1之间。通常,缩放输入数据集能够提高神经网络的性能表现。

# 导入必要的库from torch.utils.data import Dataset, DataLoader  # 数据集和 DataLoader 工具import torch                                      # PyTorch 主库import torch.nn as nn                             # 神经网络模块import numpy as np                                # 数值计算import matplotlib.pyplot as plt                   # 绘图from torchvision import datasets                  # 内置数据集
# 检测是否可用 GPU,否则使用 CPUdevice = "cuda" if torch.cuda.is_available() else "cpu"
# 下载 FashionMNIST 数据集到本地文件夹(仅训练集)data_folder = './data/FMNIST'fmnist = datasets.FashionMNIST(data_folder, download=True, train=True)
# 提取图像数据和标签(原始格式:torch.Tensor)tr_images = fmnist.data      # 形状为 [60000, 28, 28],像素值范围 0~255tr_targets = fmnist.targets  # 形状为 [60000],标签 0~9

# 自定义数据集类,将原始数据转换成模型需要的格式class FMNISTDataset(Dataset):    def __init__(self, x, y):        # x: 原始图像张量,形状 [N, 28, 28],dtype=torch.uint8        # y: 原始标签张量
        # 将像素值从 0~255 缩放到 0~1,有利于神经网络训练        x = x.float() / 255.        # 将二维图像 (28,28) 展平为一维向量 (784)        x = x.view(-128*28)   # -1 表示自动计算该维度大小(样本数)        self.x, self.y = x, y   # 存储处理后的数据和标签
    def __getitem__(self, ix):        """根据索引 ix 返回一个样本 (图像, 标签)"""        x, y = self.x[ix], self.y[ix]        # 将数据移动到指定设备(GPU/CPU)        return x.to(device), y.to(device)
    def __len__(self):        """返回数据集总样本数"""        return len(self.x)

def get_data():    """创建数据集和 DataLoader,用于批量加载训练数据"""    train = FMNISTDataset(tr_images, tr_targets)   # 实例化数据集    # DataLoader 负责打乱数据、分批、并行加载等    trn_dl = DataLoader(train, batch_size=32, shuffle=True)    return trn_dl

from torch.optim import SGD  # 随机梯度下降优化器
def get_model():    """定义模型结构、损失函数和优化器"""    # 使用 Sequential 搭建前馈神经网络    model = nn.Sequential(        nn.Linear(28*281000),   # 输入层 784 -> 隐藏层 1000        nn.ReLU(),                # 激活函数,增加非线性        nn.Linear(100010)       # 输出层 1000 -> 10(对应 10 个类别)    ).to(device)                  # 将模型移到指定设备
    loss_fn = nn.CrossEntropyLoss()  # 交叉熵损失,适用于多分类    optimizer = SGD(model.parameters(), lr=1e-2 )  # 学习率 0.01    return model, loss_fn, optimizer

def train_batch(x, y, model, optimizer, loss_fn):    """在一个 batch 数据上执行一次训练步骤(前向传播、损失、反向传播、参数更新)"""    model.train()  # 设置为训练模式(影响 Dropout/BatchNorm 等,本模型未使用)
    # 前向传播:将输入 x 送入模型得到预测值    prediction = model(x)
    # 计算预测值与真实标签 y 之间的损失    batch_loss = loss_fn(prediction, y)
    # 反向传播:计算损失对模型所有可训练参数的梯度    batch_loss.backward()
    # 优化器根据梯度更新模型参数(例如:w = w - lr * grad)    optimizer.step()
    # 将本轮计算出的梯度清零,避免下一 batch 累加    optimizer.zero_grad()
    # 返回当前 batch 的损失值(标量)    return batch_loss.item()

@torch.no_grad()   # 该装饰器下的代码不会计算梯度,节省内存和计算def accuracy(x, y, model):    """计算模型在输入 x 上的预测准确率(返回每个样本是否正确)"""    model.eval()   # 设置为评估模式
    prediction = model(x)          # 前向传播,形状 [batch_size, 10]    # 在最后一个维度(类别维度)上取最大值的索引,即预测的类别    max_values, argmaxes = prediction.max(-1)
    # 比较预测类别与真实标签,得到布尔值列表    is_correct = argmaxes == y    # 返回 CPU 上的 Python 列表(方便之后计算平均准确率)    return is_correct.cpu().numpy().tolist()

@torch.no_grad()def val_loss(x, y, model, loss_fn):    """计算模型在输入 x 上的损失值(用于验证,但不更新参数)"""    prediction = model(x)    val_loss = loss_fn(prediction, y)    return val_loss.item()

# ==================== 主训练流程 ====================
# 获取 DataLoadertrn_dl = get_data()# 获取模型、损失函数、优化器model, loss_fn, optimizer = get_model()
# 存储每个 epoch 的平均损失和平均准确率,用于后续绘图losses, accuracies = [], []
# 训练 10 个 epoch(整个数据集完整遍历一次为一个 epoch)for epoch in range(10):    # 记录当前 epoch 内每个 batch 的损失    epoch_losses = []    # ---------- 计算当前 epoch 的平均损失 ----------    for ix, batch in enumerate(iter(trn_dl)):        x, y = batch                     # 取出一个 batch 的数据        batch_loss = train_batch(x, y, model, optimizer, loss_fn)        epoch_losses.append(batch_loss)  # 记录该 batch 的损失    # 计算当前 epoch 所有 batch 的平均损失    epoch_loss = np.array(epoch_losses).mean()
    # ---------- 计算当前 epoch 的训练准确率 ----------    epoch_accuracies = []    # 再次遍历整个训练集(注意:这里使用的是同样的 DataLoader,但没有重置,可能顺序不同)    # 通常推荐在训练完成后单独用一个循环统计准确率,本代码为简洁这样写    for ix, batch in enumerate(iter(trn_dl)):        x, y = batch        is_correct = accuracy(x, y, model)   # 得到每个样本是否正确        epoch_accuracies.extend(is_correct)  # 收集所有 batch 的正确列表    # 计算本 epoch 的平均准确率    epoch_accuracy = np.mean(epoch_accuracies)
    # 打印当前 epoch 的损失和准确率    print(f"epoch:{epoch} loss:{epoch_loss:.2f} epoch_accuracy: {epoch_accuracy * 100:.2f}%")
    # 保存数据用于绘图    losses.append(epoch_loss)    accuracies.append(epoch_accuracy)
# ==================== 绘制训练曲线 ====================epochs = np.arange(10) + 1   # 创建 [1,2,...,10]
plt.figure(figsize=(205))plt.subplot(121) plt.title('Loss value over increasing epochs')plt.plot(epochs, losses, label='Training Loss')plt.legend()
plt.subplot(122)plt.title('Accuracy value over increasing epochs')plt.plot(epochs, accuracies, label='Training Accuracy')# 将 y 轴刻度显示为百分比形式plt.gca().set_yticklabels(['{:.0f}%'.format(x*100for x in plt.gca().get_yticks()])plt.legend()
plt.show()


相关:

PyTorch深度学习实战(6)——神经网络性能优化技术(b)

PyTorch深度学习实战(6)—神经网络性能优化技术(a)

PyTorch深度学习实战(5)—计算机视觉基础

PyTorch深度学习实战(4)--常用激活函数和损失函数详解

PyTorch深度学习实战(3)—使用PyTorch构建神经网络(b)

PyTorch深度学习实战(3)—使用PyTorch构建神经网络(a)

PyTorch深度学习实战(2)-PyTorch基础

示例:反向传播和梯度下降的计算过程

AI基础 | 前向传播

AI基础 | 反向传播

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/195970