🧠 第六章 自然语言处理
📄 一句话概括

同一句话在字符层要 33000 个数(11 个码位各一个 3000 维 one-hot),词层 56000 个, 句法层只要 9 个标签,语义层 8 个实数。从 33000 压到 8,压了 4125 倍。

📝 本节和前面几节的关系

上一节说了「一句话进来要变成什么」,这一节把这四种「变成」摊开看,比一比它们各要多少个数、 各丢掉了什么。

一、四层表示,四种代价

同一句话可以停在四个层面上表示,越往下越抽象,越抽象越省地方: 1. 字符层。11 个码位,每个用 3000 维 one-hot。合计 33000 个数。 2. 词层。7 个词,每个用 8000 维 one-hot。合计 56000 个数。 3. 句法层。3 条依存边,每条 3 个标签。合计 9 个数。 4. 语义层。1 个句向量,8 维。合计 8 个数。 注意词层比字符层还大:词表比字表长,词又比字少得不够多,一乘反而涨了。 这就是 one-hot 的毛病——它不带任何相似性信息。

二、句法层:三条边就说清了谁修饰谁

Demo 里的三条边是:拍 用 手机、拍 拍 照片、拍 施事 小明。 这三条边表达的信息,比 7 个词的顺序多得多:它说清了「拍」是中心,手机是工具,照片是对象, 小明是施事。 而全部成本只有 9 个数。这就是结构化表示的威力——它把人能看懂的关系直接写成了数据。 代价是要有人(或一个句法分析器)把树建出来。建错了,后面全错。 所以现在很少有人手工建树,都让模型自己学。

三、语义层:8 个数代表一整句

Demo 的 8 维向量是我手工定的:前六维分别是拍照、天气、工具、室内、人物、静物,后两维填零占位。 本句和「他用相机拍了几张照片」的余弦是 0.989——几乎一样,因为两句都是「人用工具拍东西」。 和「今天天气很好」的余弦只有 0.229。差得很干净。 这 8 个数是我拍的,不是学出来的。 所以它准不准,取决于我定的维度对不对——这正是「表示学习」要解决的问题:让人定维度,改成让数据定。

四、4125 倍是怎么来的

33000 除以 8,得 4125。这个数字好看,但要看清它压掉了什么。 字符层保留了全部字面,一个字都没丢; 语义层只保留「说的是拍照」这件事,具体用了什么词、什么句式,全没了。 所以压缩不是白来的:你要什么,就留什么。要字面相似度,别用语义向量;要抗同义改写,别用字符。 真正难的不是压,是「压完之后还够用」。这件事没有通用答案,只能按下游任务试。

五、动手 Demo:一句话在四层上的表示与成本

同一句话分别按字符、词、依存句法、语义向量四种方式表示,打出每层要多少个数;把三条依存边列出来; 再用两个手工定的 8 维句向量和本句算余弦,最后算字符层到语义层的压缩倍数。

V_CHAR, V_WORD = 3000, 8000          # 假设的字表、词表大小

cost_char = len(s) * V_CHAR          # 11 × 3000
cost_word = len(ws) * V_WORD         # 7 × 8000
cost_dep = 3 * 3                     # 3 条边 × 3 个标签
cost_sem = 8                         # 1 个 8 维向量

实跑输出:

--------------------------------------------------------------------
语言学与计算机科学的交汇:一句话在四层上的表示
--------------------------------------------------------------------
  层       单元数              表示形式   元素个数
  -----------------------------------------------
  字符层   11 个码位    one-hot 3000 维      33000
  词层     7 个词       one-hot 8000 维      56000
  句法层   3 条依存边     每条 3 个标签          9
  语义层   1 个句向量          8 维实数          8

  句法层的三条边:
  中心词   关系   依存词
  ---------------------
  拍       用     手机
  拍       拍     照片
  拍       施事   小明

  语义层的 8 维向量(手工定的六个维度加两个填充):
  本句                     [0.8, 0.1, 0.9, 0.2, 0.7, 0.3, 0.0, 0.0]
  他用相机拍了几张照片     [0.7, 0.2, 0.9, 0.1, 0.6, 0.4, 0.0, 0.0]
  今天天气很好             [0.1, 0.9, 0.0, 0.8, 0.1, 0.0, 0.0, 0.0]
  本句 vs 拍照那句         0.989
  本句 vs 天气那句         0.229

  字符层元素个数           33000
  语义层元素个数           8
  压缩倍数                 4125 倍
  从 33000 个数压到 8 个数,还不丢「说的是拍照」这件事——这就是表示学习要干的活。

第一张表最扎眼的是词层 56000 比字符层 33000 还大。 这不是错,是 one-hot 的必然结果:维度等于表大小。 句法层只要 9 个数,却把「谁修饰谁」说清了。这说明表示的好坏不看长度,看它装没装关系。 两个语义余弦 0.989 和 0.229 差距很大,但这个向量是我手写的六维打分, 不是学出来的——它能拉开差距,是因为维度是我照着这两句的差别定的,属于自证。 最后一行的 4125 倍,是字符层个数除以语义层个数。 这个倍数只说明「省了多少」,不说明「丢了多少」。

30 秒实验

  1. 把字表假设成 6000 维,重跑,看压缩倍数变成多少。
  2. 给句子再加一条依存边,看句法层成本从 9 变成多少。
  3. 想一想:为什么 one-hot 表示不出「手机」和「相机」很像?

常见误区

  1. 「层数越深表示越好」——每一层丢的东西不同,选错层下游就废。
  2. 「词表示一定比字表示小」——one-hot 下词层反而更大。
  3. 「压缩越多越先进」——压掉的可能是任务正需要的信息。
自测三问(点开对答案) 1. 为什么词层的 one-hot 总量会比字符层还大? —— 维度等于表大小,词表比字表长得多,词数又没少到能抵消。 2. 句法层只花 9 个数就表达了什么? —— 三条依存边,说清中心词、关系、依存词,也就是谁修饰谁。 3. 从 33000 压到 8,压缩的代价是什么? —— 字面和句式全丢了,只剩一个粗粒度的语义方向。

四层看完了,下一节比两条技术路线:手工特征的老路和端到端的新路。

相关笔记