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
embedding类似于一个字典,里面是英文,src是需要查找的英文在字典中的位置,
src_embedding_table是对应的英文内容。
1.序列建模:source和target,里面的字符是单词索引
2.创建embedding_table,1中的索引表示对应table的位置,0留给padding
3.创建src_embedding_table或tgt_embedding_table
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】
由列表变成了一个张量
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)
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)
# 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