模型简介
模型特点
模型能力
使用案例
🚀 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。



