SentencePiece 是一種無監督文本分詞器和去分詞器,主要用於基於神經網路的文本生成系統,其中詞彙量大小在神經模型訓練之前預先確定。 SentencePiece 透過擴展原始句子的直接訓練來實現子字單元(例如,位元組對編碼(BPE) [Sennrich 等人])和一元語言模型[Kudo.])。 SentencePiece 讓我們可以製作一個純粹的端對端系統,不依賴特定於語言的預處理/後處理。
這不是 Google 官方產品。
對於那些不熟悉 SentencePiece 軟體/演算法的人,可以在這裡閱讀一篇溫和的介紹。
特徵 | 句子片段 | 子詞-nmt | 字片 |
---|---|---|---|
支援的演算法 | BPE、一元語法、字元、單字 | BPE | BPE* |
開源軟體? | 是的 | 是的 | 谷歌內部 |
子字正則化 | 是的 | 不 | 不 |
Python 函式庫 (pip) | 是的 | 不 | 不適用 |
C++ 函式庫 | 是的 | 不 | 不適用 |
需要預先分段嗎? | 不 | 是的 | 是的 |
可自訂的標準化(例如,NFKC) | 是的 | 不 | 不適用 |
直接生成id | 是的 | 不 | 不適用 |
請注意,WordPiece 中使用的 BPE 演算法與原始 BPE 略有不同。
SentencePiece 是子詞單元的重新實現,是緩解神經機器翻譯中開放詞彙問題的有效方法。 SentencePiece 支援兩種分段演算法:位元組對編碼 (BPE) [Sennrich et al.] 和一元語言模型[Kudo.]。以下是與其他實現的高級差異。
神經機器翻譯模型通常使用固定詞彙進行操作。與大多數假設無限詞彙量的無監督分詞演算法不同,SentencePiece 訓練分詞模型,使得最終詞彙量是固定的,例如 8k、16k 或 32k。
請注意,SentencePiece 指定了訓練的最終詞彙量,這與使用合併操作次數的 subword-nmt 不同。合併操作的數量是 BPE 特定的參數,不適用於其他分段演算法,包括一元語法、單字和字元。
以前的子詞實現假設輸入句是預先標記化的。此限制是有效訓練所必需的,但使預處理變得複雜,因為我們必須提前運行語言相關的分詞器。 SentencePiece 的實現速度足夠快,足以從原始句子訓練模型。這對於訓練中文和日文的分詞器和解分詞器非常有用,因為單字之間不存在明確的空格。
自然語言處理的第一步是文字標記化。例如,標準英語分詞器會對文字「Hello world」進行分段。分為以下三個標記。
[你好世界] [。
一項觀察是原始輸入和標記化序列不可逆地轉換。例如,「World」和「.」之間沒有空格的資訊。從標記化序列中刪除,因為例如Tokenize(“World.”) == Tokenize(“World .”)
SentencePiece 將輸入文字視為 Unicode 字元序列。空格也被當作普通符號處理。為了明確地將空格作為基本標記處理,SentencePiece 首先使用元符號「」 (U+2581) 轉義空格,如下所示。
你好世界。
然後,該文字被分割成小塊,例如:
[你好][世界][ld][.]
由於空格保留在分段文字中,因此我們可以毫無歧義地對文字進行去標記。
detokenized = ''.join(pieces).replace('▁', ' ')
此功能使得無需依賴特定於語言的資源即可執行去標記化。
請注意,當使用標準分詞器分割句子時,我們無法套用相同的無損轉換,因為它們將空格視為特殊符號。標記化序列不保留恢復原始句子所需的資訊。
子字正則化 [Kudo.] 和 BPE-dropout Provilkov 等人是簡單的正則化方法,它們實際上透過動態子字採樣來增強訓練數據,這有助於提高 NMT 模型的準確性和穩健性。
為了啟用子字正規化,您需要將 SentencePiece 函式庫(C++/Python)整合到 NMT 系統中,以便為每個參數更新取樣一個分段,這與標準的離線資料準備不同。這是 Python 函式庫的範例。您可以發現「New York」在每個SampleEncode (C++)
上的分段方式不同,或encode with enable_sampling=True (Python)
。採樣參數的詳細資訊可以在sentencepiece_processor.h中找到。
>>> import sentencepiece as spm
>>> s = spm.SentencePieceProcessor(model_file='spm.model')
>>> for n in range(5):
... s.encode('New York', out_type=str, enable_sampling=True, alpha=0.1, nbest_size=-1)
...
['▁', 'N', 'e', 'w', '▁York']
['▁', 'New', '▁York']
['▁', 'New', '▁Y', 'o', 'r', 'k']
['▁', 'New', '▁York']
['▁', 'New', '▁York']
SentencePiece 提供了支援 SentencePiece 訓練和分割的 Python 包裝器。您可以安裝SentencePiece的Python二進位套件。
pip install sentencepiece
有關更多詳細信息,請參閱 Python 模組
建置 SentencePiece 需要以下工具和函式庫:
在 Ubuntu 上,可以使用 apt-get 安裝建置工具:
% sudo apt-get install cmake build-essential pkg-config libgoogle-perftools-dev
然後,您可以如下建置和安裝命令列工具。
% git clone https://github.com/google/sentencepiece.git
% cd sentencepiece
% mkdir build
% cd build
% cmake ..
% make -j $(nproc)
% sudo make install
% sudo ldconfig -v
在 OSX/macOS 上,將最後一個指令替換為sudo update_dyld_shared_cache
您可以使用 vcpkg 依賴管理器下載並安裝句子:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install sentencepiece
vcpkg 中的句子連接埠由 Microsoft 團隊成員和社群貢獻者保持最新。如果版本已過時,請在 vcpkg 儲存庫上建立問題或拉取要求。
您可以從 GitHub 發布頁面下載輪子。我們在發布過程中使用 OpenSSF 的 slsa-framework/slsa-github-generator 產生 SLSA3 簽章。若要驗證發布二進位檔案:
attestation.intoto.jsonl
。slsa-verifier -artifact-path < the-wheel > -provenance attestation.intoto.jsonl -source github.com/google/sentencepiece -tag < the-tag >
pip 安裝wheel_file.whl
% spm_train --input=<input> --model_prefix=<model_name> --vocab_size=8000 --character_coverage=1.0 --model_type=<type>
--input
:每行一句話的原始語料庫檔案。無需運行分詞器、標準化器或預處理器。預設情況下,SentencePiece 使用 Unicode NFKC 規範化輸入。您可以傳遞以逗號分隔的文件清單。--model_prefix
:輸出模型名稱前綴。產生<model_name>.model
和<model_name>.vocab
。--vocab_size
: 詞彙量大小,例如 8000、16000 或 32000--character_coverage
:模型覆蓋的字元數量,好的預設值是:對於日文或中文等字元集豐富的語言, 0.9995
;對於其他字元集較小的語言,預設1.0
。--model_type
:模型類型。從unigram
(預設)、 bpe
、 char
或word
中選擇。使用word
類型時,必須對輸入句子進行預先標記。使用--help
標誌顯示訓練的所有參數,或請參閱此處以了解概述。
% spm_encode --model=<model_file> --output_format=piece < input > output
% spm_encode --model=<model_file> --output_format=id < input > output
使用--extra_options
標誌插入 BOS/EOS 標記或反轉輸入順序。
% spm_encode --extra_options=eos (add </s> only)
% spm_encode --extra_options=bos:eos (add <s> and </s>)
% spm_encode --extra_options=reverse:bos:eos (reverse input and add <s> and </s>)
SentencePiece 使用--output_format=(nbest|sample)_(piece|id)
標誌支援 nbest 分段和分段取樣。
% spm_encode --model=<model_file> --output_format=sample_piece --nbest_size=-1 --alpha=0.5 < input > output
% spm_encode --model=<model_file> --output_format=nbest_id --nbest_size=10 < input > output
% spm_decode --model=<model_file> --input_format=piece < input > output
% spm_decode --model=<model_file> --input_format=id < input > output
使用--extra_options
標誌以相反的順序解碼文字。
% spm_decode --extra_options=reverse < input > output
% spm_train --input=data/botchan.txt --model_prefix=m --vocab_size=1000
unigram_model_trainer.cc(494) LOG(INFO) Starts training with :
input: "../data/botchan.txt"
... <snip>
unigram_model_trainer.cc(529) LOG(INFO) EM sub_iter=1 size=1100 obj=10.4973 num_tokens=37630 num_tokens/piece=34.2091
trainer_interface.cc(272) LOG(INFO) Saving model: m.model
trainer_interface.cc(281) LOG(INFO) Saving vocabs: m.vocab
% echo "I saw a girl with a telescope." | spm_encode --model=m.model
▁I ▁saw ▁a ▁girl ▁with ▁a ▁ te le s c o pe .
% echo "I saw a girl with a telescope." | spm_encode --model=m.model --output_format=id
9 459 11 939 44 11 4 142 82 8 28 21 132 6
% echo "9 459 11 939 44 11 4 142 82 8 28 21 132 6" | spm_decode --model=m.model --input_format=id
I saw a girl with a telescope.
可以發現,從詞彙id序列中恢復出了原來的輸入句。
% spm_export_vocab --model=<model_file> --output=<output file>
<output file>
儲存詞彙表和排放日誌機率的清單。詞彙表 id 對應於該文件中的行號。
預設情況下,句子分別使用ID,分別為0、1和2的IDS句子,BOS(<s>)和EOS(</s>)令牌。我們可以在訓練階段重新定義這個映射,如下所示。
% spm_train --bos_id=0 --eos_id=1 --unk_id=5 --input=... --model_prefix=... --character_coverage=...
當設定 -1 id 例如bos_id=-1
時,此特殊令牌被停用。請注意,未知 ID 無法被停用。我們可以將填充 (<pad>) 的 id 定義為--pad_id=3
。
如果您想指派其他特殊標記,請參閱使用自訂符號。
spm_encode
接受--vocabulary
和--vocabulary_threshold
選項,以便spm_encode
只會產生也出現在詞彙表中的符號(至少有一定頻率)。此功能的背景在 subword-nmt 頁面中描述。
用法與subword-nmt
基本上相同。假設 L1 和 L2 是兩種語言(源語言/目標語言),訓練共享 spm 模型,並獲得每種語言的結果詞彙:
% cat {train_file}.L1 {train_file}.L2 | shuffle > train
% spm_train --input=train --model_prefix=spm --vocab_size=8000 --character_coverage=0.9995
% spm_encode --model=spm.model --generate_vocabulary < {train_file}.L1 > {vocab_file}.L1
% spm_encode --model=spm.model --generate_vocabulary < {train_file}.L2 > {vocab_file}.L2
使用shuffle
指令是為了以防萬一,因為spm_train
預設載入語料庫的前 10M 行。
然後使用--vocabulary
選項對訓練/測試語料庫進行分段
% spm_encode --model=spm.model --vocabulary={vocab_file}.L1 --vocabulary_threshold=50 < {test_file}.L1 > {test_file}.seg.L1
% spm_encode --model=spm.model --vocabulary={vocab_file}.L2 --vocabulary_threshold=50 < {test_file}.L2 > {test_file}.seg.L2