神经网络
由多层参数化变换和非线性激活组成的可学习函数。
学习目标
- 画出前馈网络
- 追踪层间形状
- 区分隐藏层和输出层
为什么需要这个概念
神经网络把很多简单计算单元组合成一个可学习函数。理解各层的输入输出、参数数量和非线性位置,比只记“网络有多少层”更能帮助你读懂模型结构。
本页同时用一个可手算的小网络核对数值,用一个稍大的批量网络核对形状。两个例子目的不同:前者解释计算,后者训练阅读实际代码所需的维度意识。
学习前需要掌握
背景与问题
单个线性变换只能表达有限的关系。面对弯曲边界、图像结构或复杂文本模式时,需要把输入经过多步变换,形成对任务有用的中间表示。
这些中间表示不是人提前写好的所有规则,而是与输出任务一起通过训练调整。网络结构只提供一类可能的函数;是否学到有用规律,还要依赖数据、损失和优化过程。
概念定义
前馈神经网络通常由输入、若干隐藏层和输出层组成。每层接收上一层的表示,先进行参数化变换,再根据结构应用激活或其他运算。
隐藏层的“隐藏”表示它通常不是直接提供给模型的目标标签,而是计算得到的中间表示。输出层则必须匹配任务:回归可以输出实数,多分类常输出每个类别的 logit,而不是默认给所有任务都套同一种激活。
直观理解
每一层都在重新组合已有特征。早期表示可以较接近输入,后面的表示可以组合前面的结果;这种描述是理解结构的起点,不保证每个神经元都对应一个能用自然语言命名的概念。
可以先把模型看成一条有明确接口的计算流水线:上一层输出最后一维的长度,要与下一层要求的输入特征数对上。样本所在的 batch 维通常不会被 Linear 自动变成类别维。
核心原理
非线性让组合后的函数突破单一线性映射。若只有连续的仿射层,第二层可以与第一层的权重和偏置合并,整体仍等价于一个仿射变换;增加层数本身没有产生所需的非线性。
层的形状和参数数量可以在训练前计算。Linear(10, 32) 有 10×32 个权重和 32 个偏置;随后 Linear(32, 4) 有 32×4 个权重和 4 个偏置,总计 484 个可训练参数。
前向传播计算当前输出,损失比较输出与目标,反向传播计算各参数的梯度,优化器再执行更新。把四者分开,能避免“调用了模型就已经训练”这类误解。
更多参数并不自动带来更好结果。容量过大可能加重过拟合,结构过深也可能增加优化难度;需要在验证协议下比较,并检查数据与实现是否正确。
数学表达
核心公式
l 是层编号,h 是该层表示。
变量含义
h^(l)第 l 层输出表示W^(l)第 l 层权重矩阵
计算步骤
- 1第一层第一个分数:1×1 − 1×2 + 0 = -1。
- 2第一层第二个分数:0.5×1 + 0.5×2 + 1 = 2.5。
- 3ReLU 后隐藏表示为 [0, 2.5],负分数被截成 0。
- 4输出为 2×0 − 1×2.5 + 0.5 = -2。
代码对应位置
示例 1核对 10→32→4 网络的 batch 形状和参数量:检查批量输入的维度流向,并把参数数量与手算对照。示例 2用纯 Python 核对小网络的每一步:复现上面的 2→2→1 固定参数例子,不依赖训练或随机初始化。
变量解释
| 变量 | 含义 |
|---|---|
h^(l) | 第 l 层输出表示 |
W^(l) | 第 l 层权重矩阵 |
完整数值示例
一个 2→2→1 网络的完整前向计算
已知条件
- 输入 x = [1, 2]。
- 第一层权重的两行为 [1, -1]、[0.5, 0.5],偏置为 [0, 1]。
- 隐藏层使用 ReLU;输出层权重为 [2, -1],偏置为 0.5,作为实数回归输出。
计算步骤
- 第一层第一个分数:1×1 − 1×2 + 0 = -1。
- 第一层第二个分数:0.5×1 + 0.5×2 + 1 = 2.5。
- ReLU 后隐藏表示为 [0, 2.5],负分数被截成 0。
- 输出为 2×0 − 1×2.5 + 0.5 = -2。
计算结果
这个小网络的输出是 -2;它是回归头的实数值,不是概率。
处理前后对比
- 如果移除 ReLU,隐藏表示为 [-1, 2.5],同样输出权重会得到 -4;非线性改变了函数。
- 下面第一段 PyTorch 代码使用 10→32→4 的另一个结构,只用于核对批量形状和参数量;第二段代码复现本手算例。
计算与实现步骤
- 定义输入输出
- 声明子层
- 实现 forward
- 随机输入检查
- 选择损失并训练
代码实现
示例 1
核对 10→32→4 网络的 batch 形状和参数量
example_01.py用途:检查批量输入的维度流向,并把参数数量与手算对照。
import torch
from torch import nn
model = nn.Sequential(nn.Linear(10, 32), nn.ReLU(), nn.Linear(32, 4))
x = torch.zeros(8, 10)
output = model(x)
print("shape:", tuple(output.shape))
print("params:", sum(parameter.numel() for parameter in model.parameters()))代码解析
解析始终位于完整代码下方,并按实际代码段逐项对应。
输入数据与任务
检查批量输入的维度流向,并把参数数量与手算对照。
model- 组合预处理和估计器的模型对象。
Step 1 · 1–2 行
导入当前步骤需要的数值计算、预处理、模型或评价工具。依赖集中写在代码开头,便于复现。
import torch
from torch import nnStep 2 · 4–8 行
输出中间参数、形状或最终指标,用于核对代码是否符合预期。
model = nn.Sequential(nn.Linear(10, 32), nn.ReLU(), nn.Linear(32, 4))
x = torch.zeros(8, 10)
output = model(x)
print("shape:", tuple(output.shape))
print("params:", sum(parameter.numel() for parameter in model.parameters()))预期输出或运行结果
shape: (8, 4) params: 484
常见错误 · 5 条
- 认为层数越多必然更好,或把神经元数直接等同于已学会的概念数。
- 把 batch 维当成特征维,或者让相邻 Linear 层的特征长度对不上。
- 把 logit 当成已经归一化的概率,或在损失函数前重复应用不合适的激活。
- 只检查输出形状,却没有用小数据核对实际数值与训练步骤。
- 确认样本轴、特征轴以及 X 与 y 的第一维完全对应。
示例 2
用纯 Python 核对小网络的每一步
example_02.py用途:复现上面的 2→2→1 固定参数例子,不依赖训练或随机初始化。
x = [1.0, 2.0]
w1 = [[1.0, -1.0], [0.5, 0.5]]
b1 = [0.0, 1.0]
z1 = [sum(w * value for w, value in zip(row, x)) + bias
for row, bias in zip(w1, b1)]
h = [max(0.0, value) for value in z1]
y = 2.0 * h[0] - h[1] + 0.5
print("hidden:", h)
print(f"output={y:.4f}")代码解析
解析始终位于完整代码下方,并按实际代码段逐项对应。
输入数据与任务
复现上面的 2→2→1 固定参数例子,不依赖训练或随机初始化。
y- 目标标签或连续目标值。
w- 模型权重或当前待优化参数。
Step 1 · 1–9 行
输出中间参数、形状或最终指标,用于核对代码是否符合预期。
x = [1.0, 2.0]
w1 = [[1.0, -1.0], [0.5, 0.5]]
b1 = [0.0, 1.0]
z1 = [sum(w * value for w, value in zip(row, x)) + bias
for row, bias in zip(w1, b1)]
h = [max(0.0, value) for value in z1]
y = 2.0 * h[0] - h[1] + 0.5
print("hidden:", h)
print(f"output={y:.4f}")预期输出或运行结果
hidden: [0.0, 2.5] output=-2.0000
常见错误 · 4 条
- 认为层数越多必然更好,或把神经元数直接等同于已学会的概念数。
- 把 batch 维当成特征维,或者让相邻 Linear 层的特征长度对不上。
- 把 logit 当成已经归一化的概率,或在损失函数前重复应用不合适的激活。
- 只检查输出形状,却没有用小数据核对实际数值与训练步骤。
实际应用
- 分类
- 回归
- 表示学习
常见错误
- 认为层数越多必然更好,或把神经元数直接等同于已学会的概念数。
- 把 batch 维当成特征维,或者让相邻 Linear 层的特征长度对不上。
- 把 logit 当成已经归一化的概率,或在损失函数前重复应用不合适的激活。
- 只检查输出形状,却没有用小数据核对实际数值与训练步骤。
常见问题
网络为什么要有隐藏层?
用于学习中间表示与非线性组合。
深度越大越好吗?
不一定,还受优化、数据和泛化限制。
推荐学习资料
Dive into Deep Learning
把数学、图示、文字与可执行代码结合,系统覆盖深度学习基础和现代模型。
Zhang / Lipton / Li / Smola · D2L.ai
资料笔记
Practical Deep Learning for Coders
以项目驱动方式学习视觉、NLP、表格模型、协同过滤和模型部署。
Jeremy Howard · fast.ai
资料笔记
Deep Learning
系统讲解线性代数、优化、前馈网络、正则化、卷积、序列模型与研究主题。
Goodfellow / Bengio / Courville · DeepLearningBook.org
资料笔记
MIT Introduction to Deep Learning
以密集讲座和实验介绍神经网络、序列模型、生成模型和深度学习应用。
MIT 6.S191 Team · MIT
资料笔记
TensorFlow Playground
在浏览器中调整特征、隐藏层、激活函数和学习率,观察分类边界变化。
TensorFlow Team · TensorFlow