深度学习 PyTorch 代码全集

目录

  1. PyTorch 安装与验证
  2. 张量(Tensor)创建
  3. 张量转换
  4. 张量数值计算
  5. 张量统计运算
  6. 张量索引操作
  7. 张量形状操作
  8. 张量拼接
  9. 神经网络基础
  10. 损失函数
  11. 数据集与数据加载器
  12. 自动微分与反向传播
  13. 完整模型训练流程
  14. 优化器与学习率调度
  15. 参数初始化

1. PyTorch 安装与验证

# 导入PyTorch库
import torch

# 打印PyTorch版本号
print(torch.__version__)

# Windows系统:检查CUDA GPU是否可用
print(torch.cuda.is_available())

# Apple M系列芯片:检查MPS加速是否可用
print(torch.backends.mps.is_available())

2. 张量(Tensor)创建

2.1 基于内容创建张量

import torch
import numpy as np

# 1. 创建标量张量(0维)
scalar1 = torch.tensor(10)  # 传入单个数字创建标量
scalar2 = torch.tensor(3.14)
print("标量张量1:", scalar1)
print("张量维度:", scalar1.dim())  # 输出0,表示0维
print("张量形状:", scalar1.shape)  # 输出torch.Size([]),表示无维度

# 2. 创建一维张量(向量)
vec1 = torch.tensor([1, 2, 3, 4])  # 传入单层列表创建一维张量
vec2 = torch.tensor([0.1, 0.2, 0.3])
print("一维张量1:", vec1)
print("张量维度:", vec1.dim())  # 输出1,表示1维
print("张量形状:", vec1.shape)  # 输出torch.Size([4]),表示4个元素

# 3. 创建二维张量(矩阵)
t1 = torch.tensor([[1, 2, 3], [10, 20, 30]])  # 传入二维嵌套列表创建二维张量
print(t1)
print(t1.shape)  # 输出torch.Size([2, 3]),表示2行3列

# 4. 创建三维张量
t1 = torch.tensor([[[1,2,3], [4,5,6]], [[7,8,9], [10,11,12]]])  # 传入三层嵌套列表
print(t1)
print(t1.shape)  # 输出torch.Size([2, 2, 3])

# 5. 基于NumPy数组创建张量
t1 = torch.tensor(np.array([10, 20, 30]))  # 将NumPy数组转换为张量(创建副本)
t2 = torch.from_numpy(np.array([10, 20, 30]))  # 共享内存,修改原数组会影响张量
print(t1)
print(t1.shape)

2.2 基于形状创建张量

# 基于形状创建张量(默认float32类型)
t1 = torch.Tensor(2, 3, 5)  # 创建2×3×5的三维张量,元素未初始化
print(t1)
print(t1.shape)  # 输出torch.Size([2, 3, 5])

2.3 创建指定类型的张量

# 方法1:通过dtype参数指定类型
t1 = torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.float64)
print(t1.dtype)  # 输出torch.float64

# 方法2:使用特定类型的构造函数
t1 = torch.IntTensor(2, 3)    # int32类型
t1 = torch.LongTensor(2, 3)   # int64类型
t1 = torch.FloatTensor(2, 3)  # float32类型
t1 = torch.DoubleTensor(2, 3) # float64类型
t1 = torch.BoolTensor(2, 3)   # bool类型
t1 = torch.ByteTensor(2, 3)   # uint8类型
t1 = torch.HalfTensor(2, 3)   # float16类型

2.4 根据数据区间创建张量

# 1. 固定步长生成:torch.arange
t1 = torch.arange(10)  # 生成[0,10)的整数,步长1
print(t1)
t1 = torch.arange(2, 10, 2)  # 生成[2,10)的整数,步长2
print(t1)

# 2. 固定数量线性生成:torch.linspace
t1 = torch.linspace(2, 10, 6)  # 在[2,10]之间生成6个均匀间隔的数
print(t1)

# 3. 对数间隔生成:torch.logspace
t1 = torch.logspace(1, 3, 3)  # 生成10^1, 10^2, 10^3
print(t1)
t1 = torch.logspace(1, 3, 3, base=np.e)  # 以e为底生成e^1, e^2, e^3
print(t1)

2.5 根据填充创建张量

# 1. 全1张量
t1 = torch.ones(3)  # 创建长度为3的全1一维张量
t1 = torch.ones_like(t1)  # 创建与t1形状相同的全1张量
print(t1)

# 2. 未初始化张量(速度最快,但值随机)
t1 = torch.empty(3)
print(t1)

# 3. 全常量张量
t1 = torch.full((2, 3), 10)  # 创建2×3的张量,所有元素为10
print(t1)

# 4. 单位矩阵
t1 = torch.eye(3)  # 创建3×3的单位矩阵
t1 = torch.eye(5, 6)  # 创建5×6的矩阵,对角线为1
print(t1)

2.6 随机创建张量

# 1. [0,1)均匀分布
t2 = torch.rand(2, 3)
print(t2)

# 2. 整数均匀分布
t2 = torch.randint(1, 100, size=(2, 3))  # [1,100)之间的整数
print(t2)

# 3. 标准正态分布(均值0,方差1)
t2 = torch.randn(2, 3)
print(t2)

# 4. 自定义均值和标准差的正态分布
t2 = torch.normal(5, 2, size=(2, 3))  # 均值5,标准差2
print(t2)

# 5. 随机打乱(洗牌)
t2 = torch.randperm(10)  # 生成[0,10)的随机排列
print(t2)

# 6. 设置随机种子(保证实验可复现)
torch.manual_seed(42)
seed = torch.random.initial_seed()
print(seed)

3. 张量转换

3.1 元素类型转换

# 初始化一个int64类型的张量
t1 = torch.tensor([1, 2, 3])
print("初始类型:", t1.dtype)

# 方式1:type()方法
t1 = t1.type(torch.float32)
print(t1.dtype)

# 方式2:to()方法(推荐,功能更全面)
t1 = t1.to(torch.int32)
print(t1.dtype)

# 方式3:直接调用类型方法
t1 = t1.float()  # 转换为float32
print(t1.dtype)

3.2 Tensor 与 NumPy ndarray 转换

# 1. Tensor → NumPy
t1 = torch.tensor([1, 2, 3])
a1 = t1.numpy()  # 默认共享内存,修改t1会影响a1
print(type(a1))

# 避免内存共享:深拷贝
a2 = t1.numpy().copy()
t1[0] = 100
print(t1)
print(a2)  # a2不受影响

# 2. NumPy → Tensor
a1 = np.array([1, 2, 3])
t1 = torch.from_numpy(a1)  # 默认共享内存
print(type(t1))

# 避免内存共享:clone()
t1 = torch.from_numpy(a1).clone()

3.3 Tensor → 标量(Scalar)

t1 = torch.tensor(10)
t2 = torch.tensor([10])
t3 = torch.tensor([[10]])

# 只有当张量只有一个元素时才能调用item()
print(t1.item())  # 输出10(Python原生int类型)
print(t2.item())
print(t3.item())

4. 张量数值计算

4.1 基本运算(张量与标量)

import torch

# 初始化2×3张量
t1 = torch.tensor([[1, 2, 3], [4, 5, 6]])

# 1. 运算符重载(非原地操作,不修改原张量)
print(t1 + 10)  # 每个元素加10
print(t1 - 10)  # 每个元素减10
print(t1 * 10)  # 每个元素乘10
print(t1 / 10)  # 每个元素除10
print(t1 ** 2)  # 每个元素平方
print(-t1)      # 每个元素取反

# 2. 非原地方法(与运算符等价)
print(t1.add(10))
print(t1.sub(10))
print(t1.mul(10))
print(t1.div(10))
print(t1.pow(2))
print(t1.neg())

# 3. 原地方法(修改原张量,以下划线结尾)
t1.add_(10)  # 直接修改t1,每个元素加10
print(t1)

4.2 元素级运算(张量与张量)

# 初始化两个形状相同的2×3张量
t1 = torch.tensor([[1, 2, 3], [4, 5, 6]])
t2 = torch.tensor([[10, 20, 30], [40, 50, 60]])

# 逐元素相加
print(t1 + t2)
# 逐元素相乘(哈达玛积,不是矩阵乘法)
print(t1 * t2)
# 逐元素相除
print(t1 / t2)

4.3 矩阵相乘

# 初始化二维矩阵
t1 = torch.tensor([[1, 2, 3], [4, 5, 6]])  # 形状(2,3)
t2 = torch.tensor([[10, 20, 30, 40], [40, 50, 60, 70], [40, 50, 60, 70]])  # 形状(3,4)

# 方式1:运算符@(推荐,简洁)
print(t1 @ t2)  # 输出形状(2,4)

# 方式2:mm()方法(仅支持二维矩阵)
print(t1.mm(t2))

# 方式3:matmul()方法(支持任意维度,批量矩阵乘法)
print(t1.matmul(t2))

5. 张量统计运算

import torch

# 生成形状为(2,3,4)的随机整数张量
t1 = torch.randint(1, 10, (2, 3, 4))
print("原始张量:\n", t1)

# 1. 求和运算
print("全局求和:", t1.sum())  # 所有元素相加,返回标量
print("按dim=0求和:\n", t1.sum(dim=0))  # 压缩第0维,输出形状(3,4)
print("按dim=1求和:\n", t1.sum(dim=1))  # 压缩第1维,输出形状(2,4)
print("按dim=2求和:\n", t1.sum(dim=2))  # 压缩第2维,输出形状(2,3)

# 2. 均值运算(仅支持浮点型)
print("按dim=0求均值:\n", t1.float().mean(dim=0))

# 3. 最值运算(返回值和索引)
max_val, max_idx = t1.float().max(dim=1)
print("最大值:\n", max_val)
print("最大值索引:\n", max_idx)

# 4. 方差与标准差
print("按dim=1求方差:\n", t1.float().var(dim=1))
print("按dim=1求标准差:\n", t1.float().std(dim=1))

# 5. 去重运算
print("元素去重:\n", t1.float().unique())

# 6. 排序运算
sorted_val, sorted_idx = t1.float().sort(dim=2)
print("排序后的值:\n", sorted_val)
print("排序索引:\n", sorted_idx)

6. 张量索引操作

import torch

# 生成形状为(2,5,4)的随机整数张量
t = torch.randint(0, 10, (2, 5, 4))
print("原始张量:\n", t)

# 1. 简单索引
print(t[0][0][0])  # 链式索引
print(t[0, 0, 0])  # 逗号分隔索引(推荐)
print(t[1])        # 取第1个矩阵,输出形状(5,4)
print(t[1, 2])     # 取第1个矩阵第2行,输出形状(4)

# 2. 范围索引(切片)
print(t[1, 1:])    # 取第1个矩阵从第1行到末尾
print(t[-1:, 1:4, 0:3:2])  # 复杂切片

# 3. 列表索引(提取非连续元素)
list1 = [0, 1, 1]
list2 = [1, 3, 2]
print(t[list1, list2])  # 提取(0,1),(1,3),(1,2)位置的行

# 4. 布尔索引
print(t[t > 5])  # 取出所有大于5的值
mask = t[:, :, 0] > 5  # 每行首元素大于5的行
print(t[mask])

7. 张量形状操作

import torch

# 创建形状为(3,2,6)的三维张量
t1 = torch.randint(1, 10, (3, 2, 6))
print("原始形状:", t1.shape)

# 1. 维度交换
print("转置所有维度:", t1.T.shape)  # 反转所有维度
print("只转置最后两个维度:", t1.mT.shape)  # 矩阵转置
print("交换0和1维:", t1.transpose(0, 1).shape)
print("重新排列所有维度:", t1.permute(1, 0, 2).shape)

# 2. 调整形状
print("展平为一维:", t1.reshape(36).shape)
print("调整为(3,1,-1):", t1.reshape(3, 1, -1).shape)  # -1自动推导维度

# 3. 增删维度
t2 = torch.randint(1, 10, (2, 4))
print("原始形状:", t2.shape)
print("增加维度dim=2:", t2.unsqueeze(dim=2).shape)  # 增加维度
t3 = t2.unsqueeze(dim=0)
print("删除维度:", t3.squeeze().shape)  # 删除所有大小为1的维度

8. 张量拼接

import torch

# 1. torch.cat():按指定维度拼接(维度不变)
t1 = torch.randint(1, 10, (2, 1, 3))
t2 = torch.randint(1, 10, (2, 3, 3))
print("cat拼接结果形状:", torch.cat([t1, t2], dim=1).shape)  # 输出(2,4,3)

# 2. torch.stack():堆叠操作(新增维度)
t1 = torch.randint(1, 10, (3, 4, 5))
t2 = torch.randint(1, 10, (3, 4, 5))
print("stack堆叠结果形状:", torch.stack([t1, t2], dim=0).shape)  # 输出(2,3,4,5)

9. 神经网络基础

9.1 全连接层

import torch
import torch.nn as nn

# 定义全连接层:2个输入神经元,3个输出神经元
linear = nn.Linear(in_features=2, out_features=3, bias=True)

# 查看权重和偏置形状
print("权重形状:", linear.weight.shape)  # 输出torch.Size([3, 2])
print("偏置形状:", linear.bias.shape)    # 输出torch.Size([3])

# 构造输入数据:2个样本,每个样本2个特征
x = torch.tensor([[1.0, 2.0], [3.0, 4.0]])

# 前向传播(自动调用forward方法)
y = linear(x)
print("输出形状:", y.shape)  # 输出torch.Size([2, 3])

9.2 激活函数

import torch
import torch.nn as nn

x = torch.tensor([0.7, -1.2, 2.5, 0, -3.1])

# 1. Sigmoid函数(二分类输出层)
print(torch.sigmoid(x))

# 2. Tanh函数
print(torch.tanh(x))

# 3. ReLU函数(隐藏层首选)
print(torch.relu(x))

# 4. Softmax函数(多分类输出层)
print(torch.softmax(x, dim=0))

# 5. 其他激活函数
print(nn.LeakyReLU(0.01)(x))  # LeakyReLU
print(nn.GELU()(x))           # GELU(Transformer默认)

9.3 自定义模型

import torch
import torch.nn as nn

# 自定义模型必须继承nn.Module
class MyModule(nn.Module):
    def __init__(self):
        super().__init__()  # 必须调用父类初始化方法
        # 定义网络层
        self.linear1 = nn.Linear(3, 4)  # 输入层→第1隐藏层
        self.linear2 = nn.Linear(4, 4)  # 第1隐藏层→第2隐藏层
        self.out = nn.Linear(4, 2)      # 第2隐藏层→输出层

    # 必须实现forward方法,定义前向传播逻辑
    def forward(self, x):
        x = self.linear1(x)
        x = torch.tanh(x)
        x = self.linear2(x)
        x = torch.relu(x)
        x = self.out(x)
        y = torch.softmax(x, dim=-1)
        return y

# 测试模型
if __name__ == '__main__':
    x = torch.randn(10, 3)  # 10个样本,每个3个特征
    model = MyModule()
    y = model(x)
    print("输出形状:", y.shape)  # 输出torch.Size([10, 2])

9.4 使用 Sequential 定义模型

import torch
import torch.nn as nn

# 对于纯顺序结构的网络,使用Sequential更简洁
model = nn.Sequential(
    nn.Linear(3, 4),
    nn.Tanh(),
    nn.Linear(4, 4),
    nn.ReLU(),
    nn.Linear(4, 2),
    nn.Softmax(dim=-1)
)

# 测试
x = torch.randn(10, 3)
y = model(x)
print("输出形状:", y.shape)

9.5 模型保存与加载

import torch
import torch.nn as nn

# 定义模型
model = nn.Sequential(
    nn.Linear(3, 4),
    nn.Tanh(),
    nn.Linear(4, 4),
    nn.ReLU(),
    nn.Linear(4, 2),
    nn.Softmax(dim=-1)
)

# 保存模型(只保存参数,推荐)
torch.save(model.state_dict(), 'model.pth')

# 加载模型
loaded_model = nn.Sequential(
    nn.Linear(3, 4),
    nn.Tanh(),
    nn.Linear(4, 4),
    nn.ReLU(),
    nn.Linear(4, 2),
    nn.Softmax(dim=-1)
)
state_dict = torch.load('model.pth')
loaded_model.load_state_dict(state_dict)

# 验证
x = torch.randn(10, 3)
print(torch.allclose(model(x), loaded_model(x)))  # 输出True

10. 损失函数

import torch
import torch.nn as nn

# 1. MAE损失(L1损失)
output = torch.randn(5)
target = torch.randn(5)
loss_l1 = nn.L1Loss()
loss = loss_l1(output, target)
print("MAE损失:", loss)

# 2. MSE损失(L2损失)
loss_l2 = nn.MSELoss()
loss = loss_l2(output, target)
print("MSE损失:", loss)

# 3. Smooth L1损失
loss_smooth_l1 = nn.SmoothL1Loss()
loss = loss_smooth_l1(output, target)
print("Smooth L1损失:", loss)

# 4. 二元交叉熵损失
output = torch.randn(5)
proba = torch.sigmoid(output)
target = torch.tensor([0, 0, 1, 1, 0]).float()
loss_bce = nn.BCELoss()
loss = loss_bce(proba, target)
print("BCELoss:", loss)

# 5. 带Logits的二元交叉熵(更稳定)
loss_bce_logits = nn.BCEWithLogitsLoss()
loss = loss_bce_logits(output, target)
print("BCEWithLogitsLoss:", loss)

# 6. 交叉熵损失(多分类)
output = torch.randn(8, 6)  # 8个样本,6个类别
target = torch.tensor([1, 0, 5, 4, 2, 3, 0, 5])  # 标签编码
loss_ce = nn.CrossEntropyLoss()
loss = loss_ce(output, target)
print("CrossEntropyLoss:", loss)

11. 数据集与数据加载器

11.1 自定义 Dataset

from torch.utils.data import Dataset

# 自定义Dataset必须继承Dataset
class MyDataset(Dataset):
    def __init__(self, data):
        self.data = data  # 初始化数据
    
    def __len__(self):
        return len(self.data)  # 返回数据集大小
    
    def __getitem__(self, idx):
        return self.data[idx]  # 按索引返回单条数据

# 使用示例
data = [1, 2, 3, 4]
dataset = MyDataset(data)
print(dataset[0])  # 输出1
print(len(dataset))  # 输出4

11.2 TensorDataset

import torch
from torch.utils.data import TensorDataset, DataLoader

# 创建特征和标签张量
x = torch.randn(10, 3)
y = torch.randn(10)

# 构建TensorDataset
dataset = TensorDataset(x, y)
print(dataset[0])  # 输出第一个样本的特征和标签

11.3 DataLoader

# 创建数据加载器
loader = DataLoader(
    dataset, 
    batch_size=3,    # 每个批次大小
    shuffle=True,    # 每个epoch打乱数据
    drop_last=False  # 是否丢弃最后一个不完整的批次
)

# 遍历数据
for x_batch, y_batch in loader:
    print(x_batch, y_batch)
    print("-------")

12. 自动微分与反向传播

import torch
import torch.nn as nn

# 定义数据
x = torch.tensor([10.0])
y = torch.tensor([3.0])

# 定义需要求导的参数(requires_grad=True)
w = torch.randn(1, requires_grad=True)
b = torch.randn(1, requires_grad=True)

# 前向传播
z = w * x + b
z.retain_grad()  # 保留非叶子节点的梯度
print("前向传播结果:", z)

# 计算损失
loss_fn = nn.MSELoss()
loss = loss_fn(z, y)
loss.retain_grad()
print("损失值:", loss)

# 反向传播:计算所有参数的梯度
loss.backward()

# 查看梯度
print("损失的梯度:", loss.grad)
print("z的梯度:", z.grad)
print("w的梯度:", w.grad)
print("b的梯度:", b.grad)

# 查看是否为叶子节点
print("w是叶子节点:", w.is_leaf)
print("z是叶子节点:", z.is_leaf)

13. 完整模型训练流程

13.1 线性回归示例

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import TensorDataset, DataLoader
import matplotlib.pyplot as plt

# 1. 准备数据
x = torch.randn(100, 1)  # 100个样本,1个特征
y = x * 2.5 + 5.0 + torch.randn(100, 1) * 0.2  # 真实关系:y=2.5x+5+噪声

# 超参数
batch_size = 6
lr = 0.01
epochs = 200

# 2. 构建数据集和数据加载器
dataset = TensorDataset(x, y)
dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)

# 3. 定义模型:单层线性层
model = nn.Linear(1, 1)

# 4. 定义损失函数和优化器
loss_fn = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=lr)

# 5. 训练模型
loss_list = []
for epoch in range(epochs):
    total_loss = 0
    iter_num = 0
    for x_batch, y_batch in dataloader:
        # 前向传播
        y_pred = model(x_batch)
        # 计算损失
        loss = loss_fn(y_pred, y_batch)
        # 反向传播
        loss.backward()
        # 更新参数
        optimizer.step()
        # 梯度清零(必须,否则梯度会累加)
        optimizer.zero_grad()
        
        total_loss += loss.item()
        iter_num += 1
    
    # 记录每轮平均损失
    avg_loss = total_loss / iter_num
    loss_list.append(avg_loss)
    if (epoch+1) % 20 == 0:
        print(f"Epoch {epoch+1}/{epochs}, Loss: {avg_loss:.4f}")

# 打印训练后的参数
print("训练后的斜率:", model.weight.item())  # 接近2.5
print("训练后的偏置:", model.bias.item())    # 接近5.0

# 画图
fig, axs = plt.subplots(1, 2, figsize=(12, 4))
axs[0].plot(loss_list)
axs[0].set_title('Loss Curve')
axs[1].scatter(x, y)
axs[1].plot(x, model(x).detach().numpy(), c='r')
axs[1].set_title('Fitting Result')
plt.show()

13.2 手写数字识别完整训练

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import TensorDataset, DataLoader
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler

# 0. 定义超参数
lr = 0.1
epochs = 20
batch_size = 256

# 1. 加载和预处理数据
def get_digit_data():
    dataset = pd.read_csv("./data/train.csv")
    x = dataset.drop("label", axis=1)
    y = dataset["label"]
    
    # 划分训练集和测试集
    x_train, x_test, y_train, y_test = train_test_split(
        x, y, test_size=0.2, random_state=42
    )
    
    # 归一化到[0,1]
    scaler = MinMaxScaler()
    x_train = scaler.fit_transform(x_train)
    x_test = scaler.transform(x_test)
    
    # 转换为张量
    x_train = torch.tensor(x_train).float()
    x_test = torch.tensor(x_test).float()
    y_train = torch.tensor(y_train.to_numpy()).long()
    y_test = torch.tensor(y_test.to_numpy()).long()
    
    return x_train, x_test, y_train, y_test

x_train, x_test, y_train, y_test = get_digit_data()

# 2. 构建数据集和数据加载器
train_dataset = TensorDataset(x_train, y_train)
train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)

valid_dataset = TensorDataset(x_test, y_test)
valid_dataloader = DataLoader(valid_dataset, batch_size=batch_size)

# 3. 定义模型
model = nn.Sequential(
    nn.Linear(784, 50),
    nn.ReLU(),
    nn.Linear(50, 100),
    nn.ReLU(),
    nn.Linear(100, 10)
)

# 定义设备(自动选择GPU/CPU)
device = torch.device(
    "cuda" if torch.cuda.is_available()
    else "mps" if torch.backends.mps.is_available()
    else "cpu"
)
model.to(device)
print(f"使用设备: {device}")

# 4. 定义损失函数和优化器
loss_fn = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=lr)

# 5. 训练模型
for epoch in range(epochs):
    # 训练模式
    model.train()
    train_loss = 0
    train_acc_num = 0
    
    for inputs, targets in train_dataloader:
        inputs = inputs.to(device)
        targets = targets.to(device)
        
        # 前向传播
        y_pred = model(inputs)
        # 计算损失
        loss = loss_fn(y_pred, targets)
        # 反向传播
        loss.backward()
        # 更新参数
        optimizer.step()
        # 梯度清零
        optimizer.zero_grad()
        
        train_loss += loss.item() * inputs.shape[0]
        y_pred_class = torch.argmax(y_pred, dim=1)
        train_acc_num += torch.sum(y_pred_class == targets).item()
    
    # 计算训练指标
    train_loss_avg = train_loss / len(train_dataset)
    train_acc = train_acc_num / len(train_dataset)
    
    # 验证模式
    model.eval()
    val_loss = 0
    val_acc_num = 0
    
    with torch.no_grad():  # 验证时不需要计算梯度
        for inputs, targets in valid_dataloader:
            inputs = inputs.to(device)
            targets = targets.to(device)
            
            y_pred = model(inputs)
            loss = loss_fn(y_pred, targets)
            
            val_loss += loss.item() * inputs.shape[0]
            y_pred_class = torch.argmax(y_pred, dim=1)
            val_acc_num += torch.sum(y_pred_class == targets).item()
    
    val_loss_avg = val_loss / len(valid_dataset)
    val_acc = val_acc_num / len(valid_dataset)
    
    # 打印结果
    print(f'第{epoch+1}轮, 训练损失: {train_loss_avg:.4f}, 训练准确率: {train_acc:.4f}, '
          f'验证损失: {val_loss_avg:.4f}, 验证准确率: {val_acc:.4f}')

14. 优化器与学习率调度

14.1 动量法

import torch
import torch.optim as optim

# 定义参数
w = torch.tensor([-7.0, 2.0], requires_grad=True)

# 普通SGD
optimizer_sgd = optim.SGD([w], lr=0.01)

# 带动量的SGD(momentum=0.9)
optimizer_momentum = optim.SGD([w], lr=0.01, momentum=0.9)

14.2 学习率调度

import torch
import torch.optim as optim
from torch.optim.lr_scheduler import StepLR, MultiStepLR, ExponentialLR

# 定义参数和优化器
w = torch.tensor([-7.0, 2.0], requires_grad=True)
optimizer = optim.SGD([w], lr=0.9)

# 1. 等间隔衰减:每10个epoch衰减为原来的0.7
scheduler_step = StepLR(optimizer, step_size=10, gamma=0.7)

# 2. 指定间隔衰减:在[10,20,70]epoch时衰减
scheduler_multi = MultiStepLR(optimizer, milestones=[10, 20, 70], gamma=0.7)

# 3. 指数衰减:每个epoch乘以0.99
scheduler_exp = ExponentialLR(optimizer, gamma=0.99)

# 训练循环中更新学习率
for epoch in range(100):
    # ... 训练步骤 ...
    optimizer.step()
    optimizer.zero_grad()
    scheduler_step.step()  # 更新学习率

14.3 其他优化器

import torch
import torch.optim as optim

w = torch.tensor([-7.0, 2.0], requires_grad=True)

# AdaGrad
optimizer_adagrad = optim.Adagrad([w], lr=0.9)

# RMSProp
optimizer_rmsprop = optim.RMSprop([w], lr=0.1, alpha=0.99)

# Adam(最常用)
optimizer_adam = optim.Adam([w], lr=0.1, betas=(0.9, 0.999))

15. 参数初始化

import torch
import torch.nn as nn

linear = nn.Linear(5, 2)

# 1. 常数初始化
nn.init.zeros_(linear.weight)    # 全部初始化为0
nn.init.ones_(linear.weight)     # 全部初始化为1
nn.init.constant_(linear.weight, 10)  # 全部初始化为10

# 2. 单位矩阵初始化
nn.init.eye_(linear.weight)

# 3. 正态分布初始化
nn.init.normal_(linear.weight, mean=0.0, std=1.0)

# 4. 均匀分布初始化
nn.init.uniform_(linear.weight, a=0, b=10)

# 5. Xavier初始化(适用于Sigmoid/Tanh)
nn.init.xavier_normal_(linear.weight)  # 正态分布
nn.init.xavier_uniform_(linear.weight) # 均匀分布

# 6. He初始化(适用于ReLU及其变体)
nn.init.kaiming_normal_(linear.weight)  # 正态分布
nn.init.kaiming_uniform_(linear.weight) # 均匀分布

更多推荐