PyTorch深度教程(一):快速入门与核心概念

4 阅读15分钟

目标读者:具有Python基础,追求十年经验级别的深度理解 学习路径:从实践出发,在需要时补充数学原理


第一部分:5分钟快速上手

1.1 第一个神经网络

import torch
import torch.nn as nn
import torch.optim as optim

# 1. 创建一个简单的线性回归模型
model = nn.Linear(in_features=1, out_features=1)

# 2. 准备数据(y = 2x + 3)
x_train = torch.tensor([[1.0], [2.0], [3.0], [4.0]])
y_train = torch.tensor([[5.0], [7.0], [9.0], [11.0]])

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

# 4. 训练循环
for epoch in range(100):
    # 前向传播
    y_pred = model(x_train)

    # 计算损失
    loss = criterion(y_pred, y_train)

    # 反向传播
    optimizer.zero_grad()  # 清空梯度
    loss.backward()         # 计算梯度
    optimizer.step()        # 更新参数

    if (epoch + 1) % 20 == 0:
        print(f'Epoch [{epoch+1}/100], Loss: {loss.item():.4f}')

# 5. 测试模型
with torch.no_grad():
    test_x = torch.tensor([[5.0]])
    test_y = model(test_x)
    print(f'Input: 5.0, Predicted: {test_y.item():.2f}, Expected: ~13.0')

运行结果分析

  • 模型学习到了线性关系 y ≈ 2x + 3
  • 损失函数逐渐降低,说明模型在优化
  • 最终预测结果接近真实值

第二部分:PyTorch核心架构

2.1 张量(Tensor):PyTorch的核心数据结构

2.1.1 什么是张量?

简单理解

  • 0维张量 = 标量(一个数字):torch.tensor(3.14)
  • 1维张量 = 向量(一串数字):torch.tensor([1, 2, 3])
  • 2维张量 = 矩阵(表格):torch.tensor([[1, 2], [3, 4]])
  • 3维张量 = 立方体(如RGB图像):torch.tensor([[[...]]])
# 创建张量的多种方式
import torch

# 1. 从Python列表创建
a = torch.tensor([1, 2, 3])
print(a)  # tensor([1, 2, 3])

# 2. 创建特殊张量
zeros = torch.zeros(2, 3)        # 全0矩阵
ones = torch.ones(2, 3)          # 全1矩阵
rand = torch.randn(2, 3)         # 标准正态分布随机数
arange = torch.arange(0, 10, 2)  # [0, 2, 4, 6, 8]

# 3. 查看张量属性
print(f"形状: {rand.shape}")      # torch.Size([2, 3])
print(f"数据类型: {rand.dtype}")  # torch.float32
print(f"设备: {rand.device}")     # cpu 或 cuda:0

2.1.2 张量的基本运算

# 基础运算
x = torch.tensor([[1.0, 2.0], [3.0, 4.0]])
y = torch.tensor([[5.0, 6.0], [7.0, 8.0]])

# 逐元素运算
z1 = x + y      # 加法:[[6, 8], [10, 12]]
z2 = x * y      # 逐元素乘法:[[5, 12], [21, 32]]
z3 = x / y      # 除法
z4 = x ** 2     # 平方

# 矩阵运算
z5 = x @ y      # 矩阵乘法
z6 = x.T        # 转置

# 聚合运算
print(x.sum())      # 所有元素求和:10.0
print(x.mean())     # 平均值:2.5
print(x.max())      # 最大值:4.0
print(x.argmax())   # 最大值索引:3
📐 数学补充:矩阵乘法的数学原理(点击展开)

💡 记忆口诀

行乘列,对应乘,求和填新位
左行数,右列数,中间要相等

矩阵乘法定义

给定 A(m×n) 和 B(n×p),结果 C(m×p) 的计算:
C[i,j] = Σ(k=1 to n) A[i,k] * B[k,j]

意思:左边第i行,乘以右边第j列,对应位置相乘再求和

手工计算示例

A = [1  2]    B = [5  6]
    [3  4]        [7  8]

AB = [(1×5 + 2×7)  (1×6 + 2×8)]   [19  22]
     [(3×5 + 4×7)  (3×6 + 4×8)] = [43  50]1行第1列: A的第1行 × B的第1列 = 1×5 + 2×7 = 191行第2列: A的第1行 × B的第2列 = 1×6 + 2×8 = 22

PyTorch验证

A = torch.tensor([[1., 2.], [3., 4.]])
B = torch.tensor([[5., 6.], [7., 8.]])
print(A @ B)  # tensor([[19., 22.], [43., 50.]])

几何意义

  • 矩阵乘法 = 线性变换的组合
  • A @ x:用矩阵A变换向量x
  • 神经网络的每一层本质上就是矩阵乘法 + 非线性激活

2.1.3 内存布局与存储机制

class TensorStorageSystem:
    """
    深入理解PyTorch张量的存储系统
    """

    def storage_and_view(self):
        """
        存储(Storage)与视图(View)机制
        """
        # 1. 存储是一维连续内存块
        x = torch.tensor([[1, 2, 3], [4, 5, 6]])
        print(f"存储内容: {x.storage()}")  # [1, 2, 3, 4, 5, 6]

        # 2. 张量是存储的视图
        # 通过offset, size, stride定义
        print(f"偏移量: {x.storage_offset()}")
        print(f"形状: {x.size()}")
        print(f"步幅: {x.stride()}")  # (3, 1) 表示行间隔3,列间隔1

        # 3. 视图操作零拷贝
        y = x.view(3, 2)  # 只改变形状元数据
        z = x.t()          # 转置只改变步幅

        # 4. 步幅的数学意义
        # 元素x[i,j]的内存地址:
        # addr = storage_offset + i*stride[0] + j*stride[1]

    def advanced_indexing(self):
        """
        高级索引与内存连续性
        """
        x = torch.randn(10, 20, 30)

        # 基础索引(不复制)
        y1 = x[0]         # shape: (20, 30)
        y2 = x[:, 0, :]   # shape: (10, 30)

        # 高级索引(复制数据)
        indices = torch.tensor([0, 2, 4])
        y3 = x[indices]   # 需要复制,因为索引不连续

        # 掩码索引
        mask = x > 0
        y4 = x[mask]      # 返回一维张量

    def memory_format(self):
        """
        内存格式:NCHW vs NHWC
        """
        # Channels Last格式(对某些硬件更优)
        x = torch.randn(8, 3, 224, 224)  # NCHW
        x_cl = x.to(memory_format=torch.channels_last)  # NHWC

        # 检查内存格式
        print(f"是否channels_last: {x_cl.is_contiguous(memory_format=torch.channels_last)}")

# 实战演示
demo = TensorStorageSystem()
demo.storage_and_view()

为什么理解内存布局很重要?

  1. 性能优化:连续内存访问更快
  2. 避免意外bug:理解何时发生数据复制
  3. GPU优化:不同内存格式对GPU性能影响巨大

2.2 自动微分(Autograd):反向传播的魔法

2.2.1 梯度计算入门

# 开启梯度追踪
x = torch.tensor(2.0, requires_grad=True)
y = x ** 2 + 3 * x + 1

# 计算梯度
y.backward()

print(f"x = {x.item()}")           # 2.0
print(f"y = {y.item()}")           # 4 + 6 + 1 = 11
print(f"dy/dx = {x.grad.item()}")  # 2*2 + 3 = 7
📐 数学补充:梯度的含义(点击展开)

💡 记忆口诀

梯度就是斜率坡,告诉方向怎么走
自变量变一小步,因变量跟着走

梯度定义

对于函数 y = f(x),梯度 dy/dx 表示:
- x变化一个小量Δx时,y变化多少
- 函数在该点的斜率
- 优化时的前进方向(负梯度 = 下降最快)

例子:y = x² + 3x + 1

dy/dx = 2x + 3x = 2:
dy/dx = 2(2) + 3 = 7

含义:x从2增加到2.01时,
     y大约增加 7 × 0.01 = 0.07

验证

x = 2.0
y1 = x**2 + 3*x + 1  # 11.0
x = 2.01
y2 = x**2 + 3*x + 1  # 11.0701
print(f"实际变化: {y2 - y1:.4f}")      # 0.0701
print(f"梯度预测: {7 * 0.01:.4f}")     # 0.0700

2.2.2 多变量梯度

# 多变量函数
x = torch.tensor([1.0, 2.0], requires_grad=True)
y = x[0]**2 + 3*x[0]*x[1] + x[1]**2

y.backward()

print(f"∂y/∂x₀ = {x.grad[0].item()}")  # 2*1 + 3*2 = 8
print(f"∂y/∂x₁ = {x.grad[1].item()}")  # 3*1 + 2*2 = 7

2.2.3 计算图与反向传播

class ComputationGraphDemo:
    """
    理解PyTorch的动态计算图
    """

    def visualize_graph(self):
        """
        可视化计算图
        """
        x = torch.tensor(2.0, requires_grad=True)
        y = torch.tensor(3.0, requires_grad=True)

        # 构建计算图
        a = x + y       # a = 5.0
        b = x * y       # b = 6.0
        c = a * b       # c = 30.0

        c.backward()

        print(f"dc/dx = {x.grad}")  # 11.0
        print(f"dc/dy = {y.grad}")  # 13.0

        """
        计算图:

        x=2 ─┬─(+)─→ a=5 ─┐
             │            ├─(*)─→ c=30
        y=3 ─┼─(*)─→ b=6 ─┘
             │

        反向传播:
        dc/dx = dc/da * da/dx + dc/db * db/dx
              = b * 1 + a * y
              = 6 + 5*1 = 11
        """

    def gradient_accumulation(self):
        """
        梯度累积机制
        """
        x = torch.tensor(1.0, requires_grad=True)

        # 第一次前向+反向
        y1 = x ** 2
        y1.backward()
        print(f"第一次梯度: {x.grad}")  # 2.0

        # 不清零,再次反向(梯度会累积!)
        y2 = x ** 3
        y2.backward()
        print(f"累积后梯度: {x.grad}")  # 2.0 + 3.0 = 5.0

        # 这就是为什么训练时需要 optimizer.zero_grad()

# 实战演示
demo = ComputationGraphDemo()
demo.visualize_graph()
demo.gradient_accumulation()
📐 数学补充:链式法则与反向传播(点击展开)

💡 记忆口诀

链式求导像接力,一棒一棒往回递
外层导数乘内层,从后往前全连起

链式法则(Chain Rule)

如果 z = f(y), y = g(x),那么:
dz/dx = (dz/dy) × (dy/dx)

意思:z对x的导数 = z对y的导数 × y对x的导数
就像接力赛,梯度从后往前一层层传

反向传播本质

  • 就是链式法则的递归应用
  • 从输出节点开始,逐层向后计算梯度
  • 神经网络训练的核心算法

例子:z = (x² + 1)³

y = x² + 1, z = y³

前向传播(从左到右算值):
x = 2 → y = 5 → z = 125

反向传播(从右到左算梯度):
dz/dy = 3y² = 75
dy/dx = 2x = 4
dz/dx = (dz/dy) × (dy/dx) = 75 × 4 = 300

PyTorch验证

x = torch.tensor(2.0, requires_grad=True)
z = (x**2 + 1)**3
z.backward()
print(x.grad)  # tensor(300.)

2.3 神经网络模块(nn.Module)

2.3.1 构建自定义网络

import torch.nn as nn
import torch.nn.functional as F

class SimpleNN(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(SimpleNN, self).__init__()

        # 定义层
        self.fc1 = nn.Linear(input_size, hidden_size)
        self.fc2 = nn.Linear(hidden_size, output_size)

    def forward(self, x):
        # 前向传播逻辑
        x = F.relu(self.fc1(x))  # 隐藏层 + ReLU激活
        x = self.fc2(x)           # 输出层
        return x

# 创建模型
model = SimpleNN(input_size=10, hidden_size=20, output_size=2)

# 查看模型结构
print(model)

# 查看参数
for name, param in model.named_parameters():
    print(f"{name}: {param.shape}")

输出解释

SimpleNN(
  (fc1): Linear(in_features=10, out_features=20, bias=True)
  (fc2): Linear(in_features=20, out_features=2, bias=True)
)

fc1.weight: torch.Size([20, 10])  # 第一层权重矩阵
fc1.bias: torch.Size([20])         # 第一层偏置
fc2.weight: torch.Size([2, 20])    # 第二层权重矩阵
fc2.bias: torch.Size([2])          # 第二层偏置

2.3.2 激活函数

# 常用激活函数
x = torch.linspace(-5, 5, 100)

# ReLU: max(0, x)
relu_out = F.relu(x)

# Sigmoid: 1 / (1 + e^(-x))
sigmoid_out = torch.sigmoid(x)

# Tanh: (e^x - e^(-x)) / (e^x + e^(-x))
tanh_out = torch.tanh(x)

# LeakyReLU: max(0.01x, x)
leaky_relu_out = F.leaky_relu(x, 0.01)

# GELU (现代Transformer常用)
gelu_out = F.gelu(x)

为什么需要激活函数?

  • 没有激活函数,多层神经网络 = 一个线性变换
  • 激活函数引入非线性,让网络能拟合复杂函数
📐 数学补充:为什么线性层叠加还是线性?(点击展开)

💡 记忆口诀

线性套线性,还是线性变
加个激活函数,才能拐弯弯

证明

假设两层线性变换:
h = W₁x + b₁
y = W₂h + b₂

代入:
y = W₂(W₁x + b₁) + b₂
  = W₂W₁x + W₂b₁ + b₂
  = Wx + b  (其中 W = W₂W₁, b = W₂b₁ + b₂)

结论:两层线性变换等价于一层!
就像 y = 2(3x + 1) + 5 = 6x + 7,最终还是一条直线

加入激活函数后

h = σ(W₁x + b₁)   # σ是激活函数(如ReLU)
y = W₂h + b₂

此时无法简化为单层,因为σ是非线性的
就像先折叠再拉伸,能拟合复杂曲线

目的

  • 没有激活函数:多层网络 = 浪费计算
  • 有激活函数:能学习复杂的非线性模式

2.4 设备管理(CPU vs GPU)

# 检查CUDA是否可用
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f"使用设备: {device}")

# 将张量移到GPU
x_cpu = torch.randn(1000, 1000)
x_gpu = x_cpu.to(device)

# 将模型移到GPU
model = SimpleNN(10, 20, 2)
model = model.to(device)

# 完整训练循环示例
def train_on_gpu(model, data_loader, optimizer, criterion, device):
    model.train()
    for batch_x, batch_y in data_loader:
        # 数据移到GPU
        batch_x = batch_x.to(device)
        batch_y = batch_y.to(device)

        # 前向传播
        outputs = model(batch_x)
        loss = criterion(outputs, batch_y)

        # 反向传播
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

性能对比

import time

# CPU版本
x = torch.randn(5000, 5000)
y = torch.randn(5000, 5000)

start = time.time()
z = x @ y
print(f"CPU耗时: {time.time() - start:.4f}秒")

# GPU版本(如果可用)
if torch.cuda.is_available():
    x_gpu = x.to('cuda')
    y_gpu = y.to('cuda')

    start = time.time()
    z_gpu = x_gpu @ y_gpu
    torch.cuda.synchronize()  # 等待GPU计算完成
    print(f"GPU耗时: {time.time() - start:.4f}秒")

第三部分:数值稳定性与实践技巧

3.1 数值稳定性问题

3.1.1 指数函数的数值稳定实现

def softmax_naive(x):
    """
    朴素实现(数值不稳定)
    """
    exp_x = torch.exp(x)
    return exp_x / exp_x.sum(dim=-1, keepdim=True)

def softmax_stable(x):
    """
    数值稳定版本
    """
    # 减去最大值,防止指数溢出
    x_max = x.max(dim=-1, keepdim=True)[0]
    exp_x = torch.exp(x - x_max)
    return exp_x / exp_x.sum(dim=-1, keepdim=True)

# 测试
x = torch.tensor([1000., 1001., 1002.])

try:
    result1 = softmax_naive(x)
    print(f"朴素版本: {result1}")  # 可能出现NaN
except:
    print("朴素版本溢出!")

result2 = softmax_stable(x)
print(f"稳定版本: {result2}")  # tensor([0.0900, 0.2447, 0.6652])
📐 数学补充:Softmax数值稳定性(点击展开)

💡 记忆口诀

指数函数易爆炸,减去最大保平安
上下同除不改值,稳定计算是关键

Softmax定义

softmax(xᵢ) = exp(xᵢ) / Σⱼ exp(xⱼ)

作用:把一组数字转换成概率(和为1,都在0-1之间)

问题:当x很大时,exp(x)会溢出

exp(1000) = ∞ (超出浮点数范围)

解决方案:利用数学恒等式

softmax(x) = softmax(x - c)  对任意常数c成立

证明:
softmax(xᵢ - c) = exp(xᵢ - c) / Σⱼ exp(xⱼ - c)
                = [exp(xᵢ) / exp(c)] / [Σⱼ exp(xⱼ) / exp(c)]
                = exp(xᵢ) / Σⱼ exp(xⱼ)
                = softmax(xᵢ)

选择 c = max(x),可以保证:
- 所有 exp(xᵢ - c) ≤ 1(防止溢出)
- 至少一个 exp(xᵢ - c) = 1(防止下溢)

目的

  • 朴素实现:exp(大数) → 溢出 → NaN
  • 稳定实现:减最大值 → 数值在安全范围 → 正确结果

3.1.2 梯度消失与爆炸

class GradientFlowDemo:
    """
    演示梯度消失和梯度爆炸
    """

    def gradient_vanishing(self):
        """
        梯度消失示例
        """
        # 使用Sigmoid激活函数的深层网络
        x = torch.randn(1, 10, requires_grad=True)

        # 10层网络,每层都用Sigmoid
        h = x
        for _ in range(10):
            W = torch.randn(10, 10) * 0.5
            h = torch.sigmoid(h @ W)

        loss = h.sum()
        loss.backward()

        print(f"输入梯度范数: {x.grad.norm().item():.6f}")
        # 很小的值,说明梯度消失了

    def gradient_exploding(self):
        """
        梯度爆炸示例
        """
        x = torch.randn(1, 10, requires_grad=True)

        # 权重过大导致梯度爆炸
        h = x
        for _ in range(10):
            W = torch.randn(10, 10) * 2  # 权重较大
            h = h @ W

        loss = h.sum()
        loss.backward()

        print(f"输入梯度范数: {x.grad.norm().item():.6f}")
        # 很大的值,说明梯度爆炸了

demo = GradientFlowDemo()
demo.gradient_vanishing()
demo.gradient_exploding()

解决方案

  1. 批归一化(Batch Normalization)
  2. 残差连接(ResNet)
  3. 合适的权重初始化
  4. 梯度裁剪

3.2 权重初始化策略

import math

def xavier_uniform_init(tensor, gain=1.0):
    """
    Xavier均匀初始化(适用于Tanh、Sigmoid)
    """
    fan_in, fan_out = tensor.shape
    a = gain * math.sqrt(6.0 / (fan_in + fan_out))
    with torch.no_grad():
        tensor.uniform_(-a, a)

def kaiming_normal_init(tensor, mode='fan_in', nonlinearity='relu'):
    """
    Kaiming正态初始化(适用于ReLU)
    """
    fan_in, fan_out = tensor.shape
    fan = fan_in if mode == 'fan_in' else fan_out

    # ReLU的增益因子
    gain = math.sqrt(2.0) if nonlinearity == 'relu' else 1.0
    std = gain / math.sqrt(fan)

    with torch.no_grad():
        tensor.normal_(0, std)

# PyTorch内置初始化
layer = nn.Linear(100, 50)
nn.init.xavier_uniform_(layer.weight)
nn.init.zeros_(layer.bias)

# 或者
nn.init.kaiming_normal_(layer.weight, mode='fan_in', nonlinearity='relu')
📐 数学补充:Xavier初始化的数学原理(点击展开)

💡 记忆口诀

输入输出取平均,方差倒数是关键
前向反向都稳定,信号传播不衰减

目标:保持信号的方差在前向和反向传播中不变

推导(简化版):

假设输入 x 的方差为 Var(x) = 1
层输出 y = Wx(忽略偏置)

Var(y) = Var(Σᵢ wᵢxᵢ)
       = Σᵢ Var(wᵢxᵢ)  (假设独立)
       = Σᵢ E[wᵢ²]E[xᵢ²]  (假设零均值)
       = n_in × Var(w) × Var(x)

要使 Var(y) = Var(x),需要:
n_in × Var(w) = 1
Var(w) = 1 / n_in

同理,考虑反向传播,得到:
Var(w) = 1 / n_out

折中:Var(w) = 2 / (n_in + n_out)

对于均匀分布 U(-a, a):
Var = a² / 3
所以 a = sqrt(6 / (n_in + n_out))

目的

  • 太小:信号逐层衰减,梯度消失
  • 太大:信号逐层放大,梯度爆炸
  • 刚好:信号稳定传播,训练顺畅

适用场景

  • Xavier:适合Tanh、Sigmoid等对称激活函数
  • Kaiming:适合ReLU(会砍掉一半,需要更大的初始化)

第四部分:完整实战案例

4.1 图像分类:MNIST手写数字识别

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader
from torchvision import datasets, transforms

# 1. 数据准备
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.1307,), (0.3081,))
])

train_dataset = datasets.MNIST('./data', train=True, download=True, transform=transform)
test_dataset = datasets.MNIST('./data', train=False, transform=transform)

train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=1000)

# 2. 定义模型
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, 3, 1)
        self.conv2 = nn.Conv2d(32, 64, 3, 1)
        self.fc1 = nn.Linear(9216, 128)
        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):
        x = F.relu(self.conv1(x))
        x = F.max_pool2d(x, 2)
        x = F.relu(self.conv2(x))
        x = F.max_pool2d(x, 2)
        x = x.view(-1, 9216)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return F.log_softmax(x, dim=1)

model = CNN()
optimizer = optim.Adam(model.parameters(), lr=0.001)
criterion = nn.NLLLoss()

# 3. 训练函数
def train(model, device, train_loader, optimizer, 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' Loss: {loss.item():.6f}')

# 4. 测试函数
def test(model, device, test_loader):
    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)
    accuracy = 100. * correct / len(test_loader.dataset)
    print(f'\nTest set: Average loss: {test_loss:.4f}, '
          f'Accuracy: {correct}/{len(test_loader.dataset)} ({accuracy:.2f}%)\n')

# 5. 训练循环
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = model.to(device)

for epoch in range(1, 6):
    train(model, device, train_loader, optimizer, epoch)
    test(model, device, test_loader)

# 6. 保存模型
torch.save(model.state_dict(), 'mnist_cnn.pth')

总结与学习路线图

你已经学会了什么

核心概念

  • 张量的创建、操作和内存管理
  • 自动微分与梯度计算
  • 神经网络的构建与训练
  • GPU加速

实践技能

  • 数值稳定性的处理
  • 权重初始化策略
  • 完整的训练流程
  • 模型的保存与加载

下一步学习方向

📖 教程02 - 张量运算与自动微分深度解析

  • 高级索引与广播机制
  • 自定义autograd函数
  • 内存优化技巧

📖 教程03 - 神经网络架构设计

  • CNN、RNN、Transformer详解
  • 自定义网络层
  • 模型组合技巧

📖 教程04 - 优化器与训练技巧

  • 各种优化器的数学原理
  • 学习率调度
  • 正则化技术

📖 教程05 - 分布式训练与性能优化

  • 数据并行与模型并行
  • 混合精度训练
  • 性能分析工具

📖 教程06 - 实战应用案例

  • 计算机视觉
  • 自然语言处理
  • 生成模型

附录:常用数学知识速查

📐 线性代数基础(点击展开)

向量运算

# 向量点积
a = torch.tensor([1., 2., 3.])
b = torch.tensor([4., 5., 6.])
dot_product = (a * b).sum()  # 32.0

# 向量范数
l1_norm = a.abs().sum()       # L1范数: 6.0
l2_norm = a.norm()            # L2范数: 3.742

矩阵运算

# 矩阵乘法
A = torch.randn(3, 4)
B = torch.randn(4, 5)
C = A @ B  # (3, 5)

# 矩阵转置
A_T = A.T

# 逆矩阵
A_square = torch.randn(3, 3)
A_inv = torch.inverse(A_square)

特征值分解

A = torch.randn(3, 3)
eigenvalues, eigenvectors = torch.linalg.eig(A)
📐 微积分基础(点击展开)

常用导数

d/dx (x^n) = nx^(n-1)
d/dx (e^x) = e^x
d/dx (ln x) = 1/x
d/dx (sin x) = cos x
d/dx (cos x) = -sin x

链式法则

d/dx f(g(x)) = f'(g(x)) × g'(x)

常用激活函数的导数

# Sigmoid: σ(x) = 1/(1+e^(-x))
# 导数: σ'(x) = σ(x)(1-σ(x))

# ReLU: f(x) = max(0, x)
# 导数: f'(x) = 1 if x>0 else 0

# Tanh: tanh(x)
# 导数: 1 - tanh²(x)
📐 概率论基础(点击展开)

常用分布

# 正态分布
x = torch.randn(1000)  # N(0, 1)

# 均匀分布
x = torch.rand(1000)   # U(0, 1)

# 伯努利分布
x = torch.bernoulli(torch.full((1000,), 0.5))

期望与方差

# 期望(均值)
mean = x.mean()

# 方差
var = x.var()

# 标准差
std = x.std()

恭喜你完成第一章的学习! 🎉

现在你已经掌握了PyTorch的核心基础,可以开始构建自己的深度学习模型了。记住:

  • 多动手实践,理论结合代码
  • 遇到数学概念时,查看补充说明
  • 循序渐进,不要急于求成

继续加油!💪