模型概述
模型特點
模型能力
使用案例
🚀 BERT-th
BERT-th 是基於 BERT-Base 結構的泰語預訓練模型,它解決了原始 BERT 模型在泰語處理上因分詞困難而無法覆蓋泰語的問題,為泰語的文本處理提供了強大的預訓練能力,可應用於多種下游任務。
🚀 快速開始
本項目改編自 https://github.com/ThAIKeras/bert,以適配 HuggingFace/Transformers 庫。
預分詞
你必須運行原始的泰語分詞器(ThaiTokenizer),以確保你的分詞結果與原始模型的分詞結果一致。如果你跳過此步驟,效果不會比 mBERT 或隨機猜測好多少!
你可以參考此 CoLab 筆記本,或按照以下步驟操作:
pip install pythainlp six sentencepiece python-crfsuite
git clone https://github.com/ThAIKeras/bert
# 從 ThAIKeras/bert > Tokenization 部分下載 .vocab 和 .model 文件
然後設置泰語分詞器類(ThaiTokenizer),該類經過了輕微修改,以去除對 TensorFlow 的依賴。
import collections
import unicodedata
import six
def convert_to_unicode(text):
"""Converts `text` to Unicode (if it's not already), assuming utf-8 input."""
if six.PY3:
if isinstance(text, str):
return text
elif isinstance(text, bytes):
return text.decode("utf-8", "ignore")
else:
raise ValueError("Unsupported string type: %s" % (type(text)))
elif six.PY2:
if isinstance(text, str):
return text.decode("utf-8", "ignore")
elif isinstance(text, unicode):
return text
else:
raise ValueError("Unsupported string type: %s" % (type(text)))
else:
raise ValueError("Not running on Python2 or Python 3?")
def load_vocab(vocab_file):
vocab = collections.OrderedDict()
index = 0
with open(vocab_file, "r") as reader:
while True:
token = reader.readline()
if token.split(): token = token.split()[0] # to support SentencePiece vocab file
token = convert_to_unicode(token)
if not token:
break
token = token.strip()
vocab[token] = index
index += 1
return vocab
#####
from bert.bpe_helper import BPE
import sentencepiece as spm
def convert_by_vocab(vocab, items):
output = []
for item in items:
output.append(vocab[item])
return output
class ThaiTokenizer(object):
"""Tokenizes Thai texts."""
def __init__(self, vocab_file, spm_file):
self.vocab = load_vocab(vocab_file)
self.inv_vocab = {v: k for k, v in self.vocab.items()}
self.bpe = BPE(vocab_file)
self.s = spm.SentencePieceProcessor()
self.s.Load(spm_file)
def tokenize(self, text):
bpe_tokens = self.bpe.encode(text).split(' ')
spm_tokens = self.s.EncodeAsPieces(text)
tokens = bpe_tokens if len(bpe_tokens) < len(spm_tokens) else spm_tokens
split_tokens = []
for token in tokens:
new_token = token
if token.startswith('_') and not token in self.vocab:
split_tokens.append('_')
new_token = token[1:]
if not new_token in self.vocab:
split_tokens.append('<unk>')
else:
split_tokens.append(new_token)
return split_tokens
def convert_tokens_to_ids(self, tokens):
return convert_by_vocab(self.vocab, tokens)
def convert_ids_to_tokens(self, ids):
return convert_by_vocab(self.inv_vocab, ids)
接下來,對自己的文本進行預分詞:
from pythainlp import sent_tokenize
tokenizer = ThaiTokenizer(vocab_file='th.wiki.bpe.op25000.vocab', spm_file='th.wiki.bpe.op25000.model')
txt = "กรุงเทพมหานครเป็นเขตปกครองพิเศษของประเทศไทย มิได้มีสถานะเป็นจังหวัด คำว่า \"กรุงเทพมหานคร\" นั้นยังใช้เรียกองค์กรปกครองส่วนท้องถิ่นของกรุงเทพมหานครอีกด้วย"
split_sentences = sent_tokenize(txt)
print(split_sentences)
"""
['กรุงเทพมหานครเป็นเขตปกครองพิเศษของประเทศไทย ',
'มิได้มีสถานะเป็นจังหวัด ',
'คำว่า "กรุงเทพมหานคร" นั้นยังใช้เรียกองค์กรปกครองส่วนท้องถิ่นของกรุงเทพมหานครอีกด้วย']
"""
split_words = ' '.join(tokenizer.tokenize(' '.join(split_sentences)))
print(split_words)
"""
'▁กรุงเทพมหานคร เป็นเขต ปกครอง พิเศษ ของประเทศไทย ▁มิ ได้มี สถานะเป็น จังหวัด ▁คําว่า ▁" กรุงเทพมหานคร " ▁นั้น...' # continues
"""
✨ 主要特性
Google 的 BERT 是目前最先進的文本預訓練表示方法,它還提供了多語言模型。不過,由於分詞困難,泰語是 103 種語言中唯一未被覆蓋的語言。
BERT-th 基於 BERT-Base 結構,提供了僅針對泰語的預訓練模型,目前可下載使用:
BERT-Base, Thai
: BERT-Base 架構,僅針對泰語的模型
BERT-th 除了預訓練模型外,還包含相關代碼和腳本,這些都是對原始 BERT 項目中的代碼進行修改後的版本。
📦 安裝指南
預分詞依賴安裝
pip install pythainlp six sentencepiece python-crfsuite
git clone https://github.com/ThAIKeras/bert
下載相關文件
💻 使用示例
基礎用法
from pythainlp import sent_tokenize
tokenizer = ThaiTokenizer(vocab_file='th.wiki.bpe.op25000.vocab', spm_file='th.wiki.bpe.op25000.model')
txt = "กรุงเทพมหานครเป็นเขตปกครองพิเศษของประเทศไทย มิได้มีสถานะเป็นจังหวัด คำว่า \"กรุงเทพมหานคร\" นั้นยังใช้เรียกองค์กรปกครองส่วนท้องถิ่นของกรุงเทพมหานครอีกด้วย"
split_sentences = sent_tokenize(txt)
print(split_sentences)
"""
['กรุงเทพมหานครเป็นเขตปกครองพิเศษของประเทศไทย ',
'มิได้มีสถานะเป็นจังหวัด ',
'คำว่า "กรุงเทพมหานคร" นั้นยังใช้เรียกองค์กรปกครองส่วนท้องถิ่นของกรุงเทพมหานครอีกด้วย']
"""
split_words = ' '.join(tokenizer.tokenize(' '.join(split_sentences)))
print(split_words)
"""
'▁กรุงเทพมหานคร เป็นเขต ปกครอง พิเศษ ของประเทศไทย ▁มิ ได้มี สถานะเป็น จังหวัด ▁คําว่า ▁" กรุงเทพมหานคร " ▁นั้น...' # continues
"""
📚 詳細文檔
預處理
數據源
BERT-th 的訓練數據來自 2018 年 11 月 2 日的 泰語維基百科最新文章轉儲,原始文本使用 WikiExtractor 進行提取。
句子分割
輸入數據在由 BERT 模塊進一步處理之前,需要分割成單獨的句子。由於泰語句子末尾沒有明確的標記,因此確定句子邊界存在一定問題。據我們所知,目前其他地方還沒有實現泰語句子分割的方法。因此,在本項目中,句子分割是通過應用簡單的啟發式方法實現的,考慮了空格、句子長度和常見連詞。
預處理後,訓練語料庫大約包含 200 萬個句子和 4000 萬個單詞(使用 PyThaiNLP 進行分詞後統計)。可以 在此處
下載純文本和分割後的文本。
分詞
BERT 使用 WordPiece 作為分詞機制,但這是 Google 內部的方法,我們無法先應用現有的泰語分詞方法,然後再利用 WordPiece 學習子詞單元集。最佳替代方案是 SentencePiece,它實現了 BPE,並且不需要分詞。
在本項目中,我們採用了來自 BPEmb 的預訓練泰語 SentencePiece 模型。選擇了具有 25000 個詞彙的模型,並需要用 BERT 的特殊字符(包括 '[PAD]'、'[CLS]'、'[SEP]' 和 '[MASK]')擴充詞彙文件。可以 在此處
下載模型和詞彙文件。
SentencePiece
和 BPEmb 中的 bpe_helper.py
都用於對數據進行分詞。已將 ThaiTokenizer
類添加到 BERT 的 tokenization.py
中,用於對泰語文本進行分詞。
預訓練
可以使用以下腳本在預訓練前準備數據:
export BPE_DIR=/path/to/bpe
export TEXT_DIR=/path/to/text
export DATA_DIR=/path/to/data
python create_pretraining_data.py \
--input_file=$TEXT_DIR/thaiwikitext_sentseg \
--output_file=$DATA_DIR/tf_examples.tfrecord \
--vocab_file=$BPE_DIR/th.wiki.bpe.op25000.vocab \
--max_seq_length=128 \
--max_predictions_per_seq=20 \
--masked_lm_prob=0.15 \
--random_seed=12345 \
--dupe_factor=5 \
--thai_text=True \
--spm_file=$BPE_DIR/th.wiki.bpe.op25000.model
然後,可以運行以下腳本從頭開始學習模型:
export DATA_DIR=/path/to/data
export BERT_BASE_DIR=/path/to/bert_base
python run_pretraining.py \
--input_file=$DATA_DIR/tf_examples.tfrecord \
--output_dir=$BERT_BASE_DIR \
--do_train=True \
--do_eval=True \
--bert_config_file=$BERT_BASE_DIR/bert_config.json \
--train_batch_size=32 \
--max_seq_length=128 \
--max_predictions_per_seq=20 \
--num_train_steps=1000000 \
--num_warmup_steps=100000 \
--learning_rate=1e-4 \
--save_checkpoints_steps=200000
我們已經對模型進行了 100 萬步的訓練。在 Tesla K80 GPU 上,大約需要 20 天才能完成。不過,我們提供了 80 萬步的快照,因為它在下游分類任務中能取得更好的結果。
下游分類任務
XNLI
XNLI 是一個用於評估跨語言推理分類任務的數據集。開發集和測試集包含 15 種語言,數據經過了精心編輯。還提供了訓練數據的機器翻譯版本。
可以使用翻譯成泰語的訓練數據,將僅針對泰語的預訓練 BERT 模型應用於 XNLI 任務。需要去除訓練數據中單詞之間的空格,使其與預訓練步驟中的輸入保持一致。可以 在此處
下載與泰語相關的 XNLI 處理文件。
之後,可以使用以下腳本學習 XNLI 任務:
export BPE_DIR=/path/to/bpe
export XNLI_DIR=/path/to/xnli
export OUTPUT_DIR=/path/to/output
export BERT_BASE_DIR=/path/to/bert_base
python run_classifier.py \
--task_name=XNLI \
--do_train=true \
--do_eval=true \
--data_dir=$XNLI_DIR \
--vocab_file=$BPE_DIR/th.wiki.bpe.op25000.vocab \
--bert_config_file=$BERT_BASE_DIR/bert_config.json \
--init_checkpoint=$BERT_BASE_DIR/model.ckpt \
--max_seq_length=128 \
--train_batch_size=32 \
--learning_rate=5e-5 \
--num_train_epochs=2.0 \
--output_dir=$OUTPUT_DIR \
--xnli_language=th \
--spm_file=$BPE_DIR/th.wiki.bpe.op25000.model
以下表格比較了僅針對泰語的模型與 XNLI 基線模型以及同樣使用翻譯數據訓練的多語言大小寫模型:
模型類型 | Translate Train | Translate Test | Multilingual Model | Thai-only Model |
---|---|---|---|---|
準確率 | 62.8 | 64.4 | 66.1 | 68.9 |
Wongnai 評論數據集
Wongnai 評論數據集收集了來自 Wongnai 網站的餐廳評論和評分。任務是將評論分類為五個評分等級之一(1 到 5 星)。可以 在此處
下載數據集,並運行以下腳本使用僅針對泰語的模型完成此任務:
export BPE_DIR=/path/to/bpe
export WONGNAI_DIR=/path/to/wongnai
export OUTPUT_DIR=/path/to/output
export BERT_BASE_DIR=/path/to/bert_base
python run_classifier.py \
--task_name=wongnai \
--do_train=true \
--do_predict=true \
--data_dir=$WONGNAI_DIR \
--vocab_file=$BPE_DIR/th.wiki.bpe.op25000.vocab \
--bert_config_file=$BERT_BASE_DIR/bert_config.json \
--init_checkpoint=$BERT_BASE_DIR/model.ckpt \
--max_seq_length=128 \
--train_batch_size=32 \
--learning_rate=5e-5 \
--num_train_epochs=2.0 \
--output_dir=$OUTPUT_DIR \
--spm_file=$BPE_DIR/th.wiki.bpe.op25000.model
在不進行額外預處理和進一步微調的情況下,僅針對泰語的 BERT 模型在公共測試集和私有測試集上的得分分別為 0.56612 和 0.57057。



