一、什么是向量化?
核心定义
向量化是将离散的符号(如文字)转换为连续的数值向量的过程。在深度学习中,它把人类可读的文本转换成计算机能够理解和处理的数学表示。
生动比喻:语言翻译成数学坐标
想象每个词在一个高维空间中的位置:
- 传统词典:用文字解释文字
- 向量空间:用数学坐标精确定位每个词的含义
"国王" → [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, ...]
向量化的神奇特性
二、从文字到向量化的完整过程
整体流程概览
步骤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])
词嵌入的可视化理解
词向量的语义特性
经过训练后,词向量会捕捉丰富的语义关系:
# 语义关系的向量运算示例 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])
位置编码的可视化
完整的位置感知嵌入
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动态词嵌入
对比表格
特性 |
传统静态嵌入 |
Transformer动态嵌入 |
上下文处理 |
每个词固定向量 |
根据上下文动态调整 |
多义词处理 |
一个向量表示所有含义 |
不同上下文不同向量 |
训练方式 |
预训练后固定 |
端到端联合训练 |
示例 |
Word2Vec, GloVe |
BERT, GPT, T5 |
向量质量 |
"bank"只有一个向量 |
"river bank"和"money bank"向量不同 |
四、向量化的意义与价值
1.语义空间的几何结构
经过良好训练的向量空间具有优美的数学结构:
语义相近 → 向量距离近 语义相反 → 向量方向相反 语义关系 → 向量运算可表达
2.模型能力的基石
3.实际应用价值
- 相似度计算:通过余弦相似度比较文本相似度
- 语义搜索:在向量空间中快速检索相关文档
- 文本分类:基于向量表示进行情感分析、主题分类
- 机器翻译:在不同语言的向量空间之间建立映射
总结:数字化的语言革命
文字向量化不仅是技术实现,更是思维范式的转变:
从符号到向量的哲学意义
- 传统语言学:研究符号之间的关系和规则
- 向量语义学:在连续空间中捕捉语义的相似性和关联性
技术演进的价值
这个过程让计算机从字面理解进化到语义理解,从规则驱动进化到数据驱动,最终实现了真正意义上的语言智能。
向量化就像为人类语言和计算机思维之间搭建了一座桥梁,让两种完全不同的"思维方式"能够相互理解和沟通。这正是现代自然语言处理技术能够取得突破性进展的根本基础。