揭秘大模型的魔法:從Transformer架構開始,一步步揭開它的神秘面紗

大家好,我是寫代碼的中年人,本章我們正式進入Transformer架構的學習。
從 ChatGPT 到文生圖,從語音助手到AI繪本的自動生成,背后幾乎都躲著一個強大的架構,它像一臺“魔法機器”,能讀懂語言、生成內容、甚至推理判斷。但這一切魔法的根基,其實都是數學和工程的藝術結晶。
這一章,我們不再浮于表面,不再喊口號,不再說“Transformer很強”,“注意力是核心”這種說了等于沒說的廢話,而是擼起袖子,從最基本的構件開始,一點點拼出這個神奇架構的模樣,帶你看懂它、拆解它、理解它的工作邏輯。
什么是注意力機制
要想搞懂 Transformer,我們得從一個聽起來就很學術、但其實非常接地氣的概念說起--注意力機制(Attention Mechanism)。
什么是注意力機制呢?我們先看下生活中的例子:
當你你在咖啡館里一邊聽朋友聊天,一邊偷瞄手機上的消息,還要留意服務員端來的咖啡。這時候,你的大腦會自動分配注意力:朋友講到關鍵劇情時,你耳朵豎起來;手機彈出老板的消息,你眼睛趕緊掃一眼。這就是“注意力”的本質——在信息爆炸的場景里,挑出最重要的部分優先處理。Transformer的注意力機制,干的就是這個活兒!
01、注意力機制:我為什么只看你?
好了,進入正題。注意力機制的核心思想是:不是所有信息都同樣重要。在處理一段話或者一堆數據時,模型得學會“挑重點”。比如,你讀“今天天氣很好,我想去爬山”這句話,注意力機制會幫模型搞清楚“很好”和“爬山”之間的關系,而不是傻乎乎地把“今天”看得跟“爬山”一樣重要。
那它怎么挑重點呢?我來給你拆解一下這個機制的三個步驟,用我的“第一人稱視角”帶你體驗一下:
1. 我先給每個詞打個分!
假設我是一個Transformer模型,正在處理“我愛吃蘋果”這句話。每個詞(“我”“愛”“吃”“蘋果”)都會被轉成一個數字向量(就像給每個詞發一個“身份證”)。然后,我會用一種叫:查詢(Query)、鍵(Key)、值(Value)的機制來算每個詞的重要性。
查詢(Query):我問自己,“現在我在看哪個詞?它想跟誰搭上關系?”
鍵(Key):每個詞都舉手說,“嘿,我在這兒!看看我有多重要!”
值(Value):如果某個詞被我選中,它會把自己的“信息”貢獻出來。
比如,我在看“吃”這個詞時,會問:“‘吃’跟哪個詞最相關?”然后我會算一下“吃”跟“我”“愛”“蘋果”的匹配度(通過向量點積)。結果發現,“吃”跟“蘋果”的關系最緊密(畢竟吃的是蘋果,不是“我”),于是我給“蘋果”打個高分!
2. 我把分數變成權重!
得分算出來后,我會把這些分數變成注意力權重。
這就像我在咖啡館里決定:朋友的八卦占我注意力的70%,手機消息占20%,服務員的咖啡占10%。在Transformer里,我用一個叫Softmax的函數,把分數變成0到1之間的比例,確保總和是100%。這樣,在“我愛吃蘋果”這句話中,“蘋果”可能得到0.6的權重,“我”和“愛”各分到0.2和0.1。
3. 我根據權重提取信息!
有了權重,我就知道該多關注誰了。我會把每個詞的“值”(Value)按權重加起來,生成一個新的向量。
這個向量就像是“吃”這個詞的“注意力總結”,里面融合了“蘋果”的信息最多,還有一點“我”和“愛”的影子。這樣,我就能更好地理解“吃蘋果”這件事,而不是被無關的信息干擾。
02、Transformer的基本結構
我們知道在論文《Attention is All You Need》中首次提出了Transformer,主要有兩個部分組成了Transformer架構:
編碼器(Encoder):把輸入句子“壓縮”成一坨高維向量;
解碼器(Decoder):根據這些向量,“翻譯”成輸出。
在GPT這種大模型中,其實只用了Decoder部分;而在機器翻譯里,比如英語轉中文的模型,會把兩個都用上。
在這里我不做太多解釋,本次文章有淺到深會做詳細說明。
03、實現一個簡單的自注意力機制
前面文章我們已經講過把詞元變為隨機的向量值,本次我們就實現計算一個詞元的上下文向量。
我們使用四維嵌入向量,并隨機初始化它們的值,我們用"年"詞元進行求上下文向量。
import numpy as np
# 固定隨機種子,確保結果一致
np.random.seed(42)
# 句子和每個字
tokens = list("寫代碼的中年人")
n = len(tokens)
d = 4 # 每個字的向量維度
# 生成詞向量:shape (n, d)
embeddings = np.random.randn(n, d)
# 打印初始化向量
print("=== 每個字的初始向量 ===")
for i in range(n):
print(f"{tokens[i]}: {embeddings[i]}")
# 以“年”作為 Query
query_index = tokens.index("年")
query_vector = embeddings[query_index] # shape: (d,)
# 點積計算注意力分數(query_vector 與每個詞做點積)
scores = embeddings @ query_vector # shape: (n,)
# Softmax 歸一
def softmax(x):
e_x = np.exp(x - np.max(x)) # 減去最大值防止數值爆炸
return e_x / e_x.sum()
attention_weights = softmax(scores) # shape: (n,)
# 計算上下文向量(加權求和)
context_vector = attention_weights @ embeddings # shape: (d,)
# 輸出注意力分數
print("\n=== 注意力分數(點積) ===")
for i, s in enumerate(scores):
print(f"‘{tokens[i]}’ 的分數: {s:.4f}")
# 輸出注意力權重
print("\n=== 注意力權重(softmax歸一) ===")
for i, w in enumerate(attention_weights):
print(f"‘{tokens[i]}’ 的權重: {w:.4f}")
# 輸出上下文向量
print(f"\n=== 上下文向量 for ‘年’ ===\n{context_vector}")# 輸出
=== 每個字的初始向量 ===
寫: [ 0.49671415 -0.1382643 0.64768854 1.52302986]
代: [-0.23415337 -0.23413696 1.57921282 0.76743473]
碼: [-0.46947439 0.54256004 -0.46341769 -0.46572975]
的: [ 0.24196227 -1.91328024 -1.72491783 -0.56228753]
中: [-1.01283112 0.31424733 -0.90802408 -1.4123037 ]
年: [ 1.46564877 -0.2257763 0.0675282 -1.42474819]
人: [-0.54438272 0.11092259 -1.15099358 0.37569802]
=== 注意力分數(點積) ===
‘寫’ 的分數: -1.3670
‘代’ 的分數: -1.2771
‘碼’ 的分數: -0.1783
‘的’ 的分數: 1.4712
‘中’ 的分數: 0.3955
‘年’ 的分數: 4.2336
‘人’ 的分數: -1.4359
=== 注意力權重(softmax歸一) ===
‘寫’ 的權重: 0.0033
‘代’ 的權重: 0.0036
‘碼’ 的權重: 0.0109
‘的’ 的權重: 0.0570
‘中’ 的權重: 0.0194
‘年’ 的權重: 0.9025
‘人’ 的權重: 0.0031
=== 上下文向量 for ‘年’ ===
[ 1.31085939 -0.30172873 -0.05573854 -1.34141581]代碼詳解
整體代碼回顧:我們在干什么?
我們以“寫代碼的中年人”這7個字為輸入,給每個字隨機分配一個 4 維向量(不區分 Q/K/V,僅用于演示)。
然后: 假設我們以“年”這個詞為 query,計算它對其他每個詞的注意力強度,并據此得到一個上下文向量。
整個過程包含以下步驟:
- 初始化詞向量(隨機)
- 選定 query(“年”)
- 計算點積注意力分數
- 使用 softmax 將分數歸一為概率
- 利用注意力權重對所有詞向量加權,得到最終的上下文表示

























