文章目錄
- 一、核心關系概述
- 二、分詞工具的核心作用
- 三、未登錄詞(OOV)問題
- 3.1 問題本質分析
- 3.2 解決方案
- 3.2.1 預對齊詞匯表(最優解)
- 3.2.2 子詞回退策略
- 3.2.3 詞匯表擴展(適合專業領域)
- 3.3 技術選型建議
- 3.4 關鍵驗證方法
- 3.5 總結
- 四、分詞工具與Tokenizer的區別
- 五、NLP 中的特殊標記
- 5.1 特殊標記解釋
- 5.2 示例
- 六、大模型輸入的核心組成部分
- 6.1 名詞解釋
- 6.2 輸入示例
- 6.3 關鍵總結
一、核心關系概述
分詞工具(如Jieba、SentencePiece)與 AI大模型(如GPT、BERT)的關系可總結為:
- 分詞工具是AI大模型的“前處理引擎”,為大模型提供數據預處理支持
- 大模型是任務的“智能大腦”,它利用分詞結果可以進行更高級的語言理解和生成任務
二、分詞工具的核心作用
- 文本標準化處理
- 中文分詞示例:
"深度學習" → ["深度", "學習"]
- 解決英文子詞問題:
"unhappiness" → ["un", "happiness"]
- 中文分詞示例:
- 降低計算復雜度
- 長文本分割為詞/子詞單元,減少模型計算量
- 跨語言適配
- 針對不同語言特性設計(如中文需分詞,英文需處理子詞)
三、未登錄詞(OOV)問題
3.1 問題本質分析
分詞工具(如 Jieba)分出的詞匯后續由 Tokenizer(如 BERT)轉換為詞匯表中的索引時,若詞匯表中不包含某些詞,則會出現 OOV(Out-of-Vocabulary)問題,這會導致:
- 稀有詞/專業術語被拆解為
<UNK>
(未知標記) - 語義信息丟失(如 “量子計算” →
[UNK]
) - 模型性能下降
3.2 解決方案
3.2.1 預對齊詞匯表(最優解)
原理:強制分詞工具只輸出 Tokenizer 詞匯表中存在的詞匯
from transformers import BertTokenizer
import jieba# 加載Tokenizer并提取詞匯表
tokenizer = BertTokenizer.from_pretrained("bert-base-chinese")
vocab = set(tokenizer.get_vocab().keys()) # 獲取所有合法token# 定制化分詞函數
def aligned_cut(text):words = []for word in jieba.lcut(text):# 檢查詞匯是否存在(處理子詞情況)if word in vocab:words.append(word)else:# 遞歸拆解未登錄詞(直到字符級)for char in word:if char in vocab:words.append(char)else:words.append("[UNK]")return words# 測試
text = "量子計算是未來趨勢"
print(aligned_cut(text)) # 輸出保證在vocab中的分詞
3.2.2 子詞回退策略
原理:利用 Tokenizer 的子詞分解能力處理未登錄詞
from transformers import AutoTokenizertokenizer = AutoTokenizer.from_pretrained("bert-base-chinese")def safe_tokenize(text):# 先用分詞工具粗分words = jieba.lcut(text) # 再用Tokenizer的子詞處理tokens = []for word in words:tokens.extend(tokenizer.tokenize(word)) # 自動處理OOVreturn tokens# 測試
print(safe_tokenize("區塊鏈技術")) # ['區', '塊', '鏈', '技術']
3.2.3 詞匯表擴展(適合專業領域)
步驟:
-
收集領域專有詞匯(如醫療術語)
-
添加到分詞工具用戶詞典
jieba.load_userdict("medical_terms.txt") # 每行格式: `術語 詞頻 詞性`
-
微調 Tokenizer(需重新訓練模型)
new_tokens = ["COVID-19", "mRNA疫苗"] tokenizer.add_tokens(new_tokens) # 擴展詞匯表 model.resize_token_embeddings(len(tokenizer)) # 調整模型嵌入層
3.3 技術選型建議
場景 | 推薦方案 | 優點 | 缺點 |
---|---|---|---|
通用領域 | 子詞回退策略 | 無需額外資源 | 可能拆解專業術語 |
專業領域(如醫療/法律) | 詞匯表擴展+預對齊 | 保持術語完整性 | 需要領域詞典和模型微調 |
多語言混合文本 | 使用SentencePiece分詞 | 統一處理多種語言 | 需替換原有分詞工具 |
3.4 關鍵驗證方法
-
覆蓋率測試
def check_coverage(texts):vocab = set(tokenizer.get_vocab().keys())oov_rate = 0for text in texts:words = jieba.lcut(text)oov_rate += sum(1 for w in words if w not in vocab) / len(words)print(f"OOV率: {oov_rate/len(texts):.2%}")check_coverage(["量子物理", "臨床試驗"]) # 示例輸出: OOV率: 15.00%
-
可視化調試
from transformers import pipeline nlp = pipeline("ner", model="bert-base-chinese")text = "患者有COVID-19癥狀" print(nlp(text)) # 檢查專業術語是否被正確識別
3.5 總結
通過 詞匯表預對齊 + 子詞回退 + 領域適配擴展 的組合策略,可確保:
? 分詞結果 100% 被 Tokenizer 接受
? 專業術語完整性保留
? 避免 <UNK>
導致的語義損失
最終效果取決于分詞工具與 Tokenizer 的協同設計,建議在預處理階段加入 OOV檢測模塊 進行質量監控。
四、分詞工具與Tokenizer的區別
特性 | jieba(傳統分詞工具) | 大模型Tokenizer(如BERT/GPT) |
---|---|---|
設計目標 | 針對特定語言(如中文)的詞匯級分割 | 將文本轉換為模型可處理的子詞/字符級ID |
輸出單元 | 詞語(如[“深度學習”, “是”, “未來”]) | 子詞(如[“深”, “度”, “學習”, “是”, “未”, “來”]) |
語言適應性 | 需針對不同語言訓練專用模型 | 通過統一算法(如BPE/WordPiece)支持多語言 |
典型應用場景 | 搜索引擎、文本分析等傳統NLP任務 | 大模型的輸入預處理 |
問題:為什么大模型仍需自研Tokenizer?
- 子詞平衡:Tokenizer通過算法(如BPE)解決OOV(未登錄詞)問題,而
jieba
無法動態生成子詞。 - 多語言統一:大模型需處理混合語言文本(如中英混雜),
jieba
僅支持中文。 - 端到端訓練:Tokenizer的分詞方式與模型架構強相關(如BERT的WordPiece需與預訓練一致)。
五、NLP 中的特殊標記
在自然語言處理(NLP)任務中,特殊標記(Special Tokens)用于處理文本輸入和輸出的特定需求。以下是常見的特殊標記及其作用:
5.1 特殊標記解釋
-
[CLS]
(Classification Token)- 作用:用于分類任務的特殊標記。
- 位置:通常添加到輸入文本的開頭。
- 用途:
- 在 BERT 等模型中,
[CLS]
標記的最終隱藏狀態(即模型輸出的對應向量)通常用作整個輸入序列的聚合表示,用于分類任務(如情感分析、文本分類)。 - 例如,在句子分類任務中,模型會根據
[CLS]
標記的向量輸出分類結果。
- 在 BERT 等模型中,
-
[SEP]
(Separator Token)- 作用:用于分隔不同句子或文本段的特殊標記。
- 位置:
- 在單句任務中,通常添加到句子末尾。
- 在雙句任務(如句子對分類、問答任務)中,用于分隔兩個句子。
- 用途:
- 幫助模型區分不同的句子或文本段。
- 例如,在問答任務中,
[SEP]
標記用于分隔問題和上下文。
-
[MASK]
(Mask Token)- 作用:用于掩碼語言模型(Masked Language Model, MLM)任務。
- 位置:替換輸入文本中的某些詞(通常隨機選擇)。
- 用途:
- 在 BERT 等模型的預訓練過程中,
[MASK]
標記用于掩蓋部分輸入詞,模型需要預測被掩蓋的詞。 - 例如,輸入
"I love [MASK] learning."
,模型需要預測[MASK]
位置的實際詞(如"deep"
)。
- 在 BERT 等模型的預訓練過程中,
-
[PAD]
(Padding Token)- 作用:用于填充輸入序列,使其達到固定長度。
- 位置:添加到輸入序列的末尾。
- 用途:
- 在批處理(Batching)過程中,不同序列的長度可能不同,
[PAD]
標記用于將短序列填充到相同長度。 - 模型通常會忽略
[PAD]
標記的計算(通過注意力掩碼實現)。
- 在批處理(Batching)過程中,不同序列的長度可能不同,
-
[UNK]
(Unknown Token)- 作用:用于表示詞匯表中未包含的詞(即未知詞)。
- 位置:替換輸入文本中的未知詞。
- 用途:
- 當輸入文本中的詞不在模型的詞匯表中時,模型會將其替換為
[UNK]
標記。 - 例如,如果詞匯表中沒有
"ChatGPT"
,輸入"I use ChatGPT."
可能會被轉換為"I use [UNK]."
。
- 當輸入文本中的詞不在模型的詞匯表中時,模型會將其替換為
5.2 示例
以下是一個包含特殊標記的輸入示例(以 BERT 為例):
[CLS] I love deep learning . [SEP] It is a fascinating field . [SEP] [PAD] [PAD]
六、大模型輸入的核心組成部分
在自然語言處理(NLP)和大模型(如BERT、GPT等)中,input_ids
、attention_mask
和 token_type_ids
是模型輸入的核心組成部分,用于將原始文本轉換為模型可處理的數值化格式。以下是它們的詳細解釋和實際示例:
6.1 名詞解釋
-
input_ids
(文本的數值化表示)-
作用:將分詞后的文本(Tokens)轉換為模型詞匯表中對應的整數ID。
-
生成方式:
- 分詞器(Tokenizer)先將文本拆分為詞/子詞(如
"深度學習"
→["深", "度", "學", "習"]
)。 - 然后查詢詞匯表,將每個Token映射為對應的ID(如
"深"
→3918
)。
- 分詞器(Tokenizer)先將文本拆分為詞/子詞(如
-
示例:
from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("bert-base-chinese") text = "深度學習很重要" inputs = tokenizer(text) print(inputs["input_ids"]) # 輸出如:[101, 3918, 2428, 2110, 739, 2523, 7028, 6206, 102]
101
和102
是BERT的[CLS]
和[SEP]
特殊標記的ID。
-
-
attention_mask
(注意力掩碼)-
作用:標識哪些Token是有效輸入,哪些是填充(Padding)部分。
1
:真實Token(模型需處理)。0
:填充Token(模型忽略)。
-
為什么需要:批量訓練時,不同文本長度不同,需填充到相同長度。
-
示例:
print(inputs["attention_mask"]) # 輸出如:[1, 1, 1, 1, 1, 1, 1](無填充)
如果填充到長度10:
padded_inputs = tokenizer(text, padding="max_length", max_length=10) print(padded_inputs["attention_mask"]) # 輸出如:[1, 1, 1, 1, 1, 1, 1, 0, 0, 0]
-
-
token_type_ids
(或segment_ids
,句子分段標識):-
作用:區分輸入中的不同句子(如問答任務中的問題和上下文)。
0
:第一個句子。1
:第二個句子。
-
適用場景:BERT等模型處理句子對任務(如文本相似度、問答)。
-
示例:
text_pair = ("深度學習是什么?", "它是AI的一個分支") inputs = tokenizer(*text_pair) print(inputs["token_type_ids"]) # 輸出如:[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]
-
6.2 輸入示例
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-chinese")# 處理單句
single_text = "你好,世界!"
inputs = tokenizer(single_text, return_tensors="pt")
print("單句輸入:")
print(f"input_ids: {inputs['input_ids']}") # 輸出 input_ids: tensor([[ 101, 872, 1962, 8024, 686, 4518, 8013, 102]])
print(f"attention_mask: {inputs['attention_mask']}") # 輸出 attention_mask: tensor([[1, 1, 1, 1, 1, 1, 1, 1]])
print(f"token_type_ids: {inputs['token_type_ids']}") # 輸出 token_type_ids: tensor([[0, 0, 0, 0, 0, 0, 0, 0]])# 處理句子對
text_pair = ("今天天氣如何?", "今天下雨了。")
inputs_pair = tokenizer(*text_pair, return_tensors="pt")
print("\n句子對輸入:")
print(f"input_ids: {inputs_pair['input_ids']}") # 輸出 input_ids: tensor([[ 101, 791, 1921, 1921, 3698, 1963, 862, 8043, 102, 791, 1921, 678,7433, 749, 511, 102]])
print(f"attention_mask: {inputs_pair['attention_mask']}") # 輸出 attention_mask: tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])
print(f"token_type_ids: {inputs_pair['token_type_ids']}") # 輸出 token_type_ids: tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1]])
6.3 關鍵總結
input_ids
:文本的數字身份證,決定模型“看到”什么內容。attention_mask
:告訴模型“哪些部分需要關注”,優化計算效率。token_type_ids
:為模型標注“句子邊界”,解決上下文依賴問題。
這些輸入張量共同構成了大模型理解文本的基礎,類似于人類閱讀時需要的“文字+上下文+注意力焦點”。