目录

一、先解决 “数据加载”:utils.data 的两大核心工具

1. Dataset:自定义数据集的 “基础模板”

2. DataLoader:批量加载的 “加速器”

二、再搞定 “数据预处理”:torchvision 的实用工具

1. transforms:图像预处理的 “流水线”

2. ImageFolder:多目录图片的 “自动读取器”

三、最后搞定 “训练监控”:TensorBoard 可视化

1. TensorBoard 的 “使用四步走”

2. 额外技能:可视化网络结构和特征图

四、新手总结:数据处理的 “标准流程”


      之前手动处理深度学习数据时,简直是 “步步踩坑”:图片散在不同文件夹里,写了几十行代码才读进来;批量加载时维度总对不上,报错 “size mismatch”;训练时想看看损失值变化,只能一遍遍 print,满屏数字根本看不出趋势。今天学了 PyTorch 数据处理工具箱,才发现原来有这么多 “现成工具”—— 从数据加载到预处理,再到训练可视化,一套流程下来省了超多事。整理了我觉得最实用的知识点,用自己踩过的坑当例子,帮和我一样刚入门的小伙伴少走弯路。

一、先解决 “数据加载”:utils.data 的两大核心工具

      处理数据的第一步是 “把数据读进模型”,PyTorch 的utils.data里有两个 “神器”——DatasetDataLoader,搭配起来用简直绝了。

1. Dataset:自定义数据集的 “基础模板”

Dataset是 PyTorch 读取自定义数据的 “标准接口”,不管是 CSV 表格、numpy 数组还是图片,都要继承它并重写三个方法:

__init__:初始化数据集(比如读数据文件、存标签);

__getitem__:按索引取单个样本(必须转成 Tensor,不然模型不认);

__len__:返回数据集总长度(方便后续批量计算)。

我之前用 numpy 存了个简单的 2 维数据集,用Dataset包装后超清爽:

import torch
from torch.utils import data
import numpy as np

# 继承Dataset基类
class MyFirstDataset(data.Dataset):
    def __init__(self):
        # 初始化数据和标签(比如从CSV读进来的numpy数组)
        self.data = np.asarray([[1,2], [3,4], [2,1], [3,4], [4,5]])  # 2维特征
        self.label = np.asarray([0, 1, 0, 1, 2])  # 对应的标签
    
    def __getitem__(self, index):
        # 单个样本:numpy转Tensor(模型只认Tensor!)
        sample_data = torch.from_numpy(self.data[index])
        sample_label = torch.tensor(self.label[index])
        return sample_data, sample_label  # 返回(数据,标签)对
    
    def __len__(self):
        # 数据集总样本数
        return len(self.data)

# 测试一下
my_data = MyFirstDataset()
print(my_data[2])  # 取索引2的样本,相当于调用__getitem__(2)
print(f"总样本数:{my_data.__len__()}")

运行后会输出(tensor([2, 1], dtype=torch.int32), tensor(0, dtype=torch.int32))和总样本数 5—— 之前手动写循环取样本,还总忘了转 Tensor,现在用Dataset规范多了。

2. DataLoader:批量加载的 “加速器”

Dataset一次只能取一个样本,而模型训练需要 “批量输入”(batch),这时候就需要DataLoader—— 它能自动把Dataset的样本打包成 batch,还能打乱数据、多进程加载,效率直接拉满。

它的参数里有几个新手必调的,我踩过的坑都标在注释里了:

# 用DataLoader包装刚才的数据集
data_loader = data.DataLoader(
    dataset=my_data,        # 要加载的Dataset
    batch_size=2,           # 每次加载2个样本
    shuffle=False,          # 要不要打乱数据(训练时设True,测试时设False!)
    num_workers=0,          # 多进程加载数(Windows下设0,不然容易报错!)
    drop_last=False         # 样本数不是batch整数倍时,要不要丢最后一批(比如5个样本,batch=2,不丢的话最后一批1个)
)

# 遍历加载的batch
for batch_idx, (batch_data, batch_label) in enumerate(data_loader):
    print(f"第{batch_idx}批:")
    print(f"数据:{batch_data}")
    print(f"标签:{batch_label}\n")

运行后会输出 3 批数据:前两批各 2 个样本,最后一批 1 个(因为drop_last=False)。之前我没设shuffle=True,训练时模型总 “记熟” 数据顺序,准确率虚高;后来把shuffle改成 True,准确率才正常 —— 这个参数一定要注意!

二、再搞定 “数据预处理”:torchvision 的实用工具

加载数据后,还要做 “预处理”(比如缩放图片、标准化),不然模型训练慢还容易过拟合。torchvision里的transformsImageFolder,简直是图像数据的 “救星”。

1. transforms:图像预处理的 “流水线”

transforms提供了各种图像操作,比如缩放、裁剪、翻转、标准化,还能用Compose把这些操作串成 “流水线”,像工厂加工一样处理图片。

我做猫狗分类时,写了个常用的预处理流水线,每个操作的作用都标清楚了:

import torchvision.transforms as transforms

# 用Compose串联操作(顺序很重要!先裁剪再转Tensor,最后标准化)
image_transform = transforms.Compose([
    transforms.Resize((224, 224)),  # 先把图片缩放到224×224(模型输入要求统一尺寸)
    transforms.RandomHorizontalFlip(p=0.5),  # 50%概率水平翻转(数据增强,避免过拟合)
    transforms.ToTensor(),  # 把PIL图片转Tensor:(H,W,C)→(C,H,W),值从[0,255]→[0,1]
    transforms.Normalize(mean=(0.5,0.5,0.5), std=(0.5,0.5,0.5))  # 标准化到[-1,1](加速模型收敛)
])

之前我忘了ToTensor这步,直接把 PIL 图片喂给模型,报错 “expected Tensor but got PIL Image”;还有一次没做Normalize,模型训练了 10 轮损失还没降下来 —— 这些预处理步骤真的不能省!

2. ImageFolder:多目录图片的 “自动读取器”

如果图片存在不同文件夹,手动读标签要写一堆代码,而ImageFolder能自动把 “文件夹名” 当标签,直接读取数据 + 标签,省了超多事。

from torchvision import datasets

# 用ImageFolder读取多目录图片
train_dataset = datasets.ImageFolder(
    root="../data/cat_dog",  # 根目录(里面是子文件夹)
    transform=image_transform  # 刚才定义的预处理流水线
)

# 包装成DataLoader
train_loader = data.DataLoader(
    train_dataset,
    batch_size=8,
    shuffle=True,
    num_workers=0
)

# 查看标签映射(文件夹名→数字标签)
print(f"标签映射:{train_dataset.class_to_idx}")  # 输出{'cat':0, 'dog':1}

三、最后搞定 “训练监控”:TensorBoard 可视化

训练时只看 print 的损失值,根本看不出趋势;想看看模型结构对不对,也没法直观检查 —— 这时候就需要TensorBoard,它能把损失值、网络结构、特征图都画出来,训练过程一目了然。

1. TensorBoard 的 “使用四步走”

TensorBoard很简单,记住四个步骤就行,我以 “可视化损失值” 为例:

from torch.utils.tensorboard import SummaryWriter
import torch.nn as nn
import numpy as np

# 步骤1:实例化SummaryWriter,指定日志保存路径(自动创建logs文件夹)
writer = SummaryWriter(log_dir="logs", comment="linear_train")

# 模拟一个简单的线性回归训练(用来说明可视化)
input_size = 1
output_size = 1
model = nn.Linear(input_size, output_size)  # 线性模型
criterion = nn.MSELoss()  # 均方损失
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)  # SGD优化器

# 生成模拟数据
x_train = np.linspace(-1, 1, 100).reshape(100, 1)  # 输入:100个1维数据
y_train = 3 * x_train**2 + 2 + 0.2 * np.random.rand(100, 1)  # 输出:带噪声的二次函数

# 步骤2:训练并记录损失值
num_epochs = 60
for epoch in range(num_epochs):
    # 数据转Tensor
    inputs = torch.from_numpy(x_train).float()
    targets = torch.from_numpy(y_train).float()
    
    # 前向传播
    outputs = model(inputs)
    loss = criterion(outputs, targets)
    
    # 反向传播+优化
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    
    # 记录损失值:add_scalar(标签名,要记录的值,迭代次数)
    writer.add_scalar("训练损失值", loss.item(), epoch)

# 步骤3:关闭writer
writer.close()

# 步骤4:启动TensorBoard(在命令行输入)
# tensorboard --logdir=logs --port 6006
# 然后在浏览器打开 http://localhost:6006 查看

      打开浏览器后,在 “Scalars” 页面能看到损失值随 epoch 下降的曲线 —— 之前我只能 print 每轮损失,现在看曲线能直观判断模型有没有收敛,比如损失降到 1 以下后不再下降,就知道该调学习率了。

2. 额外技能:可视化网络结构和特征图

TensorBoard还能画网络结构、看特征图,帮我排查了很多问题:

  • 可视化网络结构:用writer.add_graph(model, inputs),能看到每一层的输入输出维度,之前我卷积层的out_channels设错了,看结构时一眼就发现了;
  • 可视化特征图:用writer.add_image把卷积层输出的特征图画出来,能看到浅层提取边缘、深层提取纹理,判断模型有没有学到有用的特征。

四、新手总结:数据处理的 “标准流程”

今天学完这些工具,我整理了一套 “数据处理流程”,现在跑项目都按这个来,再也不手忙脚乱了:

  1. 读数据:用ImageFolder(多目录图片)或自定义Dataset(其他数据)读取数据 + 标签;
  2. 预处理:用transforms.Compose串联缩放、翻转、标准化等操作;
  3. 批量加载:用DataLoader打包成 batch,训练时shuffle=True
  4. 监控训练:用TensorBoard记录损失值、画网络结构、看特征图。

现在我用这套流程跑猫狗分类,比之前手动处理数据快了一倍,模型收敛也更稳定了。如果和我一样刚入门,建议先从简单的数据集(比如 MNIST)练手,把这些工具用熟,再挑战复杂项目 ——PyTorch 的工具箱真的很友好,只要找对方法,数据处理一点都不难~

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐