[AI趣事]从密码本到智能翻译官:词嵌入让电脑真正"理解"文字 5-14 进阶篇

AI摘要
本文介绍了词嵌入技术如何改进词袋模型,通过密集向量表示词汇语义关系,解决了稀疏向量内存浪费和语义缺失问题。重点讲解了Embedding、Word2Vec及上下文嵌入的原理与应用,包括预训练模型使用和文本分类实战,为理解现代NLP模型奠定基础。

嗨,各位AI探索者!

还记得上次我们聊的”词袋模型”吗?把文字扔进袋子里数个数,简单粗暴但有效。不过今天我们要聊点更高级的——让电脑不仅能”看懂”文字,还能”理解”文字的真正含义!

🤔 词袋模型的”智商税”

回想一下上次的词袋模型,我们把每个词都变成了独立的数字:

"我" = [1,0,0,0,0...]  # 10000维的向量,只有第1位是1
"爱" = [0,1,0,0,0...]  # 只有第2位是1
"你" = [0,0,1,0,0...]  # 只有第3位是1

这样做有两个大问题:

  1. 太浪费内存:10000个词就要10000维向量,99.99%都是0
  2. 词与词毫无关系:”国王”和”女王”明明很相似,但在电脑眼里完全没关系

就像把”苹果”和”香蕉”分别装在不同星球上,永远不知道它们都是水果!

🎯 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)            # 分类

流程变成:

  1. 句子 → 词ID序列
  2. 词ID → 词向量
  3. 多个词向量 → 平均成句子向量
  4. 句子向量 → 分类结果

📏 处理变长文本的智慧

填充策略

不同新闻长度不一样怎么办?我们用”填充”技巧:

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:更聪明的方案

[AI趣事]从密码本到智能翻译官:词嵌入让电脑真正"理解"文字 5-14 进阶篇

# 不需要填充,直接处理变长序列
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 (猜中间词)

[AI趣事]从密码本到智能翻译官:词嵌入让电脑真正"理解"文字 5-14 进阶篇

上下文: [, 喜欢, ?, 苹果, 很甜]
目标: 猜出中间的"吃"

训练方式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 协议》,转载必须注明作者和本文链接
• 15年技术深耕:理论扎实 + 实战丰富,教学经验让复杂技术变简单 • 8年企业历练:不仅懂技术,更懂业务落地与项目实操 • 全栈服务力:技术培训 | 软件定制开发 | AI智能化升级 关注「上海PHP自学中心」获取实战干货
wangchunbo
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
啥活都干 @ 一人企业
文章
346
粉丝
364
喜欢
579
收藏
1152
排名:58
访问:12.8 万
私信
所有博文
社区赞助商