DataLoader + 归一化

🎉摘要:本文通过Python代码演示PyTorch中DataLoader与归一化(Normalize)的使用,基于MNIST数据集,展示如何创建Dataset、DataLoader,并对比归一化前后像素数值分布,帮助理解数据预处理流程。

把下面代码保存为 chapter03_preprocessing.py,运行代码了解 DataLoader 和归一化。

完整代码如下:

"""
第 3 章:数据预处理 —— DataLoader + 归一化

运行方式:python chapter03_preprocessing.py
"""
import torch
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt

# 解决matplotlib中文乱码,必须在绘图执行前设置
plt.rcParams["font.family"] = ["Microsoft YaHei"]
plt.rcParams["axes.unicode_minus"] = False  # 解决负号方框乱码显示异常


# 1. 定义图像预处理流水线
# Compose:将多个图像变换操作组合在一起,按照列表书写顺序依次执行
transform = transforms.Compose([
    # 转换:PIL图片转为Tensor张量,像素从0~255缩放到[0,1],维度变为(C,H,W)
    transforms.ToTensor(),
    # 标准化运算 x'=(x‑mean)/std
    # 使用 MNIST 数据集全局均值、标准差,将数据变换为均值0、标准差1附近
    transforms.Normalize((0.1307,), (0.3081,))
])


# 2. 创建 Dataset 数据集对象
# 训练集 Dataset:负责保存全部训练样本,单条样本读取,不做分批
train_dataset = datasets.MNIST(
    root="./data", train=True, download=True, transform=transform
)
# 测试集 Dataset:测试样本,复用本地数据集文件,使用同样的预处理
test_dataset = datasets.MNIST(
    root="./data", train=False, download=True, transform=transform
)


# 3. 创建 DataLoader 数据加载器
# 训练集加载器:每批64个样本,每个 epoch 开始时打乱样本顺序
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
# 测试集加载器:每批64个样本;测试集不需要打乱样本顺序
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)

print(f"训练集:{len(train_dataset)} 张图 → {len(train_loader)} 个 batch(batch_size=64)")
print(f"测试集:{len(test_dataset)} 张图 → {len(test_loader)} 个 batch(batch_size=64)")


# 4. 取出1个batch,查看张量维度与统计信息
# iter(train_loader):把dataloader转为迭代器;next()取出第一批数据
images, labels = next(iter(train_loader))
# 打印图像batch张量形状 [batch_size, channel, height, width]
print(f"\n一个 batch 的 images 形状: {images.shape}")
print(f"  → 解读: 64张图 × 1个通道 × 28高度 × 28宽度")
# label张量:保存这一批64张图片对应的数字标签
print(f"一个 batch 的 labels 形状: {labels.shape}")

# 打印经过Normalize标准化后的像素最小、最大值、均值、标准差
print(f"归一化后像素范围: {images.min():.3f} ~ {images.max():.3f}")
print(f"归一化后像素均值: {images.mean():.3f}, 标准差: {images.std():.3f}")

# 5. 可视化对比归一化前、归一化后
# 重新构建一套只执行ToTensor、不做Normalize的数据集,用来拿到原始[0‑1]像素图片
raw_dataset = datasets.MNIST(
    root="./data", train=True, download=True,
    transform=transforms.ToTensor()
)

# 取同一张图片:一张未归一化、一张经过归一化
raw_img, _ = raw_dataset[0]     # 原始图片:只ToTensor,没有标准化
norm_img, lbl = train_dataset[0]# 处理后图片:ToTensor + Normalize标准化

# 创建一行两列画布,左右分别放两张对比图
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 4))

# squeeze去掉通道维度(1,28,28)→(28,28),灰度图展示原始图片
ax1.imshow(raw_img.squeeze(), cmap='gray')
ax1.set_title(f"归一化前\n像素范围: [{raw_img.min():.2f}, {raw_img.max():.2f}]")

# 展示标准化之后的图片;虽然像素数值已经正负,但是matplotlib绘图会自动拉伸,肉眼看不出差别
ax2.imshow(norm_img.squeeze(), cmap='gray')
ax2.set_title(f"归一化后\n像素范围: [{norm_img.min():.2f}, {norm_img.max():.2f}]")

# 设置整张画布的总标题
plt.suptitle("归一化前 vs 归一化后(肉眼看起来一样,数值分布不同)")
# 自动调整子图布局,防止标题文字被截断重叠
plt.tight_layout()
# 弹出绘图窗口展示图片
plt.show()

运行代码,输出如下:

训练集:60000 张图 → 938 个 batch(batch_size=64)
测试集:10000 张图 → 157 个 batch(batch_size=64)

一个 batch 的 images 形状: torch.Size([64, 1, 28, 28])
  → 解读: 64张图 × 1个通道 × 28高度 × 28宽度
一个 batch 的 labels 形状: torch.Size([64])
归一化后像素范围: -0.424 ~ 2.821
归一化后像素均值: 0.006, 标准差: 1.003

归一化前后可视化如下图:

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号