文字是怎么变成数字的?把embedding词向量原理聊明白

深夜两点,电脑屏幕上是一段不算长的返回数据。我数了数,几百个密密麻麻的小数,排成一行,每个都精确到小数点后四位,像一串没有规律的气象观测记录。
这是某家大模型API的一次普通调用。我的请求是一句中文,接口除了返回生成结果,还附带了一段这样的向量数据。我盯着那些数字看了很久,忽然意识到一个容易被忽略的事实:从模型的角度看,它从头到尾没有"读"过我那句话。文字在它眼里,本来就是数字。
那文字到底是怎么变成数字的?这件事的来龙去脉,比想象中要有意思。
先说一种比较朴素的方案。要让计算机处理文字,得先给每个字一个编号,这件事叫编码。Unicode给全球几乎所有文字都编了号,"你"是某个数,"好"是另一个数。但编号是随意的——"苹果"和"香蕉"的编号差多远,跟它们是不是水果毫无关系。拿编号做计算,计算机分不清"苹果"和"拖拉机"哪个跟"香蕉"更接近。
后来有人想出一个办法:one-hot编码,也叫独热编码。把每个词表示成一个超长的向量,这个词所在的位置是1,其余全是0。"苹果"长成[0,1,0,0,...]这种样子,"香蕉"长成[0,0,0,1,...]。每个词总算有了自己的"位置",但问题更扎眼——词汇量几万,向量维度就几万,每个词只有一个位置是1,剩下全是0,数据又大又空。更要命的是,"苹果"和"香蕉"的向量距离,跟"苹果"和"拖拉机"的向量距离一模一样,都是两个互不相干的1。语义信息一点没带进去。
真正让局面改变的,是"词向量"这个概念——把每个词压进一个低维的稠密空间里,比如三百维,用一串实数表示它。关键不在数字本身,而在这些数字构成的位置:语义相近的词,在空间里离得近。
这个思路可以追溯到上世纪八十年代的分布式表示理论,但真正把它带火的是2013年Google开源的word2vec。名字起得很直白——把word变成vec(向量)。
word2vec有个流传很广的经典结果:king(国王)减去man(男人)加上woman(女人),得到的向量恰好落在queen(女王)附近。"巴黎"减"法国"加"意大利",会靠近"罗马"。也就是说,这些数字不光记住了词,还隐约记住了词与词之间的关系,像把一部词典压缩进了几何空间。
当年看到这个结果的时候我挺震撼。文字和文字之间的关系,居然能被翻译成向量之间的加减法。
不过早期的词向量有个硬伤:一个词只有一个固定的向量,管你什么语境。今天"苹果"既指水果又指手机品牌,向量却只有一个,模型只好把两个意思揉在一起,谁多谁少取决于训练数据里哪个意思出现得更频繁。
后来学界换了个更聪明的思路:让词的向量跟着语境走。2018年的ELMo模型用双向语言模型动态生成词向量,同样是"苹果",在"削苹果"和"买苹果手机"两句话里,向量长得不一样。再往后BERT干脆把"词"的粒度拆得更碎,用比词更小的子词单位做表征,上下文信息融进每一层计算里。这一套,就是今天大模型共同的地基。
回到开头那串小数点。那些数字不是模型随手写的,是文字经过层层变换之后,在高维空间里的坐标。每一维具体代表什么,人很难直接看懂——可能是"跟科技话题相关的程度",可能是"偏向动作还是偏向名词",也可能是模型自己从数据里长出来的、叫不上名字的某种特征。几百个维度叠在一起,就构成了一句话在机器世界里的模样。
理解这件事之后,再看大模型的各种表现,心态会稳很多。它之所以接得住五花八门的问题,靠的不是背答案,而是把文字翻译成了它能计算的东西。那些小数点看着冷冰冰,却是文字在数字世界里仅有的存在方式。下次再看到API返回一大串数字,你大概就知道了,那是你的话在另一个空间里留下的坐标。
