首页 > 其他分享 >(自用笔记)Word Embedding原理和Pytorch实现

(自用笔记)Word Embedding原理和Pytorch实现

时间:2024-02-22 14:59:37浏览次数:23  
标签:embedding word Embedding torch 单词 Pytorch context Word 向量

参考:
(1)从Word Embedding到Bert模型—自然语言处理中的预训练技术发展史 - 知乎 (zhihu.com)
(2)吴恩达深度学习
(3)deep_thoughts老师的原理和代码讲解:
https://space.bilibili.com/373596439
越是底层的特征越是所有不论什么领域的图像都会具备的比如边角线弧线等底层基础特征,越往上抽取出的特征越与手头任务相关。正因为此,所以预训练好的网络参数,尤其是底层的网络参数抽取出特征跟具体任务越无关,越具备任务的通用性

Word representation 词汇表征

单词的语义表征

稀疏式
one-hot encoding(维度太大)
分布式(连续浮点型的向量,长度固定)
类似于word embedding,各种embedding
应用场景
word/character/phrase/sentence/paragraph embedding
speaker/user/item embedding

基于词的one-hot的缺点:每个词孤立的分开,导致模型对相关词的泛化能力不强

image

image

将词标识为特征向量

转换为二维表示:t-SNE

image

WE Word Embedding

image

Word Embedding的特征

一个简单的例子:

已知man-woman,给出king找到对应的词

image

eman - ewoman ≈ eking - equeen

这是因为在特征向量表示中,main,woman,king,queen的差异主要由Gender决定

词特征向量相似度

image

t-SNE转换为二维标识后很多无法再明显显示为平行四边形

常用的相似度函数:余弦相似度

image

embedding matrix

当使用模型学习词嵌入时,实际上是在学习一个词嵌入矩阵

image

one-hot大部分为0,所以矩阵相乘的的效率在实际应用中太低

  1. 词汇表大小(Vocabulary Size): 这是用于训练 word embedding 的语料库中唯一单词的数量。假设词汇表大小为 V

  2. 词向量维度(Embedding Dimension): 这是将每个单词映射到的连续向量空间的维度。假设词向量维度为 D

    词向量维度通常是作为一个超参数(hyperparameter)在训练 word embedding 模型时手动指定的。选择词向量维度的过程通常是基于经验和任务需求的。较小的词向量维度可能会捕捉到更少的语义信息,而较大的词向量维度可能会包含更丰富的语义信息,但同时也会增加模型的复杂度和计算成本。

    一般来说,通常将词向量维度设置在 100 到 300 之间。常见的选择包括 50、100、200 或 300 维。

WE的问题

word embedding无法区分多义词的不同语义

用语言模型训练的时候,不论什么上下文的句子经过word2vec,都是预测相同的单词,而同一个单词占的是同一行的参数空间,这导致两种不同的上下文信息都会编码到相同的word embedding空间里去

语言模型,语言建模

基于已有的人类组织的文本语料,来去无监督学习如何组织一句话并还能得到单词的语义表征

统计模型-n-gram

特点: 统计性、简单、泛化能力差、无法得到单词的语义信息,只能算出单词的概率不能得到单词的语义表征的和单词之间的关联
定义:n个相邻字符构成的序列:n-gram

  • 用途:基于n-gram的频数分析文本,如垃圾邮件分类
  • 对于word n-gram(基于单词的),特征维度随着语料词汇增大和n增大而指数增大 (curse of dimensionality,维度灾难)
  • 对于character n-gram(基于字母的),特征维度只随着n增大而增大

无监督学习-NNLM

NNLM(Bengjo提出)

学习任务是输入某个句中单词 Wt = bert 前面句子的t-1个单词,要求网络正确预测单词Bert

最大化:image

image

输入层:wt-n+1,wt-1,n个相邻的单词

并且是one hot的索引表示,传入投影层,根据索引查询embedding table,one -hot encoding vector和embedding table做矩阵相乘得到word embedding

隐藏层:

image

原始单词xi用one-hot编码为Wi作为原始输入(作为矩阵W)

C×W(即为图中的C(W)(为每个向量拼接)),上接隐层,然后接softmax去预测后面应该后续接哪个单词

到了每个词的词向量表示后,将其拼接在一起,即进行concat操作,形成了一个(n-1)*w的向量,我们用X来表示。然后将X送入隐藏层进行计算,即图中中间的一层神经元,使用tanh作为激活函数

训练刚开始用随机值初始化矩阵C,矩阵C有v行(词典大小),矩阵C也是参数,需要不断更新,每一行代表一个单词对应的Word embedding值

word embedding 是 NNLM的副产品

image

大规模无监督学习-word2vec,BERT

word2vec

改进1:抛弃了隐藏层

为了获得word embedding

(1)CBOW,核心思想是从一个句子里面把一个词抠掉,用这个词的上文和下文去预测被抠掉的这个词(与Bert中的随机mask一个单词,预测这个单词类似)。考虑了前后上下文,使用周围单词预测中间单词。

image

image

输入加起来到一个softmax,输出一个概率分布,目标函数即为希望得到的中间的单词的概率最大

(2)Skip-gram,和CBOW正好反过来,输入某个单词,要求网络预测它的上下文单词。

学习词嵌入的几种上下文:

image

将所有周围单词t周围单词的概率求和:

image

image

构建很多个input和context word的组合,每次输入一个input,得到embedding后映射到概率分布,使得预测到希望的单词概率最大

类似bert中的nsp任务,两个句子是否互为相邻

改进2:优化softmax

在分类任务中,softmax需要将隐含层输出映射到大小为序列中单词数目的概率分布上,所以计算量和单词表数目k线性相关

image

huffman树构造思路的softmax

Hierarchical Softmax 使用了多个连续的二分类来逼近整个 softmax 函数。具体来说,它将词汇表中的单词按照概率分布构建成一棵二叉树,其中每个单词对应树中的一个节点。在构建过程中,每个单词的概率被用来指导节点的安排,常见的做法是使用 Huffman 编码树构建。一旦树被构建完成,针对每个中心词,softmax 的计算路径就沿着从根节点到目标单词的叶子节点的路径进行,每次选择左子节点或右子节点,直到到达目标单词的叶子节点。在这个过程中,树的深度通常与词汇表的大小相关,而不是固定的。因此,对于一个具有 V 个单词的词汇表,计算整个 softmax 的时间复杂度由 O(V) 降低到了 O(log V)

image

左分类当作负样本,右分类当作正样本,则可以算出p(cat|context)

image

单词表达成Word Embedding后,很容易找出语义相近的其它词汇

训练好的WE×word_one-hot = new_word_E

Word Embedding 和 One-hot 编码的对比:

  1. 形式:
    • Word Embedding:是一个实数向量,通常具有固定的维度,可以捕捉单词之间的语义关系。
    • One-hot 编码:是一个稀疏的向量,维度等于词汇表的大小,其中只有一个元素为 1,其余元素为 0。
  2. 表示效率:
    • Word Embedding:提供了密集的向量表示,相比于稀疏的 One-hot 编码,能够更有效地表示单词。
    • One-hot 编码:是一种稀疏的表示方法,需要存储大量的零值,浪费了存储空间。
  3. 语义信息:
    • Word Embedding:能够捕捉单词之间的语义关系,使得在向量空间中相似的单词在几何距离上也是相近的。
    • One-hot 编码:每个单词之间的距离都是相等的,无法捕捉语义信息。
  4. 泛化能力:
    • Word Embedding:由于能够学习到单词之间的语义关系,具有一定的泛化能力,适用于许多自然语言处理任务。
    • One-hot 编码:仅表示单词的存在与否,缺乏语义信息,泛化能力较弱。
pytorch中的实现
Word Embeddings: Encoding Lexical Semantics — PyTorch Tutorials 2.2.0+cu121 documentation

在nlp中特征就是单词(nlp最基础的单元),但是在计算机中需要用数字来表示单词

最简单的就是one-hot encoding(之前说过)(缺点:维度爆炸,只能表示单词顺序)There is an enormous drawback to this representation, besides just how huge it is. It basically treats all words as independent entities with no relation to each other. What we really want is some notion of similarity between words.

获取语义之间的相似度和关联度十分重要

语言模型的作用:根据句法推断出语义的相似度和关联度

获得两个句子的dense WE后:通过余弦相似度[-1,1]来就算

给出WE可以知道两个单词的语义是否接近,但无法得知两个单词的语义为什么接近

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
torch.manual_seed(1)
#对单词表构造字典用于将单词映射到索引
word_to_ix = {'hello':0,'world':1}
#2个单词(词汇表大小为2)和每个单词的嵌入维度为5。这意味着每个单词都将被表示为一个长度为5的向量。
embeds = nn.Embedding(2, 5)
#包含单词索引的PyTorch张量,表示要查询嵌入的单词。在这里,我们使用索引0来表示单词"hello"
lookup_tensor = torch.tensor([word_to_ix["hello"]], dtype=torch.long)
print(lookup_tensor)#tensor([0])
hello_embed = embeds(lookup_tensor)#根据索引查找对应的词嵌入向量
print(hello_embed)
#tensor([[-0.8923, -0.0583, -0.1955, -0.9656,  0.4224]],
#        grad_fn=<EmbeddingBackward0>)
n-gram pytorch
CONTEXT_SIZE = 2#上下文2
EMBEDDING_DIM = 10#we维度
# We will use Shakespeare Sonnet 2
test_sentence = """When forty winters shall besiege thy brow,
And dig deep trenches in thy beauty's field,
Thy youth's proud livery so gazed on now,
Will be a totter'd weed of small worth held:
Then being asked, where all thy beauty lies,
Where all the treasure of thy lusty days;
To say, within thine own deep sunken eyes,
Were an all-eating shame, and thriftless praise.
How much more praise deserv'd thy beauty's use,
If thou couldst answer 'This fair child of mine
Shall sum my count, and make my old excuse,'
Proving his beauty by succession thine!
This were to be new made when thou art old,
And see thy blood warm when thou feel'st it cold.""".split()
#ngrams为一个元组列表,其中每个元素都是单词i和单词i的上文(n = 2)
ngrams = [
    (
        [test_sentence[i - j - 1] for j in range(CONTEXT_SIZE)],
        test_sentence[i]
    )
    for i in range(CONTEXT_SIZE, len(test_sentence))
]
print(ngrams[:3])

vocab = set(test_sentence)
#构造索引字典
word_to_ix = {word: i for i, word in enumerate(vocab)}
print(word_to_ix)

#构建NLM
class NGramLanguageModeler(nn.Module):

    def __init__(self, vocab_size, embedding_dim, context_size):
        super(NGramLanguageModeler, self).__init__()
        #投影层,构建WE表
        self.embeddings = nn.Embedding(vocab_size, embedding_dim)
        #上下文大小*we维度得到一个大的向量
#         self.linear1 的输入是通过词嵌入层得到的上文单词的词嵌入向量
# 这些单词的词嵌入向量会被展平为一个大的向量,然后输入到线性层 self.linear1 中进行线性变换
        self.linear1 = nn.Linear(context_size * embedding_dim, 128)
#     将隐藏表示空间映射到词汇表大小的向量,以便生成每个单词的概率分布
        self.linear2 = nn.Linear(128, vocab_size)

    def forward(self, inputs):
        embeds = self.embeddings(inputs).view((1, -1))
        out = F.relu(self.linear1(embeds))
        out = self.linear2(out)
#         对输出进行log_softmax操作,得到模型预测的每个单词的对数概率。
        log_probs = F.log_softmax(out, dim=1)
        return log_probs


losses = []#存储每个epoch的损失值
#负对数似然损失函数 nn.NLLLoss(),用于计算模型输出和目标值之间的损失。
loss_function = nn.NLLLoss()
model = NGramLanguageModeler(len(vocab), EMBEDDING_DIM, CONTEXT_SIZE)
optimizer = optim.SGD(model.parameters(), lr=0.001)

for epoch in range(10):
    total_loss = 0
    for context, target in ngrams:

#         将上下文单词转换为整数索引,并封装成张量 context_idxs
        context_idxs = torch.tensor([word_to_ix[w] for w in context], dtype=torch.long)
        model.zero_grad()
        log_probs = model(context_idxs)
#计算损失,将模型的输出和目标单词的索引作为输入,并使用负对数似然损失函数计算损失值。
        loss = loss_function(log_probs, torch.tensor([word_to_ix[target]], dtype=torch.long))
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
    losses.append(total_loss)
print(losses) 
# 打印特定单词(如"beauty")对应的词嵌入向量。
print(model.embeddings.weight[word_to_ix["beauty"]])
def predict_next_word(model, word_to_ix, context_words):
    # 将上下文单词转换为整数索引,并封装成张量
    context_idxs = torch.tensor([word_to_ix[w] for w in context_words], dtype=torch.long)
    
    # 使用模型计算给定上下文的对数概率
    log_probs = model(context_idxs)
    
    # 从对数概率中选择概率最高的单词作为预测结果
    _, predicted_idx = torch.max(log_probs, dim=1)
    
    # 获取预测单词的整数索引,并找到对应的单词
    predicted_word = [k for k, v in word_to_ix.items() if v == predicted_idx.item()][0]
    
    return predicted_word
context_words = ['When',"youth's"]

test = predict_next_word(model,word_to_ix,context_words)
test
CBOW pytorch
import torch
import torch.nn as nn
import torch.optim as optim

CONTEXT_SIZE = 2  # 左右各2个单词作为上下文
raw_text = """We are about to study the idea of a computational process.
Computational processes are abstract beings that inhabit computers.
As they evolve, processes manipulate other abstract things called data.
The evolution of a process is directed by a pattern of rules
called a program. People create programs to direct processes. In effect,
we conjure the spirits of the computer with our spells.""".split()

vocab = set(raw_text)
vocab_size = len(vocab)
word_to_ix = {word: i for i, word in enumerate(vocab)}

data = []
for i in range(CONTEXT_SIZE, len(raw_text) - CONTEXT_SIZE):
    context = [raw_text[i - j - 1] for j in range(CONTEXT_SIZE)] + [raw_text[i + j + 1] for j in range(CONTEXT_SIZE)]
    target = raw_text[i]
    data.append((context, target))


class CBOW(nn.Module):
    def __init__(self, vocab_size, embedding_dim, context_size):
        super(CBOW, self).__init__()
        self.embeddings = nn.Embedding(vocab_size, embedding_dim)
        self.linear = nn.Linear(context_size *2* embedding_dim, vocab_size)

    def forward(self, inputs):
        embeds = self.embeddings(inputs).view((1, -1))
#         print(embeds.shape)
        
        out = self.linear(embeds)
        return out


# 创建模型实例
EMBEDDING_DIM = 100
model = CBOW(vocab_size, EMBEDDING_DIM, CONTEXT_SIZE)

# 定义损失函数和优化器
loss_function = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)

# 开始训练
for epoch in range(100):
    total_loss = 0
    for context, target in data:
        # 准备输入和目标张量
        context_idxs = torch.tensor([word_to_ix[w] for w in context], dtype=torch.long)
        target_idx = torch.tensor([word_to_ix[target]], dtype=torch.long)
        # 清除之前的梯度
        model.zero_grad()
        # 前向传播
        log_probs = model(context_idxs)
        # 计算损失
        loss = loss_function(log_probs, target_idx)
        # 反向传播和参数更新
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
    # 打印损失
    print(f"Epoch {epoch + 1}, Loss: {total_loss}")

标签:embedding,word,Embedding,torch,单词,Pytorch,context,Word,向量
From: https://www.cnblogs.com/ziggystardust-pop/p/18027312

相关文章

  • spark编写WordCount代码(scala)
    代码demopackagecom.spark.wordcountimportorg.apache.spark.SparkContextimportorg.apache.spark.SparkContext._importorg.apache.spark.SparkConfobjectWordCount{defmain(args:Array[String]){//文件位置valinputFile="hdfs://192.168.10......
  • sensitive-word v0.13 特性版本发布 支持英文单词全词匹配
    拓展阅读sensitive-word-adminv1.3.0发布如何支持分布式部署?sensitive-word-admin敏感词控台v1.2.0版本开源sensitive-word基于DFA算法实现的高性能敏感词工具介绍更多技术交流业务背景对于英文单词Disburse之类的,其中的sb字母会被替换,要怎么处理,能不......
  • password_encryption_type 和 pg_hba.conf 不匹配导致用户连不上
    问题概述xxx客户新上一套opengauss数据库,在测试中用户输入正确的密码,提示用户密码错误,导致用户被锁问题原因password_encryption_type和pg_hba.conf不匹配导致用户连不上模拟问题因没有opengauss的环境,测试环境选择Mogdb1、准备测试环境,修改password_encryption_type。......
  • 利用COM组件实现对WORD书签各种操作大全
    有个需求是,程序导出一份word报告,报告中有各种各样的表格,导出时还需要插入图片。脑海中迅速闪过好几种组件,openxml组件,com组件,npoi。为了减少程序画复杂表格,我们选用了com组件+word模板的方式,程序只需要对word中的书签进行赋值即可。不知道这几种组件的(或者还有其他......
  • sensitive-word-admin v1.3.0 发布 如何支持敏感词控台分布式部署?
    拓展阅读sensitive-word-adminv1.3.0发布如何支持分布式部署?sensitive-word-admin敏感词控台v1.2.0版本开源sensitive-word基于DFA算法实现的高性能敏感词工具介绍更多技术交流业务背景如果我们的敏感词部署之后,不会变化,那么其实不用考虑这个问题。但是......
  • 自然语言生成任务中的5种采样方法介绍和Pytorch代码实现
    在自然语言生成任务(NLG)中,采样方法是指从生成模型中获取文本输出的一种技术。本文将介绍常用的5中方法并用Pytorch进行实现。束搜索(BeamSearch)是贪婪解码的一种扩展,通过在每个时间步保留多个候选序列来克服贪婪解码的局部最优问题。在每个时间步保留概率最高的前几个候选词语,然......
  • CF1365G Secure Password 题解
    Description本题是交互题。有一个固定的数组\(A\),同时通过数组\(A\)构造出数组\(P\),具体来讲,\(P_i\)是\(A\)中除\(A_i\)外的所有元素的按位或。你需要在最多\(13\)次询问中得到最后的\(P\)数组。\(2\leqn\leq1000\)。Solution首先有一个\(2\logn\)的是注......
  • conda安装gpu版本pytorch与gpu版本tensorflow
    创建环境进入环境nvidia-smi查看cuda版本,根据cuda版本安装对应版本的pytorch,在pytorch官网可以查看,版本不合适可以使用较低版本cuda的torch,使用官网提供的命令行安装即可,importtorch``print(torch.cuda.is_available())验证安装结果。tensorflow的安装要在环境中安装cudatoolki......
  • pytorch深度学习入门(8)之-Torchaudio使用Tacotron2 文本转语音
    https://blog.csdn.net/ajunbin859/article/details/134380417?ops_request_misc=&request_id=&biz_id=102&utm_term=pytorch%E7%89%88%E6%9C%AC%E7%9A%84tacotron%E8%AF%A6%E7%BB%86%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B&utm_medium=distribute.pc_search_r......
  • Go 100 mistakes - #10: Not being aware of the possible problems with type embedd
     Becausethemutexisembedded,wecandirectlyaccesstheLockandUnlockmethods fromtheireceiver.Wementionedthatsuchanexampleisawrongusageoftypeembedding.What’s thereasonforthis?Sincesync.Mutexisanembeddedtype,theLockand......