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模型。这个例子包含了完整的数据加载、模型定义、训练和测试流程。

相关推荐
海尔辛24 分钟前
学习黑客三次握手快速熟悉
网络·学习·tcp/ip
珊珊而川25 分钟前
3.1监督微调
人工智能
我是小伍同学29 分钟前
基于卷积神经网络和Pyqt5的猫狗识别小程序
人工智能·python·神经网络·qt·小程序·cnn
界面开发小八哥2 小时前
界面控件DevExpress WinForms v25.1新功能预览 - 功能区组件全新升级
人工智能·.net·界面控件·winform·devexpress
zhz52143 小时前
开源数字人框架 AWESOME-DIGITAL-HUMAN 技术解析与应用指南
人工智能·ai·机器人·开源·ai编程·ai数字人·智能体
丰锋ff3 小时前
考研英一学习笔记 2018年
笔记·学习·考研
沉默媛4 小时前
RuntimeError: expected scalar type ComplexDouble but found Float
人工智能·pytorch·深度学习
契合qht53_shine4 小时前
NLP基础
人工智能·自然语言处理
闭月之泪舞4 小时前
YOLO目标检测算法
人工智能·yolo·目标检测