# 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)
详细解析:
-
__init__:初始化 Dataset 对象,存储数据和标签。 -
__len__:Dataset 的长度(样本数),DataLoader 内部会用它来计算 batch 数量。 -
__getitem__:-
接收一个整数
index。 -
从列表中取数据和标签。
-
转为 PyTorch 张量:
x为 float32,用于计算。y为 long,用于分类任务的 CrossEntropyLoss。
-
返回
(x, y)元组。
-
-
关键点: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) # 样本总数
详细解析:
-
__iter__:-
返回一个迭代器,用于生成索引序列。
-
range(len(self.data_source)-1, -1, -1):- 从最大索引到 0
-
例如数据有 5 个样本,索引顺序为
[4,3,2,1,0]
-
-
__len__:- 返回 Dataset 长度
- DataLoader 内部可能用它计算 batch 总数或进度条。
-
关键点:
- 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:使用我们自定义的倒序索引。 -
内部流程:
- DataLoader 调用
sampler.__iter__()→ 得到索引迭代器[4,3,2,1,0] - 使用
batch_size=2将索引分批:
- Batch 0:
[4,3] - Batch 1:
[2,1] - Batch 2:
[0]
-
对每个 batch 调用
dataset.__getitem__,获得(x, y)张量。 -
返回 batch 张量。
x_batch.shape = [batch_size, feature_dim]y_batch.shape = [batch_size]
- DataLoader 调用
-
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
- 输入 2 维特征
-
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())
详细解析:
-
for x_batch, y_batch in dataloader:- DataLoader 迭代 batch
- 每个 batch 为
(x_batch, y_batch)张量
-
outputs = model(x_batch):- 前向传播,输出
[batch_size, num_classes]张量
- 前向传播,输出
-
loss = criterion(outputs, y_batch):- 计算 loss
-
optimizer.zero_grad():- 清空梯度,否则梯度会累加
-
loss.backward():- 自动计算梯度
-
optimizer.step():- 更新模型参数
-
打印 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()
关键点:
- Dataset:管理原始数据和取样方式。
- Sampler:决定索引顺序。
- DataLoader:负责 batch 聚合数据。
- 模型训练:接收 batch,计算梯度,更新参数。
