# dataset->dataloader

import torch
from torch.utils.data import Dataset, DataLoader, Sampler
import torch.nn as nn
import torch.optim as optim

解析:

  • torch:PyTorch 主库,用于张量操作。
  • Dataset:数据集基类。
  • DataLoader:批次生成器。
  • Sampler:索引生成器。
  • nn:神经网络模块。
  • optim:优化器。

# 1. 定义 Dataset

class MyDataset(Dataset):
    def __init__(self, data, labels):
        self.data = data       # 存储特征列表
        self.labels = labels   # 存储标签列表

    def __len__(self):
        return len(self.data)  # 返回样本总数

    def __getitem__(self, index):
      x = self.data[index]  # 取第 index 个特征
      y = self.labels[index]  # 取第 index 个标签
      # 转为 tensor 并指定数据类型
        return torch.tensor(x, dtype=torch.float32), torch.tensor(y, dtype=torch.long)

详细解析:

  1. __init__:初始化 Dataset 对象,存储数据和标签。

  2. __len__:Dataset 的长度(样本数),DataLoader 内部会用它来计算 batch 数量。

  3. __getitem__

    • 接收一个整数 index

    • 从列表中取数据和标签。

    • 转为 PyTorch 张量:

      • x 为 float32,用于计算。
      • y 为 long,用于分类任务的 CrossEntropyLoss。
    • 返回 (x, y) 元组。

  4. 关键点:Dataset 本身不处理 batch,也不决定顺序,它只知道如何根据索引取单个样本。


# 2. 定义 Sampler

class ReverseSampler(Sampler):
    def __init__(self, data_source):
        self.data_source = data_source  # Dataset 对象

    def __iter__(self):
        # 返回索引迭代器:倒序取样
        return iter(range(len(self.data_source)-1, -1, -1))

    def __len__(self):
        return len(self.data_source)  # 样本总数

详细解析:

  1. __iter__

    • 返回一个迭代器,用于生成索引序列。

    • range(len(self.data_source)-1, -1, -1)

      • 从最大索引到 0
    • 例如数据有 5 个样本,索引顺序为 [4,3,2,1,0]

  2. __len__

    • 返回 Dataset 长度
    • DataLoader 内部可能用它计算 batch 总数或进度条。
  3. 关键点

    • Sampler 只负责“索引顺序”,不涉及数据本身。
    • 可以用它实现顺序、随机或自定义采样策略。

# 3. 初始化 Dataset + Sampler

data = [[1,2], [3,4], [5,6], [7,8], [9,10]]
labels = [0, 1, 0, 1, 0]

dataset = MyDataset(data, labels)
sampler = ReverseSampler(dataset)
  • Dataset 保存原始数据。

  • Sampler 定义索引顺序(倒序)。

  • 此时数据和索引是分开的:

    Dataset: [ [1,2], [3,4], [5,6], [7,8], [9,10] ]
    Sampler: [4,3,2,1,0]

# 4. 定义 DataLoader

batch_size = 2
dataloader = DataLoader(dataset, batch_size=batch_size, sampler=sampler)

详细解析:

  • DataLoader 接收 Dataset 对象。

  • batch_size=2:每个 batch 2 个样本。

  • sampler=sampler:使用我们自定义的倒序索引。

  • 内部流程

    1. DataLoader 调用 sampler.__iter__() → 得到索引迭代器 [4,3,2,1,0]
    2. 使用 batch_size=2 将索引分批:
    • Batch 0:[4,3]
    • Batch 1:[2,1]
    • Batch 2:[0]
    1. 对每个 batch 调用 dataset.__getitem__,获得 (x, y) 张量。

    2. 返回 batch 张量。

      • x_batch.shape = [batch_size, feature_dim]
      • y_batch.shape = [batch_size]
  • DataLoader 可以多线程加载数据(通过 num_workers),提升效率。


# 5. 定义模型和优化器

model = nn.Linear(2, 2)  # 输入 2 维,输出 2 维(可理解为 2 类 logits)
criterion = nn.CrossEntropyLoss()  # 分类损失
optimizer = optim.SGD(model.parameters(), lr=0.01)
  • nn.Linear(2,2)

    • 输入 2 维特征 [x1, x2]
    • 输出 2 类的 logits
  • CrossEntropyLoss

    • 用于分类任务
    • 内部会自动做 softmax
  • SGD

    • 随机梯度下降优化
    • 更新模型参数

# 6. 模拟训练循环

for epoch in range(1):
    for x_batch, y_batch in dataloader:
        # 前向传播
        outputs = model(x_batch)   # [batch_size, num_classes]
        loss = criterion(outputs, y_batch)

        # 反向传播
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        print("Batch x:", x_batch)
        print("Batch y:", y_batch)
        print("Loss:", loss.item())

详细解析:

  1. for x_batch, y_batch in dataloader

    • DataLoader 迭代 batch
    • 每个 batch 为 (x_batch, y_batch) 张量
  2. outputs = model(x_batch)

    • 前向传播,输出 [batch_size, num_classes] 张量
  3. loss = criterion(outputs, y_batch)

    • 计算 loss
  4. optimizer.zero_grad()

    • 清空梯度,否则梯度会累加
  5. loss.backward()

    • 自动计算梯度
  6. optimizer.step()

    • 更新模型参数
  7. 打印 batch 信息,观察训练数据流与 loss

示例输出(倒序 batch):

Batch x: tensor([[ 9., 10.],
                 [ 7.,  8.]])
Batch y: tensor([0,1])
Loss: 0.7378
Batch x: tensor([[5.,6.],
                 [3.,4.]])
Batch y: tensor([0,1])
Loss: 0.6923
Batch x: tensor([[1.,2.]])
Batch y: tensor([0])
Loss: 0.6789

# 7. 数据流可视化

原始数据
data = [[1,2],[3,4],[5,6],[7,8],[9,10]]
labels = [0,1,0,1,0]


Dataset (MyDataset)
  - __getitem__ 返回单个样本


Sampler (ReverseSampler)
  - 返回索引序列 [4,3,2,1,0]


DataLoader (batch_size=2)
     - Batch 0: idx=[4,3] → x=[[9,10],[7,8]], y=[0,1]
     - Batch 1: idx=[2,1] → x=[[5,6],[3,4]], y=[0,1]
     - Batch 2: idx=[0]   → x=[[1,2]], y=[0]


模型训练
  - 前向传播: y_pred = model(x_batch)
  - 计算 loss
  - 反向传播: loss.backward()
  - 参数更新: optimizer.step()

关键点:

  1. Dataset:管理原始数据和取样方式。
  2. Sampler:决定索引顺序。
  3. DataLoader:负责 batch 聚合数据。
  4. 模型训练:接收 batch,计算梯度,更新参数。