Bert和gpt都是基于transformer的,在此之前流行的是rnn,复杂度有限且效率不高,容易受到文本长度的限制。
 项目地址:https://github.com/lansinuote/Transformer_Example
 b站视频:https://www.bilibili.com/video/BV19Y411b7qx?p=9&spm_id_from=pageDriver&vd_source=eca9b4f9ea9577b666c089a010621a99
总体架构

 
 
 编码器:自注意力层->全连接层
 解码器:自注意力层->编码解码注意力->全连接层
计算注意力

 词向量编码
 x1*wq得到queries,以此类推,得到Q K V
 
 除以8和词向量的编码有关
 z1是自注意力计算的结果
 
 
 得到多组QKV向量,就是多头注意力
 
 图中有八组这样的矩阵
词向量编码

 右边计算出的结果是一样的,transformer会做同样的处理


 pos是第几个词,i是第几个向量,pos是行,i是列,偶数列是上面的式子计算,奇数列是下面的式子计算
 红色是大数,蓝色是小数,第0列是sin,第1列是cos,波动比较快,波动频率会逐渐降低
MASK

 把a b pad理解为一句话,为了把各个句子保持相同长度,会补充pad。对pad的计算没有意义,把对pad的注意力全部替换成mask,但是pad对其他的词的注意力不做处理。
 
 b和c是要预测的结果,所以计算b的时候不能让a看到。
 
对两个mask取一个并集
完整计算流程

 layerNorm这部分是短接的计算,然后数据标准化,得到z1,z2,全连接运算
 
 n个encoder上下串联,decoder拿到x1,x2,也要计算注意力,标准化,encoder-decoder这一层和self-attention其实一样,只不过qkv是拿encoder计算得出的结果当作kv,自己的自注意力层计算出的结果当作q,短接相加,标准化,全连接,标准化,decoder也会有n个,串联,最终做一个全连接层的输出。
 
 翻译过程,不断预测下一个字
实验数据的生成策略
 
词表是x语言的所有词汇,这里只有7个词,模仿自然语言,采样概率不等,x的长度随机,均为模仿自然语言。
 最终目的:x翻译成y
 所以x和y要有关联性,这里的关系非常简单,黑色箭头表明y当中的每一个词是x逆序得到的,小写字母翻译成大写字母,y当中的数字用9-x得到
 虚线的箭头表明,y中的第一位取决于x的最后一位,这样y的第一位和第二位是相同的,这样做是为了让y中的数据长度比x多一位,同时增加映射复杂度
 
 
代码实现:定义数据

 data.py
 
 字典中共39个词
 
 m的概率最高
 生成数据的函数:
 
 
 
 
 定义数据集:

 len固定返回10万,get_data生成一对x和y
 数据加载器比较简单,每次调用生成8对x和y
代码实现:util.py
注意力计算函数:
 
 几维向量就除以几的平方根
归一化层:
 
 规范化,数值的均值是0,标准差是1,bn(batch normalization)取不同的样本做归一化,ln(layer nomalization)对不同通道做归一化。
多头注意力计算层:
 
 
 
 位置编码层:
 
 
 全连接输出层:
 
mask.py

 trilmask 上三角mask
 
 
model.py
编码器:
 
 完整的编码器:
 
 解码器:
 
 完整的解码器:
 
 主模型:
 
 维度是变化的,注释有误
main.py

 第一列是epoch 第二列是i 第三列是learning rate 第四列是loss 不断下降 第五列是正确率,97%
 
 预测时不需要y的最后一个字符,y的第0个字符一定是SOS,不需要预测
 
 在后面补上49个pad
 
 
 
 
 预测结果几乎一模一样
一个更加复杂的翻译任务
用transformer做加法
 
 y是x左右两边的相加得到的,这个难度要高一些,替换掉生成数据的函数就可以得到,训练10个epoch,learning rate decay也生效了,最终准确率是92%
 



















