成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

揭秘大模型的魔法:從嵌入向量說起

人工智能
本文將以Transformer架構為核心,深入探討嵌入向量的生成過程,剖析其背后的“魔法”,并通過代碼示例展示如何實現這一過程。

大家好,我是寫代碼的中年人,上一篇文章我們介紹了詞元的概念及如何訓練自己的詞元,待訓練的數據變成詞元后,我們發現詞元(文本)之間沒有任何聯系,也就是說它們是離散的數據,所以我們沒辦法對詞元進行計算。

將離散的文本轉化為連續的向量表示,即嵌入向量(Embedding Vector)。嵌入向量是大模型處理自然語言的起點,它將人類語言的符號轉化為機器可以理解的數學表示。

本文將以Transformer架構為核心,深入探討嵌入向量的生成過程,剖析其背后的“魔法”,并通過代碼示例展示如何實現這一過程。

嵌入向量的簡介

從上一篇我們已經了解了詞元和詞元ID的概念,最后我們生成了一個詞匯表(Vocabulary),并且知道詞匯表的大小通常在幾萬到幾十萬之間,具體大小取決于模型設計。

詞元ID是離散的整數,無法直接用于神經網絡的數學運算。因此,嵌入層(Embedding Layer)將詞元ID映射為連續的向量表示。嵌入層本質上是一個可學習的查找表,存儲為一個形狀為 [vocab_size, embedding_dim] 的矩陣,其中:

vocab_size:詞匯表的大小。

embedding_dim:每個詞元的向量維度。

詞匯表的概念我們已經了解,嵌入向量的概念可以簡單理解為:你用多少個數字來表示一個詞,維度越高,詞向量表達的語義就越豐富,但也更復雜。

我們要記住的是嵌入向量是模型最早期的“參數矩陣”,通常是隨機初始化的,然后在訓練中慢慢學習。

我們先看一個例子,如下代碼:

import torch
import torch.nn as nn


# 設置打印選項
torch.set_printoptions(threshold=10000, precisinotallow=4, sci_mode=False)


# 參數定義
vocab_size = 10000
embedding_dim = 256
embedding_layer = nn.Embedding(vocab_size, embedding_dim)


# 輸入 token id
token_ids = torch.tensor([101, 102, 103, 104, 105, 106, 107])


# 獲取嵌入向量
embeddings = embedding_layer(token_ids)


# 輸出嵌入矩陣
print("嵌入矩陣:")
print(embeddings)

執行上面代碼后,我們看到程序會輸出如下信息:

嵌入矩陣:
tensor([[    -1.1887,     -0.3787,     -1.6036,      1.2109,     -1.5041,
              0.5217,     -0.0660,      0.8761,     -1.3062,     -0.5456,
             -2.2370,     -0.7596,      0.6463,      1.3679,     -0.7995,
             -0.8499,     -1.1883,     -0.4964,     -0.9248,      1.3193,
             -0.3776,     -1.6146,     -0.2606,      1.3084,      1.5899,
             -0.3184,      0.7106,      0.4439,     -1.0974,     -0.0911,
              0.0765,     -1.1273,     -2.0399,     -0.7867,      0.5819,
....中間信息省略
-0.6946,      0.1002,     -0.8110,     -1.1093,      0.4499,
             -0.5466,      0.8090,      1.3586,     -0.4617,      0.0936,
              0.4514,     -1.0935,      1.1986,      0.5158,      0.7961,
              0.1658,      0.9241,     -0.2872,     -1.5406,      0.6301,
              1.3381,     -1.6376,      0.5164,     -1.1603,     -1.0949,
              0.7568,     -0.8883,     -0.0534,     -1.1359,     -0.1575,
             -0.7413]], grad_fn=<EmbeddingBackward0>)

這段代碼到底做了什么事情?我們接下來進行詳解:

定義嵌入矩陣的大小:

vocab_size = 10000

表示你有一個詞匯表(vocabulary),大小是 10,000,意思是你有 10,000 個獨立的詞(或子詞、token),詞匯表的概念可以參照上篇文章的介紹。

embedding_dim = 256

表示每個詞要被映射為一個256維的向量。這就是“嵌入維度”,你可以理解為:

把每個離散的 token 映射到一個連續空間中,變成一個可學習的向量(表示它的“意義”或“語義”)

初始化嵌入層:

embedding_layer = nn.Embedding(vocab_size, embedding_dim)

nn.Embedding(vocab_size, embedding_dim) 是 PyTorch 提供的嵌入層。

它的作用是創建一個大小為 [vocab_size, embedding_dim] 的查找表,每行對應一個 token 的向量。

換句話說,它是一個形狀為 [10000, 256] 的矩陣。每一行是一個詞的向量:

token_id = 0 → [0.1234, -0.5321, ..., 0.0012]  # 長度為256

token_id = 1 → [0.3332, -0.8349, ..., -0.2176]

...

token_id = 9999 → [...]

這個矩陣的參數是可訓練的,會隨著模型訓練不斷優化,使得語義相近的 token 向量距離也更近。

定義 token id:

token_ids = torch.tensor([101, 102, 103, 104, 105, 106, 107])

這里創建了一個 tensor,內容是 [101, 102, 103, 104, 105, 106, 107],它代表你輸入的 7 個詞/子詞的索引(ID)。

每個數字表示詞表中的一個詞,例如:

101 → “寫”

102 → “代”

103 → “碼”

104 → “的”

105 → “中”

106 → “年”

107 → “人”

(這里只是舉例,真實情況看 tokenizer)

變為嵌入向量:

embeddings = embedding_layer(token_ids)

把 token_ids [101, 102, 103, 104, 105, 106, 107] 送進嵌入層后,會從嵌入矩陣中取出它們對應的向量,得到:

embeddings.shape == [7, 256]

每個詞變成了一個 256 維的向量,這些向量是浮點數,比如:

embeddings[0] = tensor([ 0.1371, -0.0208, ..., 0.0415])  # token 101 的嵌入

embeddings[1] = tensor([-0.0817, 0.2991, ..., 0.0034])  # token 102 的嵌入

...

 輸出的向量是啥?

這些 256 維向量就是詞的語義向量表示(Word Embedding):

它們是模型可訓練參數;

它們的數值是隨機初始化的(除非你加載了預訓練模型);

它們的作用是:把 token 編碼成模型能處理的“連續表示”;

在模型訓練過程中,這些向量會逐步學習到語義,比如 “我” 和 “我們” 的向量距離會比 “我” 和 “電腦” 更近。如何訓練我們后續再講,這里只要明白它們是怎么初始化的和有什么作用就行。

最終經過大量語料訓練之后,每個 token 的 embedding都是模型學習到的語義表示,它不再“隨機”,而是能捕捉詞義的相似性。

大概的流程為:

原始輸入文本 → tokenizer → token_id → embedding向量 → 加入位置編碼 → 輸入Transformer

位置編碼簡介

位置編碼(Positional Encoding)是 Transformer 架構的關鍵組件之一,在Transformer架構中,模型主要依賴自注意力機制來處理輸入序列。然而,自注意力機制本身是無序的,即它不考慮輸入序列中詞或標記(token)的相對位置或絕對位置信息。這會導致模型無法區分序列中不同位置的詞,即使它們的語義完全相同。為了解決這個問題,引入了位置編碼(Positional Encoding),其作用是:

提供位置信息:為序列中的每個位置賦予一個獨特的表示,使模型能夠感知詞的順序和相對位置。

保持序列順序的語義:通過位置編碼,Transformer可以理解序列中詞的排列順序對語義的影響。

支持并行計算:位置編碼是預先計算或固定的(不像RNN那樣依賴序列處理),因此不會影響Transformer的并行化優勢。

常見的位置編碼方法:

位置編碼是在 進入 Transformer 架構的第一層之前添加的,通常在模型的輸入端(即嵌入層之后)。

對于標準 Transformer(如 GPT 或 BERT),位置編碼是直接加到詞嵌入上,作為整個模型的初始輸入。

對于某些變體(如使用 RoPE 的模型),位置信息可能在注意力機制內部通過旋轉矩陣應用,但這仍然發生在 Transformer 層處理之前或作為注意力計算的一部分。

接著上面的嵌入向量代碼,我們先使用正弦/余弦編碼來實現一個位置編碼:

import torch
import torch.nn as nn
import math


# 設置打印選項
torch.set_printoptions(threshold=10000, precisinotallow=4, sci_mode=False)


# 定義位置編碼類
class PositionalEncoding(nn.Module):
    def __init__(self, d_model, max_len=5000):
        super(PositionalEncoding, self).__init__()
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        pe = pe.unsqueeze(0)  # Shape: (1, max_len, d_model)
        self.register_buffer('pe', pe)


    def forward(self, x):
        # x: (batch_size, seq_len, d_model)
        x = x + self.pe[:, :x.size(1), :]  # Add positional encoding
        return x


# 參數定義
vocab_size = 10000
embedding_dim = 256
embedding_layer = nn.Embedding(vocab_size, embedding_dim)
pos_encoder = PositionalEncoding(d_model=embedding_dim, max_len=5000)


# 輸入 token id
token_ids = torch.tensor([101, 102, 103, 104, 105, 106, 107])


# 獲取嵌入向量
embeddings = embedding_layer(token_ids)


# 輸出嵌入矩陣
print("嵌入矩陣:")
print(embeddings)


# 添加位置編碼
embeddings_with_pe = pos_encoder(embeddings.unsqueeze(0)).squeeze(0)  # Add batch dimension and remove it


# 輸出添加位置編碼后的矩陣
print("\n添加位置編碼后的嵌入矩陣:")
print(embeddings_with_pe)

RoPE 旋轉位置編碼:(RoPE 只作用在自注意力中的 Query 和 Key 上,不是 Value,也不是 Embedding 本身,下面代碼只是示例。)

import torch
import torch.nn as nn
import math


# 設置打印選項(便于查看向量)
torch.set_printoptions(threshold=10000, precisinotallow=4, sci_mode=False)


# ========================
# 旋轉位置編碼(RoPE)模塊
# ========================
class RotaryPositionalEncoding(nn.Module):
    def __init__(self, dim, max_len=5000, base=10000):
        super(RotaryPositionalEncoding, self).__init__()
        assert dim % 2 == 0, "RoPE要求維度必須是偶數。"
        self.dim = dim
        self.max_len = max_len
        self.base = base
        self._build_cache()


    def _build_cache(self):
        half_dim = self.dim // 2
        inv_freq = 1.0 / (self.base ** (torch.arange(0, half_dim).float() / half_dim))  # [dim/2]
        pos = torch.arange(self.max_len).float()  # [max_len]
        sinusoid = torch.einsum('i,j->ij', pos, inv_freq)  # [max_len, dim/2]
        self.register_buffer('sin', torch.sin(sinusoid))  # [max_len, dim/2]
        self.register_buffer('cos', torch.cos(sinusoid))  # [max_len, dim/2]


    def forward(self, x):
        """
        輸入:
            x: Tensor, shape (batch, seq_len, dim)
        輸出:
            Tensor, shape (batch, seq_len, dim),應用RoPE后
        """
        batch_size, seq_len, dim = x.size()
        sin = self.sin[:seq_len].unsqueeze(0).to(x.device)  # [1, seq_len, dim/2]
        cos = self.cos[:seq_len].unsqueeze(0).to(x.device)


        x1 = x[..., 0::2]
        x2 = x[..., 1::2]
        x_rotated = torch.cat([x1 * cos - x2 * sin, x1 * sin + x2 * cos], dim=-1)
        return x_rotated


# ========================
# 主程序:嵌入 + RoPE 演示
# ========================


# 參數定義
vocab_size = 10000
embedding_dim = 256
embedding_layer = nn.Embedding(vocab_size, embedding_dim)
rope_encoder = RotaryPositionalEncoding(dim=embedding_dim, max_len=5000)


# 輸入 token ids(假設是一個樣本)
token_ids = torch.tensor([101, 102, 103, 104, 105, 106, 107])  # [seq_len]
embeddings = embedding_layer(token_ids).unsqueeze(0)  # [1, seq_len, dim]


# 應用 RoPE 位置編碼
rope_embeddings = rope_encoder(embeddings).squeeze(0)  # [seq_len, dim]


# 打印結果
print("原始嵌入向量:")
print(embeddings.squeeze(0))
print("\n應用 RoPE 后的嵌入向量:")
print(rope_embeddings)

結尾語

在大模型的世界里,嵌入向量和位置編碼就像是兩把開啟理解語言奧秘的鑰匙:前者將離散的語言符號映射到連續的語義空間,后者則幫助模型理解“誰先誰后”、“誰靠誰近”。我們從嵌入矩陣的初始化講起,了解了這些向量是如何從隨機開始,逐步在訓練中學會“懂語言”的;然后走進了位置編碼的演化史,從經典的正弦余弦到如今主流的旋轉位置編碼(RoPE),我們看到了模型如何用巧妙的方式“感知順序”,并最終在注意力機制中扮演關鍵角色。

值得強調的是,RoPE 并不是一種加法編碼,而是一種乘法思維,它精準地嵌入在自注意力中的 Query 和 Key 上,為模型引入位置的相對關系感。這種設計既數學優雅,又計算高效,成為當前大語言模型如 LLaMA、ChatGLM 的標配。

理解這些底層機制,不僅有助于我們更好地使用大模型,更是在 AI 工程實踐中邁出的堅實一步,也是為我們親自訓練一個基礎模型,必須打通的一道關卡。

責任編輯:龐桂玉 來源: 寫代碼的中年人
相關推薦

2025-04-25 00:20:00

大模型tokenizer

2025-04-17 09:00:00

2024-04-02 11:43:08

向量化編程NEON

2023-11-21 09:00:00

大型語言模型LangChain庫

2024-06-28 09:25:51

2022-06-22 08:02:11

CPU操作系統Java

2025-01-14 14:54:57

2025-04-02 00:00:00

2025-03-26 10:57:40

PyTorchGGUF

2010-09-16 10:46:47

2023-10-06 13:52:40

數據庫模型

2013-06-13 13:42:29

OS X蘋果系統

2024-09-04 15:12:35

2024-02-01 08:34:30

大模型推理框架NVIDIA

2018-02-27 12:41:21

Serverless邊緣計算存儲

2012-03-19 21:06:52

Android

2025-06-05 00:00:00

向量數據庫線程安全Redis

2025-04-24 11:09:13

2024-12-02 09:37:09

大模型AI產品
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: www四虎com| 欧美激情精品久久久久久变态 | 久久蜜桃资源一区二区老牛 | 久久精品 | 中文字幕高清免费日韩视频在线 | 国产美女在线播放 | 精品欧美一区二区在线观看视频 | 精品视频一区二区三区在线观看 | 九九热在线免费观看 | 国产久| 日本手机在线 | 亚洲精品一区二区三区蜜桃久 | 一级黄色片日本 | 欧美精品三区 | 特级做a爱片免费69 精品国产鲁一鲁一区二区张丽 | 国产99久久精品一区二区永久免费 | 国产成人精品一区二区三区网站观看 | 国产一区二区精品自拍 | 一区二区国产精品 | 国产亚洲一区二区精品 | 99pao成人国产永久免费视频 | 亚洲va中文字幕 | 精品99久久久久久 | 成人精品免费 | 欧美日韩精品在线一区 | 亚洲性在线 | 91高清免费 | 久久69精品久久久久久久电影好 | 欧美一区二区三区在线播放 | 一区二区三区网站 | 在线观看日本高清二区 | 国产精品3区 | 国产99久久精品一区二区永久免费 | 日韩区| 欧美日韩国产一区二区三区不卡 | 亚洲欧美另类在线 | 超碰网址 | 国产91精品网站 | 中文字幕av一区二区三区 | 99久久成人| 麻豆精品国产91久久久久久 |