跳到主要内容

把真实世界装进张量:图像、CT、表格、时间序列与文字

这一章讲三件事: 五种最常见的数据各要怎么变成张量;类别数据为什么不能直接编个号;以及嵌入——全书第一次让「意思」变成「距离」的办法。 它在链条里的位置:第 02 章给了容器(张量),这一章把货装进去;第 04 章开始,这些装好的货就要进训练机器了。

1. 顶层全景与主走查:一张狗照片从硬盘走到模型门口

神经网络只吃一种饭:浮点张量。所以不管你手里是什么数据,都走同一条流水线1:

原始文件 → 读进来(某个库)→ 转成张量 → 摆成约定的布局 → 归一化数值范围
↑ 每种数据的差别只在头两步,后三步人人要做

图说:这一章就是这条流水线的五次过站。

空看这五个箭头是学不会的,所以先拿一个具体的东西从头走到尾——就用第 01 章那张狗照片,你已经认识它:720 行 × 1280 列的彩色 JPEG。

① 读进来
imageio 读出来是一个 720×1280×3 的数组:高 × 宽 × 通道(H×W×C),
三个通道分别是红、绿、蓝的强度,每个数管一个像素的一种颜色。
一共 720 × 1280 × 3 = 2764800 个数,每个是 0–255 的整数。
挑一个来跟着走:左上角那个像素的红色通道,值是 200。

② 摆布局:PyTorch 的图像模块要的是 C×H×W —— 通道在最前
img.permute(2, 0, 1) → 形状变成 3×720×1280
存储里一个数都没搬,只改了第 02 章那张「说明书」上的 stride:
改之前 (3840, 3, 1) ← 往下挪一行跳 3840 个数,换个通道跳 1 个
改之后 (1, 3840, 3) ← 换个通道跳 1 个,往下挪一行还是跳 3840 个
2764800 个数,复制了 0 个。

③ 加批量维:模型永远按「一批」算,单张图也要凑成一批
img.unsqueeze(0) → 形状 1×3×720×1280
这就是全书到处可见的 N×C×H×W;数还是那 2764800 个,又没动。

④ 归一化:整个张量除以 255,把 0–255 的整数压成 0–1 的小数
跟着走的那个 200 → 200 ÷ 255 = 0.784
这一步是全程唯一真的改动了每一个数的地方。

图说:形状 (720,1280,3) → (1,3,720,1280),数值 200 → 0.784。
第 ②③ 步是纯记账,第 ④ 步才动手。

(第 ② 步那两组 stride 是我们按第 02 章的规则算出来的——书里只写了「permute 不复制数据」,没印这两个数组。你可以自己验:一行有 1280 个像素、每像素 3 个数,所以往下挪一行是 1280×3=3840 个数2。)

第 ③ 步那个新加的维,叫批量(batch,一次一起送进模型算的那一组样本)。模型的第 0 维永远留给它,所以哪怕只有一张图,也得凑成「一组 1 个」——N×C×H×W 里的 N 就是它,这个形状你会在全书每一章见到3

换成别的数据,这条线只有一两步不一样——下面四节各走一支:

换成什么主走查的哪一步变了
CT 扫描第 ② 步多一维:一摞切片摞成一个体
表格第 ② 步换成「按列分三种数,类别那种要展开」
时间序列第 ② 步换成「重排」:把一长条按天切开再换序
文字第 ① 步最重:得先把连成串的字切成一块块,才谈得上变数

「约定的布局」不是洁癖:第 01 章已经见过,预处理必须和训练时一致;而布局就是预处理的一部分。全章我们只走到「喂给模型之前」为止——这是数据工程师的终点、研究者的起点1

2. 图像这一支的其余两件事:归一化怎么选,CT 多在哪

主走查第 ④ 步那个「除以 255」是最省事的一种归一化(把数值缩到约定范围)。网络在输入大致落在 0 到 1(或 −1 到 1)时训得最好,常用做法有两种4:

  • 除以 255:值域直接落到 0–1,跟着走的那个 200 变成 0.784。省事,但每张图各缩各的。
  • 减均值、除标准差:让每个通道变成「平均 0、波动 1」,行话叫标准化。第 01 章那三组固定的均值和标准差走的就是这一路——注意那三组数是在整个训练集上算的,不是这一张图上算的。

为什么非要折腾这一步,第 04 章会用一次真实的训练事故讲透。

CT 扫描(医学上那种断层扫描)在这条流水线上只改第 ② 步:一张张二维切片沿头到脚的方向码成一摞,得到一个三维体;强度值大致对应组织密度——空气黑、骨头白。数据天然没有通道维,用 unsqueeze 补一个;加上批量维,就是 N×C×D×H×W 的五维张量5。狗照片是 1×3×720×1280 的四维,CT 比它多出来的那一维,是「第几张切片」。这个五维形态到第 12 章的肺癌项目就是主角。

3. 表格:先分清三种数

一张 CSV(逗号分隔的纯文本表格,Excel 能直接打开)表(书里用的是葡萄牙白酒的化学分析数据集,4898 行 × 12 列:11 个化学测量值 + 一个 0–10 的感官评分)读成张量只要几行代码。真正的坑不在读,在于列和列不是同一种数6:

种类例子能干什么
连续值气温、价格差值有意义:25℃−20℃ = 35℃−30℃
序数值小/中/大杯只有大小有意义;「大杯+小杯÷2=中杯」不成立
类别值水/咖啡/苏打/牛奶连大小都没有:编号纯粹是为了区分

这张表为什么性命攸关:类别值如果直接编号(水=1,咖啡=2,牛奶=4),你就向模型谎称了「牛奶是咖啡的两倍」——模型会把编号当大小来用。正确做法是把每个类别展开成一个「只有一个 1、其余全 0」的向量,叫 one-hot 编码(独热编码):10 个评分等级就展开成长度 10 的向量,评分 5 是 [0,0,0,0,1,0,0,0,0,0]7。在 PyTorch 里用 scatter_(按索引把 1 撒进全零张量)一行写完。

书里接着做了一个漂亮的对照实验:拿「总二氧化硫」一列手划一条阈值(141.83)来猜好酒坏酒,结果——猜中的酒里 74% 真的好,但真正的好酒只找回了 61%8单特征、单阈值的天花板就这么高。 记住这两个数:第 04 章之后,「让全部 11 个特征一起参与决策」就是神经网络要干的事。

4. 时间序列:重排,一个数都不动

共享单车数据集:华盛顿特区 2011–2012 年,每小时一行——天气、气温、湿度、租车数,共 17520 行 × 17 列。

想让模型按「天」看问题,就得把这张 2D 表重排成 3D:730 天 × 17 个变量(表格里的一列,每次测量取一个值) × 每天 24 小时。做法是第 02 章那套说明书把戏:view(730, 24, 17) 先按 24 小时一捆切开(纯改 stride,零复制),再 transpose(1, 2) 把「小时」和「变量」两维换序9。书里把 stride 的变化也打印出来了:原来沿行走一步跳 17 格,重排后沿「天」走一格跳 408 格(17×24)——一个数都没有被搬动

这一节的隐藏知识点:有顺序的数据给了我们利用「因果」的机会(早上下雨影响下午租车),但怎么把顺序喂给模型是模型侧的事,第 10 章再说。

5. 文字:先切碎,再变成数

文字是本章的高潮,因为它把一个真问题摆到桌面上:词有几十万个,one-hot 装不下。

第一步:切碎

书里的素材是《傲慢与偏见》。先看最低一档的切法——按字符切:一句话 70 个字符,每个字符按 ASCII 码(一个 1960 年代的 128 字符编码表)one-hot 成 128 维向量10

再往上是按词切:先建一本「词→编号」的词典(这本书全文去重后 7261 个词),再 one-hot。这一支的走查用这一句:「Impossible, Mr. Bennet, …」清洗后 11 个词,「impossible」查到编号 3394,于是一句话变成 11×7261 的矩阵,每行只有一个 111

问题立刻就来了:7261 已经是一本书的词表(能认的全部不同词的清单),而通用英语词表是这个的几十倍。 每多一个新词,向量就要多一维、模型就要多一列参数——这条路根本长不大12

真实系统用的是折中的切法:常见的词整词保留,罕见的拆成片段(书里演示了「Impossible」被切成 ▁Im|pos|s|ible),清单长度可控。这套切法叫字节对编码(BPE,从单字开始、反复把最常相邻的一对并进词表);切出来的每一小段,行话叫标记(token)——它是模型眼里文字的最小单位,可能是一个词,也可能是半个词12

第二步:从 one-hot 到嵌入

换掉 one-hot 的思路一句话:不再用「7261 维里一个 1」,改用「100 维的一串浮点数」表示一个词。 这样表示一个词的方法叫嵌入(embedding)——把词「嵌」进一个 100 维的空间里13

为什么这就够了?100 维听起来少,但它是 100 个可以连续取值的浮点数,组合空间是天文数字;而且——这是关键——可以让意思相近的词,嵌入也相近。书里用手工搭的 2 维嵌入演示:横轴是「水果—花—狗」,纵轴是颜色,于是苹果落在(水果,红),玫瑰落在(花,红)……15 个词各就各位14。真实嵌入不靠手搭:拿海量文本训一个小网络去「根据上下文(一个词前后出现的文字)猜这个词」,训完,常出现在同类上下文里的词自然就靠到了一起——鳄鱼和短吻鳄挨着,芜菁和鹰远着。

这一步是全书第一次出现「意思变成距离」: 嵌入之后,「两个词意思近不近」变成了「两串数离得远不远」——机器终于能对「意思」做计算了。它还附带一个著名彩蛋:嵌入空间里可以做类比运算,「苹果 − 红 − 甜 + 黄 + 酸 ≈ 柠檬」15

技术上,嵌入可以看作 one-hot 向量乘上一个「词表长度 × 嵌入维度(一个向量有几个分量,就说它有几维)」的矩阵——查表和矩阵乘是同一个动作的两种看法13。 而这张表本身是可训练的参数。它可以从随机数开始、跟你的任务一起学;也可以先拿别人在海量文本上训好的一份,再在你自己的数据上接着调——这种「拿现成训好的接着训」的做法叫微调(fine-tuning)。第 15 章会拿微调当整章的主角16

6. 作者的判断与证据

说法性质
五种数据的布局与读法(N×C×H×W、N×C×D×H×W、N×C×L)有据,全部带可运行的代码和打印出的形状
三种数值的划分(连续/序数/类别)统计学标准概念,书里给了原典口径(ratio/interval/nominal scale)6
「硫阈值 74%/61%,barely better than random」有据,4898 行数据上算出来的8
「嵌入能让意思相近的词相近、支持类比运算」方向正确,书里引了 word2vec 但没展开算法;当作「已被广泛验证的领域共识」接受15
「嵌入维度 100–1000」2010 年代词嵌入(每个词对应的那串浮点数)的典型值;今天大模型内部用得比这大得多(补充:来自通用知识,书里没写今天的数值)

7. 边界与局限

  • 本章每节都停在「喂给模型之前」;「喂进去之后模型怎么消化」是第 04–08 章的事
  • one-hot 章节只演示了字符级和词级;真实系统的 BPE 切分本书只在专栏里点到,第 10 章会真正训练一个 tokenizer。
  • 时间序列一节只做了重排,没有建模;「顺序怎么用」欠着,第 10 章还。
  • 音频、视频书里有配套 notebook 但正文没展开17;医学影像的工程细节(DICOM 格式)留到了第 12 章。

8. 可带走的

  1. 所有数据共用一条流水线:读进来 → 转张量 → 摆布局 → 归一化;布局约定(N×C×H×W)是预处理的一部分,必须和模型训练时一致。
  2. CT 体数据只是多一维:N×C×D×H×W;没有通道维就用 unsqueeze 补一个。
  3. 先分清连续/序数/类别三种数,再决定编码;类别值直接编号 = 向模型谎称大小关系。
  4. one-hot 把类别展开成「一个 1 其余 0」的向量;scatter_ 一行搞定。
  5. 单特征单阈值的天花板:74% 的命中率、61% 的找回率——这是「为什么需要模型」的最小实锤。
  6. 重排时间序列不用动数据:view + transpose 只改说明书。
  7. 文字先切碎成标记(token),再编码;词级 one-hot 会随词表爆炸,BPE 用「常见整词、罕见拆段」把词表压住。
  8. 嵌入 = 用一串浮点数代替一个 1;意思相近 → 向量相近,「意思」从此可算。
  9. 嵌入表是参数:可以用别人训好的再微调,也可以从随机开始一起学。

9. 原文地图

主题原书章原文位置
共同流水线、停在喂模型之前ch4text/12-ch04-4-real-world-data-representation-using-tensors.txt:47(搜「before feeding the data to a model」)
图像布局 C×H×W、permutech4text/12-ch04-4-real-world-data-representation-using-tensors.txt:115(搜「C × H × W」) · :131(搜「does not make a copy」)
归一化两种做法ch4text/12-ch04-4-real-world-data-representation-using-tensors.txt:184(搜「zero mean and unit standard deviation」)
CT 五维与 unsqueezech4text/12-ch04-4-real-world-data-representation-using-tensors.txt:236(搜「N × C × D × H × W」)
三种数值ch4text/12-ch04-4-real-world-data-representation-using-tensors.txt:414(搜「Continuous, ordinal, and categorical」)
one-hot 与 scatter_ch4text/12-ch04-4-real-world-data-representation-using-tensors.txt:490(搜「one-hot encoding」)
硫阈值 74%/61%ch4text/12-ch04-4-real-world-data-representation-using-tensors.txt:735(搜「74%」) · :738(搜「barely better than random」)
自行车时间序列重排ch4text/12-ch04-4-real-world-data-representation-using-tensors.txt:912(搜「view(-1, 24」) · :935(搜「408」)
字符/词 one-hot、7261 词表ch4text/12-ch04-4-real-world-data-representation-using-tensors.txt:1161(搜「Impossible」) · :1228(搜「7261」)
BPE 切分ch4text/12-ch04-4-real-world-data-representation-using-tensors.txt:1271(搜「byte pair encoding」)
嵌入定义与手工 2D 例子ch4text/12-ch04-4-real-world-data-representation-using-tensors.txt:446(搜「embedding」) · :1345(搜「fruit」)
类比运算、嵌入=矩阵乘ch4text/12-ch04-4-real-world-data-representation-using-tensors.txt:1399(搜「analogies」) · :1413(搜「multiplication with the matrix」)
微调一词ch4text/12-ch04-4-real-world-data-representation-using-tensors.txt:1421(搜「fine-tuning」)

Footnotes

  1. 出处:「4 Real-world data representation using tensors」第 47 段(text/12-ch04-4-real-world-data-representation-using-tensors.txt:47,搜「before feeding the data to a model」)。原文:「每一节我们都会停在深度学习研究者起步的地方:就在把数据喂给模型之前。」 2

  2. 出处:「4 Real-world data representation using tensors」第 115 段(text/12-ch04-4-real-world-data-representation-using-tensors.txt:115,搜「C × H × W」)与第 131 段(:131,搜「does not make a copy」)。PyTorch 的图像模块要求 C×H×W;permute 只动 size/stride 信息,不复制数据。

  3. 出处:「4 Real-world data representation using tensors」第 143 段(text/12-ch04-4-real-world-data-representation-using-tensors.txt:143,搜「N × C × H × W」)。多图数据集沿第一维堆出批量维。

  4. 出处:「4 Real-world data representation using tensors」第 184 段(text/12-ch04-4-real-world-data-representation-using-tensors.txt:184,搜「zero mean and unit standard deviation」)。除以 255,或减均值除标准差(标准化);网络在输入约 0–1 或 −1–1 时训练表现最好。

  5. 出处:「4 Real-world data representation using tensors」第 236 段(text/12-ch04-4-real-world-data-representation-using-tensors.txt:236,搜「N × C × D × H × W」)。体数据比图像多一个深度维;CT 强度对应密度,从肺到骨由暗到亮。

  6. 出处:「4 Real-world data representation using tensors」第 414 段(text/12-ch04-4-real-world-data-representation-using-tensors.txt:414,搜「Continuous, ordinal, and categorical」)。三类值的原典划分:连续值再分 ratio/interval 尺度,类别值是 nominal 尺度;「给大杯=3、小杯=1 求平均,不会得到中杯」。 2

  7. 出处:「4 Real-world data representation using tensors」第 490 段(text/12-ch04-4-real-world-data-representation-using-tensors.txt:490,搜「one-hot encoding」)与第 511 段(:511,搜「scatter_」)。评分 5 → (0,0,0,0,1,0,0,0,0,0);scatter_ 按标签索引把 1.0 撒进全零张量。

  8. 出处:「4 Real-world data representation using tensors」第 735 段(text/12-ch04-4-real-world-data-representation-using-tensors.txt:735,搜「74%」)与第 738 段(:738,搜「barely better than random」)。阈值法:预测为好的酒里 74% 真好,真好的酒只找回 61%;作者评:「也就比瞎猜强一点」。 2

  9. 出处:「4 Real-world data representation using tensors」第 912 段(text/12-ch04-4-real-world-data-representation-using-tensors.txt:912,搜「view(-1, 24」)与第 935 段(:935,搜「408」)。view 重排不复制;沿天走一格在存储里跳 408=17×24 个元素。

  10. 出处:「4 Real-world data representation using tensors」第 1126 段(text/12-ch04-4-real-world-data-representation-using-tensors.txt:1126,搜「ASCII」)。ASCII 用 128 个整数编 128 个字符,1960 年代的标准;Unicode/UTF-8 的说明在同段注记。

  11. 出处:「4 Real-world data representation using tensors」第 1161 段(text/12-ch04-4-real-world-data-representation-using-tensors.txt:1161,搜「Impossible」)与第 1228 段(:1228,搜「7261」)。一句话 11 个词;全书词表 7261 个,「impossible」的编号是 3394。

  12. 出处:「4 Real-world data representation using tensors」第 1271 段(text/12-ch04-4-real-world-data-representation-using-tensors.txt:1271,搜「byte pair encoding」)。词表一大 one-hot 就崩;BPE 从单字符开始迭代合并最常见相邻对,直到词表达到预定大小。 2

  13. 出处:「4 Real-world data representation using tensors」第 446 段(text/12-ch04-4-real-world-data-representation-using-tensors.txt:446,搜「embedding」)与第 1413 段(:1413,搜「multiplication with the matrix」)。嵌入 = 用浮点向量替代一坨零一个 1;等价于 one-hot 乘上嵌入矩阵。 2

  14. 出处:「4 Real-world data representation using tensors」第 1345 段(text/12-ch04-4-real-world-data-representation-using-tensors.txt:1345,搜「fruit」)。手工 2D 嵌入:一轴水果/花/狗、一轴颜色,15 个词各就各位。

  15. 出处:「4 Real-world data representation using tensors」第 1399 段(text/12-ch04-4-real-world-data-representation-using-tensors.txt:1399,搜「analogies」)。类比例:apple − red − sweet + yellow + sour ≈ lemon;嵌入常由「从上下文预测词」的小网络训出。 2

  16. 出处:「4 Real-world data representation using tensors」第 1421 段(text/12-ch04-4-real-world-data-representation-using-tensors.txt:1421,搜「fine-tuning」)。原文首次给出 fine-tuning 一词:在手头任务上继续改进预训练好的嵌入。

  17. 出处:「4 Real-world data representation using tensors」第 1436 段(text/12-ch04-4-real-world-data-representation-using-tensors.txt:1436,搜「bonus Jupyter」)。音频、视频的张量构造放在书的配套 notebook 里。