1.Transformer的word embedding、position embedding、编码器子注意力的掩码

来源

B站up:deep_thoughts
https://www.bilibili.com/video/BV1cP4y1V7GF/?spm_id_from=333.1007.top_right_bar_window_history.content.click&vd_source=46b0ded1b361f3be84555a12b5121509


Transformer的词向量、位置编码、编码器子注意力的掩码的原理,并用pytorch实现。
首先4个常用的导入

embedding类似于一个字典,里面是英文,src是需要查找的英文在字典中的位置,
src_embedding_table是对应的英文内容。

word embedding

1.序列建模:source和target,里面的字符是单词索引
2.创建embedding_table,1中的索引表示对应table的位置,0留给padding
3.创建src_embedding_table或tgt_embedding_table

第2步

batch_size = 2

生成src_len、tgt_len

src_len=torch.randint(2,5,(batch_size,))
tgt_len=torch.randint(2,5,(batch_size,))

使其固定

src_len = torch.Tensor([2,4]).to(torch.int32)
tgt_len = torch.Tensor([4,3]).to(torch.int32) 

此时设置单词最大数为8

#单词索引构成的句子,即每个句子里是单词所在的索引数
#src_seq:[tensor([7, 4]), tensor([2, 1, 5, 4])]
#tgt_seq:[tensor([4, 4, 4, 3]), tensor([5, 7, 6])]
src_seq = [torch.randint(1,max_num_src_words,(L,))for L in src_len]
tgt_seq = [torch.randint(1,max_num_tgt_words,(L,))for L in tgt_len]

L分别取2,4,取2是长度为2的一个元组,取4是长度为4的一个元组
因为长度不一样,需要进行padding,使其对齐。
使用F.pad()补齐,F.pad(补齐对象,(左边几个零,后面几个零)),默认补0
生成的是一个列表,里面两个元素

src_seq = [F.pad(torch.randint(1,max_num_src_words,(L,)),(0,max(src_len)-L))for L in src_len]
tgt_seq = [F.pad(torch.randint(1,max_num_tgt_words,(L,)),(0,max(tgt_len)-L))for L in tgt_len]

src_seq:[tensor([5, 3, 0, 0, 0]), tensor([4, 2, 1, 5, 0])]
tgt_seq:[tensor([6, 3, 1, 5, 0]), tensor([1, 2, 5, 0, 0])]
进行拼接
使用torch.cat()拼接

src_seq = torch.cat([torch.unsqueeze(F.pad(torch.randint(1,max_num_src_words,(L,)),(0,max(src_len)-L)),0)for L in src_len])
tgt_seq = torch.cat([torch.unsqueeze(F.pad(torch.randint(1,max_num_tgt_words,(L,)),(0,max(tgt_len)-L)),0)for L in tgt_len])

src_seq:[tensor([5, 3, 0, 0, 0]), tensor([4, 2, 1, 5, 0])]
src_seq【2,5】=》【1,2,5】
由列表变成了一个张量

第3步

nn.Embedding(嵌入大小,)、

print(src_embedding_table)
print(src_embedding_table.weight)
print(src_seq)
print(src_embedding)

src_seq中索引是几,就是src_embedding_table中的第几行。

在这里插入图片描述

代码

batch_size = 2

#单词表大小
#单词对应的索引数的最大值
max_num_src_words = 8
max_num_tgt_words = 8
#每一个单词的大小
model_dim=8

#序列最大长度
#一整个句子的最大长度
max_src_seq_len=5
max_tgt_seq_len=5


src_len = torch.Tensor([2,4]).to(torch.int32)
tgt_len = torch.Tensor([4,3]).to(torch.int32) 

#单词索引构成源句子和目标句子,即每个句子里是单词所在的索引数。构建batch,做了padding,默认值为0
#L分别取2,4,取2是长度为2的一个元组,取4是长度为4的一个元组
#src_seq:[tensor([7, 4]), tensor([2, 1, 5, 4])]
#tgt_seq:[tensor([4, 4, 4, 3]), tensor([5, 7, 6])]
src_seq = torch.cat([torch.unsqueeze(F.pad(torch.randint(1,max_num_src_words,(L,)),(0,max(src_len)-L)),0)for L in src_len])
tgt_seq = torch.cat([torch.unsqueeze(F.pad(torch.randint(1,max_num_tgt_words,(L,)),(0,max(tgt_len)-L)),0)for L in tgt_len])

#构造embedding
#一个单词对应一行,从1开始,pad的0,所以0行对应pad
#每一行一个embedding向量,每个单词索引是几,我们就取第几行
src_embedding_table=nn.Embedding(max_num_src_words+1,model_dim)
tgt_embedding_table=nn.Embedding(max_num_tgt_words+1,model_dim)
src_embedding=src_embedding_table(src_seq)
tgt_embedding=tgt_embedding_table(tgt_seq)

positiona embedding

在这里插入图片描述

pos_mat=torch.arange(max_position_len).reshape(-1,1)
i_mat=torch.pow(10000,torch.arange(0,model_dim,2).reshape(1,-1)/model_dim)
print(pos_mat)
print(i_mat)

在这里插入图片描述

pe_embedding_table[:,::2]=torch.sin(pos_mat/i_mat)
pe_embedding_table[:,1::2]=torch.cos(pos_mat/i_mat)

偶数列:
在这里插入图片描述
奇数列:
在这里插入图片描述


pe_embedding=nn.Embedding(max_position_len,model_dim)
pe_embedding.weight=nn.Parameter(pe_embedding_table,requires_grad=False)

print(pe_embedding_table)
print(pe_embedding)
print(pe_embedding.weight)

在这里插入图片描述

src_pos=[torch.arange(max(src_len))for _ in src_len]
tgt_pos=[torch.arange(max(tgt_len))for _ in tgt_len]

src_pos_embedding=pe_embedding(src_pos)
tgt_pos_embedding=pe_embedding(tgt_pos)

TypeError: embedding(): argument ‘indices’ (position 2) must be Tensor, not list
torch.Tensor()只能转换单个元素

#构造position embedding
pos_mat=torch.arange(max_position_len).reshape(-1,1)
i_mat=torch.pow(10000,torch.arange(0,model_dim,2).reshape(1,-1)/model_dim)
pe_embedding_table=torch.zeros(max_position_len,model_dim)
pe_embedding_table[:,::2]=torch.sin(pos_mat/i_mat)
pe_embedding_table[:,1::2]=torch.cos(pos_mat/i_mat)


#改写了pe_embedding
pe_embedding=nn.Embedding(max_position_len,model_dim)
pe_embedding.weight=nn.Parameter(pe_embedding_table,requires_grad=False)

src_pos=torch.Tensor(torch.cat([torch.unsqueeze(torch.arange(max(src_len)),0)for _ in src_len]))
tgt_pos=torch.Tensor(torch.cat([torch.unsqueeze(torch.arange(max(tgt_len)),0)for _ in tgt_len]))

src_pos_embedding=pe_embedding(src_pos)
tgt_pos_embedding=pe_embedding(tgt_pos)
valid_encoder_pos=torch.unsqueeze(torch.cat([torch.unsqueeze(F.pad(torch.ones(L),(0,max(src_len)-L)),0)for L in src_len]),2)
v=torch.cat([torch.unsqueeze(F.pad(torch.ones(L),(0,max(src_len)-L)),0)for L in src_len])
#两个矩阵相乘可以得到两两之间的关联性
valid_encoder_pos_matrix=torch.bmm(valid_encoder_pos,valid_encoder_pos.transpose(1,2))
print(v)
print(valid_encoder_pos)
print(valid_encoder_pos.shape)
print(src_len)
print(valid_encoder_pos_matrix)

对于该句子,前面有俩单词,第一行是第一个单词对其他位置的关联性,由于剩下两个是pad的0,所以相关性为0。
在这里插入图片描述

invalid_encoder_pos_matrix=1-valid_encoder_pos_matrix
# True代表这个位置我们需要对它mask
mask_encoder_self_attention=invalid_encoder_pos_matrix.to(torch.bool)

print(invalid_encoder_pos_matrix)
print(mask_encoder_self_attention)

在这里插入图片描述

valid_encoder_pos=torch.unsqueeze(torch.cat([torch.unsqueeze(F.pad(torch.ones(L),(0,max(src_len)-L)),0)for L in src_len]),2)

#两个矩阵相乘可以得到两两之间的关联性
valid_encoder_pos_matrix=torch.bmm(valid_encoder_pos,valid_encoder_pos.transpose(1,2))
invalid_encoder_pos_matrix=1-valid_encoder_pos_matrix
# True代表这个位置我们需要对它mask
mask_encoder_self_attention=invalid_encoder_pos_matrix.to(torch.bool)

score=torch.randn(batch_size,max(src_len),max(src_len))
masked_score=score.masked_fill(mask_encoder_self_attention,-1e9)
prob=F.softmax(masked_score,-1)

print(score)
print(masked_score)
print(prob)

masked_fill(mask,value),mask是元素为布尔值的张量(Tensor),把true位置填充value值。

在这里插入图片描述

代码

import torch
import numpy as np
import torch.nn as nn
import torch.nn.functional as F


batch_size = 2

#单词表大小
#单词对应的索引数的最大值
max_num_src_words = 8
max_num_tgt_words = 8
#每一个单词的大小
model_dim=8

#序列最大长度
#一整个句子的最大长度,一个句子最多拥有的单词数
max_src_seq_len=5
max_tgt_seq_len=5
max_position_len=5


src_len = torch.Tensor([2,4]).to(torch.int32)
tgt_len = torch.Tensor([4,3]).to(torch.int32) 

#单词索引构成源句子和目标句子,即每个句子里是单词所在的索引数。构建batch,做了padding,默认值为0
#L分别取2,4,取2是长度为2的一个元组,取4是长度为4的一个元组
#src_seq:[tensor([7, 4]), tensor([2, 1, 5, 4])]
#tgt_seq:[tensor([4, 4, 4, 3]), tensor([5, 7, 6])]
src_seq = torch.cat([torch.unsqueeze(F.pad(torch.randint(1,max_num_src_words,(L,)),(0,max(src_len)-L)),0)for L in src_len])
tgt_seq = torch.cat([torch.unsqueeze(F.pad(torch.randint(1,max_num_tgt_words,(L,)),(0,max(tgt_len)-L)),0)for L in tgt_len])

#构造embedding
#一个单词对应一行,从1开始,pad的0,所以0行对应pad
#每一行一个embedding向量,每个单词索引是几,我们就取第几行
src_embedding_table=nn.Embedding(max_num_src_words+1,model_dim)
tgt_embedding_table=nn.Embedding(max_num_tgt_words+1,model_dim)
src_embedding=src_embedding_table(src_seq)
tgt_embedding=tgt_embedding_table(tgt_seq)

#构造position embedding
pos_mat=torch.arange(max_position_len).reshape(-1,1)
i_mat=torch.pow(10000,torch.arange(0,model_dim,2).reshape(1,-1)/model_dim)
pe_embedding_table=torch.zeros(max_position_len,model_dim)
pe_embedding_table[:,::2]=torch.sin(pos_mat/i_mat)
pe_embedding_table[:,1::2]=torch.cos(pos_mat/i_mat)


#改写了pe_embedding
pe_embedding=nn.Embedding(max_position_len,model_dim)
pe_embedding.weight=nn.Parameter(pe_embedding_table,requires_grad=False)

src_pos=torch.Tensor(torch.cat([torch.unsqueeze(torch.arange(max(src_len)),0)for _ in src_len]))
tgt_pos=torch.Tensor(torch.cat([torch.unsqueeze(torch.arange(max(tgt_len)),0)for _ in tgt_len]))

src_pos_embedding=pe_embedding(src_pos)
tgt_pos_embedding=pe_embedding(tgt_pos)

# #softmax演示,scaled的重要性
# alpha1=0.1
# alpha2=10
# score=torch.randn(5)
# prob1=F.softmax(score*alpha1,-1)
# prob2=F.softmax(score*alpha2,-1)
# def softmax_fun(score):
#     return F.softmax(score,-1)
# jaco_mat1=torch.autograd.functional.jacobian(softmax_fun,score*alpha1)
# jaco_mat2=torch.autograd.functional.jacobian(softmax_fun,score*alpha2)

# 构造encoder的self-attention mask,就是一个关系矩阵,没有因果
# mask的shape:[batch_size,max_src_len,max_src_len],值为1或负无穷,负无穷经过softmax变为0,1相乘维持不变
# valid_encoder_pos:[2,4]=>[2,1,4]
valid_encoder_pos=torch.unsqueeze(torch.cat([torch.unsqueeze(F.pad(torch.ones(L),(0,max(src_len)-L)),0)for L in src_len]),2)

#两个矩阵相乘可以得到两两之间的关联性
valid_encoder_pos_matrix=torch.bmm(valid_encoder_pos,valid_encoder_pos.transpose(1,2))
invalid_encoder_pos_matrix=1-valid_encoder_pos_matrix
# True代表这个位置我们需要对它mask
mask_encoder_self_attention=invalid_encoder_pos_matrix.to(torch.bool)

score=torch.randn(batch_size,max(src_len),max(src_len))
masked_score=score.masked_fill(mask_encoder_self_attention,-1e9)
prob=F.softmax(masked_score,-1)

print(score)
print(masked_score)
print(prob)

decoder

# step 6:构造decoder self-attention的mask
tril_matrix=[torch.tril(torch.ones(L,L))for L in tgt_len]
print(tril_matrix)

在这里插入图片描述
这里的1表示有特殊字符。
对于第一行,解码器的输入给一个特殊字符,解码器的输入与输出有一个shift,输入往左shift一位,刚好和输出有一个偏移。
对于第二行,解码器的输入给一个特殊字符和第一个字符,预测下一个字符。

代码

import torch
import numpy as np
import torch.nn as nn
import torch.nn.functional as F


batch_size = 2

#单词表大小
#单词对应的索引数的最大值
max_num_src_words = 8
max_num_tgt_words = 8
#每一个单词的大小
model_dim=8

#序列最大长度
#一整个句子的最大长度,一个句子最多拥有的单词数
max_src_seq_len=5
max_tgt_seq_len=5
max_position_len=5


src_len = torch.Tensor([2,4]).to(torch.int32)
tgt_len = torch.Tensor([4,3]).to(torch.int32) 

# step 1:
#单词索引构成源句子和目标句子,即每个句子里是单词所在的索引数。构建batch,做了padding,默认值为0
#L分别取2,4,取2是长度为2的一个元组,取4是长度为4的一个元组
#src_seq:[tensor([7, 4]), tensor([2, 1, 5, 4])]
#tgt_seq:[tensor([4, 4, 4, 3]), tensor([5, 7, 6])]
src_seq = torch.cat([torch.unsqueeze(F.pad(torch.randint(1,max_num_src_words,(L,)),(0,max(src_len)-L)),0)for L in src_len])
tgt_seq = torch.cat([torch.unsqueeze(F.pad(torch.randint(1,max_num_tgt_words,(L,)),(0,max(tgt_len)-L)),0)for L in tgt_len])

## step 2:构造word embedding
#一个单词对应一行,从1开始,pad的0,所以0行对应pad
#每一行一个embedding向量,每个单词索引是几,我们就取第几行
src_embedding_table=nn.Embedding(max_num_src_words+1,model_dim)
tgt_embedding_table=nn.Embedding(max_num_tgt_words+1,model_dim)
src_embedding=src_embedding_table(src_seq)
tgt_embedding=tgt_embedding_table(tgt_seq)

#step 3:构造position embedding
pos_mat=torch.arange(max_position_len).reshape(-1,1)
i_mat=torch.pow(10000,torch.arange(0,model_dim,2).reshape(1,-1)/model_dim)
pe_embedding_table=torch.zeros(max_position_len,model_dim)
pe_embedding_table[:,::2]=torch.sin(pos_mat/i_mat)
pe_embedding_table[:,1::2]=torch.cos(pos_mat/i_mat)


#改写了pe_embedding
pe_embedding=nn.Embedding(max_position_len,model_dim)
pe_embedding.weight=nn.Parameter(pe_embedding_table,requires_grad=False)

src_pos=torch.Tensor(torch.cat([torch.unsqueeze(torch.arange(max(src_len)),0)for _ in src_len]))
tgt_pos=torch.Tensor(torch.cat([torch.unsqueeze(torch.arange(max(tgt_len)),0)for _ in tgt_len]))

src_pos_embedding=pe_embedding(src_pos)
tgt_pos_embedding=pe_embedding(tgt_pos)

# #softmax演示,scaled的重要性
# alpha1=0.1
# alpha2=10
# score=torch.randn(5)
# prob1=F.softmax(score*alpha1,-1)
# prob2=F.softmax(score*alpha2,-1)
# def softmax_fun(score):
#     return F.softmax(score,-1)
# jaco_mat1=torch.autograd.functional.jacobian(softmax_fun,score*alpha1)
# jaco_mat2=torch.autograd.functional.jacobian(softmax_fun,score*alpha2)

# step 4:构造encoder的self-attention mask,就是一个关系矩阵,没有因果
# mask的shape:[batch_size,max_src_len,max_src_len],值为1或负无穷,负无穷经过softmax变为0,1相乘维持不变
# valid_encoder_pos:[2,4]=>[2,1,4]
valid_encoder_pos=torch.unsqueeze(torch.cat([torch.unsqueeze(F.pad(torch.ones(L),(0,max(src_len)-L)),0)for L in src_len]),2)

#两个矩阵相乘可以得到两两之间的关联性
valid_encoder_pos_matrix=torch.bmm(valid_encoder_pos,valid_encoder_pos.transpose(1,2))
invalid_encoder_pos_matrix=1-valid_encoder_pos_matrix
# True代表这个位置我们需要对它mask
mask_encoder_self_attention=invalid_encoder_pos_matrix.to(torch.bool)

score=torch.randn(batch_size,max(src_len),max(src_len))
masked_score=score.masked_fill(mask_encoder_self_attention,-1e9)
prob=F.softmax(masked_score,-1)

#step 5:构造intra-attention的mask
# Q @ K^T shape:[batch_size,tgt_seq_len,src_seq_len]
valid_decoder_pos=torch.unsqueeze(torch.cat([torch.unsqueeze(F.pad(torch.ones(L),(0,max(tgt_len)-L)),0)for L in tgt_len]),2)

valid_cross_pos_matrix=torch.bmm(valid_decoder_pos,valid_encoder_pos.transpose(1,2))
invalid_cross_pos_matrix=1-valid_cross_pos_matrix
mask_cross_attention=invalid_cross_pos_matrix.to(torch.bool)

score=torch.randn(batch_size,max(tgt_len),max(src_len))
masked_cross_score=score.masked_fill(mask_cross_attention,-1e9)
prob2=F.softmax(masked_cross_score,-1)

# step 6:构造decoder self-attention的mask
valid_decoder_tril_matrix=torch.cat([torch.unsqueeze(F.pad(torch.tril(torch.ones(L,L)),(0,max(tgt_len)-L,0,max(tgt_len)-L)),0)for L in tgt_len],0)
invalid_decoder_tril_matrix=1-valid_decoder_tril_matrix
invalid_decoder_tril_matrix=invalid_decoder_tril_matrix.to(torch.bool)

score=torch.randn(batch_size,max(tgt_len),max(tgt_len))
masked_score=score.masked_fill(invalid_decoder_tril_matrix,-1e9)
prob=F.softmax(masked_score,-1)

# 构建scaled self-attention
# Q,K,V shape:[batch_size*num_head,seq_len,model_dim/num_head]
def scaled_dot_product_attention(Q,K,V,attn_mask):
    score=torch.bmm(Q,K.transpose(-2,-1))/torch.sqrt(model_diml_dim)
    masked_score=score.masked_fill(attn_mask,-1e9)
    prob=F.softmax(masked_score,-1)
    context=torch.bmm(prob,V)
    return context
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值