生物大分子平台(13)
2021SC@SDUSC
0 本周工作
本周学习谷歌gpt的相关概念,并阅读了gpt-2的代码。
1 概述
Transformer的出现给NLU和NLG任务带来了巨大进步,GPT-2成为了最近几年顶尖生成模型的泛型,代码部分OpenAI原始Code基于tensorflow1.x。下面我们将根据gpt的几个不同部分进行代码的解读。
2 代码解读
2.1 embedding
def model(hparams, X, past=None, scope='model', reuse=tf.AUTO_REUSE):
模型的输入信息分为两个部分,分别是X和past,X是语言模型的输入,past是已生成上文的状态,实际上分为四种情况:
1、训练阶段,X为一组训练数据,past为空
2、条件生成初始阶段,X为条件语句,past为空
3、无条件生成初始阶段,X为[end],past为空
4、生成过程中,X为上一次生成的词语,past为之前所有K和V
在讲解代码之前,我们首先要了解,信息的流动是本质性的,我们要利用好信息流动这个主线
- wpe为位置嵌入矩阵,size为最大序列长度X嵌入维数,定义为tf.variable,并用正态分布进行初始化
- wte是词语嵌入矩阵,size为单词表长度X的嵌入维数,定义为tf.variable,并用正态分布进行初始化
- past_length是已生成上文的长度,如果past为空,则为0,若不为空,则为最后第二维的第五位
- h是由输入X提供的信息,也是12层Transformer block的初始输入,它由词语嵌入向量和位置嵌入向量加和而成
- 词语嵌入向量由tf.gather()在词语嵌入矩阵wte中取X对应的值,位置嵌入向量由tf.gather()在位置嵌入矩阵wpe中取X对应的值
- position_for函数输入X和已产生的上文长度past_length,输出为要生成的下标
wpe = tf.get_variable('wpe', [hparams.n_ctx, hparams.n_embd],
initializer=tf.random_normal_initializer(stddev=0.01))
wte = tf.get_variable('wte', [hparams.n_vocab, hparams.n_embd],
initializer=tf.random_normal_initializer(stddev=0.02))
past_length = 0 if past is None else tf.shape(past)[-2]
h = tf.gather(wte, X) + tf.gather(wpe, positions_for(X, past_length))
batch_size = tf.shape(tokens)[0]
nsteps = tf.shape(tokens)[1]
return expand_tile(past_length + tf.range(nsteps), batch_size)
2.2 attn
- x为嵌入向量,n_state为嵌入维度,past为K值和V值。
- 模块输入嵌入向量,输出向量在本层的特征。
def attn(x, scope, n_state, *, past, hparams):
2.3 multihead_attn(q,k,v)
- matmul中transpose_b参数意味着乘之前将K转置。
- matmul对最后二维进行,即对Q的feature和K的feature做点积,计算出W的值,表示V的得分。
def multihead_attn(q, k, v):
w = tf.matmul(q, k, transpose_b=True)
W = Q K T W=QK^T W=QK
w = w * tf.rsqrt(tf.cast(v.shape[-1].value, w.dtype))
W = W d k W=\frac {W}{\sqrt d_k}
- Gpt-2模型使用masked attention,目的是为了避免模型在生成第i个词时使用i之后的词语, 因为在实际预测时后面的词是不可知的。
3 gpt适用领域
谷歌公司提供专门的API接口对相关需求的项目提供支持。