第 01 课 · 写给第一次见到大脑的人

它只有十个神经元,
却走完了学习的全部过程

你不需要会写代码。只需要回想一件事:人第一次认东西是什么样子——看一眼,猜一次,被纠正一次。这个只有 7850 个参数的小大脑,学的正是这件事,只是对象换成了衣服,时间压缩成几分钟。

一 · 数字二 · 名字三 · 打分四 · 扣分五 · 改正六 · 新题七 · 长大
一 · 数字

照片放大之后,都是格子

打开手机相册,把一张衣服的照片不断放大,边缘会碎成一个个小方格。这里的每一张图,一出生就是碎好的:28 行、28 列,共 784 格。每个格子里只记一件事——那一点有多亮。最黑记 0,最白记 255。

下面是一张缩小到 5×5 的示意(真的 28×28 更细),黑边是 0,衣服是亮数。你看到的是“衣”,它收到的是这些数:

数字太大,它会晕。所以第一件事是把秤换小:所有数除以 255。黑还是 0,白变成 1,灰变成零点几。明暗的次序丝毫没变,只是数字变小了,好计算。这一步叫归一化。

# 换小单位,不换明暗;两套卷子用同一杆秤
train_images = train_images / 255.0
valid_images = valid_images / 255.0
注:输入形状 (60000,28,28) 与 (10000,28,28),值域 [0,1]。量级过大时输出与梯度随之过大,默认步长下难以收敛。
二 · 名字

十件衣服,十个编号

文字太长,数字最快。T恤是 0,衬衫是 6,短靴是 9——看到照片,报出编号,这就是它的全部考题,叫标签。

编号衣服难易
0 / 2 / 4 / 6T恤 · 毛衣 · 外套 · 衬衫最难认,都是上衣
1 / 3 / 8裤子 · 裙子 · 包轮廓差得大,好认
5 / 7 / 9凉鞋 · 运动鞋 · 短靴都是穿在脚上的,中等

照片分两摞。六万张是练习册,可以看答案;一万张是密封的,留到最后检验。如果提前拆开,分数再高也不作数——换一件没见过的新款,立刻露馅。往后每一课的“考考它”,都是这条规矩。

# 六万练,一万考,互不相见
(train_images, train_labels), (valid_images, valid_labels) = fashion_mnist.load_data()
三 · 打分

每个格子投一票

认衣服的方法,笨拙而有效:投票。784 个格子,每个只看得见自己那一点。领口发白的那格喊“像 T恤”,角落漆黑的那格直接弃权——亮度是 0,乘以多少都是 0。每个格子心里有个分量:重要的位置分量大,背景的分量接近 0。再加上每种衣服自带的一点印象分,加总就是得分。

三格的例子一看就懂:亮度 [0.9, 0, 0.5],分量 [2.0, 1.0, −1.0],印象分 0.2,总分 1.5。784 格同理,只是更长:

总分 = 每一格的亮度 × 它的分量,加起来,再加一点印象分。
分量 = 权重 w;印象分 = 偏置 b。整个学习过程改的,就是这些分量。

十种衣服,备十套分量,各打各的分。谁最高,就判谁。这十个原始分数叫 logits,可正可负,不必换成百分比——比个高低就够了。

model = tf.keras.Sequential([
    tf.keras.layers.Input(shape=(28, 28)),
    tf.keras.layers.Flatten(),  # 把表格拍平成一列,一眼看全件
    tf.keras.layers.Dense(10)   # 十套分量,各打一分
])

7850 从哪里来?每格对十套分量各有一份:784×10=7840;每套再加一份印象分:+10。共 7850,还不到一张手机照片大。拨动看看:

格数 784 种类 10
总数 = 7850 ≈ 30.7KB
注:即 y=Wx+b,W ∈ R10×784,b ∈ R10。Flatten 只改变形状,0 参数。
想一下:为什么黑格子不用看?
亮度为 0,分量再大乘出来也是 0,天然弃权。所以背景的分量最后都会变得很小。
四 · 扣分

错得越肯定,扣得越重

接下来的角色,是一张扣分表。它从不看过程,只看一件事:你分给正确答案多少信心。给九成,几乎不扣;给五成,小扣;给一成,重扣;如果以十足的把握说错,扣到没有上限。随口猜错没关系,斩钉截铁还错,代价最大。信心一共一百分,给错一分,就是从正确答案那里抢走一分。

扣分 = −log(分给正确的信心)
0.9 扣约 0.11 · 0.5 扣约 0.69 · 0.1 扣约 2.3。亲手拨一下。
信心 p = 0.50 → 扣分 = 0.69

衬衫认成 T恤,哪怕情有可原,照扣——扣分表不讲缘由,只认分错了多少。门口还贴一张光荣榜(猜对百分之几,叫准确率),那是给人看的;真正动手改,永远只看明细账。

注:L=−log py,p=softmax(z)。梯度为 p−ytrue,分错越多回传越强。准确率为监控指标,不参与求导。
五 · 改正

错一题,调一点分量

罚完就改。谁误导了判决,就调小它的分量;谁说对了,就调大;印象分也一起校准。往哪调、调多少,扣分明细里写得清清楚楚。动手的叫 Adam,步子很小,约千分之一,宁可多走五遍,不肯一步走偏。

model.compile(optimizer='adam',  # 动手的人,步子自适应
  loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
  metrics=['accuracy'])  # 明细用来改,光荣榜用来看

# 六万张从头看到尾叫一遍,共看五遍;每遍后检验一次,只打分不讲解
history = model.fit(train_images, train_labels, epochs=5, verbose=2,
  validation_data=(valid_images, valid_labels))

五遍下来,练习约对八成五,检验约对八成四。第一章那条“除以 255”的规矩,此刻显出意义:单位太大,笔太重,纸就破了。

注:更新式 W←W−η∇L。epoch = 完整遍历一次训练集;验证集恒不产生梯度。固定种子使结果可比,约 80%±2%。
六 · 新题

两条线,看出真懂还是死记

拿高分有两种办法:真懂了,或把练习册背下来。分辨只有一种办法:出新题。练习的线叫训练,检验的线叫验证——

两条线的走向结论
两条都变好真懂,可以去认没见过的衣服
练习变好、检验变差背答案,换题就露馅
两条都不动没学进去,回查单位、步子、结构

单看一件:十套分量各报一分,最高者当选。一次至少看一件,且要放在托盘里端上来(形状 1×28×28)。下图是某件衬衫的实时行情:T恤和衬衫两柱一样高——争得最凶的地方,恰恰也是你我分不清的地方:

示意。验证集前 500 件中挑 4 件错的并排看,多为衬衫↔T恤、外套↔裙子——直线分不开拐弯的袖子,这是下一章的伏笔。

别嫌八成不高。人也只有八成三四,四种上衣本来就难分。十个神经元做到这样,已经可以独立看店了。

七 · 长大

多一层眼光,分数就涨

原来的办法,一条直线看所有衣服,袖子拐个弯就跟不上了。如果加 64 道初选:每道先把整件衣服看一遍,不像的按下不表(归零),有点像的才递上去,十套分量只看初选的条子再定。这“按下不表”叫 ReLU;弯,就是从这里来的。

# 加一层初选,其余不变,学法也不变
model2 = tf.keras.Sequential([tf.keras.layers.Input(shape=(28,28)),
  tf.keras.layers.Flatten(), tf.keras.layers.Dense(64, activation='relu'),
  tf.keras.layers.Dense(10)])
# 分量 (784×64+64)+(64×10+10)=50890,不到1MB;分数约80%→87%

衣服还是那些衣服,改法还是那个改法,只是多了一层眼光,分数就涨。这就是“人多力量大”的雏形。

这个小大脑(亲手带大)下个大模型(直接请来)
分量7,850约 70 亿(约 90 万倍)
读过的东西六万张小照片万亿文字
代价笔记本几分钟数千张卡跑几周
你从零带起带不起,但请得起(约 4.7GB,接回来就能用)

式子写出来,两边原是一回事:叠起来的打分、同一张扣分表、同一种改法。大的,是小的长大;小的,是大的童年。带过小的,再请大的,你就知道它肚子里装的是什么了。

尾声 · 结业五问

答完就可以出师

一 · 为什么检验也要过同一杆秤?
秤不同,数不可比,分数就失真了。
二 · 7850 里哪十个是印象分?
每套分量一份,共十份;其余全是分量。
三 · 明细降了,光荣榜不动?
分得更准了,只是还没跨过判对的线;回查单位、步子、结构。
四 · 分数和百分比什么关系?
分数过 softmax 就是百分比,和为一百;比高低顺序一样,直接比分数就行。
五 · 什么是背答案?
练习涨、检验跌——把练习册背下来了,没真懂。

术语收束:张量 · 像素 · 标签 · 训练/验证 · 权重/偏置 · logits · softmax · 交叉熵 · 准确率 · 梯度/Adam/epoch · 泛化/过拟合 · ReLU。口径:7850 / 约80% / 50890。

输入课堂口令

本页为课后材料,需课堂口令进入