ai全栈软件开发day26

神经网络基础、PyTorch 入门与 Transformer 架构剖析

2026-10-03 周五 AI 大模型微调基础 阅读约 30 分钟

本文目录
  1. 今日学习内容
  2. 第五阶段:从调用到训练
  3. 神经网络基础
  4. [PyTorch 入门实战](#PyTorch 入门实战)
  5. [Transformer 架构剖析](#Transformer 架构剖析)
  6. 踩坑记录
  7. 收获总结
  8. 明日计划

今日学习内容

今天是 Day 26,第五阶段(AI 大模型微调基础)的第一天 。前四个阶段我们完成了 Java 后端、Spring 全家桶、Vue3 前端、Python 编程、提示工程、LangChain 和 RAG 系统的学习。但从今天开始,我们要进入一个全新的领域 ------ 不再只是「调用」大模型,而是理解模型内部结构,甚至亲手训练和微调。

这就像从「开车」变成「修车」再变成「造车」。今天的学习目标非常明确:

  • 神经网络基础:感知机、多层感知机(MLP)、激活函数、反向传播、梯度下降优化器 ------ 这是所有深度学习的基石
  • PyTorch 入门:Tensor 张量操作、autograd 自动微分、nn.Module 模型定义、完整的训练循环模板
  • Transformer 架构剖析:Self-Attention 自注意力机制、Multi-Head 多头注意力、Position Encoding 位置编码、Encoder-Decoder 结构

**为什么今天如此重要?**神经网络和 Transformer 是大模型微调的理论基础。如果你不理解反向传播,就无法理解 LoRA 为什么能微调;如果你不理解 Self-Attention,就无法理解为什么 Transformer 能处理长文本。今天的内容是整个第五阶段的地基,地基不牢,后面的 LoRA 微调、量化压缩都会变成空中楼阁。

第五阶段:从调用到训练

阶段总览

第五阶段共 7 天,核心目标是从「使用 API 调用大模型」跨越到「理解模型原理并亲手微调」。整个阶段分为四个模块:

天数 模块 核心内容
Day 26 神经网络基础 + PyTorch + Transformer 感知机/MLP/反向传播、Tensor/autograd/nn.Module、Self-Attention 机制
Day 27 HuggingFace Transformers Pipeline API、Tokenizer 分词、模型加载与推理、模型仓库使用
Day 28 数据集构建与预处理 数据清洗、中文分词、标注格式、DataLoader、数据增强
Day 29 LoRA / QLoRA 微调 PEFT 参数高效微调、LoRA 低秩适配原理、QLoRA 量化微调
Day 30-31 模型量化压缩 INT8/INT4 量化、GPTQ/AWQ 方案、模型部署与推理优化
Day 32 微调实战 + 阶段收官 Llama-Factory 中文微调、文本分类全流程、模型评估与部署

学习心态转变:前四个阶段偏「应用开发」,第五阶段偏「算法理解」。不需要成为数学博士,但需要理解核心公式的含义和代码实现。建议多动手跑代码,感受到梯度下降的「直观」比推导公式重要得多。

神经网络基础

感知机:神经元的最小单元

感知机(Perceptron)是神经网络的基础单元,模拟生物神经元的工作方式。它接收多个输入,加权求和后经过一个激活函数输出结果:

数学表达:y = f(w₁x₁ + w₂x₂ + ... + wₙxₙ + b),其中 w 是权重,b 是偏置,f 是激活函数。

单个感知机只能解决线性可分问题(比如 AND/OR 逻辑),对于 XOR 这种非线性问题就无能为力了。这也正是多层感知机(MLP)诞生的原因。

perceptron.py --- 从零实现感知机Python

复制代码
import numpy as np

class Perceptron:
    """单层感知机:只能解决线性可分问题"""
    def __init__(self, input_size: int, lr: float = 0.01):
        self.w = np.random.randn(input_size) * 0.01  # 权重初始化
        self.b = 0.0                                    # 偏置
        self.lr = lr

    def forward(self, x: np.ndarray) -> int:
        """前向传播:加权求和 → 阶跃激活"""
        z = np.dot(x, self.w) + self.b
        return 1 if z >= 0 else 0

    def train(self, X: np.ndarray, y: np.ndarray, epochs: int = 100):
        """感知机学习规则:y_pred ≠ y_true 时更新权重"""
        for epoch in range(epochs):
            errors = 0
            for xi, yi in zip(X, y):
                y_pred = self.forward(xi)
                if y_pred != yi:
                    # 核心更新规则:w ← w + lr * (yi - y_pred) * xi
                    self.w += self.lr * (yi - y_pred) * xi
                    self.b += self.lr * (yi - y_pred)
                    errors += 1
            if errors == 0:
                print(f"收敛于第 {epoch + 1} 轮")
                break

# 测试 AND 逻辑(线性可分)
X = np.array([[0,0],[0,1],[1,0],[1,1]])
y = np.array([0,0,0,1])  # AND

p = Perceptron(input_size=2)
p.train(X, y)
print(f"AND 测试: {[p.forward(x) for x in X]}")  # [0, 0, 0, 1] ✓

XOR 问题:感知机无法解决 XOR(异或)问题,因为 XOR 不是线性可分的。这正是多层感知机(MLP)需要引入隐藏层和非线性激活函数的原因。1969 年 Minsky 在《Perceptrons》中指出了这个局限,直接导致了 AI 的第一个寒冬。

多层感知机(MLP)与激活函数

MLP 在输入层和输出层之间加入了隐藏层,并引入非线性激活函数。没有激活函数,多层网络等价于单层(线性变换的复合仍是线性变换)。

激活函数 公式 特点 适用场景
Sigmoid σ(x) = 1/(1+e⁻ˣ) 输出 (0,1),梯度消失严重 二分类输出层
Tanh tanh(x) = (eˣ-e⁻ˣ)/(eˣ+e⁻ˣ) 输出 (-1,1),零中心,仍有梯度消失 RNN 隐藏层
ReLU ReLU(x) = max(0,x) 计算快,缓解梯度消失,但 Dead Neuron 大部分隐藏层
GELU GELU(x) ≈ x·Φ(x) 平滑 ReLU,BERT/GPT 默认 Transformer 模型

mlp_numpy.py --- NumPy 手写 MLP(理解反向传播)Python

复制代码
import numpy as np

class MLP:
    """两层 MLP:输入 → 隐藏层(ReLU) → 输出层(Sigmoid)"""
    def __init__(self, in_dim: int, hidden: int, out_dim: int, lr: float = 0.1):
        # He 初始化(ReLU 专用)
        self.W1 = np.random.randn(in_dim, hidden) * np.sqrt(2.0 / in_dim)
        self.b1 = np.zeros((1, hidden))
        self.W2 = np.random.randn(hidden, out_dim) * np.sqrt(2.0 / hidden)
        self.b2 = np.zeros((1, out_dim))
        self.lr = lr

    def _relu(self, x): return np.maximum(0, x)
    def _relu_grad(self, x): return (x > 0).astype(float)
    def _sigmoid(self, x): return 1 / (1 + np.exp(-np.clip(x, -500, 500)))
    def _binary_cross_entropy(self, y_pred, y_true):
        eps = 1e-15
        return -np.mean(y_true * np.log(y_pred + eps) + (1 - y_true) * np.log(1 - y_pred + eps))

    def forward(self, X):
        """前向传播:记录中间值用于反向传播"""
        self.z1 = X @ self.W1 + self.b1      # (N, hidden)
        self.a1 = self._relu(self.z1)         # ReLU 激活
        self.z2 = self.a1 @ self.W2 + self.b2 # (N, out_dim)
        self.a2 = self._sigmoid(self.z2)      # Sigmoid 输出
        return self.a2

    def backward(self, X, y_true):
        """反向传播:链式法则计算梯度"""
        m = X.shape[0]
        # 输出层梯度:∂L/∂z2 = a2 - y_true(BCE+Sigmoid 合并简化)
        dz2 = (self.a2 - y_true) / m
        dW2 = self.a1.T @ dz2
        db2 = np.sum(dz2, axis=0, keepdims=True)

        # 隐藏层梯度:∂L/∂z1 = (dz2 @ W2^T) ⊙ ReLU'(z1)
        dz1 = dz2 @ self.W2.T * self._relu_grad(self.z1)
        dW1 = X.T @ dz1
        db1 = np.sum(dz1, axis=0, keepdims=True)

        # 梯度下降更新
        self.W2 -= self.lr * dW2; self.b2 -= self.lr * db2
        self.W1 -= self.lr * dW1; self.b1 -= self.lr * db1

    def train(self, X, y, epochs=2000):
        for i in range(epochs):
            y_pred = self.forward(X)
            loss = self._binary_cross_entropy(y_pred, y)
            self.backward(X, y)
            if i % 400 == 0:
                print(f"Epoch {i}: loss = {loss:.4f}")

# 测试 XOR 问题(MLP 可以解决!)
X = np.array([[0,0],[0,1],[1,0],[1,1]])
y = np.array([[0],[1],[1],[0]])  # XOR

mlp = MLP(in_dim=2, hidden=4, out_dim=1, lr=0.5)
mlp.train(X, y)
print(f"XOR 预测: {mlp.forward(X).round().flatten()}")  # [0. 1. 1. 0.] ✓

学习建议 :用 NumPy 手写一遍 MLP 的反向传播,比看十遍教程都有用。当你亲手推导出 dz1 = dz2 @ W2.T * ReLU'(z1) 这条链式法则时,整个深度学习的训练过程就「通了」。这也是面试中高频考点 ------ 「请手推反向传播」。

梯度下降优化器

梯度下降是神经网络训练的发动机。不同优化器的区别在于「怎么用梯度更新参数」:

优化器 核心思想 优点 缺点
SGD θ = θ - lr * ∇L 简单直接 收敛慢、震荡大
SGD + Momentum 加入动量项 v = βv + ∇L 加速收敛、减少震荡 多一个超参数 β
Adam 动量 + 自适应学习率 收敛快、鲁棒性好 可能不收敛(用 AdamW 修正)
AdamW Adam + 解耦权重衰减 Transformer 训练标配 略慢于 Adam

optimizers.py --- 优化器效果对比Python

复制代码
import torch
import torch.nn as nn
import torch.optim as optim

# 构造一个简单的回归问题
torch.manual_seed(42)
X = torch.randn(100, 3)
true_w = torch.tensor([2.0, -1.5, 0.8])
y = X @ true_w + torch.randn(100) * 0.1

def train_with_optimizer(optimizer_cls, lr=0.01, epochs=500):
    model = nn.Linear(3, 1)
    # 重置权重,保证公平对比
    model.weight.data = torch.randn(1, 3) * 0.1
    model.bias.data.zero_()

    optimizer = optimizer_cls(model.parameters(), lr=lr)
    criterion = nn.MSELoss()
    losses = []

    for _ in range(epochs):
        optimizer.zero_grad()
        loss = criterion(model(X).squeeze(), y)
        loss.backward()
        optimizer.step()
        losses.append(loss.item())

    return losses[-1], model.weight.data

# 对比三种优化器
for name, opt in [("SGD", optim.SGD), ("Adam", optim.Adam), ("AdamW", optim.AdamW)]:
    final_loss, weights = train_with_optimizer(opt, lr=0.05)
    print(f"{name:>6}: loss={final_loss:.6f}, weights={weights.numpy().round(2)}")
    # SGD: loss=0.009232, weights=[ 1.98 -1.49  0.79]
    # Adam: loss=0.008615, weights=[ 2.01 -1.51  0.81]
    # AdamW: loss=0.008701, weights=[ 2.00 -1.50  0.80]

PyTorch 入门实战

Tensor:PyTorch 的核心

Tensor 可以理解为「能在 GPU 上运行的 NumPy 数组」。它支持自动微分(autograd),这是深度学习框架区别于 NumPy 的关键。

tensor_basics.py --- Tensor 基础操作Python

复制代码
import torch

# 创建 Tensor
a = torch.tensor([1.0, 2.0, 3.0])        # 从列表创建
b = torch.zeros(2, 3)                    # 全零矩阵
c = torch.randn(3, 4)                    # 标准正态分布
d = torch.arange(0, 10, 2)                # [0, 2, 4, 6, 8]

# 属性
print(f"shape={c.shape}, dtype={c.dtype}, device={c.device}")

# 运算(与 NumPy 几乎一致)
e = a + 1; f = a * 2; g = torch.matmul(b, c.T)  # 矩阵乘法

# GPU 支持
if torch.cuda.is_available():
    a_gpu = a.cuda()     # 或 a.to('cuda')
    print(f"GPU: {a_gpu.device}")

# 与 NumPy 互转(共享内存!)
arr = a.numpy()       # Tensor → ndarray
t = torch.from_numpy(arr)  # ndarray → Tensor

autograd:自动微分

PyTorch 的 autograd 引擎会自动追踪所有操作,在 backward() 时计算梯度。这是神经网络训练的核心 ------ 你只需要定义前向传播,反向传播全自动。

autograd_demo.py --- 自动微分演示Python

复制代码
import torch

# requires_grad=True 开启梯度追踪
x = torch.tensor([3.0], requires_grad=True)
w = torch.tensor([2.0], requires_grad=True)
b = torch.tensor([1.0], requires_grad=True)

# 前向计算:y = w * x + b
y = w * x + b  # y = 2*3+1 = 7

# 反向传播:计算 ∂y/∂w, ∂y/∂x, ∂y/∂b
y.backward()

print(f"∂y/∂x = {x.grad}")  # 2.0 (w)
print(f"∂y/∂w = {w.grad}")  # 3.0 (x)
print(f"∂y/∂b = {b.grad}")  # 1.0

# 梯度清零(每次 backward 前必须清零)
x.grad.zero_(); w.grad.zero_(); b.grad.zero_()

# 禁用梯度追踪(推理/评估时)
with torch.no_grad():
    y = w * x + b  # 不追踪计算图,省内存

nn.Module:模型定义

nn_module_demo.py --- 使用 nn.Module 定义神经网络Python

复制代码
import torch
import torch.nn as nn

class SimpleClassifier(nn.Module):
    """三层神经网络:输入 → 隐藏 → 输出"""
    def __init__(self, in_dim: int, hidden: int, num_classes: int):
        super().__init__()
        self.fc1 = nn.Linear(in_dim, hidden)  # 全连接层
        self.relu = nn.ReLU()
        self.dropout = nn.Dropout(0.3)        # 防止过拟合
        self.fc2 = nn.Linear(hidden, num_classes)

    # 初始化权重:好的初始化 = 成功的一半
    def _init_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Linear):
                nn.init.kaiming_normal_(m.weight, mode='fan_in')
                nn.init.zeros_(m.bias)

    def forward(self, x):
        x = self.relu(self.fc1(x))
        x = self.dropout(x)
        x = self.fc2(x)
        return x  # 返回 logits,损失函数内部 softmax

完整训练循环:PyTorch 训练模板

一个标准的 PyTorch 训练循环包含五个步骤,这是所有深度学习项目的骨架:

train_loop.py --- 标准训练循环模板Python

复制代码
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset

def train_one_epoch(model, loader, criterion, optimizer, device):
    """单轮训练:5 步标准流程"""
    model.train()
    total_loss, correct = 0, 0

    for X, y in loader:
        X, y = X.to(device), y.to(device)

        # ① 梯度清零(每次 backward 前必须!)
        optimizer.zero_grad()

        # ② 前向传播
        outputs = model(X)

        # ③ 计算损失
        loss = criterion(outputs, y)

        # ④ 反向传播
        loss.backward()

        # ⑤ 参数更新
        optimizer.step()

        total_loss += loss.item() * X.size(0)
        correct += (outputs.argmax(1) == y).sum().item()

    return total_loss / len(loader.dataset), correct / len(loader.dataset)

def evaluate(model, loader, criterion, device):
    """评估:不计算梯度"""
    model.eval()
    total_loss, correct = 0, 0

    with torch.no_grad():
        for X, y in loader:
            X, y = X.to(device), y.to(device)
            outputs = model(X)
            total_loss += criterion(outputs, y).item() * X.size(0)
            correct += (outputs.argmax(1) == y).sum().item()

    return total_loss / len(loader.dataset), correct / len(loader.dataset)

# 完整训练流程
def train(model, train_loader, val_loader, epochs=20, lr=1e-3):
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    model = model.to(device)
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.AdamW(model.parameters(), lr=lr)
    scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=epochs)

    best_acc = 0.0
    for epoch in range(epochs):
        train_loss, train_acc = train_one_epoch(model, train_loader, criterion, optimizer, device)
        val_loss, val_acc = evaluate(model, val_loader, criterion, device)
        scheduler.step()

        if val_acc > best_acc:
            best_acc = val_acc
            torch.save(model.state_dict(), 'best_model.pt')  # 保存最佳模型

        print(f"Epoch {epoch+1:2d}: train_loss={train_loss:.4f} train_acc={train_acc:.3f} | val_loss={val_loss:.4f} val_acc={val_acc:.3f}")

    print(f"Best val_acc: {best_acc:.3f}")
    return model

训练循环五步法记忆口诀 :「清零 → 前向 → 损失 → 反向 → 更新」(zero_grad → forward → loss → backward → step)。面试时画训练流程图,这五步缺一不可。另外记得 model.train() 和 model.eval() 的切换,这会影响 Dropout 和 BatchNorm 的行为。

Transformer 架构剖析

为什么需要 Transformer?

在 Transformer 之前,NLP 领域的主流是 RNN/LSTM。但 RNN 有两个致命问题:无法并行计算 (必须按顺序处理 token)和长距离依赖(梯度消失/爆炸)。Transformer 通过 Self-Attention 机制一举解决了这两个问题,让每个 token 都能直接「看到」序列中的任意位置。

Self-Attention:自注意力机制

Self-Attention 的核心思想:每个词都和其他所有词计算相关性,然后按相关性加权融合信息。

三个关键矩阵:Q(Query,查询) 、K(Key,键) 、V(Value,值)。可以类比数据库查询:Q 是你想查什么,K 是每个条目的索引,V 是条目的实际内容。计算过程:

  1. Q = X · W_Q,K = X · W_K,V = X · W_V(三个线性变换)
  2. Attention Score = softmax(Q · K^T / √d_k)(缩放点积注意力)
  3. Output = Attention Score · V(加权求和)

self_attention.py --- 从零实现 Self-AttentionPython

复制代码
import torch
import torch.nn as nn
import torch.nn.functional as F
import math

class SelfAttention(nn.Module):
    """单头自注意力:Scaled Dot-Product Attention"""
    def __init__(self, d_model: int):
        super().__init__()
        self.d_model = d_model
        # Q、K、V 的线性投影矩阵
        self.W_Q = nn.Linear(d_model, d_model, bias=False)
        self.W_K = nn.Linear(d_model, d_model, bias=False)
        self.W_V = nn.Linear(d_model, d_model, bias=False)

    def forward(self, x):
        """
        x: (batch, seq_len, d_model)
        返回: (batch, seq_len, d_model), attention_weights
        """
        Q = self.W_Q(x)  # (B, L, d)
        K = self.W_K(x)
        V = self.W_V(x)

        # 计算注意力分数:Q @ K^T / sqrt(d_k)
        d_k = Q.size(-1)
        scores = Q @ K.transpose(-2, -1) / math.sqrt(d_k)  # (B, L, L)

        # Softmax 归一化 → 注意力权重
        attn_weights = F.softmax(scores, dim=-1)

        # 加权求和
        output = attn_weights @ V  # (B, L, d)
        return output, attn_weights

# 演示:一个简单句子中的注意力
torch.manual_seed(42)
attn = SelfAttention(d_model=8)
# 模拟 4 个 token 的嵌入向量
x = torch.randn(1, 4, 8)  # (batch=1, seq_len=4, d_model=8)
output, weights = attn(x)

print(f"注意力权重矩阵:\n{weights[0].detach().numpy().round(3)}")
# 每行之和 = 1.0(softmax 特性)
print(f"每行之和: {weights[0].sum(dim=-1).numpy()}")  # [1. 1. 1. 1.]

Multi-Head Attention:多头注意力

单头注意力只关注一种关系模式,多头注意力则让模型从多个角度同时关注:比如一个头关注语法关系,另一个头关注语义关系,再一个头关注位置关系。

multi_head_attention.py --- 多头注意力实现Python

复制代码
class MultiHeadAttention(nn.Module):
    """多头注意力:h 个 SelfAttention 并行计算"""
    def __init__(self, d_model: int = 512, num_heads: int = 8):
        super().__init__()
        assert d_model % num_heads == 0, "d_model 必须能被 num_heads 整除"
        self.d_model = d_model
        self.num_heads = num_heads
        self.d_k = d_model // num_heads  # 每个头的维度

        # 合并投影:一次矩阵乘法替代 h 次小矩阵乘法
        self.W_QKV = nn.Linear(d_model, 3 * d_model, bias=False)
        self.W_O = nn.Linear(d_model, d_model, bias=False)  # 输出投影

    def forward(self, x):
        B, L, _ = x.shape

        # 一次性计算 Q、K、V
        qkv = self.W_QKV(x)  # (B, L, 3*d_model)
        Q, K, V = qkv.chunk(3, dim=-1)

        # 拆成多头:(B, L, d_model) → (B, num_heads, L, d_k)
        Q = Q.view(B, L, self.num_heads, self.d_k).transpose(1, 2)
        K = K.view(B, L, self.num_heads, self.d_k).transpose(1, 2)
        V = V.view(B, L, self.num_heads, self.d_k).transpose(1, 2)

        # 缩放点积注意力(每个头独立计算)
        scores = Q @ K.transpose(-2, -1) / math.sqrt(self.d_k)
        attn = F.softmax(scores, dim=-1)
        out = attn @ V  # (B, num_heads, L, d_k)

        # 合并多头:(B, num_heads, L, d_k) → (B, L, d_model)
        out = out.transpose(1, 2).contiguous().view(B, L, self.d_model)
        return self.W_O(out)

Position Encoding:位置编码

Self-Attention 本身是位置无关的 ------ 打乱输入顺序,输出只是相应打乱。但语言是有顺序的!Position Encoding 通过给每个位置添加一个唯一的向量来注入位置信息。Transformer 原始论文使用正弦/余弦编码:

position_encoding.py --- 正弦位置编码Python

复制代码
class SinusoidalPositionEncoding(nn.Module):
    """Transformer 原始论文的位置编码方案"""
    def __init__(self, d_model: int, max_len: int = 5000):
        super().__init__()
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len).unsqueeze(1).float()
        # 频率随维度指数衰减:低维度编码短距离,高维度编码长距离
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
        pe[:, 0::2] = torch.sin(position * div_term)  # 偶数位用 sin
        pe[:, 1::2] = torch.cos(position * div_term)  # 奇数位用 cos
        self.register_buffer('pe', pe.unsqueeze(0))  # (1, max_len, d_model)

    def forward(self, x):
        return x + self.pe[:, :x.size(1)]  # 直接相加

**为什么用 sin/cos?**因为 sin(α+β) 可以表示为 sin(α)cos(β)+cos(α)sin(β),这种线性关系让模型能学习到相对位置信息。GPT 系列后来改用可学习的 Position Embedding,效果更好但失去了外推能力(不能处理超过训练长度的序列)。

Encoder-Decoder 完整结构

Transformer 原始架构包含 Encoder 和 Decoder 两部分。Encoder 处理输入序列,Decoder 生成输出序列。但现代大模型有不同变体:

模型 架构 特点
BERT Encoder-Only 双向上下文理解,适合分类/抽取
GPT Decoder-Only 自回归生成,用 Causal Mask 防止看到未来
T5 / BART Encoder-Decoder 完整结构,适合翻译/摘要

学习重点:现在绝大多数大模型(GPT-4、DeepSeek、Qwen、Llama)都是 Decoder-Only 架构。理解 Causal Mask(因果掩码)是关键 ------ 在训练时,当前 token 只能看到它之前的 token,不能「偷看」未来。这是自回归生成的本质。

踩坑记录

坑 1:反向传播前忘记 optimizer.zero_grad()

现象 :训练 loss 不收敛,甚至越来越大。因为 PyTorch 默认会累加梯度(accumulate gradient),不清零会导致多次 batch 的梯度混在一起。

解决 :每个 batch 开始时调用 optimizer.zero_grad() 或 model.zero_grad()。如果使用梯度累积(大 batch 模拟),则在累积 N 步后再清零。

坑 2:训练和评估时忘记切换 model.train() / model.eval()

现象:评估时准确率不稳定,每次结果都不一样。因为 Dropout 在训练模式下会随机丢弃神经元,评估时应该关闭。

解决 :训练循环前调用 model.train(),评估循环前调用 model.eval()。BatchNorm 层也会受此影响。

坑 3:Tensor 在 CPU 和 GPU 之间来回拷贝

现象:训练速度极慢,GPU 利用率低。因为每次 forward 时数据在 CPU 上,PyTorch 隐式拷贝到 GPU 后又拷贝回来。

解决 :在训练循环开始时,将 model 和 data 一次性移到 GPU:model = model.to(device),X, y = X.to(device), y.to(device)。避免在循环中频繁 .cpu() 和 .cuda()。

坑 4:CrossEntropyLoss 的输入不需要 Softmax

现象 :模型输出先过 Softmax 再传入 CrossEntropyLoss,训练完全不收敛。因为 nn.CrossEntropyLoss 内部已经集成了 LogSoftmax + NLLLoss。

解决 :模型最后一层直接返回 logits(原始分数),不要加 Softmax。只有在推理时需要概率时才手动调用 F.softmax(output, dim=-1)。

收获总结

今日核心收获

今天是第五阶段的第一天,从「调用 API」正式迈入「理解模型内部」的领域。今天学到的每一个概念,都是后续 LoRA 微调、模型量化、推理优化的理论基础:

  • 神经网络本质:多层线性变换 + 非线性激活函数,通过反向传播的链式法则自动计算梯度。用 NumPy 手写一遍 MLP 的反向传播,比看十遍教程都管用
  • PyTorch 三件套:Tensor(数据载体 + GPU 支持)、autograd(自动微分引擎)、nn.Module(模型定义框架)。训练循环五步法:清零 → 前向 → 损失 → 反向 → 更新
  • Transformer 核心:Self-Attention 让每个 token 能直接关注所有其他 token,Multi-Head 从多个角度并行关注,Position Encoding 注入位置信息。现代大模型(GPT/DeepSeek)都是 Decoder-Only 架构
  • 思维转变:从「调包侠」到「理解原理」。知道为什么 LoRA 只微调低秩矩阵、为什么量化会影响精度、为什么需要预热学习率 ------ 这些都需要今天的基础知识

明日计划

Day 27 · HuggingFace Transformers 入门
  • HuggingFace 生态概览:Models / Datasets / Spaces / Hub 四大组件
  • Pipeline API:一行代码完成情感分析、文本生成、翻译、摘要等任务
  • Tokenizer 分词器:BPE/WordPiece 原理、encode/decode、padding/truncation
  • 模型加载与推理:AutoModel / AutoTokenizer 自动加载、from_pretrained 缓存机制
  • 中文模型实战:Qwen2、ChatGLM 等国产模型的使用与对比
相关推荐
hahaha60161 小时前
完美反射法--白平衡算法
人工智能·算法
jimmyleeee1 小时前
大模型安全之三十九:幻觉防线---- AI 幻觉检测、治理与预防指南
人工智能·安全
梦帮科技2 小时前
可证伪性工程测评与生产部署红蓝对抗:压力测试、长尾鲁棒性与全生命周期安全质检守卫
人工智能·深度学习·神经网络·安全·机器学习·自然语言处理·压力测试
蜗牛互联网2 小时前
Gemini 4 Argon的1M输出窗口与长程Agent工程边界
java·人工智能·后端
dtsola2 小时前
一个人怎么指挥一支 AI 队伍
人工智能·程序员·ai创业·独立开发者·openclaw·一人公司·小遥claw
坤盾科技2 小时前
用坤擎智能体搭一套企业级 AI 中台
人工智能·大模型·企业数字化·ai智能体·坤擎智能体
johnsong2 小时前
幽灵协议:当AI推荐死去的SaaS,编码Agent控制层正在形成
大数据·人工智能
这张生成的图像能检测吗2 小时前
(论文速读)DefectDiffu:基于一致性建模的少样本工业缺陷图像生成
人工智能·深度学习·计算机视觉·异常检测·少样本学习·扩散生成
7yewh2 小时前
SLAM 从视觉里程计到建图(6)
数据结构·人工智能·机器人·自动驾驶·嵌入式