PyTorch深度学习基础教程:从核心概念到MobileNetV2完整训练与推理
希望通过这份教程掌握PyTorch基础、理解卷积层/通道/张量/参数等核心概念,并能独立编写和运行MobileNetV2模型的训练、推理代码。
这份教程会从环境搭建到代码实战,全程面向新手,兼顾易懂性和实用性。
一、环境准备(新手友好版)
1. 基础依赖安装
首先确保安装了Python(推荐3.8-3.10),然后通过pip安装核心库:
# 安装PyTorch(CPU版本,新手优先,无需显卡)
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
# 安装辅助库(数据处理、可视化)
pip install numpy matplotlib tqdm
如果你的电脑有NVIDIA显卡,想安装GPU版本,可以参考PyTorch官方安装页面选择对应命令(新手可先跳过,CPU版本足够完成本教程)。
2. 验证安装
运行以下代码,无报错则安装成功:
import torch
import torchvision
print(f"PyTorch版本:{torch.__version__}")
print(f"CUDA是否可用:{torch.cuda.is_available()}") # CPU版本显示False,正常
二、核心概念解析(通俗+代码验证)
先理解基础概念,再写代码会事半功倍,以下概念均结合PyTorch代码示例,可直接运行验证。
1. 张量(Tensor):深度学习的"基本数据单位"
通俗理解:张量就是多维数组,是PyTorch中存储数据的核心结构,类比:
- 0维张量 = 标量(比如数字5)
- 1维张量 = 向量(比如[1,2,3])
- 2维张量 = 矩阵(比如[[1,2],[3,4]])
- 3维张量 = 比如(通道, 高度, 宽度)的单张图片
- 4维张量 = 比如(批量大小, 通道, 高度, 宽度)的一批图片
代码示例:
import torch
# 1. 创建不同维度的张量
t0 = torch.tensor(5) # 0维张量(标量)
t1 = torch.tensor([1, 2, 3]) # 1维张量(向量)
t2 = torch.tensor([[1, 2], [3, 4]]) # 2维张量(矩阵)
# 4维张量(模拟批量=2,通道=3,高=28,宽=28的图片数据)
t4 = torch.randn(2, 3, 28, 28)
# 2. 核心属性(新手必看)
print("0维张量形状:", t0.shape) # torch.Size([])
print("4维张量形状:", t4.shape) # torch.Size([2, 3, 28, 28])
print("4维张量数据类型:", t4.dtype) # torch.float32(默认)
print("4维张量设备:", t4.device) # cpu(默认)
# 3. 张量操作(深度学习常用)
t = torch.randn(3, 3)
t_plus = t + 2 # 加法(广播机制)
t_mul = t * 3 # 乘法
t_matmul = torch.matmul(t, t) # 矩阵乘法(卷积层核心操作)
2. 通道(Channel):数据的"维度特征"
通俗理解:通道是张量中用于区分"特征维度"的轴,最常见的例子是图片:
- 灰度图:1个通道(只有亮度信息),张量形状如(1, 28, 28)
- RGB彩色图:3个通道(红/绿/蓝),张量形状如(3, 28, 28)
- 卷积层输出的通道:每个通道对应一个"特征图"(比如检测边缘、纹理)
代码示例:
# 模拟RGB图片(3通道,高宽各28)
rgb_img = torch.randn(3, 28, 28)
print("RGB图片形状:", rgb_img.shape) # torch.Size([3, 28, 28])
# 提取单个通道(比如红色通道)
red_channel = rgb_img[0, :, :]
print("红色通道形状:", red_channel.shape) # torch.Size([28, 28])
3. 卷积层(Conv2d):提取特征的"核心组件"
通俗理解:卷积层是深度学习模型(如MobileNetV2)的核心,作用是用"卷积核"(小矩阵)在输入数据上滑动,提取局部特征(比如边缘、角点、纹理)。
- 卷积核:也叫过滤器,是卷积层的"参数",训练过程中会自动学习最优值
- 步长(stride):卷积核滑动的步长
- 填充(padding):在输入边缘补0,保证输出尺寸与输入一致
代码示例(手动定义一个卷积层,看输入输出变化):
import torch.nn as nn
# 定义卷积层:输入通道=3(RGB),输出通道=16,卷积核大小=3,步长=1,填充=1
conv = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, stride=1, padding=1)
# 模拟输入:批量=2,3通道,高宽=28
input_tensor = torch.randn(2, 3, 28, 28)
# 卷积层前向计算
output_tensor = conv(input_tensor)
print("输入形状:", input_tensor.shape) # torch.Size([2, 3, 28, 28])
print("输出形状:", output_tensor.shape) # torch.Size([2, 28, 28, 16]) → 2,16,28,28(批量,输出通道,高,宽)
4. 参数(Parameter):模型需要学习的"权重"
通俗理解:参数是模型中需要通过训练优化的数值(比如卷积层的卷积核数值、偏置值),模型的"学习"本质就是调整这些参数,让模型预测更准确。
代码示例(查看卷积层的参数):
# 延续上面的卷积层
# 查看卷积层的参数列表
params = list(conv.parameters())
print("参数数量:", len(params)) # 2(卷积核权重 + 偏置)
# 卷积核权重:形状=(输出通道, 输入通道, 卷积核高, 卷积核宽)
weight = params[0]
print("卷积核权重形状:", weight.shape) # torch.Size([16, 3, 3, 3])
print("卷积核参数总数:", weight.numel()) # 16*3*3*3=432个参数
# 偏置:形状=(输出通道,)
bias = params[1]
print("偏置形状:", bias.shape) # torch.Size([16])
numel():计算张量中元素的总数,即参数数量- 训练前,参数是随机初始化的;训练后,参数会被优化为最优值
三、MobileNetV2完整实战:训练+推理
MobileNetV2是轻量级卷积神经网络,适合移动端/入门学习,我们会基于CIFAR10数据集(10类分类任务:飞机、汽车、鸟等)实现完整流程。
1. 完整代码(可直接复制运行)
以下代码包含:数据加载、模型定义、训练循环、推理验证,每一步都有详细注释。
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms, models
from torch.utils.data import DataLoader
from tqdm import tqdm # 进度条库,让训练过程更直观
import matplotlib.pyplot as plt
# ====================== 1. 配置全局参数 ======================
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") # 自动选择设备(CPU/GPU)
BATCH_SIZE = 32 # 每次训练的样本数(新手可保持32)
EPOCHS = 5 # 训练轮数(新手先跑5轮,验证流程)
LEARNING_RATE = 0.001 # 学习率
# ====================== 2. 数据预处理与加载 ======================
# 数据预处理:将图片转为张量,并归一化(符合PyTorch模型输入要求)
transform = transforms.Compose([
transforms.Resize((224, 224)), # MobileNetV2要求输入224x224
transforms.ToTensor(), # 转为张量(0-1范围)
transforms.Normalize(mean=[0.485, 0.456, 0.406], # 官方推荐的归一化参数
std=[0.229, 0.224, 0.225])
])
# 加载CIFAR10数据集(自动下载,第一次运行会慢一点)
train_dataset = datasets.CIFAR10(
root="./data", # 数据保存路径
train=True, # 训练集
download=True, # 自动下载
transform=transform
)
test_dataset = datasets.CIFAR10(
root="./data",
train=False, # 测试集
download=True,
transform=transform
)
# 数据加载器(批量加载数据,支持多线程)
train_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=BATCH_SIZE, shuffle=False)
# CIFAR10类别名称(对应标签0-9)
CLASSES = ['飞机', '汽车', '鸟', '猫', '鹿', '狗', '青蛙', '马', '船', '卡车']
# ====================== 3. 加载MobileNetV2模型 ======================
# 加载预训练的MobileNetV2(新手先用预训练,训练更快、效果更好)
model = models.mobilenet_v2(pretrained=True)
# 修改最后一层:适配CIFAR10的10类分类(原模型是ImageNet的1000类)
num_ftrs = model.classifier[1].in_features # 获取最后一层输入特征数
model.classifier[1] = nn.Linear(num_ftrs, 10) # 替换为10类分类层
model = model.to(DEVICE) # 将模型移到指定设备(CPU/GPU)
# ====================== 4. 定义损失函数和优化器 ======================
criterion = nn.CrossEntropyLoss() # 分类任务常用损失函数
optimizer = optim.Adam(model.parameters(), lr=LEARNING_RATE) # 常用优化器
# ====================== 5. 训练函数 ======================
def train_model(model, train_loader, criterion, optimizer, epoch):
model.train() # 模型设为训练模式(启用dropout等)
running_loss = 0.0 # 累计损失
correct = 0 # 正确预测数
total = 0 # 总样本数
# tqdm创建进度条
pbar = tqdm(train_loader, desc=f"训练第{epoch+1}轮")
for inputs, labels in pbar:
inputs, labels = inputs.to(DEVICE), labels.to(DEVICE) # 数据移到设备
# 前向传播
outputs = model(inputs) # 模型预测
loss = criterion(outputs, labels) # 计算损失
# 反向传播+优化
optimizer.zero_grad() # 清空梯度(必须!否则梯度累积)
loss.backward() # 反向传播计算梯度
optimizer.step() # 更新参数
# 统计指标
running_loss += loss.item() * inputs.size(0)
_, predicted = torch.max(outputs, 1) # 获取预测类别(概率最大的类)
total += labels.size(0)
correct += (predicted == labels).sum().item()
# 更新进度条显示
pbar.set_postfix(loss=running_loss/total, acc=100.*correct/total)
# 计算本轮平均损失和准确率
epoch_loss = running_loss / len(train_loader.dataset)
epoch_acc = 100. * correct / total
print(f"训练轮{epoch+1} | 损失:{epoch_loss:.4f} | 准确率:{epoch_acc:.2f}%")
# ====================== 6. 测试函数 ======================
def test_model(model, test_loader, criterion):
model.eval() # 模型设为评估模式(关闭dropout等)
running_loss = 0.0
correct = 0
total = 0
# 评估时不需要计算梯度,加速并节省内存
with torch.no_grad():
pbar = tqdm(test_loader, desc="测试中")
for inputs, labels in pbar:
inputs, labels = inputs.to(DEVICE), labels.to(DEVICE)
outputs = model(inputs)
loss = criterion(outputs, labels)
running_loss += loss.item() * inputs.size(0)
_, predicted = torch.max(outputs, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
pbar.set_postfix(loss=running_loss/total, acc=100.*correct/total)
epoch_loss = running_loss / len(test_loader.dataset)
epoch_acc = 100. * correct / total
print(f"测试结果 | 损失:{epoch_loss:.4f} | 准确率:{epoch_acc:.2f}%\n")
return epoch_acc
# ====================== 7. 开始训练 ======================
if __name__ == "__main__":
best_acc = 0.0
for epoch in range(EPOCHS):
# 训练
train_model(model, train_loader, criterion, optimizer, epoch)
# 测试
test_acc = test_model(model, test_loader, criterion)
# 保存最优模型
if test_acc > best_acc:
best_acc = test_acc
torch.save(model.state_dict(), "mobilenet_v2_cifar10_best.pth")
print(f"保存最优模型,当前最高测试准确率:{best_acc:.2f}%\n")
print(f"训练完成!最高测试准确率:{best_acc:.2f}%")
# ====================== 8. 推理示例(单张图片预测) ======================
def predict_single_image(image_path):
# 加载并预处理单张图片
from PIL import Image
image = Image.open(image_path).convert('RGB')
image = transform(image).unsqueeze(0) # 增加批量维度(模型要求4维输入)
image = image.to(DEVICE)
# 预测
model.eval()
with torch.no_grad():
outputs = model(image)
_, predicted = torch.max(outputs, 1)
class_name = CLASSES[predicted.item()]
print(f"预测结果:{class_name}")
return class_name
# 【使用说明】替换为你自己的图片路径(比如本地的一张汽车图片)
# predict_single_image("test_car.jpg")
2. 代码关键部分解释
(1)数据加载
- CIFAR10是入门级分类数据集,自动下载无需手动处理,适合新手;
transforms是数据预处理核心:将图片转为张量并归一化,符合MobileNetV2的输入要求;DataLoader负责批量加载数据,shuffle=True让训练集每轮打乱,提升泛化能力。
(2)模型修改
- 预训练的MobileNetV2默认是1000类分类,我们需要替换最后一层为10类(适配CIFAR10);
model.to(DEVICE)将模型移到CPU/GPU,保证数据和模型在同一设备上(否则报错)。
(3)训练循环核心
model.train():启用训练模式(比如dropout层生效);optimizer.zero_grad():清空梯度,避免梯度累积;loss.backward():反向传播计算梯度;optimizer.step():更新模型参数(核心的"学习"步骤)。
(4)推理流程
model.eval():启用评估模式(关闭dropout,避免影响预测结果);torch.no_grad():禁用梯度计算,加速预测并节省内存;unsqueeze(0):给单张图片增加批量维度(模型输入要求4维:[批量, 通道, 高, 宽])。
3. 运行结果说明
- 第一次运行会自动下载CIFAR10数据集(约170MB),耐心等待;
- 训练过程中会显示每轮的损失和准确率,5轮后测试准确率约70%-80%(预训练模型效果);
- 训练完成后会保存最优模型到
mobilenet_v2_cifar10_best.pth; - 推理时替换图片路径,即可预测单张图片的类别。
四、常见问题解决(新手必看)
- 报错:“out of memory”:降低
BATCH_SIZE(比如改为16); - 数据下载慢:可手动下载CIFAR10数据集,放到
./data目录; - 推理时图片尺寸错误:确保图片预处理后是224x224;
- 模型加载失败:确保加载的参数文件和模型结构一致。
总结
- 核心概念:张量是PyTorch的基础数据结构,通道是特征维度,卷积层负责提取特征,参数是模型需要学习的权重;
- MobileNetV2实战:核心流程为「数据加载→模型定义(适配任务)→损失/优化器→训练循环→测试→推理」;
- 关键操作:训练时用
model.train(),推理时用model.eval()+torch.no_grad(),参数更新依赖反向传播和优化器.step()。
通过这份教程,你不仅能跑通完整的MobileNetV2训练推理代码,还能理解深度学习的核心基础概念。如果想进一步学习YOLO,可基于此框架替换模型为YOLOv5/YOLOv8(PyTorch版本),核心训练推理流程基本一致。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)