今天带着大家学习一个非常强大的深度学习框架--PyTorch。
在深度学习及人工智能领域,PyTorch 凭借其高度的灵活性和强大的性能,成为最受欢迎的深度学习框架之一。以下是对 PyTorch 核心操作的精心汇总,建议珍藏以备深入学习和实践之需。
Pytorch 简介
PyTorch 是一个用于机器学习和深度学习的开源深度学习框架,由 Facebook 于 2016 年发布,其主要实现了自动微分功能,并引入动态计算图使模型建立更加灵活。
【pytorch算法入门到进阶教程】
【2025】这才是科研人该学的pytorch教程!通俗易懂,完全可以自学,7天带你构建神经网络,解决pytorch框架问题!深度学习|机器学习|人工智能https://www.bilibili.com/video/BV1FqQRYZEn3/?spm_id_from=333.1387.homepage.video_card.click这才是科研人该学的!一口气学完深度学习【TensorFlow、PyTorch 和、Keras】三大框架算法原理及实战!通俗易懂,草履虫都能学会!机器学习|深度学
https://www.bilibili.com/video/BV1Tgx7enER2/?spm_id_from=333.1387.upload.video_card.click
在 PyTorch 中,核心组件主要包括以下几个部分:
Tensor 模块
Tensor 是 PyTorch 的基本数据结构,类似于 NumPy 的 ndarray,但 Tensor 可以在 GPU 上加速计算,是神经网络中数据的主要存储和计算单元。
创建张量
使用 torch.tensor()函数可以直接从 Python 列表或 NumPy 数组重创建张量。
import numpy as np
import torch
# 从python列表中创建张量
tensor_list = torch.tensor([[1, 2], [3, 4]])
# 从NumPy数组创建张量
np_array = np.array([1, 2], [3, 4])
tensor_np = torch.tensor(np_array)
创建特定值张量
使用 torch.zeros()和 torch.ones():创建指定形状的全零或全一张量;
使用 torch.rand()和 torch.randn():创建均匀分布或正态分布的张量。
import torch
# 创建全1矩阵
tensor_ones = torch.ones(4, 3)
# 创建全0矩阵
tensor_zeros = torch.zeros(3, 3)
创建随机张量
import torch
# 从[0,1]中随机取
tensor_rand = torch.rand(3, 3)
# 从正态分布中取
tensor_randn = torch.randn(3, 3)
# 从指定范围内随机取整数
tensor_randint = torch.randint(0, 9, [3, 3])
print(tensor_randint)
#tensor([[6, 3, 0],
[8, 8, 1],
[7, 0, 7]])
张量的数学运算
a = torch.tensor([[1, 2], [3, 4]])
b = torch.tensor([[1, 2], [3, 4]])
# 加法运算
c = a + b
# 矩阵乘法(叉乘)
c = torch.mm(a, b)
# 横轴累加
print(torch.cumsum(a, dim=0))
# 纵轴累乘
print(torch.cumprod(a, dim=1))
# 均值
print(a.mean())
# 最大值
print(torch.max(a))
索引与切片
import torch
a = torch.arange(9).view(3, 3)
print(a)
#tensor([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
# 直接索引
print(a[1, 2])
#tensor(5)
# 布尔索引
index = a > 3
print(a[index])
#tensor([4, 5, 6, 7, 8])
# 切片
print(a[1:, :2])
#tensor([[3, 4],[6, 7]])
print(a[::2])
#tensor([[0, 1, 2],[6, 7, 8]])
nn.Module 模块
n.Module 模块是所有神经网络模块的基类。用户可以通过继承 nn.Module 定义自己的神经网络层、模型,并使用模块化的方式构建复杂的深度学习模型,里面提供了大量的神经网络层和损失函数。
构建网络模型
创建自定义的神经网络模块需要继承 nn.Module,并实现_init_和 forward 方法。
import torch.nn as nn
import torch.nn.functional as F
class MyModel(nn.Module):
def __init__(self):
super(MyModel, self).__init__()
self.conv1 = nn.Conv2d(3, 32, 3) # 定义一个卷积层
def forward(self, x):
x = F.relu(self.conv1(x)) # 应用ReLU激活函数
return x
上述代码表示定义一个 MyModel 类继承 nn.Module。在init法中定义网络所需的层和参数,通过重写 forward 方法来实现模型的前向传播过程。
因此我们定义一个卷积层:输入通道数为 3,输出通道数为 32,卷积核大小为:3。
nn.Module 的常用方法和属性
1.parameters() 方法
parameters() 方法: 返回要训练的参数的迭代器。参数通常以 nn.Parameter 的形式注册到模块中。
# 实例化模型
model = MyModel()
# 创建优化器,将模型参数传递给优化器
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 打印模型的参数
for param in model.parameters():
print(param.size())
model.parameters() 返回模型中所有可训练的参数,包括 conv1 的权重和偏置。
(2)named_parameters() 方法
named_parameters(): 返回一个生成器,生成 (name, parameter) 对,方便查看参数名称和形状
# 实例化模型
model = MyModel()
# 创建优化器,将模型参数传递给优化器
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 以键值对的方式打印模型的参数
for name, param in model.named_parameters():
print(f'Parameter {name}: shape {param.shape}')
(3) state_dict() 和 load_state_dict() 方法
在训练完模型后,我们通常需要保存模型的参数。
state_dict(): 回包含模型所有可学习参数和缓冲区的字典对象,因此可以使用 save()函数对模型的参数进行保存;
load_state_dict(): 参数字典加载到模型中。
# 保存模型
torch.save(model.state_dict(), 'model.pth')
# 加载模型
model = SimpleNN()
model.load_state_dict(torch.load('model.pth'))
model.eval() # 切换到评估模式
(4) train() 和 eval() 方法
model.train(): 当模型处于训练模式,它会启用 Dropout 和 Batch Normalization(BN),确保 BN 层利用每一批数据的实时统计信息,Dropout 则随机选择部分连接进行训练。
model.eval(): 在评估模式下,模型关闭 Dropout 和 BN 的随机行为,BN 使用训练时学习的均值和方差,确保测试时的稳定性,但不更新参数。
import torch
import torch.nn as nn
# 定义一个包含 Dropout 和 BatchNorm 的模型
class NetWithDropout(nn.Module):
def __init__(self):
super(NetWithDropout, self).__init__()
self.fc1 = nn.Linear(20, 50)
self.bn1 = nn.BatchNorm1d(50)
self.dropout = nn.Dropout(p=0.5)
self.fc2 = nn.Linear(50, 2)
def forward(self, x):
x = torch.relu(self.bn1(self.fc1(x)))
x = self.dropout(x)
x = self.fc2(x)
return x
# 实例化模型
model = NetWithDropout()
# 在训练过程中
model.train()
# 模拟输入
train_input = torch.randn(10, 20)
train_output = model(train_input)
# 在评估过程中
model.eval()
# 模拟输入
eval_input = torch.randn(10, 20)
eval_output = model(eval_input)
-
在训练模式下, Dropout 随机舍弃神经元,BatchNorm 计算和更新运行时统计量。
-
在评估模式下, Dropout 不起作用,BatchNorm 使用训练过程中计算的统计量。
-
通过切换模式,我们确保模型在不同阶段的行为符合预期。
损失函数模块
PyTorch 框架提供了多种内置的损失函数,用于不同类型的任务和需求,在这里我们只列举出部分常用的损失函数。
1. 回归任务损失函数
(1) nn.MSELoss(均方误差损失)
计算预测值和目标值之间的均方误差(Mean Squared Error),适用于回归问题。
import torch
import torch.nn as nn
# 计算均方误差损失
mse_loss = nn.MSELoss(outputs, targets)
2)nn.L1Loss(平均绝对误差损失)
计算预测值和目标值之间的平均绝对误差(Mean Absolute Error),对异常值更鲁棒。
import torch
import torch.nn as nn
# 计算平均绝对误差损失
l1_loss = nn.L1Loss(outputs, targets)
2. 分类任务损失函数
(1) nn.CrossEntropyLoss(交叉熵损失)
多分类任务的标准损失函数,内部结合了 LogSoftmax 和 NLLLoss。
import torch
import torch.nn as nn
# 计算交叉熵损失
ce_loss = nn.CrossEntropyLoss(outputs, targets)
autograd 模块
autograd 包是 PyTorch 的自动求导模块,支持自动计算梯度。是 PyTorch 中所有神经网络优化的基础,用于在反向传播过程中更新计算图中张量的值。
x = torch.randn(3, requires_grad=True) # 需要计算梯度的tensor
y = x * 2
z = y.mean()
z.backward() # 反向传播,计算梯度
(1) 梯度追踪(requires_grad)
requires_grad=True 表示 PyTorch 开始追踪与该张量相关的所有操作。但是只有这些要求梯度的张量在进行前向传播后才能通过 .backward() 方法来计算其梯度。
import torch
x = torch.tensor([2.0], requires_grad=True) # 启用梯度追踪
w = torch.tensor([3.0], requires_grad=True) # 例如神经网络权重
(2) 反向传播 (backward())
通过 backward() 方法,我们可以计算张量的梯度。
y = x * w
y.backward() # 自动计算梯度,结果保存在 x.grad 和 w.grad
print(x.grad) # 输出: tensor([3.]) (dy/dx = w)
print(w.grad) # 输出: tensor([2.]) (dy/dw = x)
(3) 梯度清零 (zero_grad())
为了避免不必要的内存消耗,通常会在每次参数更新之前使用 .zero_grad() 方法清零所有模型参数的梯度。
# 清空梯度(手动或通过优化器)
x.grad.zero_()
w.grad.zero_()
# 或者使用优化器(更常见):
optimizer = torch.optim.SGD([x, w], lr=0.1)
optimizer.zero_grad() # 清空所有关联张量的梯度
optim 模块
optim 包提供了多种优化算法,例如 SGD、Adam 等,用于更新网络的权重。
(1) SGD (Stochastic Gradient Descent)
随机梯度下降是最基本的优化算法之一。它在每次迭代中只使用一个样本或一个小批量样本来计算梯度,然后更新参数。
import torch.optim as optim
#第一种方法:使用SGD优化器
optimizer = optim.SGD(model.parameters(), lr=0.01) # 创建一个优化器对象
# 训练循环
for data, target in train_loader:
optimizer.zero_grad() # 清空梯度
output = model(data) # 前向传播
loss = loss_fn(output, target) # 计算损失
loss.backward() # 反向传播
optimizer.step() # 更新参数
(2) Adam
Adam 是一种自适应学习率优化算法,它结合了 RMSprop 和 Momentum 的思想。Adam 通常被认为在实践中效果很好。
import torch.optim as optim
# 第二种方式:使用Adam优化器
optimizer = optim.Adam(model.parameters(), lr=0.001, betas=(0.9, 0.999), eps=1e-08)
# 训练循环
for data, target in train_loader:
optimizer.zero_grad() # 清空梯度
output = model(data) # 前向传播
loss = loss_fn(output, target) # 计算损失
loss.backward() # 反向传播
optimizer.step() # 更新参数
(3) RMSprop
RMSprop 是一种自适应学习率方法,它通过对梯度按元素平方进行加权平均来调整每个参数的学习率。
import torch.optim as optim
# 使用RMSprop优化器
optimizer = optim.RMSprop(model.parameters(), lr=0.001, alpha=0.99, eps=1e-08, weight_decay=0.0, momentum=0, centered=False)
# 训练循环
for data, target in train_loader:
optimizer.zero_grad() # 清空梯度
output = model(data) # 前向传播
loss = loss_fn(output, target) # 计算损失
loss.backward() # 反向传播
optimizer.step() # 更新参数
(4) Adadelta
Adadelta 是另一种自适应学习率方法,它试图限制学习率的变化,从而不需要手动设置学习率。
import torch.optim as optim
# 第四种方式:使用Adadelta优化器
optimizer = optim.Adadelta(model.parameters(), lr=1.0, rho=0.9, eps=1e-06, weight_decay=0)
# 训练循环
for data, target in train_loader:
optimizer.zero_grad() # 清空梯度
output = model(data) # 前向传播
loss = loss_fn(output, target) # 计算损失
loss.backward() # 反向传播
optimizer.step() # 更新参数
(5) AdamW
AdamW 是 Adam 的一个变种,它在计算权重衰减时采用了不同的方法,通常被认为在训练某些模型时表现更好。
import torch.optim as optim
# 使用AdamW优化器
optimizer = optim.AdamW(model.parameters(), lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0.01)
# 训练循环
for data, target in train_loader:
optimizer.zero_grad() # 清空梯度
output = model(data) # 前向传播
loss = loss_fn(output, target) # 计算损失
loss.backward() # 反向传播
optimizer.step() # 更新参数
DataLoader 模块
DataLoader 是 PyTorch 中用于加载和批处理数据的工具,能够自动进行数据的批处理、随机打乱数据、并行加载数据等操作,常与 Dataset 一起使用,使得数据的预处理和加载变得更加高效和简单。
DataLoader 有很多参数,但常用的有下面五个:
dataset: 表示 Dataset 类,表示指定要加载的数据集;
batch_size: 表示指定每个数据批次包含的样本数;
num_works: 表示是否多进程读取数据,默认为 0,意味着数据将在主进程中加载;
shuffle: 表示指定在每个 epoch 开始时是否打乱数据。True 表示打乱数据,False 表示不打乱。通常在训练集上使用 shuffle=True,以确保模型不会每次都以相同的顺序看到相同的样本;
drop_last: 表示当样本数不能被 batch_size 整除时,是否舍弃最后一批数据,True 表示丢弃,False 表示不丢弃。
from torch.utils.data import DataLoader, TensorDataset
dataset = TensorDataset(x_data, y_data) # 创建数据集对象
dataloader = DataLoader(dataset, batch_size=64, shuffle=True) # 创建DataLoader对象
CUDA (GPU 加速)模块
神经网络模型通常需要大量的计算资源,如果想使用 GPU 来加速训练过程,可以将模型的所有参数和缓冲区移动到指定的设备(如 CPU 或 GPU)。
# 检查是否有可用的 GPU
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f'Using device: {device}')
# 将模型移动到指定设备
model.to(device)
model.to(device) 会递归地将模型的所有参数和缓冲区移动到指定设备。MyModel().to(device) # 将模型移至 GPU 或 CPU。
以上组件共同构成了 PyTorch 的基础架构,使得构建和训练深度学习模型变得高效和便捷。通过组合这些组件,可以创建复杂的神经网络模型并进行训练。
实战操作
使用 PyTorch 构建一个简单的神经网络来对鸢尾花(Iris)数据集进行分类。鸢尾花数据集是一个经典的多分类数据集,包含 150 个样本,每个样本有 4 个特征(花萼长度、花萼宽度、花瓣长度、花瓣宽度),这些样本属于 3 个不同的鸢尾花种类。
以下是一个使用 PyTorch 构建简单神经网络来对鸢尾花数据集进行分类的完整示例:
import torch
import torch.nn as nn
import torch.optim as optim
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from torch.utils.data import DataLoader, TensorDataset
# 加载鸢尾花数据集
iris = datasets.load_iris()
X, y = iris.data, iris.target
# 将标签转换为PyTorch张量,并进行one-hot编码(虽然对于3类问题不是必需的,但可以作为练习)
y_tensor = torch.tensor(y, dtype=torch.long)
# 如果要使用one-hot编码,可以使用以下代码(但注意,CrossEntropyLoss期望的是类索引而不是one-hot向量)
# y_one_hot = torch.nn.functional.one_hot(y_tensor, num_classes=3).float()
# 数据标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=42)
# 转换为PyTorch张量
X_train_tensor = torch.tensor(X_train, dtype=torch.float32)
X_test_tensor = torch.tensor(X_test, dtype=torch.float32)
# 创建数据加载器
train_dataset = TensorDataset(X_train_tensor, y_tensor[:len(X_train_tensor)])
test_dataset = TensorDataset(X_test_tensor, y_tensor[len(X_train_tensor):])
train_loader = DataLoader(train_dataset, batch_size=16, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=16, shuffle=False)
# 定义简单的神经网络
class SimpleNN(nn.Module):
def __init__(self, input_size, hidden_size, num_classes):
super(SimpleNN, self).__init__()
self.fc1 = nn.Linear(input_size, hidden_size)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(hidden_size, num_classes)
def forward(self, x):
out = self.fc1(x)
out = self.relu(out)
out = self.fc2(out)
return out
# 实例化模型、定义损失函数和优化器
input_size = X_train_tensor.shape[1]
hidden_size = 10# 可以根据需要调整隐藏层大小
num_classes = 3
model = SimpleNN(input_size, hidden_size, num_classes)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
# 训练模型
num_epochs = 50
for epoch in range(num_epochs):
model.train()
running_loss = 0.0
for inputs, labels in train_loader:
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item() * inputs.size(0)
epoch_loss = running_loss / len(train_loader.dataset)
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {epoch_loss:.4f}')
# 测试模型
model.eval()
correct = 0
total = 0
with torch.no_grad():
for inputs, labels in test_loader:
outputs = model(inputs)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f'Accuracy of the network on the test images: {100 * correct / total:.2f}%')
以上示例中,我们首先加载并预处理了鸢尾花数据集,包括标准化特征和划分训练集与测试集。然后,我们定义了一个简单的两层全连接神经网络,并使用交叉熵损失和随机梯度下降优化器来训练它。最后,我们在测试集上评估了模型的准确性。