PyTorch 是一个基于 Python 的开源深度学习框架,以其动态计算图和易用性著称。以下是 PyTorch 的核心 API 分类及自定义模型的详细指南:
一、PyTorch 核心 API 分类
1. 张量操作 (Tensor Operations)
1.1核心对象
`torch.Tensor`
-
定义: PyTorch 中的
Tensor是多维数组(类似 NumPy 的ndarray),支持 GPU 加速计算和自动微分。 -
与 NumPy 的关系:
-
Tensor 的设计受 NumPy 启发,但支持 GPU 和自动梯度。
-
可通过
tensor.numpy()和torch.from_numpy()与 NumPy 数组互相转换。
-
1.2创建张量
# 从数据创建
data = [[1, 2], [3, 4]]
tensor = torch.tensor(data) # dtype 自动推断(默认 float32)
# 指定数据类型
tensor = torch.tensor(data, dtype=torch.float64)
# 特殊初始化
zeros = torch.zeros((2, 3)) # 全零张量
ones = torch.ones((2, 3)) # 全一张量
rand = torch.rand((2, 3)) # [0,1) 均匀分布
randn = torch.randn((2, 3)) # 标准正态分布
arange = torch.arange(0, 10, 2) # 类似 range 的序列
1.3数学运算
a = torch.tensor([1, 2, 3])
b = torch.tensor([4, 5, 6])
# 逐元素运算
c = a + b # 等价于 torch.add(a, b),结果为tensor([5, 7, 9])
c = a * b # 逐元素乘法,等价于torch.mul(a,b),结果为tensor([ 4, 10, 18])
c = a.pow(2) # 平方,结果为tensor([1, 4, 9])
# 广播机制
a = torch.ones((2, 3))
b = torch.tensor([1, 2, 3])
c = a + b # b 被广播到 (2,3),结果为tensor([[2., 3., 4.], [2., 3., 4.]])
# 矩阵乘法
mat1 = torch.randn(3, 4)
mat2 = torch.randn(4, 5)
result = torch.matmul(mat1, mat2) # 等价于 mat1 @ mat2,
# 结果为tensor([[ 0.2384, 2.6001, -1.7793, 1.7267, -1.5907],
# [-0.0654, 1.0599, -0.5975, 1.4739, -1.6811],
# [ 0.0711, 0.9760, -1.2212, 3.3302, -2.7632]])
1.4原地操作
a = torch.tensor([1., 2., 3.])
a.add_(5) # 对原张量操作 a+=5, 结果为tensor([6., 7., 8.])
b = a.sqrt_() # 带下划线的操作符表示原地操作
torch.equal(a,b) # 判断a和b是否相同,返回为True
1.5形状操作
tensor.view(shape)和tensor.reshape(shpe)
返回一个对原张量tensor的所有元素创建按照shape重新组合的张量,shape输出的数据数量需要与原张量相同。view()方法和reshape()方法达到的效果相同,但是view方法处理的是连续张量,reshape方法可以处理不连续张量。对于不连续张量,tensor.contiguous().view()等同于tensor.reshape()。
tensor.transpose(dim0,dim1)和tensor.permute(dims)
transpose方法返回一个对原张量tensor的dim0和dim1进行交换的张量,只能对两个维度进行操作。permute方法返回一个按照dims中给出的维度角标重组后的张量。两种方法均会调整张量中元素的位置,因此对一个张量调用此方法后,新张量会变成不连续的。
a = torch.arange(24).reshape(1, 2, 3, 4)
>>> a = tensor([[[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]]])
b = a.transpose(1, 2) # 对a的第二维和第三维进行交换
c = a.view(1, 3, 2, 4) # 对a的第二维和第三维进行重组
d = a.permute(1, 3, 0, 2) # 对a按照输入的维度角标重新排列维度
>>> b : tensor([[[[ 0, 1, 2, 3],
[12, 13, 14, 15]],
[[ 4, 5, 6, 7],
[16, 17, 18, 19]],
[[ 8, 9, 10, 11],
[20, 21, 22, 23]]]])
>>> c : tensor([[[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]],
[[ 8, 9, 10, 11],
[12, 13, 14, 15]],
[[16, 17, 18, 19],
[20, 21, 22, 23]]]])
print(d.shape)
>>> torch.Size([2, 4, 1, 3])
torch.cat(tensors, dim=0)
-
作用: 沿指定维度
dim将多个张量拼接成一个连续的新张量。 -
输入:
-
tensors(sequence of Tensors): 要拼接的张量序列(列表或元组)。 -
dim(int, optional): 拼接的维度,默认为0。
-
-
输出: 拼接后的新张量。
-
形状一致性要求:
-
除
dim维度外,其他所有维度的形状必须完全相同。 -
例如:若
dim=1,则所有张量的第0、2、3等维度必须相等。
-
-
拼接结果形状:
-
dim维度的大小为所有输入张量在该维度大小的总和。 -
其他维度大小保持不变。
-
# 沿 dim=1 拼接(水平拼接)
d = torch.cat([a, b], dim=1)
print(d)
"""
输出:
tensor([[ 1, 2, 3, 7, 8, 9],
[ 4, 5, 6, 10, 11, 12]])
形状:(2, 6)
"""
torch.stack(tensors, dim=0)
-
作用:将多个形状相同的张量沿着新的维度堆叠,生成一个更高维度的张量。
-
输入:
-
tensors(sequence of Tensors):要堆叠的张量序列(列表或元组)。 -
dim(int, optional):指定新维度的位置(默认dim=0)。
-
-
输出:堆叠后的新张量,维度数比输入张量多一维。
-
所有输入张量的形状必须完全相同。
a = torch.tensor([[1, 2, 3], [4, 5, 6]]) # 形状 (2, 3)
b = torch.tensor([[7, 8, 9], [10, 11, 12]])
# 沿新维度 dim=0 堆叠
c = torch.stack([a, b], dim=0)
print(c)
"""
输出:
tensor([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
形状:(2, 2, 3)
"""
2. 自动微分 (Autograd)
2.1梯度跟踪开关
-
requires_grad属性:-
所有依赖该张量的计算都会被跟踪,形成动态计算图。
-
默认值:创建张量时默认为
False(如torch.tensor([1.0]))。
-
tensor.requires_grad = True # 启用梯度跟踪
tensor.requires_grad_(True) # 原地修改方法(推荐)
2.2梯度计算
-
.backward()方法:-
计算所有参与计算图的张量的梯度,结果存储在
.grad属性中。 -
仅限标量输出:默认只能对标量(如
loss)调用.backward(),非标量需传递gradient参数。
-
loss.backward() # 标量损失反向传播
output.backward(gradient=torch.ones_like(output)) # 非标量输出需指定梯度权重
2.3梯度累积与清零
-
梯度累积:每次调用
.backward()会累加梯度到.grad。 -
梯度清零:
optimizer.zero_grad() # 优化器清零梯度(推荐)
model.zero_grad() # 模型所有参数梯度清零
tensor.grad.zero_() # 手动清零特定张量梯度
2.4高阶梯度计算
-
create_graph=True:保留计算图以支持高阶导数。
x = torch.tensor(2.0, requires_grad=True)
y = x**3
dy_dx = torch.autograd.grad(y, x, create_graph=True)[0] # 一阶导: 3x²
d2y_dx2 = torch.autograd.grad(dy_dx, x)[0] # 二阶导: 6x
2.5梯度截断
-
梯度裁剪:
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
2.6禁用梯度:
-
torch.no_grad():
with torch.no_grad():
y = model(x) # 不跟踪计算图,节省内存
2.7自定义反向传播
-
torch.autograd.Function:
class MyFunction(torch.autograd.Function):
@staticmethod
def forward(ctx, input):
ctx.save_for_backward(input)
return input.clamp(min=0)
@staticmethod
def backward(ctx, grad_output):
input, = ctx.saved_tensors
grad_input = grad_output.clone()
grad_input[input < 0] = 0
return grad_input
3. 数据加载与处理 (Data Utilities)
3.1核心模块与类
PyTorch 数据处理的基石是 torch.utils.data 模块,主要包含以下类:
-
Dataset: 数据集的抽象类,定义数据访问接口。 -
DataLoader: 数据加载器,实现批量加载、多进程加速等功能。 -
Sampler: 控制数据采样策略(如顺序、随机、加权采样)。 -
Transform: 数据预处理与增强(通过torchvision.transforms或自定义)。
3.2数据集类的使用
必须实现 __len__ 和 __getitem__ 方法
from torch.utils.data import Dataset
class CustomDataset(Dataset):
def __init__(self, data, labels, transform=None):
self.data = data
self.labels = labels
self.transform = transform
def __len__(self):
return len(self.data)
def __getitem__(self, idx):
sample = self.data[idx]
label = self.labels[idx]
if self.transform:
sample = self.transform(sample)
return sample, label
# 假设 data 和 labels 是已加载的原始数据
dataset = CustomDataset(data, labels, transform=my_transform)
3.3数据加载器
from torch.utils.data import DataLoader
dataloader = DataLoader(
dataset, # 数据集对象
batch_size=32, # 每批数据量
shuffle=True, # 是否打乱数据(训练时建议开启)
num_workers=4, # 并行加载的进程数(建议设为 CPU 核心数)
pin_memory=True, # 数据直接加载到 GPU 内存(加速 GPU 训练)
drop_last=False, # 是否丢弃最后不足一个 batch 的数据
collate_fn=None # 自定义批次组装函数(处理不同长度样本)
)
3.4数据增强
from torchvision import transforms
# 组合多个变换
transform = transforms.Compose([
transforms.Resize(256), # 调整大小
transforms.RandomCrop(224), # 随机裁剪
transforms.RandomHorizontalFlip(), # 随机水平翻转
transforms.ToTensor(), # 转为 Tensor (范围 [0,1])
transforms.Normalize( # 标准化 (均值, 标准差)
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]
)
])
3.5内置数据集与工具
使用 torchvision 内置数据集
from torchvision.datasets import MNIST
from torchvision.transforms import ToTensor
# 下载并加载 MNIST 数据集
train_data = MNIST(
root="data", # 数据存储路径
train=True, # 训练集
download=True, # 自动下载
transform=ToTensor() # 转换到 Tensor
)
数据集分割
from torch.utils.data import random_split
# 按比例分割数据集
train_size = int(0.8 * len(dataset))
val_size = len(dataset) - train_size
train_dataset, val_dataset = random_split(dataset, [train_size, val_size])
快速封装数据
from torch.utils.data import TensorDataset
# 将数据和标签封装为 Dataset
data_tensor = torch.tensor(data)
labels_tensor = torch.tensor(labels)
dataset = TensorDataset(data_tensor, labels_tensor)
3.6高级功能
自定义采样器
from torch.utils.data import WeightedRandomSampler
# 处理类别不平衡:为每个样本指定采样权重
weights = [0.9 if label == 0 else 0.1 for label in labels]
sampler = WeightedRandomSampler(weights, num_samples=1000, replacement=True)
dataloader = DataLoader(dataset, batch_size=32, sampler=sampler)
自定义批次组装
处理边长序列(如文本)
def collate_padded(batch):
# batch 是 [(data1, label1), (data2, label2), ...]
inputs = [item[0] for item in batch]
labels = torch.tensor([item[1] for item in batch])
# 填充到相同长度
inputs_padded = torch.nn.utils.rnn.pad_sequence(inputs, batch_first=True)
return inputs_padded, labels
dataloader = DataLoader(dataset, collate_fn=collate_padded)
3.7最佳实践与注意事项
-
加速数据加载:
-
设置
num_workers=4~8(根据 CPU 核心数调整)。 -
启用
pin_memory=True(搭配 GPU 时)。 -
使用 SSD 硬盘存储数据。
-
-
内存管理:
-
大规模数据集使用
IterableDataset流式加载。 -
避免在
__getitem__中执行耗时操作。
-
-
数据增强:
-
训练集开启增强(如旋转、裁剪),验证集关闭。
-
-
调试技巧:
# 检查单个样本
sample, label = dataset[0]
print(sample.shape, label)
# 可视化批次数据
import matplotlib.pyplot as plt
batch = next(iter(dataloader))
plt.imshow(batch[0][0].permute(1,2,0))
4. 神经网络模块 (torch.nn)
4.1核心组件概览
`torch.nn` 提供了构建神经网络所需的所有基础模块,主要分为以下类别:
层类型(Layers): 如全连接层、卷积层、循环层等。
容器(Containers): 如 `Sequential`、`ModuleList` 用于组合层。
激活函数(Activation Functions): 如 `ReLU`、`Sigmoid`。
损失函数(Loss Functions): 如 `CrossEntropyLoss`、`MSELoss`。
实用工具(Utilities): 如参数初始化、归一化层。
4.2层类型
全连接层(Linear Layer)
import torch.nn as nn
# 输入特征数 784,输出特征数 128
fc = nn.Linear(in_features=784, out_features=128, bias=True)
卷积层
2D 卷积(图像处理):
# 输入通道数 3,输出通道数 64,3x3 卷积核
conv = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, stride=1, padding=1)
1D 卷积(时序数据):
conv1d = nn.Conv1d(in_channels=16, out_channels=32, kernel_size=3)
循环神经网络层
长短期记忆(LSTM):
# 输入特征数 100,隐藏层特征数 256,2 层堆叠
lstm = nn.LSTM(input_size=100, hidden_size=256, num_layers=2, batch_first=True)
门控制单元(GRU):
gru = nn.GRU(input_size=100, hidden_size=256, bidirectional=True) # 双向 GRU
其他常用层
池化层:
max_pool = nn.MaxPool2d(kernel_size=2) # 最大池化
avg_pool = nn.AvgPool2d(kernel_size=2) # 平均池化
归一化层:
batch_norm = nn.BatchNorm2d(num_features=64) # 批量归一化
layer_norm = nn.LayerNorm(normalized_shape=128) # 层归一化
嵌入层(用于 NLP):
embed = nn.Embedding(num_embeddings=10000, embedding_dim=300) # 词嵌入
4.3容器
`nn.Sequential`
按顺序堆叠层:
model = nn.Sequential(
nn.Linear(784, 128),
nn.ReLU(),
nn.Linear(128, 10)
)
`nn.ModuleList`
动态管理层列表(适用于可变层数):
class DynamicModel(nn.Module):
def __init__(self):
super().__init__()
self.layers = nn.ModuleList([
nn.Linear(784, 256),
nn.Linear(256, 128)
])
def forward(self, x):
for layer in self.layers:
x = layer(x)
return x
`nn.ModuleDict`**
通过字典管理子模块:
model_dict = nn.ModuleDict({
'conv': nn.Conv2d(3, 64, 3),
'pool': nn.MaxPool2d(2)
})
4.4激活函数
常用激活函数
relu = nn.ReLU() # 整流线性单元
sigmoid = nn.Sigmoid() # 输出范围 (0,1)
tanh = nn.Tanh() # 输出范围 (-1,1)
softmax = nn.Softmax(dim=1) # 沿指定维度归一化
leaky_relu = nn.LeakyReLU(negative_slope=0.1) # 带泄漏的 ReLU
使用方式
x = torch.randn(2, 128)
x = relu(x) # 直接应用
4.5损失函数
分类任务
# 交叉熵损失(输入为 logits,无需手动 softmax)
ce_loss = nn.CrossEntropyLoss()
loss = ce_loss(outputs, labels) # outputs: (B, C), labels: (B)
# 二元分类(输入为概率)
bce_loss = nn.BCELoss()
loss = bce_loss(predictions, labels)
回归任务
mse_loss = nn.MSELoss() # 均方误差
mae_loss = nn.L1Loss() # 平均绝对误差
smooth_l1 = nn.SmoothL1Loss() # Huber 损失
自定义损失函数
class CustomLoss(nn.Module):
def __init__(self):
super().__init__()
def forward(self, pred, target):
return (pred - target).abs().mean() # MAE 的等价实现
loss_fn = CustomLoss()
4.6优化器
常用优化器
from torch.optim import SGD, Adam, RMSprop
# 随机梯度下降(带动量)
optimizer = SGD(model.parameters(), lr=0.01, momentum=0.9)
# Adam 优化器(自适应学习率)
optimizer = Adam(model.parameters(), lr=1e-3, weight_decay=1e-4)
# RMSprop
optimizer = RMSprop(model.parameters(), lr=0.01, alpha=0.99)
学习率调度器
from torch.optim.lr_scheduler import StepLR
scheduler = StepLR(optimizer, step_size=30, gamma=0.1) # 每 30 个 epoch 学习率 ×0.1
4.7模型保存与加载
保存模型参数
torch.save(model.state_dict(), 'model.pth')
加载模型参数
model = MyModel()
model.load_state_dict(torch.load('model.pth'))
model.eval() # 切换到评估模式(关闭 Dropout/BatchNorm)
保存模型参数、优化器状态、epoch 等信息,便于恢复训练
# 保存检查点
checkpoint = {
'epoch': 10,
'model_state_dict': model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
'loss': loss,
}
torch.save(checkpoint, 'checkpoint.pth')
# 加载检查点
checkpoint = torch.load('checkpoint.pth')
model.load_state_dict(checkpoint['model_state_dict'])
optimizer.load_state_dict(checkpoint['optimizer_state_dict'])
epoch = checkpoint['epoch']
loss = checkpoint['loss']
4.8自定义模型
继承 `nn.Module`
class MyModel(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(3, 64, 3)
self.fc = nn.Linear(64 * 28 * 28, 10)
def forward(self, x):
x = self.conv1(x)
x = x.view(x.size(0), -1) # 展平
x = self.fc(x)
return x
参数初始化
def init_weights(m):
if isinstance(m, nn.Linear):
nn.init.xavier_uniform_(m.weight)
m.bias.data.fill_(0.01)
model.apply(init_weights) # 递归应用初始化函数
4.9高级功能
参数共享**
shared_layer = nn.Linear(128, 64)
model = nn.Sequential(
shared_layer,
nn.ReLU(),
shared_layer # 重复使用同一层(参数共享)
)
4.10应用场景示例
图像分类(CNN)
class CNN(nn.Module):
def __init__(self):
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(3, 64, 3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(64, 128, 3),
nn.ReLU(),
nn.MaxPool2d(2)
)
self.classifier = nn.Linear(128 * 6 * 6, 10)
def forward(self, x):
x = self.features(x)
x = x.view(x.size(0), -1)
x = self.classifier(x)
return x
序列建模(RNN)
class RNN(nn.Module):
def __init__(self, vocab_size, embed_dim, hidden_size):
super().__init__()
self.embed = nn.Embedding(vocab_size, embed_dim)
self.rnn = nn.GRU(embed_dim, hidden_size, batch_first=True)
self.fc = nn.Linear(hidden_size, 1) # 二分类
def forward(self, x):
x = self.embed(x)
_, h_n = self.rnn(x)
output = self.fc(h_n.squeeze(0))
return output
4.11注意事项
设备管理: 确保模型和数据在同一设备(CPU/GPU)。
model = model.to('cuda')
inputs = inputs.to('cuda')
训练模式切换: 训练时 `model.train()`,评估时 `model.eval()`。
梯度清零: 每个 batch 前调用 `optimizer.zero_grad()`。
参数访问: 使用 `model.parameters()` 获取所有可训练参数。
5. 设备管理 (Device Management)
5.1设备选择与初始化
设备对象 (`torch.device`)
创建设备对象:指定目标设备类型(CPU 或 CUDA)。
device_cpu = torch.device('cpu') # CPU 设备
device_gpu = torch.device('cuda') # 默认 GPU(索引 0)
device_gpu1 = torch.device('cuda:1') # 指定 GPU 索引
检查 CUDA 可用性
if torch.cuda.is_available():
print(f"可用 GPU 数量: {torch.cuda.device_count()}")
print(f"当前 GPU 索引: {torch.cuda.current_device()}")
print(f"GPU 名称: {torch.cuda.get_device_name(0)}")
else:
print("CUDA 不可用")
5.2张量与模型的设备移动
将张量移动到指定设备
使用 `to()` 方法:
tensor = torch.randn(3, 3)
tensor_gpu = tensor.to(device_gpu) # 移动到 GPU
tensor_cpu = tensor_gpu.to('cpu') # 移回 CPU
直接创建在目标设备:
tensor_on_gpu = torch.randn(3, 3, device=device_gpu)
将模型移动到指定设备
model = MyModel()
model.to(device_gpu) # 所有模型参数移至 GPU
# 前向传播时,输入数据需在同一设备
inputs = inputs.to(device_gpu)
outputs = model(inputs)
5.3多 GPU 训练
数据并行 (`DataParallel`)
单机多卡,自动分割数据到不同 GPU:
model = nn.DataParallel(model, device_ids=[0, 1]) # 使用 GPU 0 和 1
outputs = model(inputs) # inputs 自动分配到各 GPU
loss.backward() # 梯度自动聚合
分布式数据并行 (`DistributedDataParallel`)
适用于多机多卡,效率更高:
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP
# 初始化进程组
dist.init_process_group(backend='nccl', rank=rank, world_size=world_size)
# 包装模型
model = DDP(model, device_ids=[local_rank])
5.4设备相关错误处理
设备不匹配错误
# 错误示例:张量位于不同设备
a = torch.tensor([1.0], device='cuda')
b = torch.tensor([2.0], device='cpu')
c = a + b # RuntimeError: Expected all tensors to be on the same device
# 修复:统一设备
b = b.to('cuda')
c = a + b # 正常执行
加载模型时的设备映射
# 从 GPU 保存的模型加载到 CPU
model.load_state_dict(
torch.load('model_gpu.pth', map_location=torch.device('cpu'))
5.5内存管理
清空 GPU 缓存
torch.cuda.empty_cache() # 释放未使用的显存(不影响张量持有的内存)
监控显存使用
print(torch.cuda.memory_allocated()) # 当前已分配显存(字节)
print(torch.cuda.max_memory_allocated()) # 最大分配显存
5.6设备无关的代码编写
动态选择设备
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model.to(device)
inputs = inputs.to(device)
通用代码模板
class MyModel(nn.Module):
def __init__(self):
super().__init__()
self.layer = nn.Linear(10, 5)
def forward(self, x):
return self.layer(x)
model = MyModel().to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
for batch in dataloader:
inputs, labels = batch
inputs, labels = inputs.to(device), labels.to(device)
outputs = model(inputs)
loss = criterion(outputs, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
5.7最佳实践
统一设备:确保所有张量和模型在同一设备上。
高效数据传输:尽量减少 CPU 和 GPU 之间的数据拷贝。
多 GPU 选择:小规模训练用 `DataParallel`,大规模分布式用 `DDP`。
显存优化:
- 使用 `with torch.no_grad():` 减少中间变量存储。
- 混合精度训练 (`torch.cuda.amp`) 减少显存占用。
二、自定义模型开发指南
1.模型开发基础
1.1 继承 `nn.Module` 类
所有自定义模型必须继承 `nn.Module`,并实现 `__init__` 和 `forward` 方法:
import torch.nn as nn
class CustomModel(nn.Module):
def __init__(self, input_dim, hidden_dim, output_dim):
super().__init__() # 必须调用父类初始化
self.layer1 = nn.Linear(input_dim, hidden_dim)
self.act = nn.ReLU()
self.layer2 = nn.Linear(hidden_dim, output_dim)
def forward(self, x):
x = self.layer1(x)
x = self.act(x)
x = self.layer2(x)
return x
1.2模型实例化与设备管理
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = CustomModel(input_dim=784, hidden_dim=128, output_dim=10).to(device)
2.模型结构设计
2.1层组合策略
`nn.Sequential`**(顺序结构):
self.features = nn.Sequential(
nn.Conv2d(3, 64, 3),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.MaxPool2d(2)
)
`nn.ModuleList`(动态层管理):
self.layers = nn.ModuleList([nn.Linear(10, 10) for _ in range(5)])
`nn.ModuleDict`(字典式管理):
self.blocks = nn.ModuleDict({
'conv': nn.Conv2d(3, 64, 3),
'pool': nn.MaxPool2d(2)
})
2.2分支结构实现
class MultiBranchModel(nn.Module):
def __init__(self):
super().__init__()
self.branch1 = nn.Sequential(...)
self.branch2 = nn.Sequential(...)
def forward(self, x):
out1 = self.branch1(x)
out2 = self.branch2(x)
return torch.cat([out1, out2], dim=1)
3.参数管理
3.1参数初始化
def init_weights(m):
if isinstance(m, nn.Linear):
nn.init.xavier_normal_(m.weight)
nn.init.constant_(m.bias, 0.1)
model.apply(init_weights) # 递归应用初始化
3.2冻结部分参数
for name, param in model.named_parameters():
if 'layer1' in name:
param.requires_grad_(False) # 冻结 layer1 的参数
4.输入输出处理
4.1输入维度适配
def forward(self, x):
# 处理图像输入 (B,C,H,W) → 展平为 (B, C*H*W)
x = x.view(x.size(0), -1)
x = self.fc_layers(x)
return x
4.2多模态输入处理
def forward(self, img, text):
img_feat = self.img_encoder(img)
text_feat = self.text_encoder(text)
return torch.cat([img_feat, text_feat], dim=1)
5.调试与优化
5.1模型结构可视化
from torchsummary import summary
summary(model, input_size=(3, 224, 224)) # 输出各层维度信息
5.2 梯度监控
# 注册梯度钩子
def grad_hook(grad):
print(f"Gradient norm: {grad.norm().item()}")
for name, param in model.named_parameters():
if 'weight' in name:
param.register_hook(grad_hook)
5.3混合精度训练
scaler = torch.cuda.amp.GradScaler()
with torch.cuda.amp.autocast():
outputs = model(inputs)
loss = criterion(outputs, labels)
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()
6.高级功能扩展
6.1 自定义层开发
class CustomLayer(nn.Module):
def __init__(self, in_features, out_features):
super().__init__()
self.weight = nn.Parameter(torch.randn(out_features, in_features))
def forward(self, x):
return x @ self.weight.t()
# 在模型中使用
self.custom_layer = CustomLayer(128, 64)
6.2模型融合技巧
class HybridModel(nn.Module):
def __init__(self):
super().__init__()
self.cnn = torchvision.models.resnet18(pretrained=True)
self.rnn = nn.LSTM(input_size=512, hidden_size=128)
def forward(self, img, seq):
img_feat = self.cnn(img) # CNN 提取图像特征
seq_feat, _ = self.rnn(seq) # RNN 处理序列
return img_feat + seq_feat[:, -1] # 特征融合
7.模型部署准备
7.1TorchScript 导出
script_model = torch.jit.script(model) # 转换为脚本模型
script_model.save("model_scripted.pt")
7.2 ONNX 格式导出
dummy_input = torch.randn(1, 3, 224, 224)
torch.onnx.export(
model,
dummy_input,
"model.onnx",
input_names=["input"],
output_names=["output"]
)
8.最佳实践
8.1设备一致性
确保模型和输入数据位于同一设备
inputs = inputs.to(next(model.parameters()).device)
8.2模式切换
model.train() # 训练模式(启用 Dropout/BatchNorm)
model.eval() # 评估模式(关闭随机层)
8.3检查点管理
定期保存完整训练状态
torch.save({
'epoch': epoch,
'model_state': model.state_dict(),
'optim_state': optimizer.state_dict(),
}, f"checkpoint_epoch{epoch}.pt")
9.常见问题解决
9.1维度不匹配错误
- 症状:`RuntimeError: size mismatch`
- 调试:在 `forward()` 中添加 `print(x.shape)` 跟踪数据流
9.2 梯度消失/爆炸
- 解决:
- 使用梯度裁剪:`nn.utils.clip_grad_norm_(model.parameters(), 1.0)`
- 调整初始化策略
9.3模型加载失败
- 错误:`Missing key(s) in state_dict`
- 处理:
model.load_state_dict(torch.load(path), strict=False) # 忽略未知键
三、调试与优化技巧
1·调试技巧
1.1张量形状跟踪
- 在 `forward()` 中打印形状:
def forward(self, x):
print("Input shape:", x.shape) # 跟踪输入
x = self.conv1(x)
print("After conv1:", x.shape)
x = self.pool(x)
...
return x
- 使用 `torchsummary`:
from torchsummary import summary
summary(model, input_size=(3, 224, 224)) # 输出各层维度信息
1.2 梯度监控
- 检查梯度是否存在:
for name, param in model.named_parameters():
if param.grad is None:
print(f"参数 {name} 无梯度!")
- 注册梯度钩子:
def grad_hook(grad):
print(f"梯度均值: {grad.mean().item()}, 最大值: {grad.max().item()}")
for param in model.parameters():
param.register_hook(grad_hook)
1.3设备一致性检查
# 确保所有张量在同一设备
assert inputs.device == next(model.parameters()).device, "设备不匹配!"
1.4 NaN/Inf 检测
if torch.isnan(outputs).any():
raise ValueError("输出包含 NaN!")
# 或使用自动调试模式
torch.autograd.set_detect_anomaly(True) # 在反向传播时检测异常
2.性能优化技巧
2.1计算图优化
- 禁用梯度计算:
with torch.no_grad(): # 推理阶段使用
outputs = model(inputs)
- 使用 `detach()` 截断计算图:
hidden = rnn_output.detach() # 阻止梯度回传至 RNN
2.2内存优化
- 混合精度训练:
from torch.cuda.amp import autocast, GradScaler
scaler = GradScaler()
with autocast():
outputs = model(inputs)
loss = criterion(outputs, labels)
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()
- 激活检查点(Checkpointing):
from torch.utils.checkpoint import checkpoint
def forward(self, x):
# 分段保存中间结果,减少内存占用
x = checkpoint(self.layer1, x)
x = checkpoint(self.layer2, x)
return x
2.3 批量处理优化
- 增大 `batch_size`:在显存允许下最大化批次。
- 梯度累积:
for i, (inputs, labels) in enumerate(dataloader):
outputs = model(inputs)
loss = criterion(outputs, labels)
loss = loss / accumulation_steps # 梯度累积步数
loss.backward()
if (i+1) % accumulation_steps == 0:
optimizer.step()
optimizer.zero_grad()
3.分布式训练优化
3.1数据并行加速
model = nn.DataParallel(model, device_ids=[0, 1]) # 多 GPU 并行
3.2分布式训练(DDP)
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP
# 初始化进程组
dist.init_process_group(backend='nccl')
model = DDP(model, device_ids=[local_rank])
4.可视化工具
4.1TensorBoard 集成
from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter()
writer.add_graph(model, inputs) # 可视化计算图
writer.add_scalar('Loss/train', loss.item(), epoch)
4.2 使用 `torchviz` 绘制计算图
from torchviz import make_dot
outputs = model(inputs)
make_dot(outputs, params=dict(model.named_parameters())).render("model_graph", format="png")
5.常见错误与修复
5.1CUDA 内存不足
- 症状:`RuntimeError: CUDA out of memory`
- 解决方案:
- 减小 `batch_size`
- 使用混合精度训练 (`amp`)
- 启用激活检查点 (`checkpoint`)
5.2梯度爆炸/消失
- 症状:损失值剧烈波动或停滞
- 解决方案:
# 梯度裁剪
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
# 调整初始化策略
nn.init.xavier_uniform_(layer.weight)
5.3 张量设备不匹配
- 症状:`RuntimeError: Expected all tensors to be on the same device`
- 修复方案:
model = model.to(device)
inputs = inputs.to(device)
6.最佳实践总结
- 调试优先:先确保模型能运行,再优化性能。
- 增量测试:从简单数据(如单个样本)开始验证模型。
- 版本控制:记录 PyTorch 版本和硬件环境。
- 性能分析:使用 `torch.profiler` 定位瓶颈:
with torch.profiler.profile(activities=[torch.profiler.ProfilerActivity.CUDA]) as prof:
model(inputs)
print(prof.key_averages().table(sort_by="cuda_time_total"))
四、扩展资源
官方文档:
英文版 https://pytorch.org/docs/stable/index.html
中文版 主页 - PyTorch中文文档
教程推荐:
- PyTorch 官方 Tutorials
- 《Deep Learning with PyTorch》 - Eli Stevens等著
- Kaggle 上的 PyTorch 实战 Notebook
1509

被折叠的 条评论
为什么被折叠?



