[AI趣事]从密码本到智能翻译官:词嵌入让电脑真正"理解"文字 5-14 进阶篇
嗨,各位AI探索者!
还记得上次我们聊的”词袋模型”吗?把文字扔进袋子里数个数,简单粗暴但有效。不过今天我们要聊点更高级的——让电脑不仅能”看懂”文字,还能”理解”文字的真正含义!
🤔 词袋模型的”智商税”
回想一下上次的词袋模型,我们把每个词都变成了独立的数字:
"我" = [1,0,0,0,0...] # 10000维的向量,只有第1位是1
"爱" = [0,1,0,0,0...] # 只有第2位是1
"你" = [0,0,1,0,0...] # 只有第3位是1
这样做有两个大问题:
- 太浪费内存:10000个词就要10000维向量,99.99%都是0
- 词与词毫无关系:”国王”和”女王”明明很相似,但在电脑眼里完全没关系
就像把”苹果”和”香蕉”分别装在不同星球上,永远不知道它们都是水果!
🎯 Embeddings:文字的”身份证”
什么是Embeddings?
想象每个词都有一张”身份证”,上面有100个特征值:
"国王" = [0.2, 0.8, 0.1, 0.9, ...] # 100维的密集向量
"女王" = [0.1, 0.7, 0.2, 0.8, ...] # 和国王很相似!
"苹果" = [0.9, 0.1, 0.8, 0.2, ...] # 完全不同的模式
这就是词嵌入(Embeddings)!每个词都用一个相对较短但信息丰富的向量表示。
代码实战:从10000维到100维
import torch
import torch.nn as nn
# 之前:10000维的稀疏向量
# 现在:100维的密集向量
embed_size = 100
vocab_size = 10000
# 创建嵌入层
embedding = nn.Embedding(vocab_size, embed_size)
# 魔法时刻!
word_id = 42 # "苹果"的ID
word_vector = embedding(torch.tensor([word_id]))
print(f"苹果的向量表示: {word_vector.shape}") # [1, 100]
🎒 从词袋到嵌入袋
升级版分类器
现在我们的新闻分类器升级了:
class EmbedClassifier(torch.nn.Module):
def __init__(self, vocab_size, embed_dim, num_class):
super().__init__()
self.embedding = torch.nn.Embedding(vocab_size, embed_dim)
self.fc = torch.nn.Linear(embed_dim, num_class)
def forward(self, x):
x = self.embedding(x) # 每个词变成向量
x = torch.mean(x, dim=1) # 求平均得到句子向量
return self.fc(x) # 分类
流程变成:
- 句子 → 词ID序列
- 词ID → 词向量
- 多个词向量 → 平均成句子向量
- 句子向量 → 分类结果
📏 处理变长文本的智慧
填充策略
不同新闻长度不一样怎么办?我们用”填充”技巧:
def padify(batch):
# 找到最长的句子
max_len = max(len(text) for text in batch)
# 短句子用0填充到统一长度
padded = []
for text in batch:
padding = [0] * (max_len - len(text))
padded.append(text + padding)
return torch.tensor(padded)
就像排队拍照,矮的人后面垫箱子,保证队形整齐!
EmbeddingBag:更聪明的方案
# 不需要填充,直接处理变长序列
embedding_bag = nn.EmbeddingBag(vocab_size, embed_dim, mode='mean')
# 输入:[词1, 词2, 词3, 词4, 词5, 词6]
# 偏移:[0, 3] # 前3个词是句子1,后3个词是句子2
# 输出:两个句子的平均向量
🧠 Word2Vec:让电脑理解词汇关系
什么是Word2Vec?
Word2Vec就像给电脑上了”语文课”,让它理解词汇之间的关系:
训练方式1:CBOW (猜中间词)
上下文: [我, 喜欢, ?, 苹果, 很甜]
目标: 猜出中间的"吃"
训练方式2:Skip-gram (猜周围词)
中心词: "吃"
目标: 猜出周围的 [我, 喜欢, 苹果, 很甜]
神奇的词汇数学
训练好的Word2Vec可以做”词汇数学”:
import gensim.downloader as api
# 下载预训练模型
w2v = api.load('word2vec-google-news-300')
# 神奇的数学关系
result = w2v.most_similar(
positive=['king', 'woman'],
negative=['man']
)[0]
print(result) # 'queen' !
# 翻译成数学公式:king - man + woman = queen
这就像解方程:国王 - 男人 + 女人 = ?答案是女王!
实战:使用预训练嵌入
# 加载300维的Word2Vec向量
embed_size = 300
vocab_size = len(vocab)
# 创建嵌入层
net = EmbedClassifier(vocab_size, embed_size, 4)
# 用预训练向量初始化
print('正在加载预训练向量...')
found, missing = 0, 0
for i, word in enumerate(vocab.get_itos()):
try:
# 找到了预训练向量
net.embedding.weight[i].data = torch.tensor(w2v.get_vector(word))
found += 1
except:
# 没找到,随机初始化
net.embedding.weight[i].data = torch.normal(0.0, 1.0, (embed_size,))
missing += 1
print(f"成功加载 {found} 个词,{missing} 个词缺失")
🤖 部署小贴士
Python环境配置
# 记住你的偏好:指定pymysql
import pymysql
pymysql.install_as_MySQLdb()
# 安装必要包
# pip install torch gensim scikit-learn
阿里云服务器部署
在你的Linux服务器(宝塔面板+Apache)上:
# 安装依赖
pip install torch gensim transformers
# 在宝塔面板中配置反向代理
# 将Apache请求转发到Python应用端口
🔮 上下文嵌入:更聪明的理解
传统Word2Vec有个问题:一词多义。比如”play”:
"I went to a play at the theater." # 戏剧
"John wants to play with friends." # 玩耍
但Word2Vec把两个”play”当成同一个词!
上下文嵌入解决了这个问题:
- 根据上下文动态生成词向量
- 同一个词在不同句子中有不同向量
- 这就是BERT、GPT等现代模型的基础
🎯 实战代码示例
完整的新闻分类器:
import torch
import torch.nn as nn
from torch.utils.data import DataLoader
class NewsClassifier(nn.Module):
def __init__(self, vocab_size, embed_dim, num_classes):
super().__init__()
self.embedding = nn.Embedding(vocab_size, embed_dim)
self.fc = nn.Linear(embed_dim, num_classes)
self.dropout = nn.Dropout(0.5)
def forward(self, x):
# x: [batch_size, seq_len]
embedded = self.embedding(x) # [batch_size, seq_len, embed_dim]
pooled = torch.mean(embedded, dim=1) # [batch_size, embed_dim]
output = self.fc(self.dropout(pooled))
return output
# 训练
model = NewsClassifier(vocab_size=10000, embed_dim=300, num_classes=4)
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
criterion = nn.CrossEntropyLoss()
# 训练循环
for epoch in range(10):
for batch_idx, (data, target) in enumerate(train_loader):
optimizer.zero_grad()
output = model(data)
loss = criterion(output, target)
loss.backward()
optimizer.step()
🎉 今日收获
- 词嵌入:从稀疏到密集,从独立到关联
- EmbeddingBag:处理变长序列的利器
- Word2Vec:让电脑理解词汇语义关系
- 预训练嵌入:站在巨人肩膀上
- 上下文嵌入:一词多义的智能解决方案
🔮 下期预告
下次我们将进入循环神经网络(RNN)的世界!
想知道如何让电脑像人一样”从左到右”理解句子,甚至能记住前面说过的话吗?敬请期待 5-15 RNN篇!
觉得有用记得点赞分享!有问题欢迎评论区讨论~
#AI学习 #词嵌入 #Word2Vec #深度学习 #自然语言处理
本作品采用《CC 协议》,转载必须注明作者和本文链接