我用纯 Python 和 NumPy 从零写了一个神经网络——10 个神经元,7960 个参数,用来识别手写数字。然后我把它拆开,看懂了它的每一个参数在做什么。这篇文章从这个最简单的网络出发,聊聊神经网络到底是怎么工作的,以及它和今天的 ChatGPT 之间的关系。

① 数据与结构 → ② 前向传播 → ③ 损失函数与反向传播 → ④ 拆开黑盒 → ⑤ FNN → CNN → RNN → Transformer → ⑥ 当下的大模型 → ⑦ 可解释性的边界


写在前面

前段时间用 Python 从零写了一个神经网络。

没有 PyTorch,没有 TensorFlow,没有任何框架。就是矩阵乘法和梯度下降。

它只有 10 个神经元,7960 个参数,任务是识别手写数字 0-9。训练 500 步之后,准确率 85%。我写了个小程序,用鼠标画数字,它能认出来。

写完之后,我把它拆开了。W1 矩阵 reshape 成图片,W2 矩阵画成热力图,把每一张图的决策路径可视化。7960 个参数全部摊开,看看它到底学到了什么。

然后我发现一件事:**这个只有 10 个神经元的小网络,和 GPT-4 用的是同一套数学。**点积、Softmax、梯度下降——一模一样。区别只是规模和架构。

这篇文章就从这个小网络出发,聊聊神经网络在做什么,FNN、CNN、RNN、Transformer 各自解决了什么问题,以及它们和今天的大语言模型之间的关系。


一、数据:一张图片就是 784 个数字

先说数据。MNIST 数据集有 42000 张手写数字图片,每张 28×28 像素的灰度图。

MNIST 数据集样本:20 张不同人手写的数字 0-9

每个像素是一个 0-255 的灰度值:0 = 黑,255 = 白。一张 28×28 的图就是 784 个数字。

像素细节:左=灰度值,中=热力图,右=3D 地形图

把 784 个像素值排成一行,这张图就变成了一组数字——一个 784 维的向量。这就是神经网络的输入。

图像到 CSV:28×28 的图片展平成 784 个数字的向量


二、结构:784 → 10 → 10

网络很简单,三层:

  • 输入层:784 个节点,对应 784 个像素
  • 隐藏层:10 个神经元(这就是网络学到"知识"的地方)
  • 输出层:10 个节点,对应数字 0-9 的概率

网络结构示意图:784 个输入 → 10 个隐藏神经元 → 10 个输出

参数量:

  • W1 (10×784) + b1 (10) = 7850
  • W2 (10×10) + b2 (10) = 110
  • 7960 个参数

数据在进网络之前做了两步预处理:

数据预处理:归一化到 0-1,标签转 One-Hot 编码


三、前向传播:四步算出一个预测

把一张图片喂给网络,它做四步运算:

第一步:加权求和

$$Z_1 = W_1 \times X + b_1$$

每个隐藏神经元把 784 个像素值和自己的 784 个权重逐一相乘再相加。这个操作叫点积——本质上是在算"这张图和我的模板有多像"。

换一个角度看:W1 是一个 10×784 的矩阵,X 是一个 784×1 的向量。Z1 = W1 × X 就是一次矩阵乘法——10 个神经元同时和整张图做点积,一次算完。这正是神经网络里矩阵运算和神经元之间最直接的关系:**每一行权重就是一个神经元,矩阵乘法就是所有神经元同时"看"一张图。**理解了这一步,后面 Transformer 里的 Q·Kᵀ 也是同一个操作——只不过维度从 784 变成了几千。

第二步:ReLU 激活

$$A_1 = \max(0, Z_1)$$

负数变 0,正数不变。听起来简单,但没有它,两层线性运算叠在一起还是线性运算——等于白叠了一层。ReLU 引入了非线性,让网络有了"取舍"的能力:匹配的保留,不匹配的闭嘴。一个 ReLU 产生一个"折",多个折就能逼近任意曲线——这就是万能近似定理的直觉。

第三步:再来一次加权求和

$$Z_2 = W_2 \times A_1 + b_2$$

第二层把 10 个神经元的输出组合起来,形成对 10 个数字的"打分"。

第四步:Softmax 转概率

$$A_2 = \frac{e^{z_i}}{\sum e^{z_j}}$$

把原始分数变成 0 到 1 之间的概率,总和为 1。最大概率对应的数字就是答案。

这四步就是"前向传播"。数据从左到右流过网络,变成一个预测。每一步都是简单的算术——乘法、加法、取最大值、指数。没有魔法。


四、训练:怎么从错误中学习

损失函数

模型预测 P(3) = 73%,真实答案确实是 3。不错,但 73% 不是 100%。怎么量化"还不够好"?用交叉熵损失(Cross-Entropy Loss):

$$Loss = -\ln(P(\text{正确答案})) = -\ln(0.73) = 0.31$$

预测完美时 Loss = 0,预测越差 Loss 越大。训练的目标就是让 Loss 越来越小。

为什么偏偏是 −log(p)?这背后有 Shannon 信息论的深层原因——交叉熵衡量的是"模型的平均惊讶度"。这个话题我写过一篇完整的推导:《为什么用 -log(p) 做损失函数?——从信息论到 Cross-Entropy 的完整推导》,从 Shannon 的三条公理出发,证明 −log(p) 是唯一满足所有条件的函数——它不是经验选择,而是数学必然。

反向传播

反向传播回答一个问题:每个参数对这次的错误贡献了多少?从输出层开始往回推,用链式法则算出每个参数的梯度——Loss 对该参数的偏导数。

关键公式出奇地简洁:

输出层误差:dZ2 = A2 − Y          ← softmax + 交叉熵联合求导,完美约分
第二层权重:dW2 = dZ2 × A1.T      ← 误差 × 输入
隐藏层误差:dZ1 = W2.T × dZ2 × (Z1 > 0)   ← 误差传回 + ReLU 的门
第一层权重:dW1 = dZ1 × X.T       ← 同样的模式

dZ2 = A2 − Y 为什么这么简洁?因为 Softmax 用的 eˣ 和交叉熵用的 ln 天生互为逆运算,求导时完美抵消,最终只剩下"预测值 − 真实值"。

梯度下降

算出梯度之后,用它更新参数:

W1 -= lr × dW1    # lr = 学习率,控制每步走多大
W2 -= lr × dW2
b1 -= lr × db1
b2 -= lr × db2

梯度指向"上坡方向",减去梯度就是"下坡"——让 Loss 变小。

神经网络学习的全部流程: 前向传播 → 计算损失 → 反向传播 → 更新参数 → 重复

每重复一次,模型就准一点点。下面是实际的训练曲线——Loss 从 2.3 降到 0.5,准确率从 10% 涨到 85%:

训练曲线:Loss 持续下降,准确率持续上升

训练完成后,看看它在测试集上的表现——绿色是对的,红色是错的:

模型预测结果:绿色=正确,红色=错误


五、拆开黑盒:它到底学到了什么

训练完成后,7960 个参数不再是随机数。它们变成了某种"知识"。

我把 W1 的每一行——784 个权重——重新排列成 28×28 的图片,想看看每个神经元在"找什么":

W1 权重可视化:10 个神经元各自学到的"模板"

红色区域 = “我期望这里有笔画”。蓝色区域 = “我期望这里是空白”。没有人教它什么数字长什么样——这 10 张模板是它从 42000 张图片中自己"长"出来的。

然后看 W2——一个 10×10 的投票矩阵。它决定了每个模板匹配后,给哪个数字投多少票:

W2 投票矩阵热力图:每个神经元对每个数字的投票权重

这个网络的识别方式不是"理解"——而是模板匹配 + 投票

  1. 拿到一张图,和 10 个模板逐一比较(点积 = 相似度打分)
  2. 只保留匹配的(ReLU 把负分清零)
  3. 匹配的模板按权重投票(W2 矩阵)
  4. 票最多的数字就是答案

下面这张图把整个决策过程展开了。三张不同的输入图片,从左到右依次是:输入 → 哪些神经元被激活 → 10 个数字各得多少概率 → 最终预测:

完整决策路径:3 张图的输入→激活→概率→预测全过程

再具体一点——为什么某个神经元会"激活"?因为输入和模板长得像。下面的图把一张数字"5"和最匹配的模板叠在一起看:

模板叠加对比:输入的数字 5 与最匹配的 W1 模板重合区域

到这里,一个神经网络的工作原理就说完了。矩阵乘法就是所有神经元同时"看"一张图,ReLU 给每个结果"折"一下,梯度下降沿着下坡方向调整参数——这不是某一种网络特有的东西,这是所有神经网络共享的基础。关于矩阵乘法在几何上到底做了什么——旋转、缩放、剪切——以及这些 2D 变换如何直接对应 GPT 里的 QKV 投影,我在**《一看就懂:矩阵乘法到底对 LLM 做了什么?》**里用动图演示过。后面要聊的 CNN、RNN、Transformer,改变的只是前向传播里"怎么算"的部分,训练循环始终不变。


六、FNN 的问题,以及 CNN 怎么解决的

85% 的准确率不算差,但最好的模型能到 99.7%。差在哪?

我们的网络把 28×28 的图片拍平成了 784 个数字,丢失了所有空间结构。打个比方:把一张照片剪成 784 个碎片扔给你,让你猜是什么数字——你能猜个大概,但肯定不如看完整照片准。

具体来说:数字往左移两个像素,匹配分数就变了(没有位移不变性);它看的是全局模板,认不出"一个小圆弧"或"一条竖线"这种局部笔画(没有局部特征)。

**CNN(卷积神经网络)**的思路是:不看整张图,用小窗口扫描局部。

FNN:  整张图(784) → 全局模板匹配
CNN:  小窗口(3×3) → 在图上从左到右、从上到下滑动 → 找局部特征

CNN 的卷积核就是小版的"模板"。一个 3×3 的小矩阵在图片上滑动,每到一个位置做一次点积。因为同一个卷积核在所有位置共享权重,所以数字写在哪都能检测到——这就是位移不变性。

多层 CNN 从低到高提取特征:低层找边缘,中层找笔画,高层找整体形状。最后几层通常就是全连接层——也就是我们写的 FNN。CNN = 卷积提特征 + FNN 做分类。

输入 (28×28) → 卷积层 → 池化 → 卷积层 → 池化 → 全连接层 → 输出
               (找边缘)         (找笔画)         (做分类)

CNN 在 MNIST 上能到 99% 以上。代表作:LeNet(1998)、AlexNet(2012,引爆深度学习革命)、ResNet(2015,152 层)。从感知机被一本书判了死刑,到深度学习靠改名字重获新生——这段 80 年的曲折历程,我在**《神经网络沉浮录:从万众瞩目到无人问津,再到改变世界》**里讲过。

但 CNN 是为图像设计的,文本不是图片。怎么办?


七、RNN:给网络装上记忆

文本和图片有本质区别:文本是序列,字的顺序至关重要。“狗咬了人"和"人咬了狗"用一样的字,意思完全不同。

**RNN(循环神经网络)**的做法是:处理每个字的时候,带着前面的记忆。

"我" → [RNN] → h1 (记住了"我")
"喜" → [RNN] → h2 (记住了"我喜")
"欢" → [RNN] → h3 (记住了"我喜欢")
"猫" → [RNN] → h4 (记住了"我喜欢猫") → 输出

每一步,RNN 接收当前输入和上一步的隐藏状态 h,输出新的隐藏状态。h 就是"记忆”。

问题在于:读到第 100 个字的时候,第 1 个字的信息已经在 99 次变换中稀释殆尽了。这叫梯度消失——反向传播经过 100 层链式法则,梯度指数衰减。LSTM 和 GRU 通过"门控"机制缓解了这个问题,但治标不治本。

2017 年之前,NLP 主要靠 RNN / LSTM。Google 翻译、Siri 背后都是它。

然后有一篇论文改变了一切。


八、Transformer:Attention Is All You Need

2017 年,Google 发了一篇论文,标题叫 “Attention Is All You Need”。此后,GPT、BERT、Claude、DeepSeek、Llama——全部基于这篇论文提出的 Transformer 架构。

核心想法:自注意力(Self-Attention)

RNN 必须一个字一个字地读,第 100 个字很难回忆第 1 个字。Transformer 的做法是:让每个字直接和所有其他字交互。

RNN:          我 → 喜欢 → 可爱的 → 猫     (串行,"猫"很难回看"我")
Transformer:  我 ←→ 喜欢 ←→ 可爱的 ←→ 猫  (并行,每个字直接看所有字)

具体做法:每个字被变换成三个向量——Query(我在找什么)、Key(我有什么)、Value(我的内容)。然后用 Q 和 K 做点积算相关性,再用这个相关性对 V 做加权求和。

注意力得分 = Q · Kᵀ / √d      ← 又是点积
注意力权重 = Softmax(得分)      ← 又是 Softmax
输出       = 注意力权重 × V     ← 加权求和

点积和 Softmax——和我们那个 10 个神经元的小网络用的是一样的数学运算。我们的网络是"拿模板去匹配图片",Transformer 是"让句子里的每个词互相匹配"。底层数学没变,维度变了,几何没变。关于 Attention 机制的完整拆解,我写过**《从加减乘除到预测下一个字:Attention 机制零基础拆解》,从向量相似度一路推到多头注意力。而 QKV 为什么要分成三个矩阵、背后涉及的符号接地问题和分布式假说,在《从语言的本质到 Attention 的诞生——QKV 为什么长这样》**里有更深的追问。

Transformer vs RNN

RNNTransformer
处理方式串行,一个一个读并行,全部同时看
长距离依赖越远越弱直接点积,距离无关
训练速度慢(没法并行)快(GPU 友好)

一个 Transformer 层 = 自注意力 + 前馈网络(MLP) + 残差连接 + 层归一化。堆 N 层就是一个完整的模型:

输入 → Embedding → [Attention + MLP] × N 层 → 输出


九、四代架构回顾

FNNCNNRNNTransformer
核心运算W·X 矩阵乘卷积核滑动隐藏状态传递Q·Kᵀ·V
擅长分类 / 回归图像识别序列处理几乎一切
弱点无空间感知处理不了序列长距离遗忘计算量大
MNIST~85%~99%+能做但不适合大材小用
代表本文 DemoResNetLSTMGPT / Claude
年代1960s1990s–20121990s–20172017–至今

无论架构怎么变,训练循环始终不变:前向传播 → 计算损失 → 反向传播 → 更新参数 → 重复。理解了这个循环——也就是前面用 MNIST 讲的全部内容——就理解了所有神经网络最核心的部分。


十、当下的大模型

我们的小网络有 7960 个参数。看看现在真实运行的大语言模型:

我们的 NNLlama 3.1 405BDeepSeek-V3GPT-4
参数量7,9604,050 亿6,710 亿~1.76 万亿
层数212661~120
训练数据4.2 万张图15.6 万亿 token14.8 万亿 token~13 万亿 token
架构FNNDense TransformerMoE TransformerMoE Transformer

GPT-4 的参数量是我们模型的 2.2 亿倍。但底层原理是一样的——矩阵乘法、激活函数、梯度下降。区别在于 Transformer 架构和规模带来的涌现。关于 AI、Machine Learning、Deep Learning、LLM 之间的嵌套关系,我在**《AI 全景定位:从概念迷雾到清晰地图》**里画过一张完整的地图。

几个关键区别

**分词(Tokenization)。**我们的输入是像素值,LLM 的输入是文字。GPT 把文本拆成 token——大约是半个到一个英文单词,或一个到几个中文字符。每个 token 查一张嵌入表,变成高维向量。

**自回归生成。**我们的网络一次输出 10 个概率。LLM 一个字一个字地生成——预测下一个 token,然后把它加到输入里,再预测下一个。ChatGPT 一个字一个字往外蹦,就是在做这个。

**混合专家(MoE)。**DeepSeek-V3 有 6710 亿参数,但每次推理只激活约 370 亿。网络里有 256 个"专家"子网络,每个 token 只路由到最相关的 8 个。

关于预训练、SFT、RLHF 三个阶段分别在做什么——以及为什么"一杯水"的微调数据就能彻底改变"一个游泳池"的预训练模型——我在**《万亿字节的压缩术:LLM 如何把互联网装进一个模型》里有更详细的展开。MoE 的稀疏激活机制写在《MoE:671B 参数的模型,为什么只用 37B 就够了?》,知识蒸馏涉及的"偷师"争议在《当模型学会「偷师」——知识蒸馏、版权战争与学习的边界》**。

主流模型一览

模型开发者参数量开源亮点
GPT-4OpenAI~1.76TMoE,最早的旗舰级模型
ClaudeAnthropic未公开长上下文,安全对齐
Llama 3.1Meta8B–405B开源旗舰,生态最完整
DeepSeek-V3DeepSeek671B (37B 激活)极致性价比
Qwen 2.5阿里0.5B–72B中文能力强
GeminiGoogle未公开原生多模态

这些模型全部基于 Transformer,全部用同一个训练循环。区别在于规模、数据、对齐策略和工程优化。


十一、可解释性的边界

回到我们的小模型。训练完成后,我把它的"知识"全部可视化了——模板图、投票矩阵、决策路径。看起来全看懂了。

但当我试着回答更深的问题时,发现不行。

为什么是这些模板?换个随机种子训练,出来完全不同的模板,但准确率一样。为什么把某张 5 认成了 3?我能看到哪些神经元激活了,但说不清为什么训练没能学到区分它们。我能描述"做了什么",但没办法解释"为什么这样做是最好的"。

而这只是 10 个神经元、1 层隐藏层。

10 个神经元的时候,我们至少还能把 W1 reshape 成 28×28 的图片,看到模板的轮廓。但再加一层隐藏层呢?第二层的输入不再是像素,而是第一层的输出——一组抽象的激活值。你没法把它画成图片了。第三层更抽象,第四层更抽象。每多一层,人类的直觉就退后一步。

GPT-4 有 120 层,每层 96 个注意力头,参数量是我们模型的 2.2 亿倍。在那个尺度上,一个概念被分散编码在成千上万个神经元里(superposition),一个神经元同时参与编码多个不相关的概念(polysemanticity)。Anthropic 在 Claude 中找到了少数可解释的特征——比如代表"金门大桥"的方向——但那只是冰山一角。

不过我们也不是完全失明。研究者发现,LLM 的事实知识确实有迹可循——它大量存储在 MLP(前馈网络)层的权重矩阵里,就像我们小网络的 W1 存储模板一样。只不过大模型里的"模板"被加密了:知识分散编码在几百万个浮点数中,只有当正确的输入向量流过来,才能把它"解密"出来。甚至有人成功编辑了个别事实——比如把模型记忆中"埃菲尔铁塔在巴黎"改成"在罗马"。

1950 年代 AI 有两条路线:符号主义(用规则编写智能,透明但脆弱)和联结主义(用神经网络从数据中学,不写规则)。联结主义最终胜出,但有一个代价——选择"让数据塑造参数",就意味着放弃"理解每个参数为什么是这个值"。这不是技术限制,是方法论的必然结果。关于这场 70 年的拉锯战,以及为什么矩阵乘法加激活函数就能逼近任何函数,我在**《为什么矩阵和激活函数就能涌现智能?——从符号主义到万能近似定理》里写过完整的回顾。而 MLP 权重如何存储知识、为什么它们像"全息照片"一样只有被正确的输入照射才会浮现,在《LLM 的知识藏在哪里?MLP 权重中的加密记忆》**里有更深入的分析。


写在最后

从 10 个神经元出发,走了挺远。

但让我印象最深的不是这条路有多长,而是起点和终点的反差。

在这个最小的网络里,我能把每个权重都看清楚——W1 的十张模板,W2 的投票矩阵,每一步计算都摊在阳光下。这种透明感让人觉得"原来如此"。

但仔细想想,即便在这里,我也无法解释为什么是这些模板。换个随机种子,出来完全不同的模板,准确率一样。模型找到了一条路,但没人知道这条路是不是最好的,更没人知道还有多少条别的路。

10 个神经元尚且如此。GPT-4 有几千亿个。

矩阵乘法、点积、Softmax、梯度下降——1960 年代的数学,2017 年的架构,2024 年的算力。这些东西从来没变过。变的是规模,以及规模带来的涌现。我们搭了一个框架,往里面灌了人类文明几千年写下的所有文字,然后惊讶地发现它学会了推理、会了类比、懂了讽刺。但我们说不清它是怎么学会的。

也许这就是联结主义的宿命:选择了让数据塑造参数,就注定放弃了对每个参数的解释权。我们能测试、能探针、能局部验证——但完整的理解,至少目前,还不在人类手中。

不过,不理解并不意味着不能继续追问。

如果你想亲手试试,所有代码都在 Jupyter Notebook 里。从 CSV 加载到训练到可视化,Python + NumPy,不需要框架。你会看到那 10 张模板——模糊的、歪歪扭扭的数字形状——那是一个网络从零开始学到的全部"知识"。很简陋,但那里面藏着 GPT 的全部原理。


参考资料

  • Samson Zhang, “Building a neural network FROM SCRATCH” (YouTube)
  • Vaswani et al., “Attention Is All You Need” (2017)
  • Meta, Llama 3.1 Technical Report (2024)
  • DeepSeek-AI, DeepSeek-V3 Technical Report (arXiv:2412.19437)
  • MNIST Handwritten Digit Dataset (42,000 images)