神经网络基础:从感知机到多层网络
神经网络基础:从感知机到多层网络
站内搜索
直接问 AI

神经网络基础:从感知机到多层网络

神经网络经常被包装成很复杂的东西,但从入门角度看,可以先把它理解成一种可训练的函数组合:每一层做一次变换,多层连起来,就能表达更复杂的关系。

这篇文章从感知机讲起,逐步解释神经元、权重、激活函数、前向传播和反向传播的基本直觉。目标不是推完所有公式,而是让你能读懂神经网络训练代码的大体结构。

读这篇时可以先抓住一个主线:神经网络先用当前参数做预测,再根据损失反向更新参数。

一、从一个神经元开始

一个最简单的神经元可以写成:

z = w1 * x1 + w2 * x2 + ... + b
output = activation(z)

这里:

  • x 是输入特征
  • w 是权重
  • b 是偏置
  • activation 是激活函数

如果没有激活函数,多层线性变换叠在一起仍然可以合并成一个线性变换。激活函数的意义是给网络加入非线性表达能力。

二、感知机能做什么

感知机可以看成早期的简单神经网络。它根据输入特征加权求和,再通过阈值得到分类结果。

if w1 * x1 + w2 * x2 + b > 0:
    predict 1
else:
    predict 0

这个模型能解决线性可分问题,也就是可以用一条线、一个平面或更高维超平面分开的数据。

但现实中的关系往往不是线性的,所以我们需要多层网络和非线性激活函数。

三、层是什么

神经网络里的一层,就是把一组输入同时送入多个神经元,得到一组输出。常见结构包括:

  • 输入层:接收原始特征
  • 隐藏层:中间的特征变换层
  • 输出层:输出分类概率或预测数值

一个简单的多层网络可以表示成:

输入特征 -> 隐藏层 1 -> 隐藏层 2 -> 输出层

带参数的层(例如全连接层)有权重和偏置;输入层只是数据入口,ReLU 这类激活层本身没有可训练参数。训练更新的是参与损失计算且启用了梯度的参数。

四、前向传播是什么

前向传播就是从输入开始,一层一层算到输出。

x -> layer1 -> activation -> layer2 -> activation -> output

在代码里,前向传播通常对应模型的 forward 函数。它回答的是:

给定当前参数和一批输入,模型会预测什么?

训练和预测都会用到前向传播。区别是训练时还要根据预测误差更新参数。

五、反向传播的直觉

反向传播用于计算每个参数对损失的影响。直觉上,它要回答:

如果这个权重稍微变大或变小,最终损失会怎么变化?

有了这个信息,优化器就可以更新参数,让损失下降。

预测输出 -> 计算损失 -> 反向传播梯度 -> 更新参数

你不需要一开始手写反向传播。PyTorch、TensorFlow 这类框架会自动完成梯度计算。但你需要知道训练循环为什么会有 loss.backward() 和 optimizer.step() 这类步骤。

六、一个典型训练循环

用伪代码表示,神经网络训练通常长这样:

for epoch in range(num_epochs):
    for X_batch, y_batch in train_loader:
        y_pred = model(X_batch)
        loss = loss_fn(y_pred, y_batch)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

这段代码可以拆成五步:

  1. 取一批训练数据
  2. 前向传播得到预测
  3. 计算预测和真实标签之间的损失
  4. 反向传播计算梯度
  5. 优化器根据梯度更新参数

七、深度学习为什么需要更多数据和算力

神经网络的表达能力很强,但代价也很明显:

  • 参数多,容易过拟合
  • 训练通常需要更多数据
  • 调参空间更大
  • 训练速度更依赖硬件

这也是为什么入门时建议先学传统机器学习流程。你先掌握数据、特征、训练和评估,再进入神经网络,会更容易判断模型到底有没有学到可泛化的规律。

八、神经网络和大模型的关系

大语言模型、图像生成模型、语音识别模型,本质上都属于深度学习系统。它们通常使用更复杂的网络结构、更大的数据集和更长的训练过程。

但无论模型多大,基础问题仍然相似:

  • 输入如何表示成数字
  • 模型结构如何把输入变成输出
  • 损失函数如何衡量预测错误
  • 训练过程如何更新参数
  • 评估方式是否能反映真实使用效果

所以,理解神经网络基础不是为了马上训练大模型,而是为了看懂现代 AI 系统背后的共同语言。

九、初学者容易误解的点

刚接触神经网络时,下面几个误解很常见:

  • 以为层数越多一定越好,忽略数据量、过拟合和训练成本
  • 把激活函数当成可有可无的细节,没有理解非线性的作用
  • 只关注模型结构,不关注损失函数和评估指标
  • 看到训练集 loss 下降就认为模型已经可靠

神经网络的强大来自表达能力,但可靠性仍然要靠数据划分、评估和错误分析来确认。

把一次前向和反向手算一遍

看再多描述,不如把最小的例子算一遍。下面这个网络只有两个输入、一个隐藏神经元、一个输出,用平方误差做损失,所有数字都可以口算验证。

输入   x = [1.0, 2.0]        真实标签 y = 1.0
隐藏层 w = [0.3, -0.1],  b = 0.2      激活用 ReLU
输出层 v = 0.5,          c = 0.1      不加激活

前向:

z  = 0.3×1.0 + (-0.1)×2.0 + 0.2 = 0.3
a  = ReLU(0.3) = 0.3
ŷ  = 0.5×0.3 + 0.1 = 0.25
L  = (ŷ - y)² = (0.25 - 1.0)² = 0.5625

反向:从损失开始,一层层往回乘导数。

∂L/∂ŷ = 2(ŷ - y) = 2 × (-0.75) = -1.5

∂L/∂v = ∂L/∂ŷ × a  = -1.5 × 0.3 = -0.45
∂L/∂c = ∂L/∂ŷ × 1  = -1.5

∂L/∂a = ∂L/∂ŷ × v  = -1.5 × 0.5 = -0.75
∂L/∂z = ∂L/∂a × ReLU'(0.3) = -0.75 × 1 = -0.75   ← z>0 所以导数为 1

∂L/∂w₁ = ∂L/∂z × x₁ = -0.75 × 1.0 = -0.75
∂L/∂w₂ = ∂L/∂z × x₂ = -0.75 × 2.0 = -1.5
∂L/∂b  = ∂L/∂z × 1  = -0.75

在当前参数点,这些负梯度说明各参数的小幅增加会使损失沿对应坐标下降。这是局部信息,不保证任意步长都有效。学习率 0.1 时,同时更新全部参数得到 [w1,w2,b,v,c] = [0.375,0.05,0.275,0.545,0.25],重算得到 ŷ=0.65875、L=0.1164515625。

这里梯度全部来自更新前的同一组参数。不能更新输出权重后,再把新权重代回本次隐藏层梯度;那样已不是这次前向传播的梯度。只改 w1=0.375 时预测为 0.2875,同时更新在这个例子里降得更多,但这不构成一般性的下降幅度保证。

这个单样本例子里,dL/dw_j = (dL/dz) x_j,在共同的上游导数下,x2 是 x1 的两倍,所以对应梯度也是两倍。批量梯度还会对样本求和或平均,可能抵消;不能把“特征越大梯度必然越大”推广到任意网络。缩放特征的作用之一是改善优化问题的尺度。

如果把隐藏偏置改为 b=-0.2,就有 z=-0.1,ReLU 输出为 0。此时 w1、w2、b 的路径被截断,v 的梯度也因隐藏输出为 0 而为 0;但输出偏置 dL/dc=-1.8 仍能更新。单个样本上不激活不等于永久“死亡”,还要检查它在其他样本和后续步骤中的状态。

建议自己动手把上面的数字重算一遍。这个例子里出现的每个乘法,在真实的百层网络里都是同样的操作,只是数量不同。

全零初始化的问题到底在哪里

问题不在“零不能学习”,而在隐藏神经元的对称性及激活导数。对这里的全连接 MLP,如果两个隐藏单元的输入权重、偏置和输出连接均相同,且每步执行相同的确定性更新,它们的激活和梯度也相同,更新后仍无法分工。随机初始化是常用的破对称方法,不是唯一可能的方法。

实验包用三个相同的隐藏单元跑了 10 步,逐步检查它们仍完全一致。另一个全零 ReLU 例子明确选取 ReLU'(0)=0:隐藏层梯度及输出权重梯度为零,但当四个标签为 [0,0,0,1] 时,输出偏置梯度为 [-0.25,0.25],一步后平均交叉熵从 0.6931471806 降到 0.6809596480。它只是调整类别先验,没有学到输入特征。

相反,没有隐藏层的线性 softmax 分类器可以从零权重开始,数据决定的权重梯度仍可能非零。已经用权重打破对称性时,偏置通常可以初始化为零。Xavier、He 等方法还考虑扇入、扇出和激活类型,以控制信号尺度,而不是保证每个网络都能成功训练。

梯度消失、浮点精度与残差连接

在一条标量链上,梯度是局部导数的连乘;有分支的图还要把不同路径的贡献相加,向量网络则涉及雅可比乘积。若某条链每次乘 0.5,50 次后为 2^-50 = 8.881784197e-16。这在 float32 中仍是可表示的正数,并没有下溢为零。

“能表示梯度”与“能改变参数”是两件事。实验按 float32 计算 1.0 - 0.1 * 2^-50,结果仍是 1.0:更新远小于这个参数附近的浮点间距,被舍入掉了。float32 最小正规正数约为 1.175e-38,而 1.0 上方相邻数间距约为 1.192e-7。不要把动态范围与相对精度混为一谈。

  • 激活函数。Sigmoid 的导数不超过 0.25,但一层的导数还包含权重矩阵,不能断言整个网络每层都缩小四倍。ReLU 正区间导数为 1,也不能消除权重连乘、负区间截断带来的问题。
  • 归一化。它可改变数值尺度和优化条件,但不保证所有梯度范数接近 1;BatchNorm 与 LayerNorm 的归一化轴、训练与推理行为也不同。
  • 残差。标量 y=x+f(x) 的导数是 1+f'(x),向量形式是 I+J_f。恒等路径有帮助,但若 f(x)=-x,总导数仍为 0,所以残差不是“任意深度梯度都能无损传到底”的保证。

检查激活分布、梯度和参数更新量,再结合损失与验证指标判断训练状态。梯度非零不证明实现正确,损失下降也不证明泛化有效。

运行原例:学习率与局部梯度

下面是对上面的五个参数实际执行的一步更新。每一行都从同一个初始点重新开始,不是连续三步;目标是核对更新规则,不是比较训练准确率。

学习率 更新后预测 更新后平方误差
0.01 0.2890525 0.5054463478
0.1 0.65875 0.1164515625
1.0 6.16 26.6256

初始误差为 0.5625。学习率 1.0 虽然仍沿负梯度方向走,却越过了局部下降区域。这说明知道方向后,还要选择合适的步长。

查看可直接运行的单步 Python 示例
"""The article's five-parameter ReLU example; gradients use one snapshot."""


def forward_and_grad(params):
    w1, w2, b, v, c = params
    z = w1 + 2 * w2 + b
    a = max(0.0, z)
    prediction = v * a + c
    loss = (prediction - 1.0) ** 2
    d_prediction = 2 * (prediction - 1.0)
    dz = d_prediction * v * (z > 0)
    grad = [dz, 2 * dz, dz, d_prediction * a, d_prediction]
    return prediction, loss, grad


def one_step(learning_rate):
    before = [0.3, -0.1, 0.2, 0.5, 0.1]
    prediction, loss, grad = forward_and_grad(before)
    after = [p - learning_rate * g for p, g in zip(before, grad)]
    next_prediction, next_loss, _ = forward_and_grad(after)
    return {"learning_rate": learning_rate, "before": before, "grad": grad,
            "after": after, "prediction_before": prediction, "loss_before": loss,
            "prediction_after": next_prediction, "loss_after": next_loss}


if __name__ == "__main__":
    for rate in (0.01, 0.1, 1.0):
        row = one_step(rate)
        print(f"lr={rate:g}: prediction={row['prediction_after']:.8f}, loss={row['loss_after']:.10f}")

下载神经网络梯度实验包:上面的纯 Python 示例不需要额外依赖;扩展验证使用 NumPy 2.3.5,含全部输入、1029 个参数的差分对照 CSV、初始化反例和参考 JSON。运行 python audit_gradients.py --output run-results 后应看到 NEURAL_GRADIENT_AUDIT_PASSED。没有下载训练集,也没有测试 GPU 或泛化性能。

更完整的批量网络和梯度检查见 反向传播计算图的可复现实验。浮点范围和精度的定义可查 NumPy finfo 文档;拐点处的梯度选择参见 PyTorch 自动微分说明。

十、下一步读什么

上一篇是 模型训练与评估入门。如果你想把前面几篇串成一次完整练习,可以继续读 Python 人工智能小实战。

十一、用二维分类理解隐藏层

理解隐藏层时,可以先想象一个二维分类问题:输入只有 x1 和 x2,输出判断样本属于 A 类还是 B 类。单个线性分类器只能画出一条直线边界;如果数据呈现环形、月牙形或多个局部区域,一条直线就不够用了。

隐藏层的作用可以理解为重新组织特征空间。第一层神经元各自学习不同方向的分割,激活函数保留其中一部分响应;下一层再把这些响应组合起来,形成更复杂的决策边界。这个解释不等于完整数学证明,但足够帮助你理解为什么“多层 + 非线性”会比单层线性模型表达能力更强。

十二、训练日志应该怎么看

训练神经网络时,不要只盯着最后一个准确率。更可靠的做法是同时观察训练损失、验证损失和验证指标的变化趋势。

日志现象 可能含义 下一步检查
训练 loss 下降,验证 loss 上升 可能过拟合 增加正则化、减少模型规模或检查数据划分
训练和验证 loss 都不下降 学习率、特征或模型结构可能不合适 检查输入归一化、标签编码和学习率
准确率高但某些类别很差 类别不平衡或少数类特征不足 查看混淆矩阵和每类 precision/recall

这也是为什么前面反复强调评估:神经网络可以很快把训练集拟合得很好,但只有验证集和错误分析才能说明它是否真的学到了可泛化规律。

发表回复

向下探索