>>> 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])
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)
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 的基本原理
计算图构建:当你执行前向传播操作时,PyTorch 会在后台动态构建一个计算图,记录所有计算操作。
自动微分:当调用
.backward()
方法时,系统会自动计算梯度,沿着这个计算图反向传播。梯度累积:计算出的梯度会累积到各参数的
.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:
在前向传播时构建计算图
在
loss.backward()
时计算所有参数的梯度优化器使用这些梯度更新参数
Autograd 的优势
动态计算图:PyTorch 构建的是动态计算图,这使得调试更容易,且支持条件分支。
高效计算:针对常见操作高度优化,支持 GPU 加速。
灵活性:既支持立即执行模式,也支持与 TorchScript 结合进行静态图优化。
扩展性:容易扩展,添加自定义自动微分函数。
Autograd 的局限性
内存消耗:需要存储中间结果用于反向传播,可能导致内存占用较大。
性能开销:跟踪操作会带来少量额外开销。
某些数值问题:对于数值不稳定的操作,梯度计算可能不够准确。
总结
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)
这部分定义了网络的各个层:
第一个卷积层 (
conv1
):nn.Conv2d(1, 6, 3)
表示创建一个 2D 卷积层参数含义:输入通道数为 1(灰度图像),输出通道数为 6,卷积核大小为 3×3
这一层负责从原始图像中提取基本特征,如边缘、线条等
第二个卷积层 (
conv2
):nn.Conv2d(6, 16, 3)
表示第二个卷积层参数含义:输入通道数为 6(上一层的输出),输出通道数为 16,卷积核大小为 3×3
这一层负责组合第一层提取的基本特征,形成更复杂的特征模式
第一个全连接层 (
fc1
):nn.Linear(16*6*6, 120)
表示一个线性(全连接)层参数含义:输入特征数为 16×6×6=576(来自展平后的卷积层输出),输出特征数为 120
注:计算 16×6×6 假设输入图像经过卷积和池化后变为了这个尺寸
第二个全连接层 (
fc2
):nn.Linear(120, 84)
从 120 个特征映射到 84 个特征
第三个全连接层/输出层 (
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
这部分定义了数据如何通过网络流动(前向传播过程):
第一阶段处理:
self.conv1(x)
: 将输入图像通过第一个卷积层F.relu(...)
: 应用 ReLU 激活函数,引入非线性(ReLU 将所有负值置为 0)F.max_pool2d(..., (2, 2))
: 应用 2×2 的最大池化,减少空间维度并保留主要特征
第二阶段处理:
与第一阶段类似,但使用第二个卷积层
self.conv2
再次应用 ReLU 和最大池化
展平处理:
x.view(-1, self.num_flat_features(x))
: 将卷积层的 2D 输出(多通道的特征图)展平为 1D 向量-1
表示自动推断批量大小,保持批量维度不变
全连接层处理:
F.relu(self.fc1(x))
: 通过第一个全连接层,然后应用 ReLUF.relu(self.fc2(x))
: 通过第二个全连接层,然后应用 ReLUself.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
这个辅助方法计算张量除批量维度外的所有元素数量:
x.size()[1:]
: 获取除第一个维度(批量大小)外的所有维度大小计算这些维度的乘积,得到展平后的特征总数
整体工作流程
假设输入是一个 MNIST 手写数字图像,尺寸为 28×28 像素:
输入: 形状为 [batch_size, 1, 28, 28] 的张量(1 表示灰度通道)
第一个卷积层+ReLU+池化:
卷积后: [batch_size, 6, 26, 26](卷积核大小 3×3,无填充时边缘减少 2)
池化后: [batch_size, 6, 13, 13](2×2 池化将尺寸减半,向下取整)
第二个卷积层+ReLU+池化:
卷积后: [batch_size, 16, 11, 11]
池化后: [batch_size, 16, 5, 5](尽管代码中使用了 16×6×6,这里应该有一点计算差异)
展平: [batch_size, 16×5×5] = [batch_size, 400]
全连接层:
fc1: [batch_size, 120]
fc2: [batch_size, 84]
fc3: [batch_size, 10]
输出: 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模型。这个例子包含了完整的数据加载、模型定义、训练和测试流程。