从初中物理到大模型原理(四)
附上前三篇的链接:
从初中物理到大模型原理(一)
从初中物理到大模型原理(二)
从初中物理到大模型原理(三)
一、简单版大模型
结合前面几篇,我们简单整理一下大模型在整个学习过程中的步骤:
- 把输入转成词向量;
- 用三个线性层把词向量转换成 W q 、 W k 、 W v \mathbf{W_q}、\mathbf{W_k}、\mathbf{W_v} Wq、Wk、Wv,汇聚后重新得到输出;
- 再用一个线性层输出,形成由词库组成的向量;
- 选择概率最大的token,转为单词;
下面用代码实现一下以上的过程
import torch
from torch import nn
import tiktoken
# 引入分词器
tokenizer = tiktoken.get_encoding("gpt2")
# 把输入转成词向量 start
start_context_en = "Hello, I am"
en_tokenid = tokenizer.encode(start_context_en)
print(en_tokenid)
# en_tokenid = [15496, 11, 314, 716]
en_tokenid_tensor = torch.tensor(en_tokenid).unsqueeze(0)
tok_emb = nn.Embedding(50257, 768)
en_embeds = tok_emb(en_tokenid_tensor)
# 把输入转成词向量 end
# 自注力机制 start
W_query = nn.Linear(768, 768, bias=False)
W_key = nn.Linear(768, 768, bias=False)
W_value = nn.Linear(768, 768, bias=False)
query = W_query(en_embeds)
key = W_key(en_embeds)
value = W_value(en_embeds)
attn_scores = query @ key.transpose(1, 2)
attn_weights = torch.softmax(attn_scores, dim=-1)
context_vec = (attn_weights @ value)
print(context_vec.shape)
# context_vec.shape = torch.Size([1, 4, 768])
# 自注力机制 end
# 线性层将输出,形成由词库组成的向量 start
out = nn.Linear(768, 50257, bias=False)
o = out(context_vec)
# 线性层将输出,形成由词库组成的向量 end
# 选择概率最大的token,转为单词 start
logits = o[:, -1, :]
probas = torch.softmax(logits, dim=-1)
# 取概率最大的出来
idx_next = torch.argmax(probas, dim=-1, keepdim=True)
print(idx_next)
# tensor([[25777]])
decoded_text = tokenizer.decode(idx_next.squeeze(0).tolist())
print(decoded_text)
# 选择概率最大的token,转为单词 end
Republican
上面这部分代码,每个人执行的结果都不一样。因为这个模型没有进行任何的学习就直接开始输出,必然不准确。训练的部分,就不再这里展开了。
后面我再用另外一个专题,专门说一下大模型的训练和微调。
二、最后一个问题
还有最后一个问题:我们在设计模型的时候,是用一个层数少,但是很宽的,还是层数多,相对较窄的模型呢? 答案肯定是层数多,相对较窄的模型比较好。更深更窄的模型可以学习到更多的特征,对分布式的训练更友好…
这些答案随处可见,我想谈一谈我对这件事情的理解。
神经网络本身是模拟人脑中神经元之间的连接与信息传递机制。希望它可以向人一样思考和决策。那我们在学习的时候,也并不是小学,初中,高中,大学一起学,而是层层递进。如果人类在学习的时候需要这样,那么这个模拟人的网络也应该这样。
神经网络是个黑盒,一堆参数就能决策。
但是更具体,更简单易懂的解释,等到我们讲大模型训练,反向传播,优化算法的时候再说吧。
think twice code once