Current: Week 3

0%

Week 3

Week 3 — Neural Network:从一个Neuron 到多层神经网络

Key question怎样从一个 wx+b 扩展成多层网络?

Learning objectives

  • 理解并应用 Week 3 — Neural Network:从一个 Neuron 到多层神经网络

190 min estimated reading time

Week progress: 0 of 75 sections (0%)Course progress: 0 of 321 sections (0%)

上一周已经会训练一条直线。本周先不换优化方法,只问:如果目标规律不是一条直线,该怎样改预测函数?沿“单个神经元 → 非线性 → 两层网络 → 代码与任务输出”四个学习单元前进。

先回忆 y_hat=wx+b:输入是这一题给出的数,w/b 是训练要修改的规则。神经网络把多个这样的乘加单元连接起来;真正新增的关键不是名称,而是层间的非线性。先运行 ReLU,再做 XOR,最后手算并实现 2→2→1 网络。

Scroll horizontally to view all columns.

Course data table
本周实验固定条件观察目标
两层 forward输入 [1,2];隐藏层两单元;线性输出隐藏值 [1.4,1.1],预测 1.3,目标 2 时损失 0.49。
负输出对照只换输出权重为 [−1,0]、偏置 0预测应是 −1.4,不应被通用 layer 函数偷偷截成 0。
XOR人为指定两条 ReLU 分支四种输入都可手算;这是表达能力示范,不是训练成功记录。

运行入口:course_examples/week03_neuron.py;XOR 独立实验在 course_examples/week03_xor.py。完成后应能解释参数量、隐藏层激活和输出层选择;还不要求凭空推导所有梯度。Week 4 专门解决“每个参数对最终错误贡献了多少”。

学习单元一:从线性预测到一个神经元

1. 先回答最重要的问题:为什么需要Neural Network?

Week 2 学习了Linear Regression:

y^=wx+b\hat{y} = wx + b

例如预测房价:

Price=w×Area+b\mathrm{Price} = w \times \mathrm{Area} + b

假设:

w = 5000

b = 100000

那么100㎡房子:

Price=5000×100+100000\mathrm{Price} = 5000 \times 100 + 100000

得到:

$600,000\text{\$600,000}

这种关系很简单:

面积增加

价格基本按固定速度增加

也就是一个近似的线性关系Linear Relationship。

但现实世界远没有这么简单。

2. 现实世界通常不是一条直线

比如预测房价,可能需要:

面积

卧室数量

房龄

距离CBD 距离

学区

犯罪率

土地面积

装修情况

利率

市场环境

...

更麻烦的是,这些因素之间还会互相影响。

例如:

面积很大

+

距离CBD 很远

可能并不值钱。

但:

面积大

+

好学区

+

距离CBD 近

价格可能突然非常高。

也就是说:

现实问题通常是Non-linear(非线性)的。

这就是Neural Network 开始发挥作用的地方。

3. 从Week 2 的Linear Regression 开始

Week 2:

y^=wx+b\hat{y} = wx + b

现在假设有三个Feature:

  • x₁:面积
  • x₂:卧室数量
  • x₃:距离CBD

模型可以写成:

z=w1x1+w2x2+w3x3+bz = w_1x_1 + w_2x_2 + w_3x_3 + b

看起来复杂了一点。

但本质没变。

以前:

wx+bwx + b

现在只是:

w1x1+w2x2+w3x3+bw_1x_1 + w_2x_2 + w_3x_3 + b

也就是:

每个input 都有自己的weight。

4. Weight 到底是什么意思?

这是Neural Network 中最重要的概念之一。

假设:

z=w1x1+w2x2+w3x3+bz = w_1x_1 + w_2x_2 + w_3x_3 + b

如果:

x1 = 面积

x2 = 卧室

x3 = 距离CBD

模型训练后可能得到:

w1 = 0.8

w2 = 0.4

w3 = -0.7

直觉上可以理解:

面积 → 正影响比较大

卧室数量 → 正影响

距离CBD → 负影响

所以Weight 可以暂时理解成:

模型认为某个输入有多重要,以及它产生正影响还是负影响。

但注意:到了大型Neural Network 后,单个weight 通常不再具有这么直接的人类语义。

5. 这其实已经是一个Neuron

下面这个东西:

z=w1x1+w2x2+w3x3+bz = w_1x_1 + w_2x_2 + w_3x_3 + b

就是神经网络最基础的计算单元。

可以画成:

x1 ──w1 ──┐

x2 ──w2 ──┼── SUM ── z

x3 ──w3 ──┘

+

b

这就是一个最简单的:

Artificial Neuron

人工神经元。

6. 为什么叫Neuron?

它的灵感来自生物神经元,但不要把两者看得过于相同。

人工neuron 的工作其实非常简单:

接收Inputs

乘以Weights

加起来

加Bias

得到一个数

数学就是:

z=iwixi+bz = \sum_i w_ix_i + b

那个:

\sum

只是”全部加起来”的数学写法。

例如:

i=13wixi\sum_{i=1}^{3} w_i x_i

就是:

w1x1+w2x2+w3x3w_1x_1 + w_2x_2 + w_3x_3

所以不要被Σ 吓到。

7. 手算一个Neuron

假设我们做一个非常简单的”是否值得买房”模型。

三个输入:

x1 = 0.8 地段

x2 = 0.6 房屋状况

x3 = 0.2 距离问题

Weights:

w1 = 0.7

w2 = 0.5

w3 = -0.4

Bias:

b = 0.1

计算:

z=w1x1+w2x2+w3x3+bz = w_1x_1 + w_2x_2 + w_3x_3 + b

代进去:

z=(0.7)(0.8)+(0.5)(0.6)+(0.4)(0.2)+0.1z = (0.7)(0.8) + (0.5)(0.6) + (-0.4)(0.2) + 0.1

一步一步:

0.7×0.8=0.560.7 \times 0.8 = 0.56
0.5×0.6=0.300.5 \times 0.6 = 0.30
0.4×0.2=0.08-0.4 \times 0.2 = -0.08

所以:

z=0.56+0.300.08+0.1z = 0.56 + 0.30 - 0.08 + 0.1
z=0.88z = 0.88

到目前为止,仍然没有什么神秘的。

就是:

z = x1*w1 + x2*w2 + x3*w3 + b

8. 但是这里有一个严重问题

如果neuron 只有:

z=wx+bz = wx + b

那么即使我们放很多层:

Input

Linear

Linear

Linear

Output

最终仍然只是一个Linear Model。

这是理解Neural Network 的一个关键点。

9. 为什么多个Linear Layer 还是Linear?

假设第一层:

h=w1x+b1h = w_1x + b_1

第二层:

y=w2h+b2y = w_2h + b_2

把第一层代入:

y=w2(w1x+b1)+b2y = w_2(w_1x + b_1) + b_2

展开:

y=w2w1x+w2b1+b2y = w_2w_1x + w_2b_1 + b_2

把:

w2w1w_2w_1

看成一个新的weight:

WW

把:

w2b1+b2w_2b_1 + b_2

看成新的bias:

BB

最后:

y=Wx+By = Wx + B

你会发现:

两层Linear 仍然等价于一层Linear。

10 层也一样。

100 层也一样。

所以仅仅堆 wx+b 不会增加非线性表达能力。

我们缺一个东西。

这里的准确结论是:连续的线性/仿射层在输入输出关系上,仍可合并成一层,因此没有增加非线性表达能力。把它拆成多层可能改变参数化和优化过程,但还不能靠层数画出需要拐弯的决策边界。

这一段只有一个输入和一个输出,合并后的 W、B 都是标量,不是后面的权重矩阵 W 或 batch 大小 B。标量乘法 Wx=xW;进入多特征矩阵时,乘法方向才必须按 shape 区分。

学习单元二:先看 ReLU,再理解非线性

10. Activation Function

这就是:

Activation Function

激活函数。

Neuron 不再只是:

z=wx+bz = wx + b

而是:

a=f(z)a = f(z)

完整:

a=f(wx+b)a = f(wx + b)

这里:

  • z:linear calculation 的结果
  • f:Activation Function
  • a:activation/output

12. 最容易理解的Activation:ReLU

现代Neural Network 中一个非常经典的activation:

ReLU

全称:

Rectified Linear Unit

公式:

ReLU(x)=max(0,x)\operatorname{ReLU}(x) = \max(0,x)

看起来像数学。

其实翻译成代码就是:

python
def relu(x):
    return max(0, x)

就是这么简单。

13. ReLU 到底干什么?

如果:

x = 5

那么:

ReLU(5)=5\operatorname{ReLU}(5) = 5

如果:

x = -3

那么:

ReLU(3)=0\operatorname{ReLU}(-3) = 0

如果:

x = 0.7

那么:

ReLU(0.7)=0.7\operatorname{ReLU}(0.7) = 0.7

所以:

negative → 0

positive → keep it

图形大概:

y

/

/

/

/

│___/____________ x

0

11. Activation Function 为什么重要?

因为它引入:

Non-linearity

非线性。

也就是说,模型终于不再只能学习直线。

例如现实中的关系:

*

* *

*

*

*

*

*

*

或者:

________

\

\

\_______

甚至非常复杂的边界。

Neural Network 需要Non-linearity 才能学习这些关系。

14. 一个Neuron 现在完整了

之前:

Inputs

Weights

Sum

Bias

Output

现在:

Inputs

Weights

Weighted Sum

Bias

z = wx+b

Activation Function

a = ReLU(z)

Output

数学:

a=ReLU(wx+b)a = \operatorname{ReLU}(wx + b)

15. 手算一次带ReLU 的Neuron

假设:

x1=2x_1 = 2
x2=3x_2 = 3

Weights:

w1=0.5w_1 = 0.5
w2=0.8w_2 = -0.8

Bias:

b=0.2b = 0.2

先计算:

z=w1x1+w2x2+bz = w_1x_1 + w_2x_2 + b

所以:

z=(0.5)(2)+(0.8)(3)+0.2z = (0.5)(2) + (-0.8)(3) + 0.2
=12.4+0.2= 1 - 2.4 + 0.2
=1.2= -1.2

然后:

a=ReLU(1.2)a = \operatorname{ReLU}(-1.2)

得到:

a=0a = 0

这个neuron 在当前input 下没有输出正信号。

16. 如果改变Weight 呢?

例如把:

w2=0.8w_2 = -0.8

改成:

w2=0.2w_2 = 0.2

重新计算:

z=(0.5)(2)+(0.2)(3)+0.2z = (0.5)(2) + (0.2)(3) + 0.2
=1+0.6+0.2= 1 + 0.6 + 0.2
=1.8= 1.8

ReLU:

ReLU(1.8)=1.8\operatorname{ReLU}(1.8) = 1.8

所以:

a=1.8a = 1.8

这说明一个非常重要的事情:

Weights 决定neuron 对输入如何响应。

而Training 的工作,就是寻找这些weights。

这和Week 2 完全一样。

17. 一个Neuron 能做什么?

一个neuron 能表达的东西仍然有限。

真正强大的地方来自:

很多neurons 一起工作。

例如:

x1 ─┬── Neuron 1

├── Neuron 2

└── Neuron 3

x2 ─┬── Neuron 1

├── Neuron 2

└── Neuron 3

这一组neurons 就叫:

Layer

Layer

学习单元三:两层网络的完整计算

18. 什么是Layer?

假设Input:

x=[x1,x2]x = [x_1,x_2]

Hidden Layer 有三个neurons:

┌─Neuron 1

x1 ─────┼─Neuron 2

└─Neuron 3

x2 ───────┘

每个neuron 都有自己的weights。

Neuron 1:

z1=w11x1+w12x2+b1z_1 = w_{11}x_1 + w_{12}x_2 + b_1

Neuron 2:

z2=w21x1+w22x2+b2z_2 = w_{21}x_1 + w_{22}x_2 + b_2

Neuron 3:

z3=w31x1+w32x2+b3z_3 = w_{31}x_1 + w_{32}x_2 + b_3

然后分别经过ReLU:

a1=ReLU(z1)a_1 = \operatorname{ReLU}(z_1)
a2=ReLU(z2)a_2 = \operatorname{ReLU}(z_2)
a3=ReLU(z3)a_3 = \operatorname{ReLU}(z_3)

于是这一层输出:

[a1  a2  a3][a_1\; a_2\; a_3]

这里为了按神经元逐个计算,Python weights 的一行存一个输出神经元的所有输入权重,方向是 [输出数,输入数]。Week 1 的 XW+b 把同一组数放在 W 的列中,方向是 [输入数,输出数]。后面展示 nn.Linear 时仍会使用前一种存储,两者互为转置。

19. 为什么一个Layer 要有很多Neurons?

因为不同neuron 可以学习不同pattern。

为了建立直觉,假设是图片识别。

一些neuron 可能逐渐对:

竖线

敏感。

另一些:

横线

另一些:

边缘

更高层可能组合成:

眼睛

耳朵

轮廓

再组合:

猫脸

这不是程序员手工写:

python
if has_whiskers and has_ears:
    return "cat"

而是模型通过训练自己调整weights。

20. Hidden Layer 是什么?

典型Neural Network:

Input Layer

Hidden Layer 1

Hidden Layer 2

Output Layer

为什么叫Hidden?

因为这些层既不是原始输入,也不是最终答案。

它们是模型内部的:

intermediate representations

中间表示。

21. Feature Learning

这是Neural Network 相比传统方法非常重要的地方。

例如输入一张猫的图片。

最原始的数据可能只是:

pixel

pixel

pixel

pixel

...

模型逐层转换:

Pixels

Edges

Shapes

Parts

Object concepts

Cat

这里有个很重要的AI 概念:

“这个神经元可能检测耳朵”是在帮助想象组合特征,不是训练后每个单元都会有一个清楚的中文名字。实际表示常由许多单元共同承担,单个权重或激活值不能直接证明模型学到了某个现实概念。

Representation

模型内部不断把数据转换成更有用的表示。

以后学习:

  • Embedding
  • Attention
  • Transformer

会不断遇到这个思想。

22. Deep Learning 的Deep 是什么意思?

假设:

Input

Hidden

Output

层很少。

如果:

Input

Layer 1

Layer 2

Layer 3

Layer 4

Layer 5

...

Output

有很多层。

这就是所谓:

Deep Neural Network

所以:

Deep Learning 的Deep,主要就是网络有很多层。

并不是”AI 思考得很深”。

23. 现在手算一个小型Neural Network

我们做一个非常小的网络:

x1 ───── h1 ───┐

\

\

├── output

/

/

x2 ───── h2 ────┘

两个inputs:

x1=1x_1 = 1
x2=2x_2 = 2

Hidden Layer 两个neurons。

24. Hidden Neuron 1

Weights:

w11=0.5w_{11} = 0.5
w12=0.4w_{12} = 0.4

Bias:

b1=0.1b_1 = 0.1

计算:

z1=0.5(1)+0.4(2)+0.1z_1 = 0.5(1) + 0.4(2) + 0.1
=0.5+0.8+0.1= 0.5 + 0.8 + 0.1
=1.4= 1.4

经过ReLU:

h1=ReLU(1.4)h_1 = \operatorname{ReLU}(1.4)

所以:

h1=1.4h_1 = 1.4

25. Hidden Neuron 2

Weights:

w21=0.3w_{21} = -0.3
w22=0.8w_{22} = 0.8

Bias:

b2=0.2b_2 = -0.2

计算:

z2=(0.3)(1)+(0.8)(2)0.2z_2 = (-0.3)(1) + (0.8)(2) - 0.2
=0.3+1.60.2= -0.3 + 1.6 - 0.2
=1.1= 1.1

ReLU:

h2=ReLU(1.1)h_2 = \operatorname{ReLU}(1.1)

所以:

h2=1.1h_2 = 1.1

Hidden Layer 输出:

[1.4  1.1][1.4\; 1.1]

26. 注意这里发生了什么

原始输入:

[1  2][1\; 2]

经过Hidden Layer:

[1.4  1.1][1.4\; 1.1]

也就是说:

Original representation

[1, 2]

↓Neural Network

New representation

[1.4, 1.1]

这就是刚才说的:

Representation Transformation

后面Transformer 其实也一直在做这种事情。

27. Output Layer

现在output neuron 接收:

h1 = 1.4

h2 = 1.1

假设:

v1=0.7v_1 = 0.7
v2=0.2v_2 = 0.2

Bias:

b=0.1b = 0.1

计算:

y=0.7h1+0.2h2+0.1y' = 0.7h_1 + 0.2h_2 + 0.1

代入:

=0.7(1.4)+0.2(1.1)+0.1= 0.7(1.4) + 0.2(1.1) + 0.1
=0.98+0.22+0.1= 0.98 + 0.22 + 0.1
y=1.30y' = 1.30

这就是一次完整的:

Knowledge check

若目标允许 -2,最后一层使用 ReLU 会有什么限制?

Forward Pass

Forward Pass

28. Forward Pass 完整过程

刚才实际上做的是:

x1 = 1

x2 = 2

┌──────────────┐

│Hidden Layer │

│h1 = 1.4

│h2 = 1.1

└──────────────┘

┌──────────────┐

│Output Layer │

│y' = 1.30

└──────────────┘

这就是:

Concept sequence
  1. Input
  2. 一层一层计算
  3. Prediction

29. Prediction 出来了,然后呢?

这里马上重新连接Week 2。

假设正确答案:

y=2y = 2

模型预测:

y^=1.3\hat{y} = 1.3

Error:

1.32=0.71.3 - 2 = -0.7

如果使用squared error:

Loss=(1.32)2\mathrm{Loss} = (1.3 - 2)^2
=(0.7)2= (-0.7)^2
0.490.49

然后呢?

和Week 2 完全一样:

Prediction

Loss

Gradient

Update Weights

只不过现在parameters 不再只有:

w

b

而是:

w11

w12

w21

w22

b1

b2

v1

v2

b3

...

30. 这就是Neural Network Training

完整流程:

INPUT

Hidden Layer

Hidden Layer

Output

Prediction

Loss

Gradients

Update ALL Weights

└──────────────┐

Next iteration

你会发现Week 2 的核心完全没变:

Prediction  Loss  Gradient  Update\text{Prediction } \rightarrow \text{ Loss } \rightarrow \text{ Gradient } \rightarrow \text{ Update}

31. 那么问题来了:这么多Weight 怎么求Gradient?

Week 2:

y^=wx+b\hat{y} = wx + b

只有:

w

b

求导还比较简单。

但Neural Network:

x

w1

Neuron

w2

Neuron

w3

Output

Loss

我们需要知道:

Lossw1\frac{\partial\,\mathrm{Loss}}{\partial w_1}
Lossw2\frac{\partial\,\mathrm{Loss}}{\partial w_2}
Lossw3\frac{\partial\,\mathrm{Loss}}{\partial w_3}

甚至几百万、几十亿个参数。

怎么做?

答案就是:

Backpropagation

这正是Week 4 的核心。

32. 在进入Backprop 前,先理解Computational Graph

假设:

x=2x = 2
w=3w = 3

先:

z=xwz = xw

再:

y=z+1y = z + 1

程序:

python
z = x * w
y = z + 1

可以画成:

x ──┐

├──× ── z ── +1 ── y

w ──┘

这叫:

Computational Graph

计算图。

Neural Network 本质上就是一个非常巨大的computational graph。

33. 为什么Computational Graph 很重要?

因为训练时:

Forward

沿着图向前:

Input

Calculation

Calculation

Prediction

Loss

Backward

从Loss 反过来:

Loss

gradient

gradient

gradient

weights

利用Week 2 已经见过的:

Chain Rule

一层一层计算gradient。

这就是:

Backpropagation = 在computational graph 上利用chain rule 从后往前传播gradients。

Week 4 我们会真正手算。

34. Matrix 为什么会出现?

目前我们一直写:

w1x1+w2x2+w3x3w_1x_1 + w_2x_2 + w_3x_3

但如果:

1000 inputs

1000 neurons

难道写:

neuron1 = x1*w11 + x2*w12 + ...

neuron2 = x1*w21 + x2*w22 + ...

...

当然不会。

我们会把inputs 写成:

XX

把weights 写成:

WW

于是整层计算:

Z=XW+bZ = XW + b

然后:

A=ReLU(Z)A = \operatorname{ReLU}(Z)

这就是以后PyTorch 里看到的东西。

35. 不要被Matrix 吓到

例如:

X=[1  2]X = [1\; 2]

Weights:

W=[0.50.30.40.8]W = \begin{bmatrix} 0.5 & -0.3 \\ 0.4 & 0.8 \end{bmatrix}

实际上只是把我们刚才:

Neuron 1:

1×0.5 + 2×0.4

Neuron 2:

1×(-0.3) + 2×0.8

一次性计算。

所以Matrix Multiplication 在Neural Network 中并不是为了故意搞复杂。

它解决的是:

一次计算大量neurons。

36. 用程序员角度理解Matrix

你可以暂时把:

XWXW

理解成一种高效版本的:

python
for neuron in neurons:
    result = 0
    for input_value, weight in zip(inputs, neuron.weights):
        result += input_value * weight

GPU 特别擅长这种大规模matrix multiplication。

这也是为什么:

GPU 对AI 如此重要。

学习单元四:代码、输出选择与独立练习

37. 用纯Python 实现一个Neuron

不使用PyTorch:

python
def relu(x):
    return max(0, x)


def neuron(inputs, weights, bias, activation=relu):
    if len(inputs) != len(weights):
        raise ValueError("每项输入必须有一个对应权重")
    total = sum(x * w for x, w in zip(inputs, weights)) + bias
    return total if activation is None else activation(total)

inputs = [1, 2]
weights = [0.5, 0.4]
bias = 0.1
output = neuron(inputs, weights, bias)
print(output)

得到:

1.4000000000000001

和前面的手算一致。

activation=relu 表示省略这个参数时仍用 ReLU;activation=None 表示直接返回线性分数。这里函数参数只是控制计算规则,和要学习的 weights、bias 不同。1.4000000000000001 是浮点近似,手算写成 1.4 即可。

38. 实现一个Layer

本节完整定义可独立复制;后一段 hidden 的例子接在这些函数下面运行。每个输出 neuron 共享同一组 inputs,但拥有自己的权重行与偏置。

现在多个neurons:

python
def relu(x):
    return max(0, x)


def neuron(inputs, weights, bias, activation=relu):
    if len(inputs) != len(weights):
        raise ValueError("每项输入必须有一个对应权重")
    total = sum(x * w for x, w in zip(inputs, weights)) + bias
    return total if activation is None else activation(total)


def layer(inputs, weights, biases, activation=relu):
    if len(weights) != len(biases):
        raise ValueError("每个输出神经元必须有一个偏置")
    return [neuron(inputs, row, bias, activation)
            for row, bias in zip(weights, biases)]

定义两个neurons:

python
inputs = [1, 2]
weights = [
    [0.5, 0.4],
    [-0.3, 0.8],
]
biases = [0.1, -0.2]

hidden = layer(inputs, weights, biases)
print(hidden)

得到:

[1.4000000000000001, 1.1]

这正是我们前面的手算。

39. 再连接Output Layer

python
# 接在第 38 节之后;hidden 约为 [1.4, 1.1]。
output_weights = [[0.7, 0.2]]
output_biases = [0.1]
prediction = layer(hidden, output_weights, output_biases, activation=None)
print(prediction)  # 约 [1.3]

# 反例:线性回归输出必须保留负值。
negative_prediction = layer(hidden, [[-1.0, 0.0]], [0.0], activation=None)
print(negative_prediction)  # 约 [-1.4],不是 [0]

概念上:

[1, 2]

Hidden Layer

[1.4, 1.1]

Output Layer

Prediction

我们已经从零写出了一个非常小的:

第一组参数给出 1.4×0.7+1.1×0.2+0.1=1.3;因为是正数,错误地套 ReLU 也看不出问题。第二组参数特意产生 −1.4,才能检查输出层是否错误地截成 0。完整版本见 course_examples/week03_neuron.py。

Neural Network

虽然它还不会training。

Training 正是Week 4 要解决的问题。

40. Neural Network 到底”学”的是什么?

这是必须彻底理解的问题。

很多人会说:

AI 学到了猫是什么。

这个说法从高层没问题。

但底层到底发生了什么?

实际上训练过程中真正被修改的是:

WW

和:

bb

也就是大量:

Parameters

例如:

0.12531

-0.88211

0.00341

1.27342

...

模型最终可能有几十亿这样的数字。

所谓:

模型学会了知识

从底层看,很大程度上意味着:

Training 找到了一组非常复杂的parameter values。

41. 为什么Parameter 越多能力可能越强?

Linear Regression:

2 parameters

w

b

小Neural Network:

几百

几千parameters

现代Deep Learning:

Millions

Billions

更多parameters 意味着模型有更大的capacity 去表示复杂关系。

但注意:

Parameters 多≠自动更聪明。

还需要:

  • 足够的数据
  • 合适的architecture
  • 合适的training
  • optimization
  • regularization
  • compute

等等。

42. Parameters 是怎么数出来的?

这是一个很实用的问题。

假设一层:

Input size = 3

Neuron count = 4

每个neuron:

3 weights

1 bias

所以:

4 parameters per neuron

一共:

4 neurons × 4

= 16 parameters

公式:

Parameters=(Inputs×Neurons)+Neurons\text{Parameters}=(\text{Inputs}\times\text{Neurons})+\text{Neurons}

也就是:

3×4+4=163\times4+4=16

后面的+4 就是四个bias。

43. 再举一个例子

假设:

Input features = 100

Hidden neurons = 256

Weights:

100×256=25,600100\times256=25{,}600

Bias:

256256

总参数:

25,600+25625{,}600+256
25,85625{,}856

仅仅一层就有两万多个parameters。

这也是为什么我们不可能手动调整weights。

必须:

Loss

Gradient

Optimizer

Automatic update

44. Neural Network 和Linear Regression 的真正关系

现在把Week 2 和Week 3 并排看。

Linear Regression

y^=wx+b\hat y=wx+b

Input

Linear

Prediction

Neural Network

h=ReLU(xW1+b1)h=\operatorname{ReLU}(xW_1+b_1)

然后:

y^=hW2+b2\hat y=hW_2+b_2

也就是:

Input

Linear

Activation

Linear

Prediction

再复杂:

Input

Linear

ReLU

Linear

ReLU

Linear

Output

所以Neural Network 并没有突然出现某种魔法。

它只是把:

wx+bwx+b

大量组合起来,并在中间加入:

Activation

45. 把一层写成公式:所有符号都对应刚才的循环

Z=XW+b,A=f(Z)Z=XW+b,\qquad A=f(Z)

Scroll horizontally to view all columns.

Course data table
符号shape代码中做什么
X[B,in]B 个样本,每行是有固定顺序的输入。
W[in,out]第 j 列给第 j 个输出分配各输入权重。
b[out]每个输出一个偏置,沿 batch 复用。
Z、A[B,out]Z 是激活前结果,A 是应用函数后的结果。

矩阵公式统一一行一个样本。PyTorch Linear 的内部 weight 存储为 [out,in],因此 X @ layer.weight.T + layer.bias 才与这里的公式对应;转置只是在两种存储排列之间翻译,不是另一种学习算法。

带偏置的乘加在数学上叫仿射变换;线性变换是偏置为零的特例。框架通常统称 Linear。隐藏层可以用 ReLU;数值回归的输出层可以直接返回 Z。f 在这里不是强制每一层都用同一个激活。

46. ReLU 不是唯一Activation

你以后还会看到:

Sigmoid

σ(x)=11+ex\sigma(x)=\frac{1}{1+e^{-x}}

输出范围:

010\sim1

所以很容易被理解成probability。

Tanh

输出:

11-1\sim1

ReLU

max(0,x)\max(0,x)

GELU

Transformer 中非常常见。

GPT 系列architecture 中你会遇到它或其变体。

现在不用学公式。

只需要先知道:

Activation Function 的核心作用之一是引入Non-linearity。

47. 为什么Sigmoid 长这样?

公式:

σ(x)=11+ex\sigma(x)=\frac{1}{1+e^{-x}}

目前不要试图背。

只看输入输出:

x 很负 → 接近0

x = 0 → 0.5

x 很正 → 接近1

图形:

1 |

______

|

__/

|

/

.5|--------*

|

/

| __/

0 |___

+---------------- x

因此它非常适合表达:

0 → unlikely

1 → likely

例如binary classification 的输出。

48. Classification 和Regression

Week 2 主要是:

Scroll horizontally to view all columns.

Course data table
任务最后一层输出本课接的损失
预测任意实数一个不经 ReLU 的实数MSE
从 V 个互斥类别选一个V 个原始 logits交叉熵,Week 6 展开
看概率用于展示/抽样对 logits 做 Softmax这是读取输出的步骤,不要重复送入 logits 接口

本课先讲单标签分类。多个标签可以同时成立是另一种任务,不要直接照抄互斥类别的 Softmax 规则。

Regression

预测连续数值:

房价= $812,532

温度= 27.3

销量= 1052

Neural Network 还可以做:

Classification

例如:

Cat

Dog

Bird

或者:

Spam

Not Spam

或者:

Fraud

Not Fraud

模型architecture 类似。

主要变化之一是:

Output 和Loss Function。

49. Loss Function 也会改变

Week 2 使用:

MSE

它很适合Regression。

但Classification 常见:

Cross Entropy Loss

以后我们会专门解释。

现在只需要建立:

Regression → often MSE

Classification → often Cross Entropy

50. 一个容易犯的错误:Neuron 是不是一个if?

不是。

Neuron 不会直接写:

python
if image_has_ears:
    cat_score += 1

它做的是:

a=f(xW+b)a=f(xW+b)

Training 不断调整W 和b。

最终整个网络形成复杂行为。

所以它不是传统:

Rule-based Programming

51. Traditional Programming vs Machine Learning

传统程序:

Data

+

Rules written by programmer

Output

例如:

python
if age >= 18:
    allow()

Machine Learning:

Data

+

Correct Answers

Training

Learn Parameters

Model

然后:

New Data

+

Model

Prediction

这个区别非常重要。

52. 那么GPT 里的Neuron 也是这些东西吗?

底层依然大量使用:

xW+bxW+b

但Transformer 的architecture 要复杂很多。

例如:

Token

Embedding

Attention

Linear

Activation

Linear

...

其中仍然充满:

Matrix multiplication

Weights

Bias

Activation

所以你现在学的不是”一个过时的小Neural Network”。

你是在学:

GPT 内部最基础的数学building blocks。

53. 从回归到 GPT:哪里保留,哪里改变?

Scroll horizontally to view all columns.

Course data table
阶段仍然保留新增的难题
线性回归输入、参数、预测、损失、更新一个乘加规则只能表达有限关系。
神经网络损失指导参数更新隐藏层和非线性提供更灵活的表示。
语言模型同样的反向传播和更新输出不是一个连续数,而是对词表候选打分。
GPT许多 XW+b 及可微运算组成模型Attention 允许当前位置读取左侧上下文。

本周只要求你解释前两行。语言模型不是与回归完全无关的新世界:预测函数变大、输入输出改变,训练仍在追踪“参数变化怎样影响损失”。后续每周只替换或增加一个部件。

54. 合上教材,复述这七个关系

  • 一个神经元先算加权和与偏置;多个神经元可以接收同一个输入。
  • 一层的行样本公式是 Z=XW+b,激活后的表示是 A=f(Z)。
  • 连续仿射层仍可合并成仿射层,单靠堆叠不能表达 XOR;不是说改变参数化在任何意义上都没用。
  • 非线性让输入不同区域经过不同响应规则;ReLU 是 max(0,z)。
  • 隐藏单元的人为语义标签只是类比,不能保证训练后某维就代表那个含义。
  • 输出层由任务决定:回归可输出负数;分类分数和损失在 Week 6 讲。
  • forward 只算结果;梯度和 optimizer 更新才组成学习步骤。参数更多不保证更好泛化。

55. Week 3 三个最重要公式

➀Linear Calculation

z=xW+bz = xW + b

意思:

Input

×

Weights

+

Bias

➁Activation

a=f(z)a = f(z)

例如:

a=ReLU(z)a = \operatorname{ReLU}(z)

➂完整Neuron

合起来:

a=f(xW+b)a = f(xW+b)

如果你看到这个公式能够直接在脑子里转换成:

z = weighted_sum(inputs, weights) + bias

a = activation(z)

Week 3 的核心已经掌握一大半。

56. 独立练习:先预测,再展开答案

EX03-A:输入 x=[2,3],权重 w=[0.5,−0.2],偏置 b=0.1。先算 z,再算 a=ReLU(z)。EX03-B:只把第二个权重改为 −1,再算两项。EX03-C:若这是允许负预测的回归输出层,第二次应该返回 z 还是 ReLU(z)?

python
def neuron(x, w, b, activation):
    z = sum(v * weight for v, weight in zip(x, w)) + b
    # 练习片段:补上如何按 activation 返回结果。
    # activation=None 表示线性输出;"relu" 表示截断负值。

回忆题 EX03-D:3 个输入进入 4 个带偏置的神经元,一共有多少个参数?输入的 3 个数是否也计入模型参数量?

Knowledge check

写下 A–D 的结果与理由后,再看参考答案。

57. 用Software Engineer 的视角总结Week 3

可以把一个neuron 看成:

python
class Neuron:
    def __init__(self):
        self.weights = ...
        self.bias = ...

    def forward(self, inputs):
        z = dot(inputs, self.weights) + self.bias
        return activation(z)

一个Layer:

python
class Layer:
    neurons = [
        Neuron(),
        Neuron(),
        Neuron(),
    ]

一个Neural Network:

python
class NeuralNetwork:
    layers = [
        Layer(),
        Layer(),
        Layer(),
    ]

Forward:

python
x = input
for layer in layers:
    x = layer.forward(x)
prediction = x

Training:

python
for epoch in range(...):
    prediction = model.forward(input)
    loss = loss_function(prediction, target)
    gradients = backward(loss)
    update_parameters(gradients)

如果用这种角度看:

Neural Network 就是一个巨大的、参数化的Computational Graph。

Training 则是在做:

不断修改graph 中的parameters,让最终Loss 越来越低。

58. Week 3 → Week 4:最关键的问题

现在其实留下了一个巨大的未解决问题。

我们的网络:

x1 ──w1──□

Hidden Neuron

x2 ──w2──□

│w3

Output Neuron

Prediction

Loss

如果最终:

Loss = 10

我们知道模型错了。

但:

到底应该修改w1 多少?

w2 应该增加还是减少?

w3 对最终错误负多少责任?

如果网络有100 层,最前面的weight 怎么知道自己应该怎么改?

这就是Week 4 的核心:

Backpropagation

它会把Week 2 的Derivative + Partial Derivative + Chain Rule + Gradient Descent 全部串起来。

最终你会看到:

LossBackwardGradients for every weightOptimizer / Update\text{Loss} \rightarrow \text{Backward} \rightarrow \text{Gradients for every weight} \rightarrow \text{Optimizer / Update}

Week 2 教的是机器如何学习一个参数;Week 3 教的是如何把大量参数组织成Neural Network;Week 4则要解决⸺如何让这个网络里的所有参数一起学习。

Week 3 补充深入理解:为什么多层Neuron 能表达更多模式

本节保留邮件版Week 3 原文不变,只补充几个读完原文后最值得追问的“为什么”。

1. Neuron 的输入、参数和输出分别是什么

一个neuron 可以写成:

z=w1x1+w2x2++wnxn+bz=w_1x_1+w_2x_2+\cdots+w_nx_n+b

这里:

  • xᵢ是当前example 提供的feature;
  • wᵢ是模型要学习的影响倍率;
  • b 是移动触发边界的偏移;
  • z 是activation 之前的raw score;
  • activation(z) 是neuron 对这个score 的非线性响应。

Neuron 存在的作用,是把多个输入证据压成一个可学习的响应。很多neurons 并排后,每个neuron 可以学习不同的证据组合。

2. 为什么Weighted Sum 后还要Activation

如果整张网络只有Linear operations:

(xW1+b1)W2+b2(xW_1+b_1)W_2+b_2

仍可合并成一个更大的Linear operation。多层代码看起来更深,表达能力却没有真正增加。

Activation 打破这种可合并性,让不同输入区域可以走不同响应曲线。ReLU 通过门控正值,Sigmoid 把raw score 映射成0 到1 的概率式输出。

3. Hidden Layer 为什么有用

Output neuron 直接从原始features 组合,通常只能学一个相对简单的边界。Hidden layer 先产生中间features,例如:

hidden 1 → “面积大且距离近”

hidden 2 → “卧室多但价格敏感”

这些不是程序员手写的标签,而是训练后weights 形成的可用方向。下一层再组合这些中间signals,就能表达原始输入空间中更复杂的区域。

4. XOR 为什么是经典例子

XOR 在输入(0,0) 和(1,1) 时输出0,在(0,1) 和(1,0) 时输出1。单个linear neuron 无法用一条直线把这两组点分开。

两个hidden neurons 可以先各自形成不同的半平面,再由output neuron 组合它们。这个例子不是因为现代GPT 仍在手工解决XOR,而是因为它最小地说明:非线性和层叠会改变可表达的函数集合。

5. Classification 的输出为什么不同

Regression 通常输出一个连续数,例如房价;Binary classification 常输出一个logit,再通过Sigmoid得到一个probability;Multi-class classification 输出每个class 一个logit,再通过Softmax 得到整组probabilities。

6. Parameter Count 为什么重要

如果一层有n 个inputs 和m 个neurons:

weights=n×m\mathit{weights}=n\times m

再加m 个biases。Parameter count 越大,模型有更多可调自由度,但也需要更多data、memory 和training signal。容量增加可能帮助underfitting,也可能在数据不足时带来overfitting。

7. 从Forward 到Learning 的连接

邮件版中的forward 只产生prediction;它还没有告诉weights 应该怎样改变。Week 4 会把同一张network graph 反向走一遍:

Loss

↓local derivatives + Chain Rule

every weight and bias 的gradient

↓optimizer

updated parameters

所以Week 3 的最后一句“这个网络还不会学习”非常关键:Architecture 决定模型能表达什么,Backpropagation 才提供让它根据data 改善的机制。