PyTorch 神经网络基础(一文讲透)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观

前言

在人工智能领域,PyTorch 是一个不可或缺的工具。它以动态计算图、灵活的 API 设计和高效的计算性能,成为科研与工业界广泛采用的深度学习框架。对于编程初学者和中级开发者而言,掌握 PyTorch 神经网络基础不仅是踏入深度学习领域的关键一步,更是构建复杂模型的重要基石。本文将通过循序渐进的方式,结合实例代码和直观比喻,帮助读者理解 PyTorch 的核心概念与实践方法。


什么是 PyTorch?

PyTorch 是由 Facebook 开发的开源机器学习框架,其核心优势在于动态计算图(Dynamic Computation Graph)。与静态计算图框架(如 TensorFlow 的早期版本)不同,PyTorch 允许在运行时动态调整网络结构,这为调试和实验提供了极大便利。此外,PyTorch 的设计理念更贴近 Python 编程习惯,其张量(Tensor)操作与 NumPy 高度兼容,降低了学习门槛。

PyTorch 的核心组件

  1. 张量(Tensor):数据存储与计算的基本单元,类似多维数组。
  2. 自动求导(Autograd):自动计算梯度的机制,支持反向传播算法。
  3. 神经网络模块(nn.Module):封装了层(Layer)、激活函数、损失函数等组件,简化模型搭建。
  4. 优化器(Optimizer):实现梯度下降的算法工具,如 SGD、Adam 等。

神经网络基础概念

1. 神经元与层

神经网络由大量**神经元(Neuron)**组成,每个神经元接收输入信号,通过加权求和与激活函数处理后输出结果。例如,一个简单的神经元可以表示为:
$$ y = f(w \cdot x + b) $$
其中,$w$ 是权重,$b$ 是偏置,$f$ 是激活函数。

在 PyTorch 中,神经元通常以“层(Layer)”的形式存在。例如,全连接层(nn.Linear)将输入张量通过线性变换传递到下一层。

2. 激活函数

激活函数为神经网络引入非线性特性,使其能够拟合复杂函数。常见的激活函数包括:

  • ReLU(Rectified Linear Unit):$f(x) = \max(0, x)$,简单高效,适合隐藏层。
  • Sigmoid:将输出压缩到 (0, 1),常用于二分类问题的输出层。
  • Softmax:将输出转化为概率分布,适用于多分类任务。

3. 损失函数与优化目标

损失函数(Loss Function)衡量模型预测值与真实值的差异。例如,均方误差(MSE)用于回归任务,交叉熵(Cross-Entropy)用于分类任务。优化器通过最小化损失函数,调整模型参数(权重和偏置)。

4. 反向传播与梯度下降

反向传播是神经网络的核心算法,通过链式法则计算损失函数对每个参数的梯度。梯度下降则利用这些梯度逐步调整参数,使模型性能持续提升。


张量(Tensor)基础:PyTorch 的数据载体

张量是 PyTorch 的核心数据结构,类似于 NumPy 的多维数组,但支持 GPU 加速和自动求导。以下是一些常用操作:

创建张量

import torch  

tensor = torch.rand(2, 3)  
print(tensor)  

import numpy as np  
numpy_array = np.array([[1, 2], [3, 4]])  
tensor_from_numpy = torch.from_numpy(numpy_array)  

张量运算

a = torch.tensor([1, 2, 3])  
b = torch.tensor([4, 5, 6])  
result = a + b  # 输出:tensor([5, 7, 9])  

matrix1 = torch.rand(2, 3)  
matrix2 = torch.rand(3, 4)  
product = torch.mm(matrix1, matrix2)  # 输出形状为 2x4 的张量  

与 NumPy 的对比

功能PyTorch 张量NumPy 数组
创建torch.tensor()np.array()
GPU 支持支持(通过 .to('cuda')不支持
自动求导内置支持(通过 requires_grad

自动求导(Autograd):反向传播的核心

PyTorch 的 autograd 模块通过记录计算图(Computational Graph),自动计算梯度。以下是一个简单示例:

x = torch.tensor(2.0, requires_grad=True)  
y = x ** 2 + 3 * x + 5  
y.backward()  # 计算 dy/dx  

print(x.grad)  # 输出梯度:2*x + 3 = 2*2 +3 =7  

计算图的比喻

想象一个工厂流水线:

  • **输入(x)**是原材料,
  • **运算(如平方、乘法)**是加工步骤,
  • **输出(y)**是最终产品。
    反向传播就像逆向追踪每个步骤对最终结果的影响,计算每个“加工步骤”的贡献(梯度)。

构建第一个神经网络:手写数字识别

任务背景

我们将使用 MNIST 数据集(包含 60,000 张训练图像和 10,000 张测试图像),构建一个简单的全连接神经网络,实现手写数字分类。

步骤 1:准备数据

import torch  
import torch.nn as nn  
import torch.optim as optim  
from torchvision import datasets, transforms  

transform = transforms.Compose([  
    transforms.ToTensor(),  
    transforms.Normalize((0.1307,), (0.3081,))  
])  

train_dataset = datasets.MNIST(root='./data', train=True,  
                              transform=transform, download=True)  
test_dataset = datasets.MNIST(root='./data', train=False,  
                             transform=transform)  

train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True)  
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=64, shuffle=False)  

步骤 2:定义模型

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)      # 隐藏层到输出层  
        self.relu = nn.ReLU()  

    def forward(self, x):  
        x = x.view(-1, 28*28)  # 展平输入张量  
        x = self.relu(self.fc1(x))  
        x = self.relu(self.fc2(x))  
        x = self.fc3(x)  
        return x  

model = SimpleNN()  

步骤 3:训练与优化

criterion = nn.CrossEntropyLoss()  
optimizer = optim.Adam(model.parameters(), lr=0.001)  

num_epochs = 5  
for epoch in range(num_epochs):  
    model.train()  
    for images, labels in train_loader:  
        optimizer.zero_grad()  
        outputs = model(images)  
        loss = criterion(outputs, labels)  
        loss.backward()  
        optimizer.step()  

    print(f'Epoch {epoch+1}/{num_epochs}, Loss: {loss.item():.4f}')  

步骤 4:评估模型

model.eval()  
correct = 0  
total = 0  
with torch.no_grad():  
    for images, labels in test_loader:  
        outputs = model(images)  
        _, predicted = torch.max(outputs.data, 1)  
        total += labels.size(0)  
        correct += (predicted == labels).sum().item()  

print(f'Accuracy on test set: {100 * correct / total:.2f}%')  

训练过程详解

1. 前向传播(Forward Pass)

模型接收输入数据,通过各层计算预测值。例如,在 SimpleNN 中:

  1. 输入图像(形状 28×28)被展平为 784 维向量。
  2. 经过 fc1 层(784 → 128)和 ReLU 激活,提取初步特征。
  3. 再通过 fc2 层(128 → 64)和 ReLU 激活,进一步抽象特征。
  4. 最终 fc3 层将特征映射到 10 个类别(数字 0-9)。

2. 损失计算

交叉熵损失函数比较预测概率与真实标签,输出一个标量损失值。例如,若真实标签是数字“3”,而模型预测为“5”,损失值将较大。

3. 反向传播与参数更新

优化器根据损失值的梯度,通过以下步骤调整参数:

  1. 梯度清零optimizer.zero_grad() 避免梯度累积。
  2. 反向传播loss.backward() 计算所有参数的梯度。
  3. 参数更新optimizer.step() 使用梯度和学习率(Learning Rate)更新参数。

4. 超参数与调试技巧

  • 学习率(Learning Rate):控制参数更新步长,过大会导致震荡,过小会收敛慢。
  • 批次大小(Batch Size):平衡训练速度与内存占用,常用值为 32、64、128。
  • 正则化:如 L2 正则化(权重衰减)或 Dropout 层,防止过拟合。

扩展思考:优化与进阶

1. 更复杂的模型结构

可以尝试以下改进:

  • 卷积神经网络(CNN):通过 nn.Conv2dnn.MaxPool2d 处理图像局部特征。
  • 残差连接(Residual Connection):缓解深层网络的梯度消失问题。

2. 数据增强与预处理

transform = transforms.Compose([  
    transforms.RandomRotation(10),  
    transforms.RandomHorizontalFlip(),  
    transforms.ToTensor(),  
    transforms.Normalize((0.1307,), (0.3081,))  
])  

3. 模型保存与加载

torch.save(model.state_dict(), 'simple_nn.pth')  

model = SimpleNN()  
model.load_state_dict(torch.load('simple_nn.pth'))  

结论

通过本文,读者应已掌握 PyTorch 神经网络的基础知识,包括张量操作、自动求导、模型构建与训练流程。从简单的全连接网络到实际案例的实现,我们看到 PyTorch 如何将抽象的数学概念转化为可执行的代码。

对于初学者,建议从简单任务入手,逐步尝试更复杂的模型(如 CNN、RNN)和数据集(如 CIFAR-10、ImageNet)。中级开发者则可探索分布式训练、模型压缩等进阶主题。记住,实践是掌握 PyTorch 神经网络基础的最佳方式——动手编写代码,调试模型,观察结果,你将逐步揭开深度学习的神秘面纱!

PyTorch 神经网络基础的学习之旅才刚刚开始,但只要保持好奇心和耐心,你定能在这片充满可能性的领域中收获丰硕成果。

最新发布