从文字到向量:Transformer的语言数字化之旅

一、什么是向量化?

核心定义

向量化是将离散的符号(如文字)转换为连续的数值向量的过程。在深度学习中,它把人类可读的文本转换成计算机能够理解和处理的数学表示。

生动比喻:语言翻译成数学坐标

想象每个词在一个高维空间中的位置:

  • 传统词典:用文字解释文字
  • 向量空间:用数学坐标精确定位每个词的含义
"国王" → [0.8, -0.2, 0.5, 0.1, ...]
"皇后" → [0.7, -0.3, 0.6, 0.2, ...]
"男人" → [0.6, 0.1, 0.3, -0.4, ...]
"女人" → [0.5, 0.2, 0.4, -0.3, ...]

向量化的神奇特性

image


二、从文字到向量化的完整过程

整体流程概览

image

步骤1:分词 - 文本的"原子化"

基本分词方法

# 原始文本
text = "I love natural language processing!"
# 简单空格分词
tokens = text.split()
print(tokens)  # ['I', 'love', 'natural', 'language', 'processing!']
# 实际使用分词器
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
tokens = tokenizer.tokenize(text)
print(tokens)  # ['i', 'love', 'natural', 'language', 'processing', '!']

不同分词策略对比

分词方法

示例输入

输出结果

优缺点

单词级

"I'm learning NLP"

["I'm", "learning", "NLP"]

词汇表大,OOV问题

子词级

"I'm learning NLP"

["I", "'", "m", "learn", "##ing", "NL", "##P"]

平衡词汇表与OOV

字符级

"I'm learning NLP"

["I", "'", "m", " ", "l", "e", ...]

词汇表小,序列长

分词粒度比喻:乐高积木组装

  • 单词级:使用完整的大型积木块
    • 优点:表达完整,组合简单
    • 缺点:需要大量存储空间,缺少灵活性
  • 子词级:使用标准尺寸的中型积木
    • 优点:灵活组合,经济高效
    • 缺点:需要学习组合规则
  • 字符级:使用最小的基础积木单元
    • 优点:极简存储,无限组合
    • 缺点:组装复杂,效率较低

步骤2:构建词汇表 - 创建"词库字典"

词汇表构建过程

# 假设我们有训练语料
corpus = [
    "I love machine learning",
    "Deep learning is amazing", 
    "Natural language processing transforms AI"
]
# 构建词汇表
vocab = {}
for sentence in corpus:
    tokens = sentence.lower().split()
    for token in tokens:
        vocab[token] = vocab.get(token, 0) + 1
# 按频率排序并分配ID
sorted_vocab = sorted(vocab.items(), key=lambda x: x[1], reverse=True)
vocab_with_ids = {word: idx for idx, (word, _) in enumerate(sorted_vocab)}
print("词汇表:", vocab_with_ids)
# 输出: {'learning': 0, 'i': 1, 'love': 2, 'machine': 3, 
#        'deep': 4, 'is': 5, 'amazing': 6, 'natural': 7, 
#        'language': 8, 'processing': 9, 'transforms': 10, 'ai': 11}

实际Transformer词汇表示例

# BERT-base的词汇表大小
vocab_size = 30522  # 包含30522个token
# GPT-3的词汇表大小  
gpt3_vocab_size = 50257  # 包含50257个token
# 实际使用中的token到ID映射
token_ids = tokenizer.encode("Hello world!")
print("Token IDs:", token_ids)  # [101, 7592, 2088, 102]
# 反向解码
decoded_text = tokenizer.decode([101, 7592, 2088, 102])
print("Decoded:", decoded_text)  # "[CLS] hello world! [SEP]"

步骤3:词嵌入 - 从离散到连续的魔法

词嵌入的核心思想

词嵌入将离散的token ID映射到连续的向量空间:

离散ID: [101, 7592, 2088, 102] 
     ↓ 嵌入矩阵查找
连续向量: 
    [0.1, 0.4, -0.2, ..., 0.8]   # CLS token
    [0.3, -0.1, 0.5, ..., 0.2]   # "hello" 
    [-0.2, 0.6, 0.1, ..., -0.3]  # "world"
    [0.4, 0.2, -0.3, ..., 0.6]   # SEP token

代码实现词嵌入层

import torch
import torch.nn as nn
import numpy as np
class TokenEmbedding(nn.Module):
    def __init__(self, vocab_size, embedding_dim):
        super().__init__()
        self.embedding = nn.Embedding(vocab_size, embedding_dim)
        
    def forward(self, token_ids):
        # token_ids: [batch_size, seq_len]
        # 返回: [batch_size, seq_len, embedding_dim]
        return self.embedding(token_ids)
# 实际使用示例
vocab_size = 50000
embedding_dim = 512  # 常见维度: 512, 768, 1024
embedding_layer = TokenEmbedding(vocab_size, embedding_dim)
# 输入: 批次大小为2, 序列长度为5
input_ids = torch.tensor([
    [101, 7592, 2088, 102, 0],   # 句子1
    [101, 4875, 2031, 102, 0]    # 句子2
])
# 获取词嵌入
word_embeddings = embedding_layer(input_ids)
print("嵌入形状:", word_embeddings.shape)  # torch.Size([2, 5, 512])

词嵌入的可视化理解

image

词向量的语义特性

经过训练后,词向量会捕捉丰富的语义关系:

# 语义关系的向量运算示例
def analogical_reasoning(embedding_layer, word1, word2, word3, word_to_id):
    # 获取词向量
    vec1 = embedding_layer(torch.tensor([word_to_id[word1]]))
    vec2 = embedding_layer(torch.tensor([word_to_id[word2]])) 
    vec3 = embedding_layer(torch.tensor([word_to_id[word3]]))
    
    # 类比推理: king - man + woman ≈ queen
    result_vector = vec1 - vec2 + vec3
    
    # 在实际中,我们会计算与所有词向量的相似度
    # 找到最接近的结果词
    return result_vector
# 实际中,这种语义关系是通过大规模训练自然涌现的

步骤4:位置编码 - 注入顺序信息

为什么需要位置编码?

由于Transformer的自注意力机制是置换不变的(打乱输入顺序可能得到相同输出),需要显式注入位置信息。

正弦位置编码

import math
def sinusoidal_positional_encoding(seq_len, d_model):
    """
    生成正弦位置编码
    seq_len: 序列长度
    d_model: 模型维度(嵌入维度)
    """
    position = torch.arange(seq_len).unsqueeze(1)
    div_term = torch.exp(torch.arange(0, d_model, 2) * 
                        -(math.log(10000.0) / d_model))
    
    pe = torch.zeros(seq_len, d_model)
    pe[:, 0::2] = torch.sin(position * div_term)  # 偶数维度
    pe[:, 1::2] = torch.cos(position * div_term)  # 奇数维度
    
    return pe
# 示例:生成长度为10,维度为512的位置编码
pos_encoding = sinusoidal_positional_encoding(10, 512)
print("位置编码形状:", pos_encoding.shape)  # torch.Size([10, 512])

位置编码的可视化

image

完整的位置感知嵌入

class TransformerInputEmbedding(nn.Module):
    def __init__(self, vocab_size, d_model, max_seq_len=512):
        super().__init__()
        self.token_embedding = nn.Embedding(vocab_size, d_model)
        self.position_embedding = nn.Parameter(
            torch.zeros(1, max_seq_len, d_model)
        )
        self.layer_norm = nn.LayerNorm(d_model)
        self.dropout = nn.Dropout(0.1)
        
    def forward(self, token_ids):
        # 词嵌入
        token_embeddings = self.token_embedding(token_ids)
        
        # 位置嵌入(截取到实际序列长度)
        seq_len = token_ids.size(1)
        position_embeddings = self.position_embedding[:, :seq_len, :]
        
        # 相加并归一化
        embeddings = token_embeddings + position_embeddings
        embeddings = self.layer_norm(embeddings)
        embeddings = self.dropout(embeddings)
        
        return embeddings

步骤5:完整流程代码示例

import torch
import torch.nn as nn
class CompleteTextToVector(nn.Module):
    def __init__(self, vocab_size, d_model=512, max_seq_len=512):
        super().__init__()
        self.d_model = d_model
        
        # 1. 词嵌入层
        self.token_embedding = nn.Embedding(vocab_size, d_model)
        
        # 2. 位置编码(可学习或正弦)
        self.position_embedding = nn.Parameter(
            torch.randn(1, max_seq_len, d_model)
        )
        
        # 3. 层归一化和dropout
        self.layer_norm = nn.LayerNorm(d_model)
        self.dropout = nn.Dropout(0.1)
    
    def forward(self, input_ids):
        batch_size, seq_len = input_ids.shape
        
        # 词嵌入查找
        token_embeds = self.token_embedding(input_ids)  # [batch, seq_len, d_model]
        
        # 添加位置信息
        position_embeds = self.position_embedding[:, :seq_len, :]
        embeddings = token_embeds + position_embeds
        
        # 归一化和正则化
        embeddings = self.layer_norm(embeddings)
        embeddings = self.dropout(embeddings)
        
        return embeddings
# 使用示例
vocab_size = 50000
model = CompleteTextToVector(vocab_size)
# 模拟输入:批次大小=2, 序列长度=8
input_ids = torch.randint(0, vocab_size, (2, 8))
# 转换为向量
output_vectors = model(input_ids)
print("输入形状:", input_ids.shape)      # torch.Size([2, 8])
print("输出形状:", output_vectors.shape) # torch.Size([2, 8, 512])

三、不同嵌入策略的对比

静态vs动态词嵌入

image

对比表格

特性

传统静态嵌入

Transformer动态嵌入

上下文处理

每个词固定向量

根据上下文动态调整

多义词处理

一个向量表示所有含义

不同上下文不同向量

训练方式

预训练后固定

端到端联合训练

示例

Word2Vec, GloVe

BERT, GPT, T5

向量质量

"bank"只有一个向量

"river bank"和"money bank"向量不同

四、向量化的意义与价值

1.语义空间的几何结构

经过良好训练的向量空间具有优美的数学结构:

语义相近 → 向量距离近
语义相反 → 向量方向相反
语义关系 → 向量运算可表达

2.模型能力的基石

image

3.实际应用价值

  • 相似度计算:通过余弦相似度比较文本相似度
  • 语义搜索:在向量空间中快速检索相关文档
  • 文本分类:基于向量表示进行情感分析、主题分类
  • 机器翻译:在不同语言的向量空间之间建立映射

总结:数字化的语言革命

文字向量化不仅是技术实现,更是思维范式的转变

从符号到向量的哲学意义

  • 传统语言学:研究符号之间的关系和规则
  • 向量语义学:在连续空间中捕捉语义的相似性和关联性

技术演进的价值

这个过程让计算机从字面理解进化到语义理解,从规则驱动进化到数据驱动,最终实现了真正意义上的语言智能。

向量化就像为人类语言和计算机思维之间搭建了一座桥梁,让两种完全不同的"思维方式"能够相互理解和沟通。这正是现代自然语言处理技术能够取得突破性进展的根本基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一枚后端工程狮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值