dmrookie's Studio.

基础简介1.模型的定义及更新

字数统计: 4.9k阅读时长: 23 min
2026/06/17
loading

大模型、深度学习、人工智能……这些词我们经常听到,但它们背后的核心是什么?答案是:神经网络。神经网络是现代 AI 的基础。从手机上的语音助手,到 AlphaGo 战胜围棋世界冠军,再到 ChatGPT 能写诗、编程、回答问题,背后都是神经网络在"思考"。那么,神经网络到底是什么?它是如何"学习"的?这篇文章将用一个生活中的例子——预测孩子身高,带你从零开始理解神经网络的核心概念:

  • 神经网络:一个由简单计算单元组成的"大脑"
  • 梯度:告诉模型"该往哪个方向调整"的信号
  • 反向传播:高效计算梯度的巧妙算法

不需要任何数学基础,让我们开始吧。

从身高预测开始

假设你想预测你未来孩子的身高。一个简单的想法是:孩子的身高和父母身高有关。于是你写出一个公式:

孩子身高=w1×父亲身高+w2×母亲身高\text{孩子身高} = w_1 \times \text{父亲身高} + w_2 \times \text{母亲身高}

这个公式就是一个线性函数。直觉上可以认为孩子的身高一半继承父亲,一半继承母亲,所以可以设 w1=0.5w_1 = 0.5,w2=0.5w_2 = 0.5,那么父亲178cm、母亲165cm的组合,预测孩子身高为 0.5×178+0.5×165=171.50.5 \times 178 + 0.5 \times 165 = 171.5cm。

这个简单的公式可以认为是一个模型,具体来说,这是一个单层神经网络。父亲身高、母亲身高是输入,孩子身高是输出,w1w_1、w2w_2 是模型的参数(也叫权重)。

线性不够,激活来凑

但你很快发现,实际情况没这么简单。父母身高高,孩子大概率高,但不是简单的线性倍数关系。身高的预测存在一个非线性的关系,使得下一代的身高回归平均水平,比如会一个"天花板"效应——父母都超高时,孩子不一定比父母更高。

线性函数 vs 非线性函数

于是我们需要引入激活函数,把线性计算的结果做一下非线性变换:

预测身高=f(w1×父亲身高+w2×母亲身高)\text{预测身高} = f(w_1 \times \text{父亲身高} + w_2 \times \text{母亲身高})

这里的ff 称为激活函数,它的作用是让模型能拟合更复杂的关系。大模型,深度学习里常用的激活函数有:Tanh(f(x)=tanh⁡(x)f(x) = \tanh(x))、ReLU(f(x)=max⁡(0,x)f(x) = \max(0, x))、Sigmoid(f(x)=11+e−xf(x) = \frac{1}{1+e^{-x}})等,深入了解可参考这里。

更多因素:多层网络

现实中的身高预测还要考虑更多因素。比如孩子的身高还和祖父母的身高有关。于是模型变得更复杂:

第一层:从祖父母身高预测父母身高

父亲身高=f(w11×爷爷身高+w12×奶奶身高)\text{父亲身高} = f(w_{11} \times \text{爷爷身高} + w_{12} \times \text{奶奶身高})

母亲身高=f(w13×外公身高+w14×外婆身高)\text{母亲身高} = f(w_{13} \times \text{外公身高} + w_{14} \times \text{外婆身高})

第二层:从父母身高预测孩子身高

孩子身高=f(w21×父亲身高+w22×母亲身高)\text{孩子身高} = f(w_{21} \times \text{父亲身高} + w_{22} \times \text{母亲身高})

这就是一个两层神经网络。每一层都有自己的参数,一层的输出作为下一层的输入。

神经网络结构

更一般地,一个 LL 层的神经网络可以写成:

h1=f(W1x)h_1 = f(W_1 x)

h2=f(W2h1)h_2 = f(W_2 h_1)

⋮\vdots

y^=f(WLhL−1)\hat{y} = f(W_L h_{L-1})

其中 xx 是输入向量,y^\hat{y} 是输出,W1,W2,…,WLW_1, W_2, \ldots, W_L 是每一层的参数矩阵。

如何调整参数:梯度下降

上面的网络有很多参数(w1,w2,W1,W2,…w_1, w_2, W_1, W_2, \ldots)。这些参数怎么确定呢?

核心思想:用已有数据来训练。比如你收集了1000个家庭的祖父母、父母、孩子身高数据。对每个家庭,计算预测值y^\hat{y}和真实值yy的差距(损失函数):

L=12(y^−y)2\mathcal{L} = \frac{1}{2}(\hat{y} - y)^2

然后想办法调整参数,让损失尽量小。那要怎么调整每个参数呢?直觉上,如果预测出来的值比真实值高,那么可以修改假设,认为孩子的身高不是继承一半父亲的身高,可以适当地减小w1w_1,然后进行下一轮的迭代调整。但在大模型中,参数量是数百万、数亿的,手动计算是不可能的。这时候就需要用到梯度。让参数沿着梯度,也就是使损失下降最快的方向调。具体来说,对每个参数 wiw_i,计算损失函数对它的偏导数 ∂L∂wi\frac{\partial \mathcal{L}}{\partial w_i},然后用下面的公式来更新参数:

wi←wi−η⋅∂L∂wiw_i \leftarrow w_i - \eta \cdot \frac{\partial \mathcal{L}}{\partial w_i}

其中 η\eta 是学习率(步长大小)。调整的过程就叫梯度下降。

梯度是什么

梯度就是损失函数对每个参数的偏导数。它告诉你:如果稍微增加一点参数 wiw_i,损失会怎么变化。

举个直观的例子:你在山上,想最快下山。你看看四周哪个方向最陡(导数最大),就往那个方向走一步。梯度就是告诉你"哪个方向最陡"的那个量。

梯度下降可视化

对于身高预测的例子,如果 ∂L∂w1=5\frac{\partial \mathcal{L}}{\partial w_1} = 5,意思是 w1w_1 太大会让预测误差变大,需要减小w1w_1 的值。如果 ∂L∂w1=−3\frac{\partial \mathcal{L}}{\partial w_1} = -3,意思是 w1w_1 太小会让预测误差变大,需要增大w1w_1 的值。根据梯度正负,决定 w1w_1 该增大还是减小

反向传播:高效计算梯度

在多层网络中,参数可能有成千上万个。如果对每个参数都单独算导数,计算量会非常大。反向传播利用链式法则,从输出层开始,逐层往回算梯度。这是深度学习高效训练的关键。

6.1 用身高例子说明

假设我们有:

a=父亲身高=178a = \text{父亲身高} = 178

b=母亲身高=165b = \text{母亲身高} = 165

c=w1a+w2bc = w_1 a + w_2 b

y^=f(c)\hat{y} = f(c)

L=12(y^−y)2\mathcal{L} = \frac{1}{2}(\hat{y} - y)^2

设 w1=0.5w_1 = 0.5,w2=0.5w_2 = 0.5,真实孩子身高 y=175y = 175,激活函数 f(x)=xf(x) = x(方便讲解,使用线性函数)。

前向传播:

  • c=0.5×178+0.5×165=171.5c = 0.5 \times 178 + 0.5 \times 165 = 171.5
  • y^=171.5\hat{y} = 171.5
  • L=12(171.5−175)2=7.225\mathcal{L} = \frac{1}{2}(171.5 - 175)^2 = 7.225

反向传播(从后往前算):

  1. 损失对预测值的梯度:

    ∂L∂y^=y^−y=171.5−175=−3.5\frac{\partial \mathcal{L}}{\partial \hat{y}} = \hat{y} - y = 171.5 - 175 = -3.5

  2. 预测值对 cc 的梯度(假设 ff 是恒等函数,导数为1):

    ∂y^∂c=1\frac{\partial \hat{y}}{\partial c} = 1

  3. 由链式法则,损失对 cc 的梯度:

    ∂L∂c=∂L∂y^⋅∂y^∂c=−3.5×1=−3.5\frac{\partial \mathcal{L}}{\partial c} = \frac{\partial \mathcal{L}}{\partial \hat{y}} \cdot \frac{\partial \hat{y}}{\partial c} = -3.5 \times 1 = -3.5

  4. cc 对 w1w_1 的梯度:

    ∂c∂w1=a=178\frac{\partial c}{\partial w_1} = a = 178

  5. 由链式法则,损失对 w1w_1 的梯度:

    ∂L∂w1=∂L∂c⋅∂c∂w1=−3.5×178=−623\frac{\partial \mathcal{L}}{\partial w_1} = \frac{\partial \mathcal{L}}{\partial c} \cdot \frac{\partial c}{\partial w_1} = -3.5 \times 178 = -623

  6. 类似地,损失对 w2w_2 的梯度:

    ∂L∂w2=−3.5×165=−577.5\frac{\partial \mathcal{L}}{\partial w_2} = -3.5 \times 165 = -577.5

更新参数(设学习率 η=0.001\eta = 0.001):

  • w1←0.5−0.001×(−623)=0.5623w_1 \leftarrow 0.5 - 0.001 \times (-623) = 0.5623
  • w2←0.5−0.001×(−577.5)=0.5578w_2 \leftarrow 0.5 - 0.001 \times (-577.5) = 0.5578

可以看到,w1w_1 和 w2w_2 都变大了,这意味着模型认为应该给父母身高更大的权重,以提高预测值。

各种运算的梯度

在实际神经网络中,会用到加、减、乘、除、激活函数等各种运算。下面逐一介绍它们的梯度计算和传播方式。

加法 c=a+bc = a + b

前向:c=a+bc = a + b

反向:∂c∂a=1\frac{\partial c}{\partial a} = 1 ; ∂c∂b=1\frac{\partial c}{\partial b} = 1

梯度直接传递给两个输入: ∂L∂a=∂L∂c×1=∂L∂c\frac{\partial \mathcal{L}}{\partial a} = \frac{\partial \mathcal{L}}{\partial c} \times 1 = \frac{\partial \mathcal{L}}{\partial c} ; ∂L∂b=∂L∂c×1=∂L∂c\frac{\partial \mathcal{L}}{\partial b} = \frac{\partial \mathcal{L}}{\partial c} \times 1 = \frac{\partial \mathcal{L}}{\partial c}

特点:上层梯度直接复制到两个输入。

乘法 c=a×bc = a \times b

前向:c=a×bc = a \times b

反向:∂c∂a=b\frac{\partial c}{\partial a} = b ; ∂c∂b=a\frac{\partial c}{\partial b} = a

梯度传递:∂L∂a=∂L∂c×b\frac{\partial \mathcal{L}}{\partial a} = \frac{\partial \mathcal{L}}{\partial c} \times b ; ∂L∂b=∂L∂c×a\frac{\partial \mathcal{L}}{\partial b} = \frac{\partial \mathcal{L}}{\partial c} \times a

特点:乘法的梯度传递依赖另一个输入的值。

幂运算 c=abc = a^b

前向:c=abc = a^b

反向:∂c∂a=b⋅ab−1\frac{\partial c}{\partial a} = b \cdot a^{b-1} ; ∂c∂b=ab⋅ln⁡(a)\frac{\partial c}{\partial b} = a^b \cdot \ln(a)

梯度传递:∂L∂a=∂L∂c×b⋅ab−1\frac{\partial \mathcal{L}}{\partial a} = \frac{\partial \mathcal{L}}{\partial c} \times b \cdot a^{b-1} ; ∂L∂b=∂L∂c×ab⋅ln⁡(a)\frac{\partial \mathcal{L}}{\partial b} = \frac{\partial \mathcal{L}}{\partial c} \times a^b \cdot \ln(a)

常用特例:c=a2c = a^2,∂L∂a=∂L∂c×2a\frac{\partial \mathcal{L}}{\partial a} = \frac{\partial \mathcal{L}}{\partial c} \times 2a

除法 c=abc = \frac{a}{b}

前向:c=abc = \frac{a}{b}

反向:∂c∂a=1b\frac{\partial c}{\partial a} = \frac{1}{b} ; ∂c∂b=−ab2\frac{\partial c}{\partial b} = -\frac{a}{b^2}

梯度传递:∂L∂a=∂L∂c×1b\frac{\partial \mathcal{L}}{\partial a} = \frac{\partial \mathcal{L}}{\partial c} \times \frac{1}{b} ; ∂L∂b=∂L∂c×(−ab2)\frac{\partial \mathcal{L}}{\partial b} = \frac{\partial \mathcal{L}}{\partial c} \times (-\frac{a}{b^2})

注意:除法对分母的梯度是负的,且当 bb 接近0时梯度会爆炸。

激活函数

激活函数对比

ReLU:f(x)=max⁡(0,x)f(x) = \max(0, x)

前向:y=max⁡(0,x)y = \max(0, x)

反向:dydx={1if x>00if x≤0\frac{dy}{dx} = \begin{cases} 1 & \text{if } x > 0 \\ 0 & \text{if } x \leq 0 \end{cases}

梯度传递:∂L∂x=∂L∂y×{1if x>00if x≤0\frac{\partial \mathcal{L}}{\partial x} = \frac{\partial \mathcal{L}}{\partial y} \times \begin{cases} 1 & \text{if } x > 0 \\ 0 & \text{if } x \leq 0 \end{cases}

特点:正区间梯度=1,直接传递;负区间梯度=0,被截断。

Sigmoid:f(x)=11+e−xf(x) = \frac{1}{1+e^{-x}}

前向:y=11+e−xy = \frac{1}{1+e^{-x}}

反向:dydx=y(1−y)\frac{dy}{dx} = y(1-y)

梯度传递:∂L∂x=∂L∂y×y(1−y)\frac{\partial \mathcal{L}}{\partial x} = \frac{\partial \mathcal{L}}{\partial y} \times y(1-y)

特点:导数最大值为0.25,在饱和区(∣x∣|x| 很大时)梯度接近0。

Tanh:f(x)=tanh⁡(x)f(x) = \tanh(x)

前向:y=tanh⁡(x)y = \tanh(x)

反向:dydx=1−y2\frac{dy}{dx} = 1 - y^2

梯度传递:∂L∂x=∂L∂y×(1−y2)\frac{\partial \mathcal{L}}{\partial x} = \frac{\partial \mathcal{L}}{\partial y} \times (1 - y^2)

求和 c=∑iaic = \sum_i a_i

前向:c=a1+a2+⋯+anc = a_1 + a_2 + \cdots + a_n

反向:∂c∂ai=1\frac{\partial c}{\partial a_i} = 1(对每个 ii)

梯度传递:每个输入得到相同的梯度。

取负 c=−ac = -a

前向:c=−ac = -a

反向:∂c∂a=−1\frac{\partial c}{\partial a} = -1

梯度传递:∂L∂a=−∂L∂c\frac{\partial \mathcal{L}}{\partial a} = -\frac{\partial \mathcal{L}}{\partial c}

完整示例:一个小型神经网络

让我们用一个具体的例子,把上面的知识串起来。

网络结构:

  • 输入:x1=2x_1 = 2,x2=3x_2 = 3
  • 第一层:h1=w1x1+w2x2h_1 = w_1 x_1 + w_2 x_2,h2=w3x1+w4x2h_2 = w_3 x_1 + w_4 x_2
  • 激活:a1=ReLU(h1)a_1 = \text{ReLU}(h_1),a2=ReLU(h2)a_2 = \text{ReLU}(h_2)
  • 输出:y^=w5a1+w6a2\hat{y} = w_5 a_1 + w_6 a_2
  • 损失:L=12(y^−y)2\mathcal{L} = \frac{1}{2}(\hat{y} - y)^2,其中 y=10y = 10

参数初始化:w1=1,w2=1,w3=1,w4=1,w5=1,w6=1w_1=1, w_2=1, w_3=1, w_4=1, w_5=1, w_6=1

前向传播

1
2
3
4
5
6
h_1 = w_1 x_1 + w_2 x_2 = 1×2 + 1×3 = 5
h_2 = w_3 x_1 + w_4 x_2 = 1×2 + 1×3 = 5
a_1 = ReLU(h_1) = ReLU(5) = 5
a_2 = ReLU(h_2) = ReLU(5) = 5
ŷ = w_5 a_1 + w_6 a_2 = 1×5 + 1×5 = 10
L = ½(ŷ - y)² = ½(10 - 10)² = 0

(这个例子损失为0,说明参数已经很完美了。我们换个真实值演示。)

用一个预测不准的例子演示

设 y=20y = 20(真实值),其他不变。

前向传播:

  • h1=5h_1 = 5,h2=5h_2 = 5
  • a1=5a_1 = 5,a2=5a_2 = 5
  • y^=10\hat{y} = 10
  • L=12(10−20)2=50\mathcal{L} = \frac{1}{2}(10 - 20)^2 = 50

反向传播:

  1. ∂L∂y^=y^−y=10−20=−10\frac{\partial \mathcal{L}}{\partial \hat{y}} = \hat{y} - y = 10 - 20 = -10

  2. ∂y^∂w5=a1=5\frac{\partial \hat{y}}{\partial w_5} = a_1 = 5,∂y^∂a1=w5=1\frac{\partial \hat{y}}{\partial a_1} = w_5 = 1

    • ∂L∂w5=−10×5=−50\frac{\partial \mathcal{L}}{\partial w_5} = -10 \times 5 = -50
    • ∂L∂a1=−10×1=−10\frac{\partial \mathcal{L}}{\partial a_1} = -10 \times 1 = -10
  3. ∂y^∂w6=a2=5\frac{\partial \hat{y}}{\partial w_6} = a_2 = 5,∂y^∂a2=w6=1\frac{\partial \hat{y}}{\partial a_2} = w_6 = 1

    • ∂L∂w6=−10×5=−50\frac{\partial \mathcal{L}}{\partial w_6} = -10 \times 5 = -50
    • ∂L∂a2=−10×1=−10\frac{\partial \mathcal{L}}{\partial a_2} = -10 \times 1 = -10
  4. ReLU反向:h1=5>0h_1 = 5 > 0,所以 ∂a1∂h1=1\frac{\partial a_1}{\partial h_1} = 1

    • ∂L∂h1=−10×1=−10\frac{\partial \mathcal{L}}{\partial h_1} = -10 \times 1 = -10
  5. ReLU反向:h2=5>0h_2 = 5 > 0,所以 ∂a2∂h2=1\frac{\partial a_2}{\partial h_2} = 1

    • ∂L∂h2=−10×1=−10\frac{\partial \mathcal{L}}{\partial h_2} = -10 \times 1 = -10
  6. ∂h1∂w1=x1=2\frac{\partial h_1}{\partial w_1} = x_1 = 2,∂h1∂w2=x2=3\frac{\partial h_1}{\partial w_2} = x_2 = 3

    • ∂L∂w1=−10×2=−20\frac{\partial \mathcal{L}}{\partial w_1} = -10 \times 2 = -20
    • ∂L∂w2=−10×3=−30\frac{\partial \mathcal{L}}{\partial w_2} = -10 \times 3 = -30
  7. ∂h2∂w3=x1=2\frac{\partial h_2}{\partial w_3} = x_1 = 2,∂h2∂w4=x2=3\frac{\partial h_2}{\partial w_4} = x_2 = 3

    • ∂L∂w3=−10×2=−20\frac{\partial \mathcal{L}}{\partial w_3} = -10 \times 2 = -20
    • ∂L∂w4=−10×3=−30\frac{\partial \mathcal{L}}{\partial w_4} = -10 \times 3 = -30

更新参数(η=0.01\eta = 0.01):

  • w1←1−0.01×(−20)=1.2w_1 \leftarrow 1 - 0.01 \times (-20) = 1.2
  • w2←1−0.01×(−30)=1.3w_2 \leftarrow 1 - 0.01 \times (-30) = 1.3
  • w3←1−0.01×(−20)=1.2w_3 \leftarrow 1 - 0.01 \times (-20) = 1.2
  • w4←1−0.01×(−30)=1.3w_4 \leftarrow 1 - 0.01 \times (-30) = 1.3
  • w5←1−0.01×(−50)=1.5w_5 \leftarrow 1 - 0.01 \times (-50) = 1.5
  • w6←1−0.01×(−50)=1.5w_6 \leftarrow 1 - 0.01 \times (-50) = 1.5

可以看到,所有权重都增大了,因为预测值10太小,需要增大权重来提高预测。

训练过程

自动微分:让计算机帮你算梯度

上面手算梯度很麻烦。实际中我们用自动微分(Automatic Differentiation),让计算机自动帮我们算。

核心思想:每个变量都记录自己的值和梯度,在做运算时自动应用链式法则。

Andrej Karpathy 的 micrograd 项目用约100行代码实现了这个功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Value:
def __init__(self, data, _children=(), _op=''):
self.data = data
self.grad = 0
self._backward = lambda: None
self._prev = set(_children)
self._op = _op

def __add__(self, other):
other = other if isinstance(other, Value) else Value(other)
out = Value(self.data + other.data, (self, other), '+')

def _backward():
self.grad += out.grad
other.grad += out.grad
out._backward = _backward

return out

def __mul__(self, other):
other = other if isinstance(other, Value) else Value(other)
out = Value(self.data * other.data, (self, other), '*')

def _backward():
self.grad += other.data * out.grad
other.grad += self.data * out.grad
out._backward = _backward

return out

def backward(self):
topo = []
visited = set()
def build_topo(v):
if v not in visited:
visited.add(v)
for child in v._prev:
build_topo(child)
topo.append(v)
build_topo(self)

self.grad = 1
for v in reversed(topo):
v._backward()

使用方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
a = Value(-2.0)
b = Value(3.0)
c = a + b
d = a * b
e = c * d

# 前向传播
e.data # 3.0

# 反向传播
e.backward()

# 查看梯度
a.grad # 9.0 (b*c = 3*3)
b.grad # 5.0 (a+c = -2+1)

这个实现的关键是:

  1. 拓扑排序:确定计算顺序(从输出到输入)
  2. 局部梯度:每个运算定义自己的 _backward 函数
  3. 链式法则:在 _backward 中自动应用 ∂L∂x=∂L∂y⋅∂y∂x\frac{\partial \mathcal{L}}{\partial x} = \frac{\partial \mathcal{L}}{\partial y} \cdot \frac{\partial y}{\partial x}

总结

通过身高预测的例子,我们介绍了:

  1. 线性函数:最简单的模型 y=w1x1+w2x2y = w_1 x_1 + w_2 x_2
  2. 激活函数:引入非线性 y=f(wx)y = f(wx)
  3. 多层网络:组合多个层 y=f(W2f(W1x))y = f(W_2 f(W_1 x))
  4. 损失函数:衡量预测和真实的差距 L=12(y^−y)2\mathcal{L} = \frac{1}{2}(\hat{y} - y)^2
  5. 梯度下降:用梯度更新参数 w←w−η∂L∂ww \leftarrow w - \eta \frac{\partial \mathcal{L}}{\partial w}
  6. 反向传播:高效计算梯度的算法(链式法则)
  7. 各种运算的梯度:加、减、乘、除、激活函数等
  8. 自动微分:让计算机自动算梯度(如 micrograd)

这些是深度学习的基石。理解了这些,你就能理解 Transformer、大语言模型等更复杂的模型是如何训练的了。

参考资料

CATALOG
  1. 1. 从身高预测开始
  2. 2. 线性不够,激活来凑
  3. 3. 更多因素:多层网络
  4. 4. 如何调整参数:梯度下降
  5. 5. 梯度是什么
  6. 6. 反向传播:高效计算梯度
    1. 6.1. 6.1 用身高例子说明
  7. 7. 各种运算的梯度
    1. 7.1. 加法 c=a+bc = a + bc=a+b
    2. 7.2. 乘法 c=a×bc = a \times bc=a×b
    3. 7.3. 幂运算 c=abc = a^bc=ab
    4. 7.4. 除法 c=abc = \frac{a}{b}c=ba​
    5. 7.5. 激活函数
      1. 7.5.1. ReLU:f(x)=max⁡(0,x)f(x) = \max(0, x)f(x)=max(0,x)
      2. 7.5.2. Sigmoid:f(x)=11+e−xf(x) = \frac{1}{1+e^{-x}}f(x)=1+e−x1​
      3. 7.5.3. Tanh:f(x)=tanh⁡(x)f(x) = \tanh(x)f(x)=tanh(x)
    6. 7.6. 求和 c=∑iaic = \sum_i a_ic=∑i​ai​
    7. 7.7. 取负 c=−ac = -ac=−a
  8. 8. 完整示例:一个小型神经网络
    1. 8.1. 前向传播
    2. 8.2. 用一个预测不准的例子演示
  9. 9. 自动微分:让计算机帮你算梯度
  10. 10. 总结
  11. 11. 参考资料