NLP Subword 之 BPE(Byte Pair Encoding) 算法原理

本文將介紹以下內容:

  • 1. BPE 算法核心原理
  • 2. BPE 算法流程
  • 3. BPE 算法源碼實現Demo

BPE最早是一種數據壓縮算法,由Sennrich等人于2015年引入到NLP領域并很快得到推廣。該算法簡單有效,因而目前它是最流行的方法。GPT-2和RoBERTa使用的Subword算法都是BPE。

1. BPE 算法核心原理:

它的主要思想是:

  • 使用頻率統計來逐步合并高頻的字符/子詞對。
  • 從最小的單位(字符)開始,逐漸學習得到一套子詞詞表,使模型能夠兼顧 常見詞的完整表示 和 罕見詞的組合表示。

在大語言模型時代,最常用的分詞方法是Byte-Pair Encoding(BPE)和Byte-level BPE(BBPE)。該算法的核心思想是逐步合并出頻率最高的子詞對而不是像wordpiece一樣通過計算合并分數。

2. BPE 算法流程:

(1)計算初始詞表:通過訓練語料獲得或者最初的英文種26個字母加上各種符號以及常見中文字符,這些作為初始詞表。
(2)構建頻率統計:統計所有子詞單元對在文本中的出現頻率。
(3)合并頻率最高的子詞對:選擇出現頻率最高的子詞對,將它們合并成一個新的子詞單元,并更新詞匯表。
(4)重復合并步驟:不斷重復步驟2和步驟3,直到達到預定的詞匯表大小、合并次數。
(5)分詞:使用訓練得到的詞匯表對文本進行分詞。

3. 算法源碼實現Demo

import re
from collections import defaultdictclass BPE:def __init__(self, vocab_size=100):self.vocab_size = vocab_sizeself.vocab = {}       # word -> frequencyself.merges = []      # list of mergesself.bpe_ranks = {}   # pair -> rank# ---------- 構建初始詞表 ----------def build_vocab(self, corpus):"""corpus: list[str],輸入語料英文: 用空格分詞中文: 逐字處理"""vocab = defaultdict(int)for line in corpus:words = line.strip().split()for word in words:chars = list(word) + ["</w>"]   # 加上詞邊界vocab[tuple(chars)] += 1self.vocab = dict(vocab)# ---------- 統計 pair ----------def get_stats(self):"""統計 pair 的頻率"""pairs = defaultdict(int)for word, freq in self.vocab.items():for i in range(len(word)-1):pairs[(word[i], word[i+1])] += freqreturn pairs# ---------- 合并 ----------def merge_vocab(self, pair):"""執行一次合并"""new_vocab = {}bigram = re.escape(" ".join(pair))pattern = re.compile(r'(?<!\S)' + bigram + r'(?!\S)')for word, freq in self.vocab.items():word_str = " ".join(word)new_word = tuple(pattern.sub("".join(pair), word_str).split())new_vocab[new_word] = freqself.vocab = new_vocab# ---------- 訓練 ----------def train(self, save_merges="merges.txt", save_vocab="vocab.txt"):# 初始 alphabet 大小alphabet = set(ch for word in self.vocab for ch in word)num_merges = self.vocab_size - len(alphabet)print(f"初始alphabet大小={len(alphabet)},目標vocab_size={self.vocab_size},合并次數≈{num_merges}")for i in range(num_merges):pairs = self.get_stats()if not pairs:breakbest = max(pairs, key=pairs.get)self.merges.append(best)self.merge_vocab(best)# 構建 bpe_ranksself.bpe_ranks = dict(zip(self.merges, range(len(self.merges))))print(f"self.bpe_ranks:{self.bpe_ranks}")# 保存 mergeswith open(save_merges, "w", encoding="utf-8") as f:for a, b in self.merges:f.write(f"{a} {b}\n")# 保存 vocabvocab_tokens = set()for word in self.vocab:for token in word:vocab_tokens.add(token)with open(save_vocab, "w", encoding="utf-8") as f:for token in sorted(vocab_tokens):f.write(token + "\n")print(f"? merges 保存到 {save_merges}, vocab 保存到 {save_vocab}")# ---------- 推理 ----------def get_pairs(self, word):"""獲取當前詞的所有pair"""pairs = set()prev_char = word[0]for char in word[1:]:pairs.add((prev_char, char))prev_char = charreturn pairsdef encode_word(self, word):"""BPE 編碼單個詞"""word = tuple(list(word) + ["</w>"])pairs = self.get_pairs(word)if not pairs:return [word]while True:# 找到rank最小的pairbigram = min(pairs, key=lambda p: self.bpe_ranks.get(p, float("inf")))if bigram not in self.bpe_ranks:breaknew_word = []i = 0while i < len(word):if i < len(word)-1 and word[i] == bigram[0] and word[i+1] == bigram[1]:new_word.append(word[i] + word[i+1])i += 2else:new_word.append(word[i])i += 1word = tuple(new_word)if len(word) == 1:breakpairs = self.get_pairs(word)return list(word)def decode_word(self, tokens):"""還原單詞"""word = "".join(tokens)if word.endswith("</w>"):word = word[:-4]return worddef encode_sentence(self, sentence):"""BPE 編碼整句"""return [self.encode_word(w) for w in sentence.strip().split()]def decode_sentence(self, tokens_list):"""解碼整句"""return " ".join(self.decode_word(toks) for toks in tokens_list)# ================== 示例 ==================
if __name__ == "__main__":corpus = ["deep learning is the future of ai","see my eyes first","see my dogs","you are the best","you are the fast","machine learning can be applied to natural language processing","深度學習是人工智能的未來","機器學習可以應用于自然語言處理","人工智能改變世界","學習深度神經網絡在圖像識別中表現優秀"]# 訓練bpe = BPE(vocab_size=100)bpe.build_vocab(corpus)bpe.train("merges.txt", "vocab.txt")# 測試推理print("\n=== 單詞測試 ===")for w in ["lowest", "newer", "人工智能", "深度學習"]:tokens = bpe.encode_word(w)print(f"{w} -> {tokens} -> {bpe.decode_word(tokens)}")print("\n=== 句子測試 ===")sentence = "lowest newer 人工智能深度學習"tokens_list = bpe.encode_sentence(sentence)print(tokens_list)print(bpe.decode_sentence(tokens_list))# === 單詞測試 ===
# lowest -> ['l', 'o', 'w', 'e', 's', 't', '</w>'] -> lowest
# newer -> ['n', 'e', 'w', 'e', 'r', '</w>'] -> newer
# 人工智能 -> ['人工智能', '</w>'] -> 人工智能
# 深度學習 -> ['深度', '學習', '</w>'] -> 深度學習# === 句子測試 ===
# [['l', 'o', 'w', 'e', 's', 't', '</w>'], ['n', 'e', 'w', 'e', 'r', '</w>'], ['人工智能', '王', '贊', '深度', '學習', '</w>']]
# lowest newer 人工智能深度學習

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

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

相關文章

CSS 偽類選擇器

偽類選擇器&#xff08;pseudo-class selector&#xff09;是一種用于選擇HTML元素特定狀態或特征的關鍵字&#xff0c;它允許開發者基于文檔樹之外的信息&#xff08;如用戶交互、元素位置或狀態變化&#xff09;來選擇元素并應用樣式。偽類選擇器以冒號(:)開頭&#xff0c;附…

Electron 新特性:2025 版本更新解讀

引言&#xff1a;Electron 新特性在 2025 版本更新中的解讀核心價值與必要性 在 Electron 框架的持續演進中&#xff0c;新特性的引入是推動桌面開發創新的核心動力&#xff0c;特別是 2025 年的版本更新&#xff0c;更是 Electron 項目從成熟生態到前沿技術的躍進之鑰。它不僅…

MyBatis從入門到面試:掌握持久層框架的精髓

MyBatis從入門到面試&#xff1a;掌握持久層框架的精髓 前言 在Java企業級應用開發中&#xff0c;持久層框架的選擇至關重要。MyBatis作為一款優秀的半自動化ORM框架&#xff0c;以其靈活的SQL定制能力和良好的性能表現&#xff0c;成為了眾多開發者的首選。本文將帶你從MyBa…

5.Three.js 學習(基礎+實踐)

Three.js 是 “WebGL 的封裝庫”&#xff0c;幫你屏蔽了底層的著色器 / 緩沖區細節&#xff0c;專注于 “3D 場景搭建”&#xff0c;開發效率高&#xff0c;是通用 3D 開發的首選。他的核心是 “場景 - 相機 - 渲染器” 的聯動邏輯&#xff0c;先掌握基礎組件&#xff0c;再學進…

消火栓設備工程量計算 -【圖形識別】秒計量

消火栓設備工程量計算 -【圖形識別】秒計量 消防系統的消火栓設備水槍、水帶和消火栓組成&#xff0c;根據清單定額規則計算消火栓設備工程量。通過CAD快速看圖的圖形識別框選圖紙就能自動數出消火栓數量&#xff0c;省時又準確&#xff0c;是工程人做消防算量的好幫手。 一、…

Docker 與 VSCode 遠程容器連接問題深度排查與解決指南

Docker 與 VSCode 遠程容器連接問題深度排查與解決指南 引言 Visual Studio Code 的 Remote - Containers 擴展極大地提升了開發體驗&#xff0c;它將開發環境容器化&#xff0c;保證了環境的一致性&#xff0c;并允許開發者像在本地一樣在容器內進行編碼、調試和運行。然而&…

愛圖表:鏑數科技推出的智能數據可視化平臺

本文轉載自&#xff1a;https://www.hello123.com/aitubiao ** 一、? AI 圖表&#xff1a;智能數據可視化好幫手 愛圖表是鏑數科技旗下的一款智能數據可視化工具&#xff0c;它能讓復雜的數字和報表變得直觀又好懂。接入了先進的DeepSeek 系列 AI 模型&#xff0c;它不僅會做…

ENVI系列教程(四)——圖像幾何校正

目錄 1 概述 1.1 控制點選擇方式 1.2 幾何校正模型 1.3 控制點的預測與誤差計算 2 詳細操作步驟 2.1 掃描地形圖的幾何校正 2.1.1 第一步:打開并顯示圖像文件 2.1.2 第二步:啟動幾何校正模塊 2.2 Landsat5 影像幾何校正 2.2.1 第一步:打開并顯示圖像文件 2.2.2 第…

STM32-FreeRTOS操作系統-消息隊列

引言在嵌入式開發領域&#xff0c;STM32與FreeRTOS的結合應用極為廣泛。本文將探討如何在STM32上使用FreeRTOS實現消息隊列功能&#xff0c;助力高效任務通信與系統協作。消息隊列定義消息隊列是一種在 FreeRTOS 中用于任務間通信的機制。它允許任務將消息發送到隊列中&#xf…

【開題答辯全過程】以 C語言程序設計課程網站為例,包含答辯的問題和答案

個人簡介一名14年經驗的資深畢設內行人&#xff0c;語言擅長Java、php、微信小程序、Python、Golang、安卓Android等開發項目包括大數據、深度學習、網站、小程序、安卓、算法。平常會做一些項目定制化開發、代碼講解、答辯教學、文檔編寫、也懂一些降重方面的技巧。感謝大家的…

手機上有哪些比較好用的待辦事項提醒工具

在快節奏的現代工作中&#xff0c;我們每天都要面對大量的任務與事務。從項目截止日期、客戶會議&#xff0c;到日常的工作安排&#xff0c;瑣碎的事項容易讓人顧此失彼。 手機待辦事項工具早已突破傳統“記事本”的局限&#xff0c;成為移動辦公場景下的效率核心。它們通過任務…

Mysql數據庫事務全解析:概念、操作與隔離級別

MySQL系列 文章目錄MySQL系列一、什么是事務1.1事務的核心概念1.2、 事務的四大屬性&#xff08;ACID&#xff09;1.2.1 原子性&#xff08;Atomicity&#xff09;1.2.2 一致性&#xff08;Consistency&#xff09;1.2.3 隔離性&#xff08;Isolation&#xff09;1.2.4 持久性&…

【MCU EEPROM開發教程】

簡單來說把eeprom芯片當成一個傳感器來使用&#xff0c;通過IIC/SPI等協議對芯片進行讀寫操作&#xff0c;具體的讀寫操作涉及到一些算法—怎么樣讀寫更加快速&#xff0c;以及一些異常錯誤處理。 應用場景&#xff1a; 對于一些掉電也不能丟失的數據要存在eeprom/flash中&…

Docker將鏡像搬移到其他服務上的方法

導出/加載鏡像&#xff08;保留分層、標簽&#xff09;和導出/導入容器快照&#xff08;僅文件系統&#xff0c;丟失鏡像歷史與標簽&#xff09;。 一、把鏡像打包帶走&#xff08;推薦&#xff09; 適合把一個或多個鏡像搬到離線/內網機器&#xff0c;保留分層與標簽。 在源服…

Ubuntu 系統安裝 Miniconda 完整方法與注意事項

一、完整安裝步驟 1. 下載 Miniconda 安裝包 Miniconda 安裝包為 .sh 格式腳本,下載途徑分兩種: 方式 1:瀏覽器下載(適合新手) 訪問 Miniconda 官方下載頁,選擇對應系統版本(Ubuntu 選 Miniconda3-latest-Linux-x86_64.sh),默認保存到用戶目錄的 ~/Downloads 文件夾…

【后端】數據庫四大范式詳細解析

梳理一下 MySQL&#xff08;或關系型數據庫&#xff09;中的第一、二、三、四范式&#xff0c;這是數據庫設計中非常重要的規范化理論。1?? 第一范式 (1NF&#xff1a;First Normal Form)定義&#xff1a;字段具有原子性&#xff0c;不可再分。數據表中每一列都必須是不可分割…

HarmonyOS后臺任務調度:JobScheduler與WorkManager實戰指南

本文將深入探討HarmonyOS 5&#xff08;API 12&#xff09;中的后臺任務調度機制&#xff0c;重點講解JobScheduler和WorkManager的使用方法、適用場景及最佳實踐&#xff0c;幫助開發者實現高效、智能的后臺任務管理。 1. 后臺任務調度概述 HarmonyOS提供了兩種主要的后臺任務…

Prompt工程實踐

你在寫prompt時候&#xff0c;是不是總覺得大模型它不聽話。要么答非所問、要么一堆廢話。扒開思考過程仔細閱讀時而覺得它聰明絕頂&#xff0c;時而又覺得它愚蠢至極。明明已經對了怎么又推理到錯的地方去了&#xff0c;明明在提示詞中提醒過了不要這么思考它怎么就瞎想了。這…

基于springboot的畢業旅游一站式定制系統

博主介紹&#xff1a;java高級開發&#xff0c;從事互聯網行業六年&#xff0c;熟悉各種主流語言&#xff0c;精通java、python、php、爬蟲、web開發&#xff0c;已經做了多年的設計程序開發&#xff0c;開發過上千套設計程序&#xff0c;沒有什么華麗的語言&#xff0c;只有實…

輸入1.8V~5.5V 輸出28V DCDC升壓芯片TLV61046A

今天來一款TI的升壓芯片TLV61046A。輸入電壓范圍1.8V~5.5V。最高可以輸出28V。開關電流980mA&#xff0c;那具體能輸出多大的電流就得看輸入輸出的電壓了。以上面的輸入3.6V輸出12V為例&#xff0c;效率是85%&#xff0c;那最高可以輸出的電流就差不多只有200mA左右。封裝也是非…