Python课程进阶篇:PyTorch实战教程

前言

PyTorch 是一个开源的深度学习框架,由 Facebook 开发,广泛应用于学术研究和工业领域。与 TensorFlow 类似,PyTorch 提供了强大的工具用于构建和训练深度学习模型。PyTorch 的动态计算图和灵活的 API 使得它特别适合研究和实验。它还支持 GPU 加速,适用于构建复杂的神经网络。

本教程将详细介绍 PyTorch 的每个常用指令和功能,帮助你从基础知识开始,逐步掌握如何使用 PyTorch 进行深度学习开发。


目录

  1. PyTorch 基础

  2. 安装 PyTorch
  3. 创建张量(Tensors)
  4. 张量操作与计算
  5. 自动微分与反向传播
  6. 神经网络构建

  7. 使用 nn.Module 构建神经网络
  8. 激活函数与损失函数
  9. 优化器:SGD、Adam 等
  10. 自定义训练循环
  11. 高级功能

  12. 数据集与数据加载器
  13. 使用 GPU 加速模型训练
  14. 保存与加载模型
  15. 卷积神经网络 (CNN)

  16. 构建 CNN 模型
  17. 训练与评估 CNN
  18. 递归神经网络 (RNN)

  19. 构建 RNN 与 LSTM
  20. 训练与评估 RNN 模型

1. PyTorch 基础

安装 PyTorch

PyTorch 可以通过 pip 安装。你可以根据你的操作系统和硬件(例如 GPU)选择合适的安装命令:

pip install torch torchvision torchaudio

 导入 PyTorch:

import torch
创建张量(Tensors)

张量是 PyTorch 中的核心数据结构,它类似于 NumPy 数组,但支持 GPU 加速。

  • 创建张量
    # 创建一个 3x3 的随机张量
    x = torch.rand(3, 3)
    print(x)
    
    # 创建一个全 0 张量
    x = torch.zeros(3, 3)
    print(x)
    
    # 创建一个全 1 张量
    x = torch.ones(3, 3)
    print(x)
    
  • 从列表或 NumPy 创建张量
    import numpy as np
    
    # 从列表创建张量
    x = torch.tensor([1, 2, 3, 4])
    print(x)
    
    # 从 NumPy 数组创建张量
    np_array = np.array([5, 6, 7, 8])
    x = torch.from_numpy(np_array)
    print(x)
    
    张量操作与计算

    PyTorch 提供了多种张量运算函数,如加法、乘法、矩阵乘法等。它们与 NumPy 的操作类似,但支持自动微分。

  • 基本运算
    x = torch.rand(3, 3)
    y = torch.rand(3, 3)
    
    # 加法
    z = x + y
    print(z)
    
    # 乘法
    z = x * y
    print(z)
    
    # 矩阵乘法
    z = torch.matmul(x, y)
    print(z)
    
  • 重塑张量
    x = torch.rand(16)
    
    # 重塑为 4x4 的张量
    x_reshaped = x.view(4, 4)
    print(x_reshaped)
    
    自动微分与反向传播

    PyTorch 的自动微分机制通过 autograd 实现,它能够自动计算张量的梯度,从而实现反向传播。

  • 计算梯度
    # 创建一个张量,并设置 requires_grad=True 以跟踪其梯度
    x = torch.tensor([2.0, 3.0], requires_grad=True)
    
    # 定义一个简单的函数
    y = x[0]**2 + x[1]**3
    
    # 进行反向传播,计算梯度
    y.backward()
    
    # 输出梯度
    print(x.grad)  # x[0] 的梯度是 4.0,x[1] 的梯度是 27.0
    

  • 2. 神经网络构建

    PyTorch 提供了 torch.nn 模块,用于构建神经网络。通过继承 nn.Module 类,你可以创建自定义的神经网络。

    使用 nn.Module 构建神经网络

    以下是一个使用 PyTorch 构建的简单前馈神经网络:

    import torch.nn as nn
    
    class SimpleNN(nn.Module):
        def __init__(self):
            super(SimpleNN, self).__init__()
            self.fc1 = nn.Linear(28 * 28, 128)  # 输入层到隐藏层
            self.fc2 = nn.Linear(128, 64)       # 隐藏层
            self.fc3 = nn.Linear(64, 10)        # 输出层
    
        def forward(self, x):
            x = x.view(-1, 28 * 28)  # 展平输入
            x = torch.relu(self.fc1(x))  # 激活函数 ReLU
            x = torch.relu(self.fc2(x))
            x = self.fc3(x)
            return x
    
    # 创建模型实例
    model = SimpleNN()
    print(model)
    
    激活函数与损失函数
  • 激活函数:PyTorch 提供了多种激活函数,可以在网络的前向传播中使用。
    # 使用 ReLU 激活函数
    x = torch.rand(5, 5)
    x = torch.relu(x)
    
  • 损失函数:用于计算模型预测与真实标签之间的误差。
  • criterion = nn.CrossEntropyLoss()  # 适用于分类问题的交叉熵损失
    
    优化器:SGD、Adam 等

    优化器用于更新模型参数。PyTorch 提供了多种优化器,如 SGDAdam

  • 使用 SGD 优化器
    import torch.optim as optim
    
    # 使用 SGD 优化器
    optimizer = optim.SGD(model.parameters(), lr=0.01)
    
  • 使用 Adam 优化器
    optimizer = optim.Adam(model.parameters(), lr=0.001)
    
  • 自定义训练循环

    以下是一个简单的训练循环示例,用于训练神经网络模型。

    # 假设我们有训练数据 loader
    for epoch in range(10):
        for batch_idx, (data, target) in enumerate(train_loader):
            # 将梯度置零
            optimizer.zero_grad()
    
            # 前向传播
            output = model(data)
            loss = criterion(output, target)
    
            # 反向传播
            loss.backward()
    
            # 更新权重
            optimizer.step()
    
        print(f'Epoch {epoch + 1}, Loss: {loss.item()}')
    

    3. 高级功能

    数据集与数据加载器

    PyTorch 提供了 torch.utils.data 模块,用于加载数据集。你可以使用内置的数据集,或者自定义自己的数据集。

  • 使用内置数据集(MNIST)
    from torchvision import datasets, transforms
    
    # 定义数据变换
    transform = transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize((0.5,), (0.5,))
    ])
    
    # 加载 MNIST 数据集
    train_dataset = datasets.MNIST(root='data', train=True, transform=transform, download=True)
    test_dataset = datasets.MNIST(root='data', train=False, transform=transform, download=True)
    
    # 创建数据加载器
    train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=32, shuffle=True)
    test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=32, shuffle=False)
    
  • 自定义数据集
    from torch.utils.data import Dataset
    
    class MyDataset(Dataset):
        def __init__(self, data, labels):
            self.data = data
            self.labels = labels
    
        def __len__(self):
            return len(self.data)
    
        def __getitem__(self, idx):
            return self.data[idx], self.labels[idx]
    
  • 使用 GPU 加速模型训练

    PyTorch 支持使用 GPU 加速模型训练。你可以通过将模型和张量移动到 GPU 上来加速计算。

  • 检查 GPU 可用性
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    print(device)
    
  • 将模型和数据移动到 GPU
  • model.to(device)
    
    # 将数据移动到 GPU
    data, target = data.to(device), target.to(device)
    
    保存与加载模型

    你可以通过保存和加载模型的权重来持久化训练的模型。

  • 保存模型
    torch.save(model.state_dict(), 'model.pth')
    
  • 加载模型
    model = SimpleNN()
    model.load_state_dict(torch.load('model.pth'))
    

  • 4. 卷积神经网络 (CNN)

    卷积神经网络(CNN)在处理图像数据时非常有效。它能够通过卷积层提取图像的局部特征,并通过池化层减少特征图的维度。以下部分将详细介绍如何在 PyTorch 中构建和训练 CNN 模型。

    构建 CNN 模型

    我们将使用 PyTorch 的 torch.nn 模块构建一个 CNN 模型来处理 MNIST 手写数字分类任务。该模型包含卷积层、池化层和全连接层。

    import torch.nn as nn
    import torch.nn.functional as F
    
    class CNN(nn.Module):
        def __init__(self):
            super(CNN, self).__init__()
            # 卷积层 1:输入 1 个通道,输出 32 个通道,卷积核 3x3
            self.conv1 = nn.Conv2D(1, 32, kernel_size=3)
            # 卷积层 2:输入 32 个通道,输出 64 个通道
            self.conv2 = nn.Conv2D(32, 64, kernel_size=3)
            # 最大池化层:2x2 核
            self.pool = nn.MaxPool2D(2, 2)
            # 全连接层 1
            self.fc1 = nn.Linear(64 * 12 * 12, 128)  # MNIST 图像 28x28,经过两次卷积和池化后为 12x12
            # 全连接层 2
            self.fc2 = nn.Linear(128, 10)  # 输出为 10 类别(0-9)
    
        def forward(self, x):
            # 前向传播
            x = self.pool(F.relu(self.conv1(x)))  # 卷积 -> ReLU -> 池化
            x = self.pool(F.relu(self.conv2(x)))  # 卷积 -> ReLU -> 池化
            x = x.view(-1, 64 * 12 * 12)          # 展平张量以适配全连接层
            x = F.relu(self.fc1(x))               # 全连接层 -> ReLU
            x = self.fc2(x)                       # 输出层
            return x
    
    # 实例化模型
    model = CNN()
    print(model)
    
    训练与评估 CNN 模型

    接下来,我们将训练这个 CNN 模型,并在 MNIST 数据集上进行评估。

  • 数据加载与准备
    import torch.optim as optim
    from torchvision import datasets, transforms
    
    # 定义图像变换:将图像转换为张量并标准化
    transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])
    
    # 加载 MNIST 数据集
    train_dataset = datasets.MNIST(root='data', train=True, transform=transform, download=True)
    test_dataset = datasets.MNIST(root='data', train=False, transform=transform, download=True)
    
    train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=32, shuffle=True)
    test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=32, shuffle=False)
    
  • 编译模型:我们将使用 交叉熵损失Adam 优化器 来训练模型。
    criterion = nn.CrossEntropyLoss()  # 交叉熵损失函数
    optimizer = optim.Adam(model.parameters(), lr=0.001)  # Adam 优化器
    
  • 训练模型:以下是训练循环代码,它包括前向传播、计算损失、反向传播以及权重更新。
    for epoch in range(10):  # 训练 10 个周期
        running_loss = 0.0
        for i, (inputs, labels) in enumerate(train_loader):
            # 梯度清零
            optimizer.zero_grad()
    
            # 前向传播
            outputs = model(inputs)
            loss = criterion(outputs, labels)
    
            # 反向传播
            loss.backward()
            optimizer.step()
    
            # 打印损失值
            running_loss += loss.item()
            if i % 100 == 99:  # 每 100 个 batch 打印一次
                print(f'Epoch {epoch + 1}, Batch {i + 1}, Loss: {running_loss / 100:.3f}')
                running_loss = 0.0
    
  • 模型评估:在测试集上评估模型的准确性。
    correct = 0
    total = 0
    model.eval()  # 设置模型为评估模式
    with torch.no_grad():  # 禁用梯度计算,以提高推理速度
        for inputs, labels in test_loader:
            outputs = model(inputs)
            _, predicted = torch.max(outputs, 1)
            total += labels.size(0)
            correct += (predicted == labels).sum().item()
    
    print(f'Accuracy on test set: {100 * correct / total:.2f}%')
    

  • 5. 递归神经网络 (RNN)

    递归神经网络(RNN)特别适合处理序列数据,例如时间序列、自然语言处理等任务。PyTorch 提供了多种 RNN 层,如 RNNGRULSTM

    构建 RNN 与 LSTM 模型

    LSTM(长短期记忆网络)是一种改进的 RNN,能够更好地处理长期依赖关系。下面是一个简单的 LSTM 模型。

    import torch.nn as nn
    
    class LSTM(nn.Module):
        def __init__(self, input_size, hidden_size, num_layers, output_size):
            super(LSTM, self).__init__()
            self.hidden_size = hidden_size
            self.num_layers = num_layers
            # 定义 LSTM 层
            self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)
            # 全连接层
            self.fc = nn.Linear(hidden_size, output_size)
    
        def forward(self, x):
            # 初始化隐藏状态和记忆状态
            h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)
            c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)
            
            # 前向传播 LSTM
            out, _ = self.lstm(x, (h0, c0))
            
            # 取最后一个时间步的输出
            out = self.fc(out[:, -1, :])
            return out
    
    # 实例化 LSTM 模型
    model = LSTM(input_size=28, hidden_size=128, num_layers=2, output_size=10)
    print(model)
    
    训练与评估 RNN 模型
  • 数据加载
  • 假设我们使用 MNIST 数据集,但将每行像素视为序列输入。

    train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=32, shuffle=True)
    test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=32, shuffle=False)
    
  • 训练模型
  • criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(model.parameters(), lr=0.001)
    
    for epoch in range(10):
        running_loss = 0.0
        for i, (inputs, labels) in enumerate(train_loader):
            inputs = inputs.view(-1, 28, 28)  # 将图像展平为序列形式
            optimizer.zero_grad()
    
            outputs = model(inputs)
            loss = criterion(outputs, labels)
    
            loss.backward()
            optimizer.step()
    
            running_loss += loss.item()
            if i % 100 == 99:
                print(f'Epoch {epoch + 1}, Batch {i + 1}, Loss: {running_loss / 100:.3f}')
                running_loss = 0.0
    
  • 评估模型
  • correct = 0
    total = 0
    model.eval()
    with torch.no_grad():
        for inputs, labels in test_loader:
            inputs = inputs.view(-1, 28, 28)
            outputs = model(inputs)
            _, predicted = torch.max(outputs, 1)
            total += labels.size(0)
            correct += (predicted == labels).sum().item()
    
    print(f'Accuracy on test set: {100 * correct / total:.2f}%')
    

    结论

    通过本教程,你已经学习了如何使用 PyTorch 进行深度学习项目的构建与训练。PyTorch 强大的灵活性和动态计算图,使它成为了学术研究和工业应用中的首选工具。它提供了简洁的 API,可以让你轻松实现复杂的神经网络模型,并通过 GPU 加速显著提升训练效率。

    作者:可愛小吉

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python课程进阶篇:PyTorch实战教程

    发表回复