BERT (Bidirectional Encoder Representations from Transformers), một nghiên cứu mới mang đầy tính đột phá, một bước nhảy vọt thực sự của Google trong lĩnh vực xử lý ngôn ngữ tự nhiên. Sự ra đời của pre-trained BERT đã kéo theo sự cải tiến đáng kể cho rất nhiều bài toán như Question Answering, Sentiment Analysis,… Với các phiên bản cải tiến, biến thể như RoBERTa, ALBERT, DistilBERT,… BERT đã càn quét các tác vụ xử lý ngôn ngữ tự nhiên, trở lên áp đảo trong các nền tảng thi đấu như Kaggle, AIVIVN cũng như shared task của nhiều hội nghị.

1 2

“Pre-trained PhoBERT models are the state-of-the-art language models for Vietnamese (Pho, i.e. “Phở”, is a popular food in Vietnam)”.

PhoBERT khá dễ dùng, nó được build để sử dụng luôn trong các thư viện siêu dễ dùng như FAIRSeq của Facebook hay Transformers của Hugging Face nên giờ đây BERT lại càng phổ biến ngay cả với ngôn ngữ tiếng Việt hay tiếng Anh. Nhưng trước tiên, hãy quay lại một chút với lý thuyết để tìm hiểu xem PhoBERT được xây dựng như thế nào, một chút thông tin bản về nó. Sau đó, chúng ta sẽ được tìm hiểu về cách áp dụng các mô hình BERT, RoBERTa, PhoBERT cho nhiệm vụ phân loại văn bản cho cả tiếng Anh và tiếng Việt với sự hỗ trợ của FAIRSeq và Transformers. Nào, bắt đầu với PhoBERT.

PhoBERT là gì thế?

PhoBERT có một số điểm chính như sau:

  • Đây là một pre-trained được huấn luyện monolingual language, tức là chỉ huấn luyện dành riêng cho tiếng Việt. Việc huấn luyện dựa trên kiến trúc và cách tiếp cận giống RoBERTa của Facebook được Facebook giới thiệu giữa năm 2019. Đây là một cái tiến so với BERT trước đây. Còn cụ thể RoBERTa khác BERT như nào bạn có thể đọc ở paper của RoBERTa luôn nhé. Đây là một paper khá dễ đọc và mình cũng không muốn bài viết dài nên sẽ mặc định bỏ qua, RoBERTa: A Robustly Optimized BERT pretraining Approach.
  • Tương tự như BERT: PhoBERT cũng có 2 phiên bản là PhoBERTbase với 12 transformer block và PhoBERTlarge với 24 transformer block.
  • PhoBERT được train trên khoảng 20GB dữ liệu bao gồm khoảng 1GB Vietnamese Wikipedia corpus và 19GB còn lại lấy từ Vietnamese news corpus. Đây là một lượng dữ liệu khả ổn để train một mô hình như BERT.
  • PhoBERT sử dụng RDRSegmenter của VNCoreNLP để tách từ cho dữ liệu đầu vào trước khi qua BPE encoder.
  • Như đã nói ở trên, do tiếp cận theo tư tưởng của RoBERTa, PhoBERT chỉ sử dụng task Masked Language Model để train, bỏ đi task Next Sentence Prediction.

Tương tự PhoBERT, một phiên bản thứ 2 cũng được cùng nhóm tác giả của PhoBERT công bố hồi cuối tháng 05/2020 là BERTweet: A pre-trained language model for English Tweets, cái mà lát nữa chúng ta cũng sẽ sử dụng. Đây cũng là một pre-trained khá tương tự với PhoBERT, có lẽ khác nhau duy nhất là dữ liệu huấn luyện.

Nào, giờ chúng ta hãy bắt tay vào thực hành với BERT, PhoBERT và BERTweet. Cảm ơn sự tài trợ của FAIRseq (Facebook) và Transformers  (Hugging Face) đã giúp cho công việc dưới đây đơn giản và dễ dàng hơn rất nhiều.

Thực hành với BERT

Để thực hành với BERT, PhoBERT và BERTweet, chúng ta sẽ cùng thử nghiệm với 2 bài toán phân loại văn bản. Bài toán đầu tiên là Phân loại sắc thái bình luận  được tổ chức bởi  AIVIVN và bài thứ hai là Identification of informative COVID-19 English Tweets là một shared task thuộc W-NUT 2020 đang diễn ra. Hai bài toán cần giải quyết đều là các bài toán phân loại nhị phân, tức là mỗi sample cần được mô hình gán 1 trong 2 nhãn tương ứng. Tuy nhiên, bài toán đầu tiên cần giải quyết là cho tiếng Việt, do đó PhoBERT được ưu tiên sử dụng trong khi task thứ 2 là tiếng Anh do vậy ngoài BERTweet chúng ta cũng có thể sử dụng nhiều mô hình pre-trained BERT khác.

Phân loại sắc thái bình luận với PhoBERT

Đầu tiên, trước khi đọc và làm theo tất cả những điều bên dưới thì chúng ta sẽ cần phải cài các thư viện cần thiết.

2 2

Bạn cũng có thể cài đặt thư viện transformers bằng câu lệnh pip install transformers, tuy nhiên, riêng thư viện này mình ưu tiên cài đặt từ source như ở trên. Kế tiếp, chúng ta cài đặt fastBPE và FAIRSeq. Việc sử dụng thư viện FAIRSeq hay transformers để load pre-trained BERT và tune lại với bài toán của bạn là đơn giản như nhau, nên bạn cố thể chọn một trong 2 để thực hiện công việc của mình. Mình thì thấy việc sử dụng transformers thích hơn và nó có nhiều thứ hơn không chỉ là BERT, do vậy mình ưu tiên dùng thư viện này.

3 2

Cuối cùng là cài đặt vncorenlp, một thư viện tách từ được publish bởi chính tác giả của PhoBERT.

4 1

Hướng dẫn cài đặt cho VnCoreNLP này mình lấy từ repo gốc PhoBERT, yêu cầu máy bạn phải được cài trước java vì đây là một python wrapper cho java.

Để chắc chắn cài đặt thành công, bạn có thể thử sử dụng nó để tách từ cho một câu đơn giản theo cách dưới đây.

5 2

kết quả thu được là

6 1

Sau khi cài đặt các thứ xong xuôi, mình tiến hành tải về bộ dữ liệu huấn luyện từ trang chủ cuộc thi của AIVIVN và pre-trained của PhoBERT xong tiến hành giải nén. Khi tải về pre-trained BERT, tùy vào việc bạn sử dụng thư viện nào để load model thì bạn sẽ cần phải tải về pre-trained tương ứng(PhoBERT_base_fairseq hay PhoBERT_base_transformers).

7 1

Khi giải nén PhoBERT base transformers, bạn sẽ thấy thư mục này gồm 4 file nhỏ bao gồm config.json chứa config của model, model.bin lưu trữ pre-trained weight của model, bpe.codes và dict.txt chứ từ điển sẵn có của PhoBERT. Tương tự, trong PhoBERT base FAIRSeq bạn cũng sẽ thấy 3 file model.ptdict.txt và bpe.codes. Bạn có thể load model và bpe này lên theo hướng dẫn của PhoBERT.

9 1

Giờ đây, bạn có thể sử dụng bpe để encode 1 câu hay một đoạn văn bản thành một list các subword, vocab giúp bạn ánh xạ ngược từ subword về id của nó trong bộ tự vựng được cung cấp sẵn.

10 1

Ở đây, với mỗi câu mình phải thêm <s> là token đặc biệt để đánh dấu vị trí đầu câu và </s> để đánh dấu vị trí cuối mỗi câu.

Tương tự, khi bạn tải về dữ liệu của cuộc thi Phân tích sắc thái bình luận bạn sẽ thấy 3 file bao gồm sample_submission.csvtest.crash và train.crash là file test mẫu, dữ liệu test và dữ liệu train cho cuộc thi.

Trước tiên, ta tiến hành đọc dữ liệu huấn luyện và dữ liệu test, tiền xử lý chúng đơn giản bằng cách sử dụng wordsegmenter.

11 1
12 1

Giờ chúng ta đã có một list chứa các dữ liệu đã qua tách từ, ứng với list label của chúng là các nhãn 0 và 1. Coi như việc tách từ là tiền xử lý duy nhất của chúng ta.

train_text của chúng ta bây giờ sẽ như thế này.

13 1

Mình tách dữ liệu ra thành 2 tập train và validation theo tỉ lệ 90:10.

14 1

Tiếp theo, từ dữ liệu thô này, chúng ta sử dụng bpe đã load ở trên để đưa text đầu vào dưới dạng subword và ánh xạ các subword này về dạng index trong từ điển:

15 1

train_ids bây giờ đã trở thành một list dữ liệu mẫu trong đó mỗi mẫu là một list id của các subword có trong từ điển. Các câu ngắn hơn 125 subword được padding 0 ở cuối, những câu dài hơn được cắt đi cho đủ 125.

Tiếp theo, mình tạo một mask gồm các giá trị 01 để làm đầu vào cho thư viện transformers, mask này cho biết các giá trị nào của chuỗi đã được padding.

16 1

Và giờ, dữ liệu đầu vào cho mô hình đã gần như chuẩn bị xong, chỉ cần chuyển về tensor và sử dụng DataLoader của torch để tạo dataloader nữa thôi.

17 1

Cuối cùng, việc chuẩn bị dữ liệu cũng đã xong. Chúng ta quay lại với việc load model PhoBERT. Như đã đề cập ở trên, PhoBERT cho chúng ta 2 lựa chọn là Fairseq và Transformers, tùy vào việc bạn thích hay quen với việc sử dụng thư viện nào, mình thì chọn Transformers của Hugging Face.

18 1

BertForSequenceClassification sẽ nhận đầu vào là input_ids và input_mask, đầu ra trả về luôn loss cho classification task và phân phối xác xuất do mô hình dự đoán đầu ra. Chi tiết bạn có thể xem ở docs BertForSequenceClassification.

View lên nhìn xem mô hình này được thiết như nào, có gì khác biệt so với PhoBERT.

19 1
20 1
21 1
22 1
23 1
24
25
26
27

Thực ra nó vẫn là PhoBERT hay RoBERTa, chỉ khác là phần head của model đã được thêm 2 layers Dense và Dropout với droprate = 0.1.

Dưới đây là phần code hoàn thiện cho phần training mô hình. Bạn có thể để ý thì phần này không khác gì so với việc bạn train các mô hình khác sử dụng Pytorch chỉ khác việc giờ đây chúng ta đang sử dụng model được load bởi transformers.

28
29
30

Sau khi train 10 epochs, mình thấy độ chính xác của mô hình đã khá tốt. F1 score trên tập validation do mình tự chia đã đạt ~0.9(thực ra đến epochs thứ 2 F1 đã đạt ~0.9), không biết submit lên trên AIVIVN thì kết quả thế nào. Nhưng có vẻ việc sử dụng PhoBERT cho task này khá tốt.

Đó, đó là toàn bộ những việc phải làm khi sử dụng PhoBERT cho task phân loại văn bản cho tiếng Việt. Việc test với dữ liệu test khá dễ dàng nên mình sẽ không viết nữa mà đó là bài tập về nhà cho các bạn.

Tiếp theo, chúng ta sẽ làm việc với task Identification of informative COVID-19 English Tweets.

Identification of informative COVID-19 English Tweets

Thực ra task này cũng không khác task bên trên là mấy, chỉ khác là giờ ta làm việc với tiếng Anh. Việc sử dụng BERTweet cũng khá đơn giản, giống hoàn toàn với những gì bên trên chúng ta đã làm. (chỉ khác là sẽ phải tiền xử lý khác, tách từ khác và load mô hình BERTweet thay vì PhoBERT). Việc sử dụng BERTweet là tương tự nên đúng ra mình sẽ không viết tiếp mà cho các bạn tự xử(coi như bài tập về nhà). Tuy nhiên, vì đây là bài toán cho tiếng Anh nên lại được rất nhiều thư viện hỗ trợ và bạn có thể sử dụng các pre-trained khác như BERT của Google, RoBERTa của Facebook, etc.

Và đó chính là lý do chúng ta vẫn có phần này. Giải quyết bài toán Identification of informative COVID-19 English Tweets với BERT và RoBERTa với chỉ với vài chục dòng code,

BERT và RoBERTa chỉ với vài chục dòng code?

Vâng, đó là sự thật vì giờ đây là đã có thể sử dụng BERT Tokenizer thay vì những thứ lằng nhằng như trước. Và do những cái này đã trở thành 1 pipeline quá cơ bản nên cũng đã có những thư viện được viết ở mức high api hơn, giúp chúng ta có thể sử dụng BERT theo pipeline một cách dễ dàng hơn, ít công sức hơn. Và đó chính là cái tới đây mình sẽ sử dụng Simple Transformers. Về cơ bản, đây là một thư viện được viết dựa trên Transformers của Hugging Face nhưng đơn giản hơn, tự động hóa theo pipeline nhiều task như:

  • Sequence Classification
  • Token Classification (NER)
  • Question Answering
  • Language Model Fine-Tuning
  • Seq2Seq Tasks
  • Multi-Modal Classification
  • Conversational AI
  • Text Representation Generation

Quay lại với task Identification of informative COVID-19 English Tweets, đây vẫn là một bài toán phân loại nhị phân với 2 class là information và non-information. Vẫn là hàng của Vin, với 2 file dữ liệu rất chuẩn chỉnh là train.tsv và valid.tsv. Mình sẽ sử dụng Simple để thử nghiệm bài toán này vì thư viện này nhận đầu vào là các file csv, tsv luôn.

Nhưng trước tiên, chúng ta hãy quay lại tiền xử lý bộ dữ liệu này một chút. Code tiền xử lý mình sử dụng luôn ở trong repo BERTweet được cung cấp bởi team BERTweet luôn.

from nltk.tokenize import TweetTokenizer

from emoji import demojize

import re

tokenizer = TweetTokenizer()

def normalizeToken(token):

    lowercased_token = token.lower()

    if token.startswith(“@”):

        return “@USER”

    elif lowercased_token.startswith(“http”) or lowercased_token.startswith(“www”):

        return “HTTPURL”

    elif len(token) == 1:

        return demojize(token)

    else:

        if token == “’”:

            return “‘”

        elif token == “…”:

            return “…”

        else:

            return token

def normalizeTweet(tweet):

    tokens = tokenizer.tokenize(tweet.replace(“’”, “‘”).replace(“…”, “…”))

    normTweet = ” “.join([normalizeToken(token) for token in tokens])

    normTweet = normTweet.replace(“cannot “, “can not “).replace(“n’t “, ” n’t “).replace(“n ‘t “, ” n’t “).replace(“ca n’t”, “can’t”).replace(“ai n’t”, “ain’t”)

    normTweet = normTweet.replace(“‘m “, ” ‘m “).replace(“‘re “, ” ‘re “).replace(“‘s “, ” ‘s “).replace(“‘ll “, ” ‘ll “).replace(“‘d “, ” ‘d “).replace(“‘ve “, ” ‘ve “)

    normTweet = normTweet.replace(” p . m .”, ”  p.m.”) .replace(” p . m “, ” p.m “).replace(” a . m .”, ” a.m.”).replace(” a . m “, ” a.m “)

    normTweet = re.sub(r”,([0-9]{2,4}) , ([0-9]{2,4})”, r”,\1,\2″, normTweet)

    normTweet = re.sub(r”([0-9]{1,3}) / ([0-9]{2,4})”, r”\1/\2″, normTweet)

    normTweet = re.sub(r”([0-9]{1,3})- ([0-9]{2,4})”, r”\1-\2″, normTweet)     return ” “.join(normTweet.split())

Đọc dữ liệu và tiền xử lý:

import pandas as pd

train_df = pd.read_csv(‘/content/drive/My Drive/BERT/COVID19Tweet/train.tsv’, sep=’\t’, header=0)

train_df.loc[:,”Text”] = train_df[‘Text’].apply(lambda x: normalizeTweet(x))

train_df.loc[:,”Label”] = train_df[‘Label’].apply(lambda x: 1 if x == ‘INFORMATIVE’ else 0)

train_df = train_df.drop(columns=’Id’)

train_df.columns = [“text”, “labels”]

val_df = pd.read_csv(‘/content/drive/My Drive/BERT/COVID19Tweet/valid.tsv’, sep=’\t’, header=0)

val_df.loc[:,”Text”] = val_df[‘Text’].apply(lambda x: normalizeTweet(x))

val_df.loc[:,”Label”] = val_df[‘Label’].apply(lambda x: 1 if x == ‘INFORMATIVE’ else 0)

val_df = val_df.drop(columns=’Id’)

val_df.columns = [“text”, “labels”]

Cài đặt simple transformer:

pip install simpletransformers

Khởi tạo, huấn luyện và đánh giá mô hình với dữ liệu vừa xử lý:

from simpletransformers.classification import Classification

Model model = ClassificationModel(“roberta”, “roberta-base”)

model.train_model(train_df)

result, model_outputs, wrong_predictions = model.eval_model(val_df)

Và đây là kết quả:

{‘eval_loss’: 0.47565516966581345,

‘fn’: 30,

‘fp’: 71,

‘mcc’: 0.8009832811950492,

‘tn’: 457,

‘tp’: 442}

F1 score ~89.75 chỉ với 1 epochs và đống params mặc định.

Ở đây mình đang để các params là hoàn toàn mặc định, để thu được kết quả tốt hơn thì bạn phải thay đổi, tối ưu nhiều param trong quá trình huấn luyện như learning rate, số epochs, optimizer, loss weight với trường hợp dữ liệu bị imbalance. Tất cả bạn có thể đọc tại docs của Simple Transformes. Binary Classification

Ngoài ra, bạn cũng có thể thay mô hình pre-trained RoBERTa bằng các pre-trained khác như BERT, ALBER, CamemBERT, DistilBERT, etc đơn giản bằng cách thay param ở class ClassificationModel.

Và sau một thời gian tối ưu, thay đổi tham số, đây là kết quả của mình.

31

Trên đây là bài giới thiệu của mình về cách sử dụng mô hình pre-trained BERT, RoBERTa, PhoBERT và BERTweet trong nhiệm vụ phân loại văn bản bằng cách sử dụng 2 thư viện là Transformers của Hugging Face và Simple transformers một thư viện đơn giản để sử dụng với chỉ vài dòng code.

Nguồn: https://viblo.asia/p/bert-roberta-phobert-bertweet-ung-dung-state-of-the-art-pre-trained-model-cho-bai-toan-phan-loai-van-ban-4P856PEWZY3