Transformer

1 original transformer

1.1 生成时加速

past_key_value,见AtomFire的X/trick:\\wsl.localhost\Ubuntu\home\alan\desktop\project\AtomFire\demo\X\trick\past_key_value.ipynb
Pasted image 20240228203059.png

每次生成一个单词,复用前面生成单词的 K、V ,concat 起来做总的新 K、V
Pasted image 20240125230452.png

1.2 professor limu实现细节

  1. paddinmg mask数据格式分为有batch和无batch,有batch就是下图所示,第一个batch的两句话,有效长度分别是1和3,第二个则是2和4。
    Pasted image 20240129202658.png
    无batch会做一个复制操作,认为每一个batch的每一句话有效长度是一样的。
  2. 训练和预测时是分开的,训练时输入是预测监督标签的整句话,如下图1所示,而预测用的是一个一个的预测单词,如图2所示。

值得说明的是,key_padding_mask本质上是遮住key这个位置的值(置0),但是 token本身,也是会做qkv的计算的,以第三行数据的第三个位置为例,它的q是的embedding,k和v分别各是第一个的‘a’和第二个的‘b’,它也会输出一个embedding。

所以你的模型训练在transformer最后的output计算loss的时候,还需要指定ignoreindex=pad_index。以第三行数据为例,它的监督信号是[3205,1890,0,0],pad_index=0 。如此一来,即便位于的transformer会疯狂的和有意义的position做qkv,也会输出embedding,但是我们不算它的loss,任凭它各种作妖。

训练时每一次预测,第一个start预测下一个I, I预测下一个 am 以此类推。这样,最后就能生成一个len的句子。所以,实际上需要像LSTM那样有一个tgt_y_front、tgt_y_end。

Pasted image 20240125213235.png|475

  1. 预测用的是之前全部的预测值作为key、value,而query则是第t个预测值。

Pasted image 20240125230452.png

1.3 广播实现的绝对位置编码相加

>>> x = torch.randn((16, 256, 512))
>>> y = torch.randn((512, 512))
>>> y = y.unsqueeze(0)
>>> (x + y[ : , : x.shape[1]]).shape
torch.Size([16, 256, 512])

1.4 mask实现语法涉及的广播机制学习

mask 机制的实现:
其中的10表示 hidden_size,2,3,4 实际的元素个数等价于hidden前面的,也就是 b, l, h

import torch

x = torch.arange(10)[None, :]
y = torch.tensor([2,3,4], dtype=torch.int32)[:,None]
mask = x < y
print(mask)

涉及到torch 广播机制。x < y 时,x (1, hidden_size) y (number, 1)
y会将1变为hidden_size,沿着最里面的行复制,具体如下:
Pasted image 20240106143224.png|500
x会复制number份

import torch
x = torch.arange(10)
# 手动进行广播 # 扩展 x 的形状以匹配 y 的形状 
y = torch.tensor([2,3,4], dtype=torch.int32)

x_broadcasted = x.repeat(3, 1)
y_broadcasted = y.unsqueeze(1).repeat(1, 10)
print("\nManually Broadcasted x:") 
print(x_broadcasted) 
print("\nManually Broadcasted y:") 
print(y_broadcasted)
mask_Manually = x_broadcasted < y_broadcasted
print(mask_Manually)
print(torch.equal(mask, mask_Manually))

1.5 Stanford NLP实现细节

learn-nlp-with-transformers/docs/篇章2-Transformer相关原理/2.2.1-Pytorch编写Transformer.md at main · datawhalechina/learn-nlp-with-transformers · GitHub

概要

具体

  1. 编码器和解码器框架,定义了子模块参数和之间的连接方式,且不同于limu老师的耦合,其forward过程在训练和预测时也还是统一的,适合作为net进行复用。
  2. 数据流动方面:(batch, seq_len) -> mask (batch, 1, seq_len),mask之后
  3. padding_mask时详细的过程
    Pasted image 20240320201651.png|500
    每一个头、len中的每一个,的每一个hidden,都使用广播的同一个mask、函数是masked_fill。

Pasted image 20240723154514.png

这样,后面的F.softmax(x, dim = -1)就可以保证每一个头的注意力矩阵都进行全部的归零。
Pasted image 20240723154528.png|500

1.6 问题

transformer并行度问题,阐述编码器和解码器在训练和推理阶段的并行能力

encoder一直都是并行的;decoder训练时并行,推理时串行。
decoder训练时为什么可以并行?原因在于teacher-force和look-ahead mask。

transformer中的self-attention、multi-head attention均使用了mask,原因和目的

encoder self-attention中使用的是padding mask,其方法是将QK计算之后的padding位置的数字变为一个很小的数,这样在计算softmax后,padding位置的值会变为0,目的是为了使得注意力机制计算和 loss 计算时,不考虑padding的无意义字符。
decoder self-attention中使用的是look-ahead mask,其方法是将答案QK计算之后的注意力矩阵(如下图所示),进行遮掩,目的是在训练并行时遮掩使其看不到未来的信息,而预测 trg_y ,从而不泄漏答案。
Pasted image 20240125213235.png|400

FFN的(b, n, d)为什么不把n, d合并为一个纬度做 MLP

合并后 token 彼此间的独立性丧失了,从而使得 token

transformer代码中并行代码:attention mask、位置编码矩阵,理解与实现

OK

layernorm和batchnorm的区别,为什么NLP中一般采用layernorm

句子长度的不一致;一个样本内的特征联系是很密切的

Q、K矩阵相乘为什么最后要除以√d_k

一般假设 Q、K.T 512 的每一维度,均为正态分布,那么 QK 相乘后,sqrt (d_k) 可以将标准差又缩放至 1
具体计算:
为什么transformer qk之后除以根号dk

编码器与解码器的Embedding层的权重为什么要乘以√d_model

缩放 embedding,使其 embedding的编码空间和 positon 位置编码 相符合

Transformer模型的空间复杂度是多少?

Pasted image 20240125213844.png|500

1.6.1 补充

微信公众平台
Bert/Transformer 被忽视的细节(或许可以用来做面试题) - 知乎

2 Encoder-Decoder VS Decoder only

Pasted image 20240927151639.png

Pasted image 20240927151750.png

Encoder only 就是只有 self-attention 和
典型例子:Bert( mask training、trainable pos embedding、seg embedding)

2.1 参考资料

Stanford CS25: V4 I Hyung Won Chung of OpenAI - YouTube 23:29
x.com
What happened to BERT & T5? On Transformer Encoders, PrefixLM and Denoising Objectives — Yi Tay

3 RoPE

旋转编码
Pasted image 20241009162057.png
公式推导中,(8) 式的推导过程:

Θf(q,m)=Θf(q)+φ(m)Θf(k,m1)=Θf(k)+φ(m1)

整理且按照 (5) 式第二子式,即可得到 (8) 式

在θiθi的选择上,我们同样沿用了Sinusoidal位置编码的方案,即θi=10000−2i/dθi=10000−2i/d,它可以带来一定的远程衰减性。

GitHub - ZhuiyiTechnology/roformer: Rotary Transformer 提供了旋转位置编码的实现


以下参见 Transformer架构变种(优化).pdf

4 Bert

Mask-pretrain 核心代码如下:

def random_word(self, sentence):  
	tokens = sentence.split()
	output_label = []
	output = []  
  
# 15% of the tokens would be replaced  
	for i, token in enumerate(tokens):  
		prob = random.random()  
  
		# remove cls and sep token  
		token_id = self.tokenizer(token)['input_ids'][1:-1]  
		  
		if prob < 0.15:  
		prob /= 0.15  
		  
			# 80% chance change token to mask token  
			if prob < 0.8:  
				for i in range(len(token_id)):  
					output.append(self.tokenizer.vocab['[MASK]'])  
  
			# 10% chance change token to random token  
			elif prob < 0.9:  
				for i in range(len(token_id)):  
		》output.append(random.randrange(len(self.tokenizer.vocab))) 
			# 10% chance change token to current token 
			else:  
				output.append(token_id)  
				
			output_label.append(token_id)  
  
		else:  
			output.append(token_id)  
		# 表示该tnk没有被mask-pretrain,那么就置零,不能是其他数字
		for i in range(len(token_id)):  
			output_label.append(0)  
  
	# flattening  
	output = list(itertools.chain(*[[x] if not isinstance(x, list) else x for x in output]))  
	output_label = list(itertools.chain(*[[x] if not isinstance(x, list) else x for x in output_label]))  
	assert len(output) == len(output_label)  
	return output, output_label

self.criterion = torch.nn.NLLLoss(ignore_index=0)
or
self.criterion = torch.nn.CrossEntropy(ignore_index=0)

Mastering BERT Model: Building it from Scratch with Pytorch | by CheeKean | Data And Beyond | Medium

5 transformer-XL

分段式循环 + 相对位置编码

6 realformer

融合了Pre-Norm 和 Post-Norm ,加了个残差

7 Funnel-Transformer

Pasted image 20241010142552.png

轻量级 transformer:使用池化降低参数量,decode 首先上采样,

8 T5

9 LLM

9.1 资源需求

9.1.1 速度、内存

很好的一篇论文 Transformer Math 101 | EleutherAI Blog