transformer 框架(根据李宏毅老师的视频整理的笔记)
左边的是encoder编码器,右边是decoder解码器,解码器在之前时刻的输出作为 预测的输入
Embedding就是从原始数据提取出来的Feature
Lawer norm(是把行样本标准化)
Batch norm (是把某一列向量标准化)
残差链接
Add指 X+MultiHeadAttention(X),是一种残差连接,可以跨层向上传递信息
Norm指 Layer Normalization,通常用于 RNN 结构,Layer Normalization 会将每一层神经元的输入都转成均值方差都一样的,这样可以加快收敛
Key words: blue mlp 残差连接 正交基
李宏毅 transformer模型
2.1 总结:
是什么? 基于seq2seq架构的transformer模型可以完成NLP领域研究的典型任务,如机器翻译,文本生成,同时还可以构建预训练模型,用于不同任务的迁移学习。
基本组成
输入:源语言文本和目标文本,包含源文本嵌入层及位置编码,目标文本嵌入层及其位置编码
编码器
解码器
输出 包含linear(得到outputsize), softmax(求最大的值)
编码器部分
• 由N个编码器层堆叠而成
• 每个编码器由2个子层连接结构组成
• 第一个包括一个多头自注意力子层和规范化层以及一个残差连接
• 第二个子层连接结构包括一个前馈全连接子层和规范化层和一个残差连接
解码器部分
• 由N个解码器层堆叠而成
• 每个解码器由三个子层连接结构组成
• 第一个包括一个==多头自注意力子层==(masked)和规范化层以及一个残差连接
• 第二个子层包括一个多头注意力子层和规范化层以及一个残差连接
• 第三个子层连接结构包括一个前馈全连接子层和规范化层和一个残差连接
2.2 输入部分实现
○ 源文本嵌入层及位置编码
○ 目标文本嵌入层及其位置编码

○ 文本嵌入层的作用,都是为了将文本中的词汇的数字表示转变为向量表示,希望在这样高维的空间 中捕捉词汇间的关系。
最简单的方法是 one-hot(将每个单词表示成0,1元素组成的向量),文本转变向量的几种常用的方法(one-hot,TF-IDF,word2vec)_文件转向量-优快云博客
One-hot 编码():
将每个单词表示为一个独热向量,向量维度为词汇表大小,其中只有一个元素为1,其余为0。将所有单词的独热向量拼接起来,得到文本的向量表示
词转化为向量方法_通过词嵌入将单词转为向量-优快云博客
文本嵌入层的代码分析
#构建Emberdding类来实现文本嵌入层
class Embedings(nn.Module):
def __init__(self, d_model, vocab_size):
#vocab_size:词典大小
#d_model:词向量维度
#定义Embedding层
super(Embedings, self).__init__()
self.embed = nn.Embedding(vocab_size, d_model)
self.d_model = d_model
def forward(self, x):
#x 代表输入进模型的文本通过词汇映射后的数字张量
return self.embed(x) * math.sqrt(self.d_model)
d_model = 512
vocab_size = 1000
input = Variable(torch.LongTensor([[100, 2, 421, 508], [491, 998, 1, 221]]))
emb = Embedings(d_model,vocab_size)
embr = emb(input)
# print(embed(input).shape)
print("embr:",embr)
print(embr.shape)
• 位置编码器的作用
○ 因为在transformer的编码器结构中,并没有针对词汇位置信息的处理,因此需要在Embedding层后加入位置编码器,将词汇位置的不同可能会产生不同的语义的信息引入到词嵌入张量中,以弥补位置信息的缺失
○ Dropout:置0比率(置0比率就是以百分之多少的比率让神经网络中的某些神经元失效),max_length:每个句子的最大长度
• 位置编码器的代码分析
```
#定义位置编码
class PositionalEncoding(nn.Module):
def __init__(self, d_model, dropout, max_len=5000):
#d_model:词向量维度
#dropout:dropout比率,置0的概率
#max_len:最大序列长度,每个句子的最大长度
super(PositionalEncoding, self).__init__()
#实例化nn中预定义的dropout层,将dropout传入层中,获得对象self.dropout
self.dropout =nn.Dropout(p=dropout)
#初始化一个位置编码矩阵,它是一个θ阵,矩阵大小是max_len*d_model,形状很重要
pe = torch.zeros(max_len, d_model)
#初始化一个绝对位置矩阵,在这,词汇的位置矩阵就是他的索引
position = torch.arange(0, max_len).unsqueeze(1) # (1,max_lenth)convert to (max_lenth,1)
#接下里考虑的是如何将位置信息加入到位置编码矩阵中,即positional 如何加入到pe中?
# 计算位置编码
#div_term是一个变形矩阵,它的维度是d_model/2,每个元素是一个常数,这个常数是一个很大的数,这个数是一个固定值,这个值是10000的负数除以d_model
#为什么要变形矩阵,是因为positional 到pe差一个1*d_model的矩阵
div_term = torch.exp(torch.arange(0, d_model, 2) * -(math.log(10000.0) / d_model))
pe[:, 0::2] = torch.sin(position * div_term)#给偶数位置加入d_model/2个sin值
pe[:, 1::2] = torch.cos(position * div_term)#给奇数位置加入d_model/2个cos值
#pe现在是一个二维的矩阵
#输入是三维的,所以需要扩展一下
pe=pe.unsqueeze(0)
#把pe注册成一个模型buffer,相当于一个常量,不会变化,训练的时候重新加载时,模型结构与参数一同被加载
self.register_buffer('pe', pe)
def forward(self, x):
# x代表文本序列的词嵌入向量表示,是一个三维的张量,维度是batch_size*seq_len*d_model
#把pe的维度扩展成x的维度,维度是batch_size*seq_len*d_model
#pe的编码太长了,所以需要截取一下,截取成和x一样的维度,也就是max_length对应的维度缩减到x的维度,这样才能相加
#这个也可以说名,transformer可以处理变长的序列
#requires_grad=False表示不需要计算梯度
#x.size(1) 确实是指 x 张量的第二维的大小,即 x 的列数,x.size(0)是指x张量的第一维的大小,即x的行数
x = x + Variable(self.pe[:, :x.size(1)], requires_grad=False)
return self.dropout(x)
```
学习中。。。