参考资料见:https://www.bilibili.com/video/av58239477
结构示意图:
- positional embeding
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import math
def get_position_encoding(max_seq_len,embed_dim):
#先初始化一个position encoding,
# embed_dim是字嵌入的维度,
# max_seq_len是句子的最大长度
# 先将句子中每个词的位置初始化为维度与词嵌入一致的0向量,然后将每个进行幂计算
positional_encoding=np.array([
[pos/np.power(10000,2*i/embed_dim) for i in range(embed_dim)]
if pos!=0 else np.zeros(embed_dim) for pos in range(max_seq_len)])
positional_encoding[1:,0::2]=np.sin(positional_encoding[1:,0::2])#表示词嵌入是偶数的位置位置嵌入表示
positional_encoding[1:,1::2]=np.sin(positional_encoding[1:,1::2])#表示词嵌入是奇数的位置位置嵌入表示
return positional_encoding
positional_encoding=get_position_encoding(100,16)
plt.figure(figsize=(10,10))
sns.heatmap(positional_encoding)
plt.title("Sinusoidal Function")
plt.xlabel("hidden dimension")
plt.ylabel("sequence length")
plt.show()
位置编码的周期性变化为2π到10000*2π,实验所得结果如下图所示,表示一句话中的整个位置表示,
上图可较明显看出句子的周期性变化
plt.figure(figsize=(8,5))
plt.plot(positional_encoding[1,1:],label="vocab 1")
plt.plot(positional_encoding[2,1:],label="vocab 2")
plt.plot(positional_encoding[3,1:],label="vocab 3")
plt.plot(positional_encoding[4,1:],label="vocab 4")
plt.plot(positional_encoding[5,1:],label="vocab 5")
plt.plot(positional_encoding[6,1:],label="vocab 6")
plt.legend()
plt.xlabel("sequence length")
plt.ylabel("period of positional encoding")
plt.show()
从上图可以看出,每个词的词嵌入曲线都不同,所以可据此得出位置信息。
2、self-attention
X维度为batch_size,length,embedding,W维度为embeding*embedding
此处Q,K,V的维度为batch_size,length,embedding,embeding的维度需要被head个数整除
所以最后点积之后形成的矩阵维度为length*length,表示句子中单个词与其他词的关系
将最后乘积的结果恢复为均值为1,平方差为1的正态分布
因此得到了归一化矩阵,每一行和为1,表示现在这个词与其他词之间的概率之和为1,然后对V进行加权,对每一维度的信息进行加权提取。
由于通过padding操作保证一个batch中每句话的长度一致,但通过填充0,使得影响softmax函数计算,
即本来无关的词参与了词之间的相关性计算,造成误差,所以对padding 的无效区域要加一个很大的负数偏置值,使得在计算softmax时和padding时该位置都是0
3、Add&Norm(残差连接和LayerNormlization)
残差连接用以避免深层网络的梯度消失,
4、Transformer的Encoder部分的整体架构