pytorch基础的学习

python 复制代码
>>> import torch
>>> import numpy as np
>>> x = torch.zeros([1, 2, 3])
>>> x.shape
torch.Size([1, 2, 3])
>>> x = x.squeeze(0)
>>> x.shape
torch.Size([2, 3])
>>> x = torch.zeros([2, 3]) #unsqueeze : expand a new dimension
>>> x.shape
torch.Size([2, 3])
>>> x = x.unsqueeze(1)
>>> x.shape
torch.Size([2, 1, 3])
>>> x = x.unsqueeze(1)
>>> x.shape
torch.Size([2, 1, 1, 3])
>>> x = x.squeeze(0)
>>> x.shape
torch.Size([2, 1, 1, 3])
>>> #squeeze(dim) 只移除dim的维度,如果该维度的大小为1
>>> #unsqueeze(dim) 在dim上增加一个维度:x.unsqueeze(0):在最前面添加一个维度
>>> x = torch.zeros([2,3])
>>> x.shape
torch.Size([2, 3])
>>> x = x.transpose(0,1)
>>> x.shape
torch.Size([3, 2])
>>> x = torch.zeros([1, 2, 3])
>>> x.shape
torch.Size([1, 2, 3])
>>> x = x.transpose(0, 1)
>>> x.shape
torch.Size([2, 1, 3])
>>> #Cat : concatenate multiple tensors 在某一个维度上将几个tensor拼接
>>> x = torch.zeros([2, 1, 3])
>>> y = torch.zeros([2, 2, 3])
>>> z = torch.zeros([2, 3, 3])
>>> w = torch.cat([x, y, z], dim = 1)
>>> w.shape
torch.Size([2, 6, 3])
python 复制代码
import torch
import numpy as np
x = torch.tensor([[1, -1], [-1, 1]])
y = torch.from_numpy(np.array([[1, 2], [3, 4]]))
z = torch.zeros([2, 2])
a = torch.ones([1, 2, 5])
x_data = torch.tensor([[1, 2], [3, 4]])
x_ones = torch.ones_like(x_data) # retains the properties of x_data
print(f"Ones Tensor: \n {x_ones} \n")

x_rand = torch.rand_like(x_data, dtype=torch.float) # overrides the datatype of x_data
print(f"Random Tensor: \n {x_rand} \n")

shape = (2, 3,)
rand_tensor = torch.rand(shape)
ones_tensor = torch.ones(shape)
zeros_tensor = torch.zeros(shape)

print(f"Random Tensor: \n {rand_tensor} \n")
print(f"Ones Tensor: \n {ones_tensor} \n")
print(f"Zeros Tensor: \n {zeros_tensor}")

tensor = torch.rand(3, 4)

print(f"Shape of tensor: {tensor.shape}")
print(f"Datatype of tensor: {tensor.dtype}")
print(f"Device tensor is stored on: {tensor.device}")

# We move our tensor to the GPU if available
if torch.cuda.is_available():
  tensor = tensor.to('cuda')
  print(f"Device tensor is stored on: {tensor.device}")

tensor = torch.ones(3, 4)
tensor[:, 1] = 0
print(tensor)

t1 = torch.cat([tensor, tensor, tensor], dim=1)
print(t1)

torch.manual_seed(1729)
r1 = torch.rand(2, 2)
print('A random tensor:')
print(r1)

r2 = torch.rand(2, 2)
print('\nA random tensor:')
print(r2)

torch.manual_seed(1729)
r3 = torch.rand(2, 2)
print('\nshould match to r1:')
print(r3)
python 复制代码
import torch
import numpy as np

twos = torch.tensor([[2,2],[2,2]])
twos = twos ** torch.tensor([[1, 2], [3, 4]])
print(twos)

rand = torch.rand(2, 4)
print(rand)
doubled = rand * torch.ones(1, 4) * 2    #broadcasting, batch operation,相当于rand的每一行是一个batch*ones*2
print(doubled)

a = torch.ones(2, 3, 4)

b = a * torch.rand(   3, 4)
print(b)

c = a * torch.rand(   3, 1)
print(c)

d = a * torch.rand(   1, 4)
print(d)
print('--------------------------')
a = torch.rand(2, 4) * 2 - 1
print(torch.abs(a))
print(torch.ceil(a))
print(torch.floor(a))
print(torch.clamp(a, -0.5, 1))

print('--------------------------')
import math
angles = torch.tensor([0, math.pi / 4, math.pi / 2, 3 * math.pi / 4])
sines = torch.sin(angles)
inverses = torch.asin(sines)
print(angles)
print(sines)
print(inverses)

print(torch.sin_(angles))
print(angles)
print('xor----------')
a = torch.tensor([3, 4, 5])
b = torch.tensor([6, 7, 8])
print(torch.bitwise_xor(a, b))
print('bool---------')
a = torch.tensor([[1, 2], [3, 4]])
b = torch.tensor([1, 2])
print(torch.equal(a, b))
print(torch.eq(a, b))

print('ops------------')
print(d)
print(torch.max(d))
print(torch.max(d).item())
print(torch.mean(d))
print(torch.std(d))
print(torch.prod(d))
print(torch.unique(d))

print('vector & matrix---------')
v1 = torch.tensor([1, 0, 0])
v2 = torch.tensor([0, 1, 0])
m1 = torch.rand(2, 2)
m2 = torch.tensor([[3., 0.], [0., 3.]])

print(torch.cross(v2, v1, dim=0))
print(m1)
m3 = torch.matmul(m1, m2)
print(m3)
print(torch.svd(m3))

print('-------------')
m1 = torch.rand(2, 2)
m2 = torch.ones(2, 2)
print(m1)
print(m2)
print(m1.add_(m2))
print(m1)
print(m2)
print(m1.mul(m2))
print(m1)
print(m2)

print('------------')
a = torch.rand(2, 2)
b = torch.rand(2, 2)
c = torch.zeros(2, 2)
old_id = id(c)

print(c)
d = torch.matmul(a, b, out = c)
print(c)

assert c is d
assert id(c) , old_id

torch.rand(2, 2, out = c)
print(c)
assert id(c) , old_id
print('-------------')
a = torch.rand(2, 2)
b = a

a[0][1] = 888
print(b)

a = torch.randn(2, 2)
b = a.clone()
assert b is not a
print(torch.eq(a, b))
a[0][1] = 888
print(b)

print('--------------------')
a = torch.randn(2, 2, requires_grad=True)
print(a)

b = a.clone()
print(b)

c = a.detach().clone()
print(c)

print(a)

print('-------------------')
a = torch.randn(2, 2, device='cuda')
print(a)

print('------------------------')
batch_me = torch.rand(3, 226, 226)
print(batch_me.shape)
batch_me.unsqueeze_(0)
print(batch_me.shape)

print('-------------------')
output3d = torch.rand(6, 20, 20)
print(output3d.shape)

input1d = output3d.reshape(6*20*20)
print(input1d.shape)

print(torch.reshape(output3d, (6*20*20,)).shape)

PyTorch Autograd

Autograd 的核心概念

Autograd 是 PyTorch 中的自动微分系统,它能够自动计算神经网络中所有参数的梯度。简单来说,它是 PyTorch 能够进行深度学习训练的核心引擎。

Autograd 的基本原理

  1. 计算图构建:当你执行前向传播操作时,PyTorch 会在后台动态构建一个计算图,记录所有计算操作。

  2. 自动微分 :当调用 .backward() 方法时,系统会自动计算梯度,沿着这个计算图反向传播。

  3. 梯度累积 :计算出的梯度会累积到各参数的 .grad 属性中。

Autograd 的关键组件

1. Tensor 和 requires_grad

在 PyTorch 中,Tensor 是基本数据类型,它可以跟踪其计算历史:

复制代码
import torch

# 创建一个需要计算梯度的张量
x = torch.ones(2, 2, requires_grad=True)
print(x)

requires_grad=True 告诉 PyTorch 需要跟踪这个张量上的所有操作,以便之后计算梯度。

2. 计算图和 grad_fn

当你对设置了 requires_grad=True 的张量执行操作时,得到的新张量也会设置 requires_grad=True,并且有一个 grad_fn 属性记录创建该张量的操作:

复制代码
# 执行操作
y = x + 2
print(y)  # 注意观察 grad_fn
z = y * y * 3
out = z.mean()
print(z, out)  # 这些张量都有 grad_fn

3. backward() 和梯度计算

调用 .backward() 方法开始反向传播:

复制代码
# 反向传播
out.backward()  # 等同于 out.backward(torch.tensor(1.0))

# 查看 x 的梯度
print(x.grad)  # d(out)/dx

4. 梯度和链式法则

Autograd 基于链式法则计算梯度。以上例子中,最终计算结果是:

复制代码
out = (1/4) * sum(3 * (x + 2)^2)

所以 x 的梯度是:

复制代码
d(out)/dx = 3 * (x + 2) * 1/4 * 2 = 1.5 * (x + 2)

x = 1,梯度为 1.5 * 3 = 4.5

Autograd 的高级用法

1. 控制梯度计算

  • torch.no_grad():在不需要跟踪梯度的场景中使用,例如模型评估:

    with torch.no_grad():
    # 这里的计算不会被跟踪
    y = x * 2

  • detach():分离张量,阻止梯度传播:

    detached_y = y.detach() # detached_y 不会传递梯度

2. 梯度累积和清零

梯度在反向传播中会累积,因此在每次更新参数前需要清零:

复制代码
# 在模型训练中
optimizer.zero_grad()  # 清零梯度
loss.backward()        # 计算梯度
optimizer.step()       # 更新参数

3. 自定义 autograd 函数

可以通过继承 torch.autograd.Function 来定义自己的自动微分函数:

复制代码
class CustomReLU(torch.autograd.Function):
    @staticmethod
    def forward(ctx, input):
        ctx.save_for_backward(input)
        return input.clamp(min=0)

    @staticmethod
    def backward(ctx, grad_output):
        input, = ctx.saved_tensors
        grad_input = grad_output.clone()
        grad_input[input < 0] = 0
        return grad_input

custom_relu = CustomReLU.apply

Autograd 的工作示例

以一个简单的神经网络为例:

复制代码
# 定义一个小型网络
model = torch.nn.Sequential(
    torch.nn.Linear(10, 5),
    torch.nn.ReLU(),
    torch.nn.Linear(5, 1)
)

# 所有参数已经设置了 requires_grad=True
for param in model.parameters():
    print(param.requires_grad)

# 前向传播
input = torch.randn(3, 10, requires_grad=True)
output = model(input)
loss = output.sum()

# 反向传播
loss.backward()

# 现在所有模型参数都有了梯度
for param in model.parameters():
    print(param.grad)

Autograd 在 LeNet 中的应用

以 LeNet 模型为例,Autograd 在训练过程中的应用:

复制代码
# LeNet 模型定义
class LeNet(nn.Module):
    def __init__(self):
        super(LeNet, self).__init__()
        self.conv1 = nn.Conv2d(1, 6, 3)
        self.conv2 = nn.Conv2d(6, 16, 3)
        self.fc1 = nn.Linear(16*5*5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)
    
    def forward(self, x):
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
        x = F.max_pool2d(F.relu(self.conv2(x)), (2, 2))
        x = x.view(-1, 16*5*5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

# 初始化模型与优化器
model = LeNet()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
criterion = nn.CrossEntropyLoss()

# 训练循环(简化版)
for inputs, targets in train_loader:
    # 1. 清零梯度
    optimizer.zero_grad()
    
    # 2. 前向传播
    outputs = model(inputs)
    loss = criterion(outputs, targets)
    
    # 3. 反向传播:Autograd 自动计算所有参数的梯度
    loss.backward()
    
    # 4. 参数更新
    optimizer.step()

在这个过程中,Autograd:

  1. 在前向传播时构建计算图

  2. loss.backward() 时计算所有参数的梯度

  3. 优化器使用这些梯度更新参数

Autograd 的优势

  1. 动态计算图:PyTorch 构建的是动态计算图,这使得调试更容易,且支持条件分支。

  2. 高效计算:针对常见操作高度优化,支持 GPU 加速。

  3. 灵活性:既支持立即执行模式,也支持与 TorchScript 结合进行静态图优化。

  4. 扩展性:容易扩展,添加自定义自动微分函数。

Autograd 的局限性

  1. 内存消耗:需要存储中间结果用于反向传播,可能导致内存占用较大。

  2. 性能开销:跟踪操作会带来少量额外开销。

  3. 某些数值问题:对于数值不稳定的操作,梯度计算可能不够准确。

总结

Autograd 是 PyTorch 深度学习框架的核心组件,它通过自动微分让深度学习模型的训练变得简单高效。它通过动态构建计算图、利用链式法则自动计算梯度,使开发者可以专注于模型设计而不必手动实现反向传播算法。

对于神经网络的研究和应用而言,理解 Autograd 的工作原理对于高效开发、调试深度学习模型非常重要。

创建简单模型:

AGENT SYSTEM\]: 文件内容是一个实现 LeNet 卷积神经网络的 PyTorch 类。下面是代码的详细解释: class LeNet(nn.Module): def __init__(self): super(LeNet, self).__init__() self.conv1 = nn.Conv2d(1, 6, 3) self.conv2 = nn.Conv2d(6, 16, 3) self.fc1 = nn.Linear(16*6*6, 120) self.fc2 = nn.Linear(120, 84) self.fc3 = nn.Linear(84, 10) def forward(self, x): x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2)) x = F.max_pool2d(F.relu(self.conv2(x)), (2, 2)) x = x.view(-1, self.num_flat_features(x)) x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) x = self.fc3(x) return x def num_flat_features(self, x): size = x.size()[1:] num_features = 1 for s in size: num_features *= s return num_features 这段代码实现了 LeNet 卷积神经网络模型,它是由 Yann LeCun 在 1998 年提出的经典深度学习架构,主要用于手写数字识别任务。让我详细解释每部分的作用: #### 1. 类的初始化 (`__init__` 方法) def __init__(self): super(LeNet, self).__init__() self.conv1 = nn.Conv2d(1, 6, 3) self.conv2 = nn.Conv2d(6, 16, 3) self.fc1 = nn.Linear(16*6*6, 120) self.fc2 = nn.Linear(120, 84) self.fc3 = nn.Linear(84, 10) 这部分定义了网络的各个层: 1. **第一个卷积层 (`conv1`)**: * `nn.Conv2d(1, 6, 3)` 表示创建一个 2D 卷积层 * 参数含义:输入通道数为 1(灰度图像),输出通道数为 6,卷积核大小为 3×3 * 这一层负责从原始图像中提取基本特征,如边缘、线条等 2. **第二个卷积层 (`conv2`)**: * `nn.Conv2d(6, 16, 3)` 表示第二个卷积层 * 参数含义:输入通道数为 6(上一层的输出),输出通道数为 16,卷积核大小为 3×3 * 这一层负责组合第一层提取的基本特征,形成更复杂的特征模式 3. **第一个全连接层 (`fc1`)**: * `nn.Linear(16*6*6, 120)` 表示一个线性(全连接)层 * 参数含义:输入特征数为 16×6×6=576(来自展平后的卷积层输出),输出特征数为 120 * 注:计算 16×6×6 假设输入图像经过卷积和池化后变为了这个尺寸 4. **第二个全连接层 (`fc2`)**: * `nn.Linear(120, 84)` 从 120 个特征映射到 84 个特征 5. **第三个全连接层/输出层 (`fc3`)**: * `nn.Linear(84, 10)` 从 84 个特征映射到 10 个输出 * 10 个输出对应 10 个类别(对于 MNIST 数据集,这是数字 0-9) #### 2. 前向传播 (`forward` 方法) def forward(self, x): x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2)) x = F.max_pool2d(F.relu(self.conv2(x)), (2, 2)) x = x.view(-1, self.num_flat_features(x)) x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) x = self.fc3(x) return x 这部分定义了数据如何通过网络流动(前向传播过程): 1. **第一阶段处理**: * `self.conv1(x)`: 将输入图像通过第一个卷积层 * `F.relu(...)`: 应用 ReLU 激活函数,引入非线性(ReLU 将所有负值置为 0) * `F.max_pool2d(..., (2, 2))`: 应用 2×2 的最大池化,减少空间维度并保留主要特征 2. **第二阶段处理**: * 与第一阶段类似,但使用第二个卷积层 `self.conv2` * 再次应用 ReLU 和最大池化 3. **展平处理**: * `x.view(-1, self.num_flat_features(x))`: 将卷积层的 2D 输出(多通道的特征图)展平为 1D 向量 * `-1` 表示自动推断批量大小,保持批量维度不变 4. **全连接层处理**: * `F.relu(self.fc1(x))`: 通过第一个全连接层,然后应用 ReLU * `F.relu(self.fc2(x))`: 通过第二个全连接层,然后应用 ReLU * `self.fc3(x)`: 通过最后一个全连接层(没有应用激活函数,因为通常会在损失函数中包含) #### 3. 特征展平辅助函数 (`num_flat_features` 方法) def num_flat_features(self, x): size = x.size()[1:] # 除了批量维度外的所有维度 num_features = 1 for s in size: num_features *= s return num_features 这个辅助方法计算张量除批量维度外的所有元素数量: 1. `x.size()[1:]`: 获取除第一个维度(批量大小)外的所有维度大小 2. 计算这些维度的乘积,得到展平后的特征总数 #### 整体工作流程 假设输入是一个 MNIST 手写数字图像,尺寸为 28×28 像素: 1. **输入**: 形状为 \[batch_size, 1, 28, 28\] 的张量(1 表示灰度通道) 2. **第一个卷积层+ReLU+池化**: * 卷积后: \[batch_size, 6, 26, 26\](卷积核大小 3×3,无填充时边缘减少 2) * 池化后: \[batch_size, 6, 13, 13\](2×2 池化将尺寸减半,向下取整) 3. **第二个卷积层+ReLU+池化**: * 卷积后: \[batch_size, 16, 11, 11

  • 池化后: [batch_size, 16, 5, 5](尽管代码中使用了 16×6×6,这里应该有一点计算差异)
  1. 展平: [batch_size, 16×5×5] = [batch_size, 400]

  2. 全连接层:

    • fc1: [batch_size, 120]

    • fc2: [batch_size, 84]

    • fc3: [batch_size, 10]

  3. 输出: 10个值的张量,表示模型对输入图像属于每个类别的信心度(通常会应用 softmax 将其转换为概率)

这个 LeNet 模型虽然结构简单,但包含了现代 CNN 的核心组件:卷积层、激活函数、池化层和全连接层。它是深度学习发展史上的重要里程碑。

加载数据集:

在PyTorch中加载数据集有多种方法,下面我将详细介绍几种常见的方法,从内置数据集到自定义数据集的加载。

1. 使用PyTorch内置数据集

PyTorch的torchvision.datasets模块提供了许多常用的计算机视觉数据集,如MNIST、CIFAR10等。以下是加载MNIST数据集的示例:

复制代码
import torch
from torchvision import datasets, transforms

# 定义数据转换
transform = transforms.Compose([
    transforms.ToTensor(),  # 将图像转换为PyTorch张量
    transforms.Normalize((0.1307,), (0.3081,))  # 标准化:均值和标准差
])

# 加载训练集
train_dataset = datasets.MNIST(
    root='./data',  # 数据保存路径
    train=True,     # 这是训练集
    download=True,  # 如果数据不存在,则下载
    transform=transform  # 应用上面定义的转换
)

# 加载测试集
test_dataset = datasets.MNIST(
    root='./data',
    train=False,
    download=True,
    transform=transform
)

# 创建数据加载器
train_loader = torch.utils.data.DataLoader(
    train_dataset,
    batch_size=64,    # 每批处理的样本数
    shuffle=True      # 打乱数据顺序
)

test_loader = torch.utils.data.DataLoader(
    test_dataset,
    batch_size=1000,
    shuffle=False
)

2. 使用自定义数据集

如果你有自己的数据,可以通过继承torch.utils.data.Dataset类来创建自定义数据集:

复制代码
from torch.utils.data import Dataset, DataLoader
import pandas as pd
from PIL import Image
import os

class CustomImageDataset(Dataset):
    def __init__(self, annotations_file, img_dir, transform=None):
        """
        参数:
            annotations_file (string): 带有图像标签的CSV文件的路径
            img_dir (string): 图像目录的路径
            transform (callable, optional): 可选的图像转换
        """
        self.img_labels = pd.read_csv(annotations_file)
        self.img_dir = img_dir
        self.transform = transform
        
    def __len__(self):
        return len(self.img_labels)
        
    def __getitem__(self, idx):
        # 获取图像文件的路径
        img_path = os.path.join(self.img_dir, self.img_labels.iloc[idx, 0])
        # 读取图像
        image = Image.open(img_path).convert('RGB')
        # 获取对应的标签
        label = self.img_labels.iloc[idx, 1]
        
        # 应用转换(如果有)
        if self.transform:
            image = self.transform(image)
            
        return image, label

# 使用自定义数据集
transform = transforms.Compose([
    transforms.Resize((224, 224)),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])

# 创建数据集实例
custom_dataset = CustomImageDataset(
    annotations_file='./labels.csv',
    img_dir='./images',
    transform=transform
)

# 创建数据加载器
custom_loader = DataLoader(
    custom_dataset,
    batch_size=32,
    shuffle=True,
    num_workers=4  # 多进程加载
)

3. 使用ImageFolder加载分类数据集

如果你的数据已经按类别整理在不同文件夹中,可以使用ImageFolder

复制代码
from torchvision.datasets import ImageFolder

# 假设数据结构如下:
# data/
#   ├── class1/
#   │   ├── img1.jpg
#   │   └── img2.jpg
#   └── class2/
#       ├── img3.jpg
#       └── img4.jpg

transform = transforms.Compose([
    transforms.Resize((224, 224)),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])

dataset = ImageFolder(root='./data', transform=transform)

# ImageFolder会自动将文件夹名称映射为类别标签
# 可以通过dataset.class_to_idx查看类别映射
print(dataset.class_to_idx)  # 例如: {'class1': 0, 'class2': 1}

loader = DataLoader(dataset, batch_size=32, shuffle=True)

4. 使用TensorDataset加载张量数据

如果数据已经以张量形式存在,可以使用TensorDataset

复制代码
from torch.utils.data import TensorDataset

# 假设你已经有了X和y张量
X = torch.randn(1000, 3, 32, 32)  # 1000张32x32的RGB图像
y = torch.randint(0, 10, (1000,))  # 1000个标签,范围0-9

# 创建数据集
tensor_dataset = TensorDataset(X, y)

# 创建数据加载器
tensor_loader = DataLoader(tensor_dataset, batch_size=32, shuffle=True)

5. 加载文本数据集

对于NLP任务,可以使用torchtext

复制代码
from torchtext.datasets import IMDB
from torchtext.data.utils import get_tokenizer
from torchtext.vocab import build_vocab_from_iterator

# 下载IMDB数据集
train_dataset, test_dataset = IMDB(split=('train', 'test'))

# 定义分词器
tokenizer = get_tokenizer('basic_english')

# 构建词汇表
def yield_tokens(data_iter):
    for _, text in data_iter:
        yield tokenizer(text)

vocab = build_vocab_from_iterator(yield_tokens(train_dataset), specials=['<unk>'])
vocab.set_default_index(vocab['<unk>'])

# 文本处理函数
text_pipeline = lambda x: [vocab[token] for token in tokenizer(x)]
label_pipeline = lambda x: 1 if x == 'pos' else 0

# 数据处理函数
def collate_batch(batch):
    label_list, text_list = [], []
    for _label, _text in batch:
        label_list.append(label_pipeline(_label))
        processed_text = torch.tensor(text_pipeline(_text), dtype=torch.int64)
        text_list.append(processed_text)
    return torch.tensor(label_list), text_list

# 创建数据加载器
train_loader = DataLoader(train_dataset, batch_size=8, shuffle=True, collate_fn=collate_batch)

6. 使用DataLoader的高级特性

DataLoader提供了许多高级功能,如多进程数据加载、自定义采样等:

复制代码
from torch.utils.data.sampler import WeightedRandomSampler

# 假设我们有一个不平衡的数据集,需要对样本进行加权采样
# weights是每个样本的权重
weights = [1.0 if label == 0 else 5.0 for _, label in some_dataset]
sampler = WeightedRandomSampler(weights, len(weights))

# 使用自定义采样器的DataLoader
loader = DataLoader(
    some_dataset,
    batch_size=32,
    sampler=sampler,  # 使用自定义采样器
    num_workers=4,    # 使用4个工作进程加载数据
    pin_memory=True,  # 将数据加载到固定内存中,加速GPU传输
    drop_last=True    # 丢弃最后不完整的批次
)

7. 数据增强

在加载图像数据集时,通常会应用数据增强来提高模型泛化能力:

复制代码
transform_train = transforms.Compose([
    transforms.RandomResizedCrop(224),
    transforms.RandomHorizontalFlip(),
    transforms.ColorJitter(brightness=0.4, contrast=0.4, saturation=0.4),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])

transform_test = transforms.Compose([
    transforms.Resize(256),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])

train_dataset = datasets.CIFAR10(root='./data', train=True, download=True, transform=transform_train)
test_dataset = datasets.CIFAR10(root='./data', train=False, download=True, transform=transform_test)

8. 对于LeNet模型加载MNIST的完整示例

针对您的LeNet模型,这里是一个完整的MNIST数据集加载示例:

复制代码
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms

# 数据转换:将图像转换为张量并进行标准化
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.1307,), (0.3081,))
])

# 加载MNIST数据集
train_dataset = datasets.MNIST('./data', train=True, download=True, transform=transform)
test_dataset = datasets.MNIST('./data', train=False, transform=transform)

# 创建数据加载器
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=1000, shuffle=False)

# 定义LeNet模型
class LeNet(nn.Module):
    def __init__(self):
        super(LeNet, self).__init__()
        self.conv1 = nn.Conv2d(1, 6, 3)
        self.conv2 = nn.Conv2d(6, 16, 3)
        self.fc1 = nn.Linear(16*5*5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)
    
    def forward(self, x):
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
        x = F.max_pool2d(F.relu(self.conv2(x)), (2, 2))
        x = x.view(-1, 16*5*5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

# 初始化模型、损失函数和优化器
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = LeNet().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

# 训练函数
def train(epoch):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        optimizer.zero_grad()
        output = model(data)
        loss = criterion(output, target)
        loss.backward()
        optimizer.step()
        if batch_idx % 100 == 0:
            print(f'Train Epoch: {epoch} [{batch_idx * len(data)}/{len(train_loader.dataset)}'
                  f' ({100. * batch_idx / len(train_loader):.0f}%)]\tLoss: {loss.item():.6f}')

# 测试函数
def test():
    model.eval()
    test_loss = 0
    correct = 0
    with torch.no_grad():
        for data, target in test_loader:
            data, target = data.to(device), target.to(device)
            output = model(data)
            test_loss += criterion(output, target).item()
            pred = output.argmax(dim=1, keepdim=True)
            correct += pred.eq(target.view_as(pred)).sum().item()
    
    test_loss /= len(test_loader.dataset)
    print(f'Test set: Average loss: {test_loss:.4f}, '
          f'Accuracy: {correct}/{len(test_loader.dataset)} '
          f'({100. * correct / len(test_loader.dataset):.0f}%)')

# 训练模型
for epoch in range(1, 11):
    train(epoch)
    test()

通过上述代码,您可以加载MNIST数据集,并使用它来训练和测试您的LeNet模型。这个例子包含了完整的数据加载、模型定义、训练和测试流程。

相关推荐
NAGNIP7 小时前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
冬奇Lab9 小时前
一天一个开源项目(第36篇):EverMemOS - 跨 LLM 与平台的长时记忆 OS,让 Agent 会记忆更会推理
人工智能·开源·资讯
冬奇Lab9 小时前
OpenClaw 源码深度解析(一):Gateway——为什么需要一个"中枢"
人工智能·开源·源码阅读
AngelPP12 小时前
OpenClaw 架构深度解析:如何把 AI 助手搬到你的个人设备上
人工智能
宅小年12 小时前
Claude Code 换成了Kimi K2.5后,我再也回不去了
人工智能·ai编程·claude
九狼13 小时前
Flutter URL Scheme 跨平台跳转
人工智能·flutter·github
ZFSS13 小时前
Kimi Chat Completion API 申请及使用
前端·人工智能
天翼云开发者社区14 小时前
春节复工福利就位!天翼云息壤2500万Tokens免费送,全品类大模型一键畅玩!
人工智能·算力服务·息壤
知识浅谈14 小时前
教你如何用 Gemini 将课本图片一键转为精美 PPT
人工智能
Ray Liang14 小时前
被低估的量化版模型,小身材也能干大事
人工智能·ai·ai助手·mindx