照片放大之后,都是格子
打开手机相册,把一张衣服的照片不断放大,边缘会碎成一个个小方格。这里的每一张图,一出生就是碎好的: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
十件衣服,十个编号
文字太长,数字最快。T恤是 0,衬衫是 6,短靴是 9——看到照片,报出编号,这就是它的全部考题,叫标签。
| 编号 | 衣服 | 难易 |
|---|---|---|
| 0 / 2 / 4 / 6 | T恤 · 毛衣 · 外套 · 衬衫 | 最难认,都是上衣 |
| 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,还不到一张手机照片大。拨动看看:
总数 = ≈ 30.7KB
错得越肯定,扣得越重
接下来的角色,是一张扣分表。它从不看过程,只看一件事:你分给正确答案多少信心。给九成,几乎不扣;给五成,小扣;给一成,重扣;如果以十足的把握说错,扣到没有上限。随口猜错没关系,斩钉截铁还错,代价最大。信心一共一百分,给错一分,就是从正确答案那里抢走一分。
0.9 扣约 0.11 · 0.5 扣约 0.69 · 0.1 扣约 2.3。亲手拨一下。
衬衫认成 T恤,哪怕情有可原,照扣——扣分表不讲缘由,只认分错了多少。门口还贴一张光荣榜(猜对百分之几,叫准确率),那是给人看的;真正动手改,永远只看明细账。
错一题,调一点分量
罚完就改。谁误导了判决,就调小它的分量;谁说对了,就调大;印象分也一起校准。往哪调、调多少,扣分明细里写得清清楚楚。动手的叫 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”的规矩,此刻显出意义:单位太大,笔太重,纸就破了。
两条线,看出真懂还是死记
拿高分有两种办法:真懂了,或把练习册背下来。分辨只有一种办法:出新题。练习的线叫训练,检验的线叫验证——
| 两条线的走向 | 结论 |
|---|---|
| 两条都变好 | 真懂,可以去认没见过的衣服 |
| 练习变好、检验变差 | 背答案,换题就露馅 |
| 两条都不动 | 没学进去,回查单位、步子、结构 |
单看一件:十套分量各报一分,最高者当选。一次至少看一件,且要放在托盘里端上来(形状 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,接回来就能用) |
式子写出来,两边原是一回事:叠起来的打分、同一张扣分表、同一种改法。大的,是小的长大;小的,是大的童年。带过小的,再请大的,你就知道它肚子里装的是什么了。
答完就可以出师
术语收束:张量 · 像素 · 标签 · 训练/验证 · 权重/偏置 · logits · softmax · 交叉熵 · 准确率 · 梯度/Adam/epoch · 泛化/过拟合 · ReLU。口径:7850 / 约80% / 50890。