# 01. 全连接网络与"五步骨架" > 你已经发现的规律:每个模型都有 `forward`,都要 `optimizer`、`loss`、反向传播。 > 这一篇把这套通用骨架讲透。 --- ## 一、全连接层在算什么? 一个 `nn.Linear(in, out)` 就是一次矩阵运算: $$\mathbf{y} = \mathbf{W}\mathbf{x} + \mathbf{b}$$ - $\mathbf{x}$:输入(in 维) - $\mathbf{W}$:权重矩阵(**out × in**),要学习 - $\mathbf{b}$:偏置(out 维),要学习 - $\mathbf{y}$:输出(out 维) **单个神经元展开**(就是高中那个线性组合): $$y = w_1x_1 + w_2x_2 + \dots + w_nx_n + b$$ > 验证:`nn.Linear(1,32)` 的 `weight.shape = (32,1)`,`bias.shape = (32,)`, > 正好把 1 维输入升到 32 维。 --- ## 二、为什么必须加激活函数? 只堆 `Wx+b`,无论多少层,**本质还是线性**(矩阵连乘还是一个矩阵), 画不出 sin 这样的弯曲曲线。 加 ReLU 引入非线性: $$\text{ReLU}(x) = \max(0, x)$$ 多层 + 非线性 → 能拟合任意复杂函数(**万能逼近定理**)。 ```python class MLP(nn.Module): def __init__(self): super().__init__() self.fc1 = nn.Linear(1, 32) self.fc2 = nn.Linear(32, 32) self.fc3 = nn.Linear(32, 1) def forward(self, x): x = torch.relu(self.fc1(x)) # 线性 + 非线性 x = torch.relu(self.fc2(x)) return self.fc3(x) # 回归任务最后一层不加激活 ``` --- ## 三、训练五步骨架(雷打不动) ```python for epoch in range(1000): optimizer.zero_grad() # 1. 清空上轮梯度(梯度会累加,不清会错) pred = model(x) # 2. 前向(自动调用 forward) loss = criterion(pred, y) # 3. 算误差 loss.backward() # 4. 反向(autograd 自动算所有梯度) optimizer.step() # 5. 按梯度更新参数 ``` ### 逐步拆解 **① zero_grad()**:PyTorch 梯度是累加的(`+=`),不清零会把上轮叠进来。 **② model(x)**:`nn.Module` 实现了 `__call__`,`model(x)` ≈ `model.forward(x)` (还多做 hook,**别直接写 model.forward(x)**)。 **③ loss**:回归用 MSE: $$\text{MSE} = \frac{1}{N}\sum_{i=1}^{N}(\hat{y}_i - y_i)^2$$ **④ backward()**:用链式法则自动算 loss 对每个参数的偏导(梯度)。 梯度含义:「参数往哪动、动多少,能让 loss 下降最快」。(详见 02 篇) **⑤ step()**:梯度下降更新: $$w \leftarrow w - \text{lr} \times \frac{\partial L}{\partial w}$$ lr 太大震荡、太小学得慢。Adam 会自适应步长,更稳。 --- ## 四、跑通结果(拟合 sin(x)) ``` Epoch 1000 | Loss: 0.000006 预测 sin(π/2) = 0.9996 真实 = 1.0 ✅ 预测 sin(-π/2)= -0.9991 真实 = -1.0 ✅ ``` 完整代码:`code/mlp_basic_demo.py` --- ## 五、流程全景图 ``` 输入 x ▼ fc1: Wx+b → ReLU ┐ ▼ fc2: Wx+b → ReLU ├ forward 前向 ▼ fc3: Wx+b ┘ 预测 pred ─┐ 真实 y ─┐ ▼ ▼ loss = MSE(pred, y) ▼ loss.backward() ← autograd 算梯度 ▼ optimizer.step() ← 梯度下降更新 循环 1000 次 → loss↓ → 拟合越准 ``` --- by 小小叶 · OpenClaw