8383
8484</details >
8585
86- { /*
87-
88- 学习Transformer的原理,使用PyTorch实现一个简单的Transformer模型,对模型进行训练和推理。通过分布式训练,提升模型训练效率。
89-
90- 这个配置预计显存占用:约 70GB+(使用 A100 GPU)。 且需要1-2周的训练时间,你才能拥有一个属于你自己的大模型(从随机权重开始预训练到基本连贯性)。
9186
92- 如果你的显存不够,刚好也可以通过文档中计算公式,调整模型配置,降低显存占用。这算是一个实践调参练习。
9387
9488## Embedding
9589
9690提前准备:训练好的词表
9791
9892- 文本 通过提前训练好的词表拆分为 Token(分词)
99- - Token 通过提前训练好的词表转化为 Token ID(独热编码)
93+ - Token 通过提前训练好的词表转化为 Token ID
10094- Token ID 通过提前训练好的词表转化为 Token Embedding(词嵌入)
10195- 将位置信息 转化为 位置编码(位置编码)
10296- 将 Token Embedding 和 位置编码 相加 得到 最终的输入向量
121115
122116词嵌入的过程是分割好的词从【嵌入矩阵】中获取自己向量的过程,假设【嵌入矩阵】维度为4(GPT2选用768维)如下:
123117
124- | 词汇/Token | 维度1 | 维度2 | 维度3 | 维度4 |
125- | ---------- | ----- | ----- | ----- | ----- |
126- | \<PAD\> | 0.00 | 0.00 | 0.00 | 0.00 |
127- | \<UNK\> | 0.12 | -0.51 | 0.32 | 0.89 |
128- | 我 | 0.87 | 0.42 | -0.26 | 0.35 |
129- | 机器 | 0.32 | 0.52 | 0.75 | 0.22 |
130- | 学习 | 0.45 | 0.68 | 0.21 | 0.37 |
131- | 爱 | 0.65 | 0.71 | 0.38 | -0.15 |
132-
133- 当输入一个句子"我爱学习机器学习"时,会被分词为["我", "爱", "学习", "机器", "学习"],然后每个词在嵌入矩阵中查找对应的向量,得到一系列向量表示:
134-
135- - "我" → [0.87, 0.42, -0.26, 0.35]
136- - "爱" → [0.65, 0.71, 0.38, -0.15]
137- - "学习" → [0.45, 0.68, 0.21, 0.37]
138- - "机器" → [0.32, 0.52, 0.75, 0.22]
139- - "学习" → [0.45, 0.68, 0.21, 0.37]
140-
141- 这样,原本的文本序列就被转换为向量序列,这个过程人可以通过肉眼直接看到,机器如何完成?你可以使用for循环加判断,但是有更简单快速的方式:独热编码
142-
143- 独热编码(One-Hot Encoding)是一种将每个词表示为一个向量,该向量的长度等于词表大小,只有对应词的位置为1,其余位置为0的编码方式:
144-
145- ```python
146- import numpy as np
147-
148- # 假设我们有一个词表和嵌入矩阵
149- # 词 : token_id
150- vocab = {"<PAD>": 0,
151- "<UNK>": 1,
152- "我": 2,
153- "爱": 3,
154- "学习": 4,
155- #..........
156- "机器": 5000,
157- }
158- embedding_matrix = np.array([
159- # 假设为N个维度,N列,这里具象化为4列
160- [0.00, 0.00, 0.00, 0.00], # <PAD>
161- [0.12, -0.51, 0.32, 0.89], # <UNK>
162- [0.87, 0.42, -0.26, 0.35], # 我
163- [0.65, 0.71, 0.38, -0.15], # 爱
164- [0.45, 0.68, 0.21, 0.37], # 学习
165- # ........
166- [0.32, 0.52, 0.75, 0.22], # 机器
167- ])
168-
169- # 将词转换为独热编码
170- def word_to_onehot(word, vocab_size):
171- onehot = np.zeros(vocab_size)
172- if word in vocab:
173- onehot[vocab[word]] = 1
174- # 以 "我"这个字为例,vocab["我"] 为2,对应下标位置的值为1,其他为0.
175- # onehot[2] = 1 即[0,0,1,0,0,.....,0]
176- else:
177- onehot[vocab["<UNK>"]] = 1 # 即未知为1.其他为0 [0,1,0,0,0,.....,0]
178- return onehot # 形状为 :1,5000
179-
180- # 通过独热编码获取词嵌入
181- def get_embedding_via_onehot(word, vocab, embedding_matrix):
182- onehot = word_to_onehot(word, len(vocab))
183- return np.dot(onehot, embedding_matrix) # 1,5000 @ 5000,N列 = 1,N列
184-
185- # 示例
186- tokens = ["我", "爱", "学习", "机器", "学习"] # 5个词
187- embeddings = [get_embedding_via_onehot(token, vocab, embedding_matrix) for token in tokens]
188- # 形状为 5 行 N列,每行即是词对应的向量
189- ```
190-
191- 实际应用中,我们通常直接使用词索引进行查找,避免独热编码的稀疏计算:
192-
193- ```python
194- import torch
195- import numpy as np
196- embedding_matrix = np.array([
197- # 假设为N个维度,N列,这里具象化为4列
198- [0.00, 0.00, 0.00, 0.00], # <PAD>
199- [0.12, -0.51, 0.32, 0.89], # <UNK>
200- [0.87, 0.42, -0.26, 0.35], # 我
201- [0.65, 0.71, 0.38, -0.15], # 爱
202- [0.45, 0.68, 0.21, 0.37], # 学习
203- # ........
204- [0.32, 0.52, 0.75, 0.22], # 机器
205- ])
206-
207- # 使用PyTorch的Embedding层
208- vocab_size,embedding_dim = embedding_matrix.shape
209- # embedding_dim 表示词嵌入向量的维度大小,即每个词被映射为4维向量,自己根据预定义的嵌入矩阵设置
210- # vocab_size 表示词汇表的大小,自己根据预定义的嵌入矩阵设置
211-
212- # 假设我们有一个词表和嵌入矩阵
213- vocab = {"<PAD>": 0,
214- "<UNK>": 1,
215- "我": 2,
216- "爱": 3,
217- "学习": 4,
218- #..........
219- "机器": 5000,
220- }
221-
222- # 创建嵌入层并初始化权重
223- embedding = torch.nn.Embedding(vocab_size, embedding_dim)
224- # 设置预定义的嵌入矩阵
225- embedding.weight.data = torch.tensor(embedding_matrix, dtype=torch.float)
226-
227- # 将文本转换为索引
228- def tokens_to_indices(tokens, vocab):
229- return [vocab.get(token, vocab["<UNK>"]) for token in tokens]
230-
231- # 示例
232- tokens = ["我", "爱", "学习", "机器", "学习"]
233- indices = tokens_to_indices(tokens, vocab)
234- token_indices = torch.tensor(indices)
235- token_embeddings = embedding(token_indices) # 并行计算
236-
237- print(token_embeddings)
238- '''
239-
240- 在实际的Transformer模型中,词嵌入通常是模型训练的一部分,会根据任务目标不断优化调整。这种基于查表的方式比循环判断更高效,可以并行处理整个序列的所有词,大大提高了计算速度。
241-
242- 词嵌入只考虑了词的语义信息,但在序列中,词的位置也很重要。Transformer通过位置编码(Positional Encoding)来捕捉序列中词的位置信息
243- '''
244- ```
245118
246119### 位置编码
247120
@@ -322,6 +195,8 @@ print(final_input)
322195这个空间占用代表了64组数据,每组数据有1024个token,每个向量有768个参数,每个参数占用16位(2字节)。
323196:::
324197
198+ { /*
199+
325200## 注意力机制
326201
327202### 拆分QKV
@@ -340,6 +215,13 @@ print(final_input)
340215
341216其中,$W_q$、$W_k$、$W_v$ 是可变权重矩阵,$X$ 是输入的词向量。
342217
218+ :::tip
219+
220+ 在PyTorch等深度学习框架中,为了高效利用计算资源(例如CUDA核心),我们不会真的执行三次独立的矩阵乘法。
221+
222+
223+ :::
224+
343225
344226### 多头分割
345227
0 commit comments