pytorch之词嵌入(三)

1、编码词法语义

词嵌入是稠密向量。如何在计算机中表示一个单词呢?存储它的ascii字符表示形式,但这只能表明词什么,它并没有说明其含义(可以从其词缀或大写字母中得出其词性,但是不多)。在什么意义上组合这些表示形式,通常需要神经网络的稠密表示。如何从高维空间变成低维空间?

1.1、独热编码

独热编码的表示形式如下:

句子中词所在位置为1,非句子中词的位置为0;

这种表示法有两个缺点:

1)维度大 
2) 单词之间相互独立

1.2、密集词嵌入

我们如何解决这个问题?也就是说,我们如何实际编码单词中的语义相似性?也许我们想到了一些语义属性。例如,我们看到数学家和物理学家都可以运行,因此也许我们为这些单词的“能够运行”语义属性评分很高。考虑其他一些属性,并想象您会在这些属性上给一些常见的单词打分。

如果每个属性都是一个维,则可以给每个单词一个向量,如下所示:

然后,通过执行以下操作,可以得出这些词之间的相似度:

尽管通过长度进行归一化比较常见:

 

ϕϕ是两个向量之间的角度,极端相似的单词(其嵌入指向同一方向的单词)将具有相似性1。极端不相似的单词应具有相似性-1。
 

2、pytorch中的词嵌入

在开始工作示例和练习之前,先简要介绍一下如何在Pytorch和深度学习编程中使用嵌入。类似于我们在制作单热向量时为每个单词定义唯一索引的方式,我们也需要在使用嵌入时为每个单词定义索引。这些将成为查找表的关键字。也就是说,嵌入存储为|V|×D矩阵,其中 D是嵌入的维数,因此单词分配索引 i将其嵌入存储在 i矩阵的第th行。在我的所有代码中,从单词到索引的映射都是一个名为word_to_ix的字典。

允许您使用嵌入的模块是torch.nn.Embedding,它带有两个参数:词汇量和嵌入的维数。

要在该表中建立索引,必须使用torch.LongTensor(因为索引是整数,而不是浮点数)。

3、N-Gram语言建模

回想一下,在n元语法模型中,给出了一系列单词 w,我们要计算

wi 是序列的第i个词

在此示例中,我们将在一些训练示例中计算损失函数,并使用反向传播更新参数。

 
#ngram语言模型
context_size=2    #上下文大小
embedding_dim=10  #词向量维度
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()
#构建三元组
trigrams=[([test_sentence[i],test_sentence[i+1]],test_sentence[i+2]) for i in range(len(test_sentence)-2)]

#构建词典
vocab=set(test_sentence)
word_to_ix={word :i for i ,word in enumerate(vocab)}

class Ngram(nn.Module):
    def __init__(self,vocab_size,embedding_dim,context_size):
        super(Ngram,self).__init__()
        self.embeddings=nn.Embedding(vocab_size,embedding_dim) #定义embedding
        self.lin1=nn.Linear(context_size*embedding_dim,128) #定义隐含层
        self.lin2=nn.Linear(128,vocab_size) #获取vocab_size个词向量
    
    def forward(self,inputs):
        embeds=self.embeddings(inputs).view(1,-1) #定义词向量 1*(context_size*embedding_dim)
        #print("embeds:",embeds.size())
        out=F.relu(self.lin1(embeds))  #vocab_size*embedding_dim
        out=self.lin2(out)             #embedding_dim*128
        prob=F.log_softmax(out,dim=1)  #每个词的概率
        return prob

losses=[]
loss_function=nn.NLLLoss()
model=Ngram(len(vocab),embedding_dim,context_size)
opt=optim.SGD(model.parameters(),lr=0.001)

for epoch in range(10):
    total_loss=0
    for ctx,target in trigrams:
        #1、准备输入模型的三元组  
        #print("ctx:",ctx)
        ctx_ids=[]
        for w in ctx:
            ctx_ids.append(word_to_ix[w])
        
        ctx_ids = torch.tensor(ctx_ids, dtype=torch.long)
        #2、梯度置0
        model.zero_grad()
        #3、获取log_probs
        log_probs=model(ctx_ids)
        #4、计算损失函数
        loss=loss_function(log_probs,torch.tensor([word_to_ix[target]], dtype=torch.long))
        #5、反向传播更新梯度
        loss.backward()
        opt.step()
        total_loss+=loss.item()
    losses.append(total_loss)
print(losses)

4、词嵌入CBOW

NLP深度学习中经常使用连续词袋模型(CBOW)。在给定目标词之前和之后的几个词的上下文中,它是一种试图预测词的模型。这与语言建模不同,因为CBOW不是顺序的,并且不一定是概率性的。通常,CBOW用于快速训练单词嵌入,而这些嵌入用于初始化一些更复杂模型的嵌入。通常,这称为预训练嵌入。它几乎总是可以将性能提高百分之几。

CBOW模型如下。给定目标词wi和 N 两侧的上下文窗口 wi−1,…,wi−N和 wi+1,…,wi+N,将所有上下文词统称为 C,CBOW试图最小化


qw是单词的嵌入 w

#CBOW语言模型
#构建上下文窗口
cbows=[]
context_size=2
print(ctxs)
for i in range(context_size,len(ctxs)-context_size):
    ctx=ctxs[i-context_size:i+context_size+1]
    ctx.pop(context_size)
    target=ctxs[i]
    cbows.append((ctx,target))
print(cbows[:2])
    
class CBOW(nn.Module):
    def __init__(self,vocab_size,embedding_dim):
        super(CBOW,self).__init__()
        self.embeddings=nn.Embedding(vocab_size,embedding_dim) #定义embedding
        self.lin1=nn.Linear(embedding_dim,128) #定义隐含层
        self.lin2=nn.Linear(128,vocab_size) #获取vocab_size个词向量
    
    def forward(self,inputs):
        embeds=self.embeddings(inputs) #定义词向量 1*(context_size*embedding_dim)
        #print("embeds:",embeds.size())
        embeds=torch.sum(embeds,0).view(1,-1) #0:按照列求和;1:按照行求和
        #print("embeds:",embeds.size())
        out=F.relu(self.lin1(embeds))  #vocab_size*embedding_dim
        out=self.lin2(out)             #embedding_dim*128
        prob=F.log_softmax(out,dim=1)  #每个词的概率
        return prob
    
losses=[]
loss_function=nn.NLLLoss()
model=CBOW(len(vocab),embedding_dim)
opt=optim.SGD(model.parameters(),lr=0.001)

for epoch in range(10):
    total_loss=0
    for ctx,target in cbows:
        #1、准备输入模型的三元组  
        #print("ctx:",ctx)
        ctx_ids=[]
        for w in ctx:
            ctx_ids.append(word_to_ix[w])
        
        ctx_ids = torch.tensor(ctx_ids, dtype=torch.long)
        #2、梯度置0
        model.zero_grad()
        #3、获取log_probs
        log_probs=model(ctx_ids)
        #4、计算损失函数
        loss=loss_function(log_probs,torch.tensor([word_to_ix[target]], dtype=torch.long))
        #5、反向传播更新梯度
        loss.backward()
        opt.step()
        total_loss+=loss.item()
    losses.append(total_loss)
print(losses)
 

参考:

https://pytorch.org/tutorials/beginner/nlp/word_embeddings_tutorial.html#sphx-glr-beginner-nlp-word-embeddings-tutorial-py

猜你喜欢

转载自blog.csdn.net/u013069552/article/details/112549743
今日推荐