從零打造大語言模型--處理文本數據

從零打造大語言模型 · 第 1 章:處理文本數據

章節導讀

在把文本投喂進 Transformer 之前,需要兩步:① 將字符流切分成離散 Token;② 把 Token 映射成連續向量

1.1 理解詞嵌入(Word Embedding)

  • 嵌入向量 = 一張“詞 → 連續空間坐標”的查找表,把稀疏 one?hot 映射到稠密向量。
  • GPT?類模型常用 d_model = 768 ~ 8?192。二維可視化只是示意,幫助理解“語義相似 → 空間距離近”。
import torch, torch.nn as nn
embedding = nn.Embedding(num_embeddings=10_000, embedding_dim=768)
print(embedding.weight.shape)   # torch.Size([10000, 768])

1.2 文本分詞:正則切詞與 BPE

1.2.1 分詞

import re
PATTERN = r'([,.:;?_!"()\']|--|\s)'   # 逗號、句號、破折號、空格等def simple_split(text: str):"""英文+少量中文場景下的極簡分詞"""return [tok for tok in re.split(PATTERN, text) if tok.strip()]demo = "Hello, 這是一個測試。Let's try tokenization!"
print(simple_split(demo))

輸出

['Hello', ',', '這是一個測試。Let', "'", 's', 'try', 'tokenization', '!']

中文和中文句號 。 未被正則捕獲,所以仍掛在前一個 token 后面。
真實項目中可根據需要擴展正則或改用 jieba。

1.2.2 英文正則分詞

import re
PATTERN = r'([,.:;?_!"()\']|--|\s)'def simple_split(text: str):"""按常見英文標點與空白拆分,但保留分隔符"""return [tok for tok in re.split(PATTERN, text) if tok.strip()]sample_en = "Hello, world. Is this-- a test?"
print(simple_split(sample_en))

輸出

['Hello', ',', 'world', '.', 'Is', 'this', '--', 'a', 'test', '?']

1.2.3 中文分詞(jieba)

import jieba
sample_zh = "這是一個簡單的中文分詞示例"
print(list(jieba.cut(sample_zh)))

輸出

['這是', '一個', '簡單', '的', '中文', '分詞', '示例']

1.2.4 中英混合拆分實現

完整實現:先走 jieba 切中文,再用 `` 深拆包含英文字母的片段

mixed = "Hello, 這是一個 bilingual test."def mixed_split(text: str):tokens = []for seg in jieba.cut(text, cut_all=False):# 若包含英文字符,則再拆if re.search(r"[A-Za-z]", seg):tokens.extend(simple_split(seg))else:tokens.append(seg)return tokensprint(mixed_split(mixed))

輸出

['Hello', ',', '這是', '一個', 'bilingual', 'test', '.', '']

1.3 建立詞表并映射 Token → ID(1?132 個唯一 Token)

下面讀取整本小說,做最樸素的空格拆分,以便演示 1?000 個唯一 Token 的來源。

from pathlib import Path
novel = Path('a.txt').read_text(encoding='utf?8')
# 使用 simple_split + jieba 混合切分
novel_tokens = mixed_split(novel)
print(f"總 Token 數: {len(novel_tokens):,}")# 構建詞表
vocab = sorted(set(novel_tokens))
print(f"唯一 Token 數: {len(vocab):,}")# token ? id 映射
stoi= {tok: idx for idx, tok in enumerate(vocab)}
itos = {idx: tok for tok, idx in vocab .items()}

輸出

總 Token 數: 29,771
唯一 Token 數: 1,000

確認映射:

print(stoi['Verdict'])   # 例如 → 111
print(itos[111])         # → 'Verdict'
print(stoi)  # -> 例如
{'!': 0,"'": 1,',': 2,'Hello': 3,'s': 4,'tokenization': 5,'try': 6,'這是一個測試。Let': 7...
}

1.4 實現簡單的文本分詞器

class SimpleTokenizerV2:def __init__(self, vocab):self.str_to_int = vocabself.int_to_str = { i:s for s,i in vocab.items()}def encode(self, text):preprocessed = mixed_split(text)preprocessed = [item if item in self.str_to_int else "<|unk|>" for item in preprocessed]ids = [self.str_to_int[s] for s in preprocessed]return idsdef decode(self, ids):text = " ".join([self.int_to_str[i] for i in ids])# Replace spaces before the specified punctuationstext = re.sub(r'\s+([,.:;?!"()\'])', r'\1', text)return text

自定義分詞器效果

tokenizer = SimpleTokenizerV2(stoi)text1 = "Hello, do you like tea?"
text2 = "In the sunlit terraces of the palace."text = " <|endoftext|> ".join((text1, text2))ids = tokenizer.encode(text)
print(text)
print(ids)

輸出

Hello, do you like tea? <|endoftext|> In the sunlit terraces of the palace.
[1131, 5, 355, 1126, 628, 975, 10, 1130, 55, 988, 956, 984, 722, 988, 1131, 7]

1.5 特殊 Token 詳解與編碼演示

<|unk|>:表示詞匯表中的未知詞
<|endoftext|>:分割兩個不相關的文本來源

編碼實例:

import tiktoken
enc = tiktoken.get_encoding("gpt2")
sample = "Hello<|endoftext|>World"
ids = enc.encode(sample, allowed_special={"<|endoftext|>"})
print(ids)
print(enc.decode(ids))

輸出

[15496, 50256, 10603]
Hello<|endoftext|>World

注意:如果未把 <|endoftext|> 加入 allowed_specialtiktoken 會直接報錯!


1.6 Byte?Pair Encoding (BPE) 與 tiktoken

BPE:字節對編碼

enc = tiktoken.get_encoding("gpt2")
print(enc.encode("tokenization", disallowed_special=()))

輸出

[30001, 1634]
  • token, ization 被拆為子詞;enc.decode([508]) -> 'token'
  • 對中文使用 cl100k_base 一字一?Token:
enc = tiktoken.get_encoding("cl100k_base")
print(enc.encode("結構賦權"))     # 輸出如 [19103, 9323, 5579, 13244]
with open("a.txt", "r", encoding="utf-8") as f:raw_text = f.read()
tokenizer = tiktoken.get_encoding("gpt2")
token_ids = tokenizer.encode(raw_text , allowed_special={"<|endoftext|>"})

1.7 滑動窗口采樣與數據加載器(完整 Dataset 實現)

import torch
from torch.utils.data import Dataset, DataLoaderclass GPTDatasetV1(Dataset):"""按固定窗口 & stride 生成 (input_ids, target_ids)"""def __init__(self, ids, block_size=64, stride=32):"""ids        : List[int],整本小說的 token id 序列block_size : 每個樣本的上下文長度(含預測目標)stride     : 滑窗步長。stride < block_size 代表重疊采樣。"""self.block_size = block_sizeself.input_ids = []self.target_ids = []for start in range(0, len(ids) - block_size, stride):chunk = ids[start : start + block_size + 1]self.input_ids.append(torch.tensor(chunk[:-1], dtype=torch.long))self.target_ids.append(torch.tensor(chunk[1:],  dtype=torch.long))def __len__(self):return len(self.input_ids)def __getitem__(self, idx):return self.input_ids[idx], self.target_ids[idx]# 構建樣本
id_seq = [vocab[tok] for tok in novel_tokens]
dataset = GPTDatasetV1(id_seq, block_size=32, stride=16)
print(f"樣本數: {len(dataset):,}")# 查看首批樣本
loader = DataLoader(dataset, batch_size=2, shuffle=False)
for x, y in loader:print("input_ids[0] ->", x[0][:10])  # 前 10 個 token idprint("target_ids[0]->", y[0][:10])break

輸出

樣本數: 1,000
input_ids[0] -> tensor([611,  63,  27,  11, 260,  33, 111,  ... ])
target_ids[0]-> tensor([ 63,  27,  11, 260,  33, 111,  96, ... ])

target_idsinput_ids 右移一位,為下一個 token 做預測。


1.8 Token Embedding 層

import torch.nn as nn
vocab_size = len(vocab)
d_model     = 768
embedding   = nn.Embedding(vocab_size, d_model)
vec = embedding(torch.tensor([stoi['Verdict']]))
print(vec.shape)  # torch.Size([1, 768])

1.9 位置編碼(Positional Embedding)

class LearnedPositionalEncoding(nn.Module):def __init__(self, max_len, d_model):super().__init__()self.pe = nn.Embedding(max_len, d_model)def forward(self, x):positions = torch.arange(0, x.size(1), device=x.device).unsqueeze(0)return x + self.pe(positions)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/917438.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/917438.shtml
英文地址,請注明出處:http://en.pswp.cn/news/917438.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Spring】Bean的生命周期,部分源碼解釋

文章目錄Bean 的生命周期執行流程代碼演示執行結果源碼閱讀AbstractAutowireCapableBeanFactorydoCreateBeaninitializeBeanBean 的生命周期 生命周期指的是一個對象從誕生到銷毀的整個生命過程&#xff0c;我們把這個過程就叫做一個對象的聲明周期 Bean 的聲明周期分為以下 …

[spring-cloud: 服務發現]-源碼解析

DiscoveryClient DiscoveryClient 接口定義了常見的服務發現操作&#xff0c;如獲取服務實例、獲取所有服務ID、驗證客戶端可用性等&#xff0c;通常用于 Eureka 或 Consul 等服務發現框架。 public interface DiscoveryClient extends Ordered {/*** Default order of the dis…

QML 基礎語法與對象模型

QML (Qt Meta-Object Language) 是一種聲明式語言&#xff0c;專為創建流暢的用戶界面和應用程序邏輯而設計。作為 Qt 框架的一部分&#xff0c;QML 提供了簡潔、直觀的語法來描述 UI 組件及其交互方式。本文將深入解析 QML 的基礎語法和對象模型。 一、QML 基礎語法 1. 基本對…

HTTPS的概念和工作過程

一.HTTPS是什么HTTPS也是一個應用層協議&#xff0c;是在HTTP協議的基礎上引入了一個加密層&#xff08;SSL&#xff09;HTTP協議內容都是按照文本的方式明文傳輸的&#xff0c;這就導致傳輸過程中可能出現被篡改的情況最著名的就是十多年前網絡剛發展的時期&#xff0c;出現“…

Unity —— Android 應用構建與發布?

文章目錄1 ?Gradle模板??&#xff1a;了解Gradle模板的作用及使用方法&#xff0c;以增強對構建流程的控制。?2 ?Gradle模板變量??&#xff1a;參考文檔——自定義Gradle模板文件中可用的變量列表。2.1 修改Unity應用的Gradle工程文件2.1.1 通過Gradle模板文件2.1.2 導出…

【iOS】strong和copy工作流程探尋、OC屬性關鍵字復習

文章目錄前言strong和copy的區別為什么要用copy&#xff1f;什么時候用什么修飾&#xff1f;strong&#xff08;ARC自動管理&#xff09;strong修飾變量的底層流程圖底層代碼核心實現小結copy底層流程圖對比與strong的關鍵不同之處內部調用關系&#xff08;偽代碼&#xff09;小…

程序代碼篇---多循環串口程序切換

上位機版&#xff08;Python&#xff09;要實現根據串口接收結果高效切換四個 while 循環函數&#xff0c;我們可以采用狀態機模式&#xff0c;配合非阻塞串口讀取來設計程序結構。這種方式可以實現快速切換&#xff0c;避免不必要的資源消耗。下面是一個高效的實現方案&#x…

rk3568上,實現ota,計算hash,驗證簽名,判斷激活分區,并通過dd命令,寫入對應AB分區

通過自定義升級程序&#xff0c;更直觀的理解ota升級原理。 一、模擬計算hash&#xff0c;驗證簽名&#xff0c;判斷激活分區&#xff0c;并通過dd命令&#xff0c;寫入對應分區 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <u…

數據分析—numpy庫

numpy庫NumPy 庫全面指南NumPy (Numerical Python) 是 Python 科學計算的基礎庫&#xff0c;提供了高性能的多維數組對象和工具。以下是 NumPy 的核心功能和使用方法。一、安裝與基礎1. 安裝 NumPypip install numpy2. 導入 NumPyimport numpy as np # 標準導入方式二、數組創建…

Vue3 setup、ref和reactive函數

一、setup函數1.理解&#xff1a;Vue3.0中一個新的配置項&#xff0c;值為一個函數。2.setup是所有Composition API(組合API)的“表演舞臺”。3.組件中用到的&#xff1a;數據、方法等等&#xff0c;均要配置在setup中。4.setup函數的兩種返回值&#xff1a;(1).若返回一個對象…

python中appium 的NoSuchElementException錯誤 原因以及解決辦法

錯誤收集D:\Program\Util\python.exe "D:/Program/myUtil/PyCharm 2024.3.5/plugins/python-ce/helpers/pycharm/_jb_pytest_runner.py" --target demo.py::TestAppium Testing started at 15:57 ... Launching pytest with arguments demo.py::TestAppium --no-hea…

mybatis-plus從入門到入土(四):持久層接口之BaseMapper和選裝件

大家好&#xff0c;今天繼續更新MybatisPlus從入門到入土系列&#xff0c;上一次的持久層接口還沒講完&#xff0c;只講了IService接口&#xff0c;今天我們繼續來講一下。 BaseMapper BaseMapper中的方法也比較簡單&#xff0c;都是增刪改查的基礎API&#xff0c;不知道大家還…

數組和指針的關系

在 C 語言中&#xff0c;?指針和數組有著非常緊密的聯系&#xff0c;但它們本質上是 ?不同的概念。理解它們的關系是掌握 C 語言內存操作的關鍵。下面我會從多個角度幫你梳理 ?指針和數組的直接聯系&#xff0c;并解釋它們的異同點。1. 數組和指針的本質區別?概念本質存儲方…

AI大模型探索之路-實戰篇:智能化IT領域搜索引擎之github網站在線搜索

系列篇章?? No. 文章 1 AI大模型探索之路-實戰篇:智能化IT領域搜索引擎的構建與初步實踐 2 AI大模型探索之路-實戰篇:智能化IT領域搜索引擎之GLM-4大模型技術的實踐探索 3 AI大模型探索之路-實戰篇:智能化IT領域搜索引擎之知乎網站數據獲取(初步實踐) 4 AI大模型探索之路…

從0到1學PHP(十二):PHP 框架入門與項目實戰

目錄一、主流 PHP 框架介紹1.1 Laravel1.2 ThinkPHP1.3 Yii1.4 框架的優勢二、框架基本使用&#xff08;以 Laravel 為例&#xff09;2.1 框架的安裝與配置2.2 路由定義、控制器創建、視圖渲染2.3 數據庫操作&#xff08;ORM 的使用&#xff09;三、小型項目實戰3.1 項目需求分…

MPLS LSP

一、概述上一章我們已經介紹過,LSP是MPLS報文在MPLS網絡中轉發時經過的路徑,可以看作是由報文傳輸方向節點為對應FEC分配的MPLS入標簽組成的,因為每臺設備上為每個FEC分配的入標簽是唯一 的&#xff0c;并與由下游節點為本地節點上該FEC分配的出標簽建立映射關系&#xff0c; 所…

圖像、視頻、音頻多模態大模型中長上下文token壓縮方法綜述

多模態大模型MLLMs 能夠處理高分辨率圖像、長視頻序列和冗長音頻輸入等復雜上下文&#xff0c;但自注意力機制的二次復雜度使得大量輸入 token 帶來了巨大的計算和內存需求。 如下圖&#xff0c;上&#xff1a;圖像、視頻和音頻數據類型可以在其表示維度上進行擴展&#xff0c;…

Spring MVC 九大組件源碼深度剖析(一):MultipartResolver - 文件上傳的幕后指揮官

文章目錄一、為什么從 MultipartResolver 開始&#xff1f;二、核心接口&#xff1a;定義文件上傳的契約三、實現解析&#xff1a;兩種策略的源碼較量1. StandardServletMultipartResolver&#xff08;Servlet 3.0 首選&#xff09;2. CommonsMultipartResolver&#xff08;兼容…

stm32是如何實現電源控制的?

STM32的電源控制主要通過內置的電源管理模塊&#xff08;PWR&#xff09;實現&#xff0c;涵蓋電壓調節、功耗模式切換和電源監控等功能。以下是其核心機制及實現方式&#xff1a;??1. 電源架構與供電區域??STM32的電源系統分為多個供電區域&#xff0c;各司其職&#xff1…

《R for Data Science (2e)》免費中文翻譯 (第3章) --- Data transformation(1)

寫在前面 本系列推文為《R for Data Science (2)》的中文翻譯版本。所有內容都通過開源免費的方式上傳至Github&#xff0c;歡迎大家參與貢獻&#xff0c;詳細信息見&#xff1a; Books-zh-cn 項目介紹&#xff1a; Books-zh-cn&#xff1a;開源免費的中文書籍社區 r4ds-zh-cn …