神经网络的矩阵形式
Table of content
从手写计算到矩阵运算:神经网络的通用形式
1. 为什么要用矩阵?
前面的例子中,每个神经元的计算都是手写出来的。一个有两个输入的神经元长这样:
y = sigmoid(w1 * x1 + w2 * x2 + b)当网络只有三五个参数时,这样写没问题。但想象一下:如果输入有 784 个(比如 28×28 的手写数字图片),隐藏层有 256 个神经元,输出层有 10 个神经元,参数总量会达到几十万个。手写每一个 w_i * x_i 显然不现实。
矩阵运算提供了一种统一的、可扩展的表示方式。它把“对每个神经元分别写公式”变成“对整个层做一次矩阵乘法”。
2. 单个神经元的向量表示
先从一个神经元开始。
输入是两个数:
x = [x1]
[x2]权重也是两个数:
w = [w1, w2]神经元的计算可以写成向量点积加上偏置:
z = w · x + b
= w1 * x1 + w2 * x2 + b
y = σ(z)这里 σ 表示激活函数,比如 sigmoid。
用图表示:
输入 x1、x2 分别乘以权重 w1、w2,加上偏置 b 得到 z,再通过激活函数得到输出 y。
3. 从向量到矩阵:一层多个神经元
现在考虑一层里有多个神经元。假设输入仍然是 2 维,但这一层有 3 个神经元。
每个神经元都有自己的权重和偏置:
神经元 1:w11, w12, b1
神经元 2:w21, w22, b2
神经元 3:w31, w32, b3其中 wij 表示第 i 个神经元的第 j 个输入权重。
如果分别写,就是三个公式:
z1 = w11*x1 + w12*x2 + b1
z2 = w21*x1 + w22*x2 + b2
z3 = w31*x1 + w32*x2 + b3这三个式子可以合并成一个矩阵乘法:
[w11 w12] [x1] [b1] [z1]
z = [w21 w22] * [x2] + [b2] = [z2]
[w31 w32] [b3] [z3]更一般地,对于第 l 层:
z^[l] = W^[l] * a^[l-1] + b^[l]
a^[l] = σ(z^[l])其中:
a^[l-1]:上一层的输出,维度是n_in × 1W^[l]:当前层的权重矩阵,维度是n_out × n_inb^[l]:偏置向量,维度是n_out × 1z^[l]:线性组合结果,维度是n_out × 1a^[l]:经过激活函数后的输出,维度是n_out × 1
n_in 是输入数量,n_out 是当前层神经元数量。
为什么权重矩阵是 n_out × n_out?
看上面的例子:
输入 x 是 2×1
输出 z 是 3×1
权重 W 是 3×2矩阵乘法的规则是 (m × n) * (n × p) = (m × p)。所以 W 的行数等于输出维度,列数等于输入维度。这样 W * x 的结果才能和 b 相加,得到正确维度的输出。
4. 多层网络:层与层之间的传递
多层网络就是重复应用上面的公式。
假设一个三层网络:
输入层:2 个节点
隐藏层:3 个节点
输出层:1 个节点网络结构可以画成:
前向传播过程:
z^[1] = W^[1] * x + b^[1]
a^[1] = σ(z^[1])
z^[2] = W^[2] * a^[1] + b^[2]
a^[2] = σ(z^[2])最终 a^[2] 就是网络输出。
注意激活函数 σ 是逐元素应用的。也就是说,如果 z = [z1, z2, z3]^T,那么 σ(z) = [σ(z1), σ(z2), σ(z3)]^T。
5. 用矩阵形式重写 XOR 网络
XOR 网络的结构是:
输入层:2 个节点 (x1, x2)
隐藏层:2 个神经元
输出层:1 个神经元网络拓扑:
隐藏层有两个神经元,一个负责类似 OR 的逻辑,一个负责类似 NAND 的逻辑。输出层有一个神经元,负责把隐藏层的输出组合成 XOR。
第一层:输入 → 隐藏层
输入:
x = [x1]
[x2]权重矩阵 W1 是 2×2:
W1 = [w11 w12]
[w21 w22]第一行对应第一个隐藏神经元,第二行对应第二个隐藏神经元。
偏置向量 b1 是 2×1:
b1 = [b1]
[b2]隐藏层计算:
z1 = W1 * x + b1
h = σ(z1)h 就是隐藏层的输出,维度是 2×1。
第二层:隐藏层 → 输出层
权重矩阵 W2 是 1×2:
W2 = [u1, u2]偏置 b2 是 1×1(一个标量)。
输出层计算:
z2 = W2 * h + b2
y = σ(z2)完整前向传播
把两步合起来:
h = σ(W1 * x + b1)
y = σ(W2 * h + b2)代入具体参数,就可以得到 XOR 的输出。
一个具体的例子
假设训练后得到这样一组参数:
W1 = [ 5.6 -4.2]
[-3.2 5.6]
b1 = [-2.9]
[ 1.8]
W2 = [ 7.4 -7.4]
b2 = [-4.7]注意:这些数值是示意性的,不是真实训练结果。真实训练中,参数会落在让 cost 最小的某个位置。
输入 x = [0, 1]^T:
第一步:
z1 = W1 * x + b1
= [ 5.6 -4.2] * [0] + [-2.9]
[-3.2 5.6] [1] [ 1.8]
= [5.6*0 + (-4.2)*1] + [-2.9]
[(-3.2)*0 + 5.6*1] [ 1.8]
= [-4.2] + [-2.9] = [-7.1]
[ 5.6] [ 1.8] [ 7.4]
h = σ(z1) ≈ [0.0008]
[0.9994]第二步:
z2 = W2 * h + b2
= [7.4, -7.4] * [0.0008] + [-4.7]
[0.9994]
≈ 7.4*0.0008 + (-7.4)*0.9994 - 4.7
≈ -7.4 - 4.7
≈ -12.1
y = σ(z2) ≈ 0.000005输入 (0, 1) 的输出接近 0,符合 XOR 真值表。
6. 通用神经网络计算模型
把上面的过程抽象一下,就得到了一个通用的前向传播算法。
对于 L 层网络,给定输入 x:
a^[0] = x
for l = 1 to L:
z^[l] = W^[l] * a^[l-1] + b^[l]
a^[l] = σ(z^[l])
output = a^[L]这就是神经网络的通用计算模型。无论网络多深、多宽,都是这个循环。
参数规模
假设网络结构是:
输入层:784 个节点
隐藏层 1:256 个神经元
隐藏层 2:128 个神经元
输出层:10 个神经元参数数量:
W1: 256 × 784 = 200,704
b1: 256
W2: 128 × 256 = 32,768
b2: 128
W3: 10 × 128 = 1,280
b3: 10
总计:约 235,000 个参数如果不使用矩阵,而是手写每一个神经元的公式,代码会极其冗长。矩阵表示让这一切变得简洁且可扩展。
7. 线性代数的几何本质
矩阵运算不只是为了“写得简洁”,它背后有很深的几何意义。
7.1 矩阵乘法是线性变换
一个矩阵 W 乘以一个向量 x,几何上是对 x 做线性变换。线性变换包括:
- 旋转:改变方向但不改变长度比例
- 缩放:沿某些方向拉伸或压缩
- 投影:把高维空间投影到低维空间
- 剪切:把一个方向的分量叠加到另一个方向上
比如矩阵:
W = [2 0]
[0 0.5]作用在向量 x = [x1, x2]^T 上:
W * x = [2*x1]
[0.5*x2]这是把 x 轴方向拉伸 2 倍,y 轴方向压缩一半。
7.2 偏置是平移
偏置 b 的作用是把变换后的结果整体移动:
z = W * x + b没有 b 时,变换后的空间必须过原点。加上 b 后,空间可以平移到任意位置。这就是为什么偏置能让模型更灵活。
7.3 激活函数引入非线性
如果只有 z = W * x + b,无论多少层,整个网络仍然是线性变换。多个线性变换的复合还是线性变换,无法拟合 XOR 这种非线性问题。
激活函数 σ 的作用是在每层之后引入非线性。它把空间“弯折”,让网络可以表示更复杂的函数。
sigmoid 的几何意义:它把整条实数轴压缩到 (0, 1) 区间。大的正数变成接近 1,大的负数变成接近 0,中间区域是平滑过渡。
7.4 神经网络是复合非线性变换
多层网络可以看作是一系列非线性变换的复合:
x → 线性变换 + 平移 → 非线性弯折 → 线性变换 + 平移 → 非线性弯折 → ... → 输出每一层都在对输入空间进行“扭曲”。足够多的层和神经元,网络就可以把输入空间扭曲成几乎任意形状,从而分开复杂的类别。
7.5 从 XOR 看几何意义
XOR 问题的四个点:
(0,0) → 0
(0,1) → 1
(1,0) → 1
(1,1) → 0在平面上,(0,1) 和 (1,0) 是一类,(0,0) 和 (1,1) 是另一类。无法用一条直线分开。
神经网络做的事情是:
- 第一层通过线性变换和非线性激活,把四个点映射到一个新的空间。
- 在新的空间里,原本线性不可分的点变得可以用一条直线分开。
- 第二层就是在这条新空间里画一条直线,完成分类。
这就是神经网络强大之处:它通过学习和变换,把困难的问题转化成容易的问题。
8. 训练过程如何用矩阵表示
前向传播用矩阵表示后,反向传播也可以用矩阵表示。虽然具体推导涉及多元微积分,但核心思想很简单:
损失函数 L 对某个参数 w 的梯度 = L 对该参数造成的影响矩阵形式的反向传播利用链式法则,把梯度从输出层逐层传回输入层。
对于一层:
z = W * x + b
a = σ(z)
L = loss(a, target)梯度:
δ = (∂L/∂a) ⊙ σ'(z)
∂L/∂W = δ * x^T
∂L/∂b = δ其中 δ 是损失对线性组合 z 的梯度,⊙ 表示逐元素相乘,x^T 是输入向量的转置。
对于多层网络,只需要把每层的梯度连乘起来。这也是为什么矩阵运算在深度学习框架中如此重要:它让前向和反向传播都能高效地并行计算。
9. 从代码到框架
理解了矩阵形式后,再看现代深度学习框架就会清晰很多。
PyTorch 中的典型写法:
import torch.nn as nn
model = nn.Sequential(
nn.Linear(2, 2), # W1, b1
nn.Sigmoid(),
nn.Linear(2, 1), # W2, b2
nn.Sigmoid()
)这里的 nn.Linear(in, out) 就是做 W * x + b。框架内部全部用矩阵运算实现,可以处理任意规模的网络。
10. 总结
从手写单个神经元:
y = σ(w1*x1 + w2*x2 + b)到通用矩阵形式:
z^[l] = W^[l] * a^[l-1] + b^[l]
a^[l] = σ(z^[l])变化的是表示方式,不变的是核心思想:
- 线性变换:矩阵乘法对输入进行旋转、缩放、投影。
- 平移:偏置让决策边界离开原点。
- 非线性:激活函数让网络可以拟合曲线和复杂边界。
- 组合:多层复合变换,把困难的问题变成容易的问题。
矩阵表示让神经网络从“几个手写公式”变成了“可以任意扩展的通用计算模型”。这也是现代深度学习能够在图像、语音、自然语言等领域取得突破的基础。