模型:
monsoon-nlp/bert-base-thai
从HuggingFace/Transformers库的 https://github.com/ThAIKeras/bert 适配而来
您必须运行原始的ThaiTokenizer,以使您的分词与原始模型相匹配。
如果您跳过此步骤,您的效果将不会比mBERT或随机猜测好多少!
Refer to this CoLab notebook 或按照以下步骤:
pip install pythainlp six sentencepiece python-crfsuite git clone https://github.com/ThAIKeras/bert # download .vocab and .model files from ThAIKeras/bert > Tokenization section
然后设置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 """
原始README如下:
谷歌的 BERT 目前是文本表示预训练方法中的最先进方法,同时还提供多语言模型。不幸的是,泰语是103种语言中唯一被排除在外的,原因是泰语的词分割很困难。
BERT-th基于BERT-Base结构提供了仅限泰语的预训练模型。现在可以下载。
BERT-th还包括相关的代码和脚本,以及预训练模型,这些都是在原始BERT项目中修改的版本。
BERT-th的训练数据来自 the latest article dump of Thai Wikipedia ,日期为2018年11月2日。原始文本是通过 WikiExtractor 提取的。
在经过BERT模块进一步处理之前,输入数据需要分割为单独的句子。由于泰语中没有明确的句子结束标记,要确定句子边界是相当困难的。据我们所知,还没有其他地方实现泰语句子分割。因此,在这个项目中,我们采用简单的启发式方法进行句子分割,考虑空格、句子长度和常见的连接词。
预处理之后,训练语料库包括约200万个句子和4000万个单词(计算 PyThaiNLP 进行词分割后的单词)。可以下载未格式化和分割的文本 here 。
BERT使用 WordPiece 作为分词机制。但它是Google内部使用的,我们不能应用现有的泰语词分割,然后利用WordPiece来学习一组子词单元。最好的替代方案是实施 SentencePiece ,它实现了 BPE 并且不需要词分割。
在这个项目中,我们采用了 BPEmb 的预训练泰语SentencePiece模型。选择了25000个词汇的模型,词汇文件必须添加BERT的特殊字符,包括'[PAD]', '[CLS]', '[SEP]'和'[MASK]'。可以下载模型和词汇文件 here 。
SentencePiece和bpe_helper.py都用于对数据进行分词。在BERT的tokenization.py中添加了ThaiTokenizer类用于对泰语文本进行分词。
可以使用此脚本在预训练之前准备数据。
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天。但是,我们提供了在0.8百万步时的快照,因为它在下游分类任务中产生更好的结果。
XNLI 是用于评估跨语言推理分类任务的数据集。开发和测试集包含15种语言,数据经过了彻底编辑。还提供了机器翻译版本的训练数据。
可以通过使用已翻译为泰语的训练数据将仅限泰语预训练的BERT模型应用于XNLI任务。需要删除训练数据中单词之间的空格,以使其与预训练步骤中的输入一致。与泰语相关的XNLI处理文件可以下载 here 。
然后,可以使用此脚本学习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基线和同时使用翻译数据进行训练的多语言Cased模型。
XNLI Baseline | BERT | ||
Translate Train | Translate Test | Multilingual Model | Thai-only Model |
62.8 | 64.4 | 66.1 | 68.9 |
Wongnai评论数据集收集了来自 Wongnai 网站的餐厅评论和评分。任务是将评论分类为五个评级(1至5星)。可以下载数据集 here ,并可以运行以下脚本使用仅限泰语模型进行此任务。
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。