Instructions to use Minhtan210905/PhoBERT-BIO-Sequence-Labeling with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Minhtan210905/PhoBERT-BIO-Sequence-Labeling with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("token-classification", model="Minhtan210905/PhoBERT-BIO-Sequence-Labeling")# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("Minhtan210905/PhoBERT-BIO-Sequence-Labeling", dtype="auto") - Notebooks
- Google Colab
- Kaggle
🕵️♂️ PhoBERT BIO Sequence Labeling: Nhận diện và Định vị Ngôn từ Độc hại Tiếng Việt (Span Detection)
PhoBERT BIO Sequence Labeling là một mô hình học sâu chuyên biệt được phát triển dựa trên kiến trúc vinai/phobert-large. Khác với các mô hình phân loại văn bản thông thường (Sentence Classification) chỉ đưa ra kết quả nhị phân (Có/Không), mô hình này được thiết kế để giải quyết bài toán Sequence Labeling (Gán nhãn chuỗi) bằng định dạng BIO, nhằm định vị chính xác vị trí của từ lóng, teencode, và ngôn từ xúc phạm trong câu.
Dự án này hướng tới mục tiêu xây dựng Explainable AI (XAI - AI có thể giải thích được), giúp hệ thống kiểm duyệt không chỉ tự động ẩn/khóa bình luận mà còn minh bạch hóa quá trình kiểm duyệt bằng cách bôi đỏ (highlight) chính xác các cụm từ vi phạm.
📊 Thông tin Mô hình (Model Details)
- Kiến trúc gốc (Base Backbone): vinai/phobert-large (370M tham số).
- Custom Head:
Linear Classifierđược tùy chỉnh bằng PyTorch để xuất ra 3 nhãn riêng biệt cho từng token. - Nhiệm vụ (Task): Nhận diện Thực thể/Định vị Chuỗi (Token Classification / Span Detection).
- Ngôn ngữ: Tiếng Việt (
vi). - Tập dữ liệu huấn luyện: Kế thừa và mở rộng từ bộ dữ liệu ViHOS (Vietnamese Hate and Offensive Spans), kết hợp đa nguồn tạo thành kho dữ liệu ~53.000 câu.
- Nhà phát triển: Bùi Minh Tân & Nguyễn Lâm Hoàng Yến & Nguyễn Phạm Trung Nghĩa, Khoa CNTT, Trường Đại học Sư phạm TP.HCM (HCMUE).
- Giấy phép: MIT
Quy tắc dán nhãn (BIO Rules):
O (0): Outside - Từ bình thường, an toàn.B-T (1): Begin Toxic - Token đầu tiên của một cụm từ độc hại.I-T (2): Inside Toxic - Các token tiếp theo nằm bên trong cụm từ độc hại.
📈 Hiệu năng và Đánh giá (Evaluation Metrics)
Do tính chất phức tạp của bài toán định vị chính xác ranh giới từ (Span-level), mô hình được đánh giá qua hai hệ quy chiếu khác nhau trên tập Test (33.400 mẫu):
1. Đánh giá cấp độ Token (Token-level Classification Report):
Đạt độ chính xác tổng thể (Accuracy) 85.10%. Mô hình thể hiện sự nhạy bén cực cao trong việc nhận diện các từ bắt đầu một cụm vi phạm (B-T).
- F1-Score (Clean - 0): 0.9087
- F1-Score (B-T - 1): 0.6430
- F1-Score (I-T - 2): 0.4802
2. Đánh giá cấp độ Span (SEQEVAL Report - Exact Match):
Theo chuẩn đánh giá NER khắt khe nhất (bắt buộc khớp 100% ranh giới từ lóng), mô hình đạt Span F1: 0.49. Tuy nhiên, trong thực tiễn kiểm duyệt MXH, việc nhận diện được B-T (đạt F1 0.64) là đã đủ cơ sở để kích hoạt cờ cảnh báo (flag) và ngăn chặn bình luận độc hại.
🎯 Mục đích sử dụng & Định hướng tương lai
Ứng dụng thực tế:
- Kiểm duyệt minh bạch: Giao diện bôi đỏ (highlight) các từ vi phạm, giúp người dùng hoặc Quản trị viên (Admin) hiểu rõ lý do tại sao bình luận bị cấm.
- Khám phá từ lóng mới: Công cụ hỗ trợ trích xuất tự động các từ lóng mới, teencode biến thể của Gen Z từ các luồng văn bản khổng lồ.
Hạn chế & Hướng phát triển:
- Mô hình đôi khi gặp khó khăn trong việc xác định chính xác từ kết thúc của một cụm từ chửi thề dài (thể hiện qua điểm
I-Tthấp hơnB-T). - Giải pháp: Trong các phiên bản tương lai, chúng tôi đề xuất bổ sung thêm một lớp CRF (Conditional Random Field) vào sau kiến trúc PhoBERT để áp đặt các quy tắc ngữ pháp (VD:
I-Tkhông được đứng trướcB-T), kỳ vọng sẽ kéo điểm Span F1 lên mức ≥0.60.
🛠️ Hướng dẫn sử dụng nhanh (Quick Start)
Lưu ý: Mô hình này sử dụng kiến trúc PyTorch tùy chỉnh (PhoBERTForBIOTagging) thay vì lớp AutoModelForTokenClassification mặc định. Do đó, bạn cần tải file trọng số .pt và thiết lập kiến trúc thủ công như sau:
import torch
import torch.nn as nn
from transformers import AutoTokenizer, XLMRobertaModel
from huggingface_hub import hf_hub_download
# 1. Định nghĩa lại kiến trúc Model tùy chỉnh
class PhoBERTForBIOTagging(nn.Module):
def __init__(self, backbone: XLMRobertaModel, num_labels: int = 3, dropout: float = 0.1):
super().__init__()
self.bert = backbone
self.dropout = nn.Dropout(dropout)
self.classifier = nn.Linear(backbone.config.hidden_size, num_labels)
def forward(self, input_ids, attention_mask):
outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask)
sequence_output = self.dropout(outputs.last_hidden_state)
return self.classifier(sequence_output)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# 2. Tải Tokenizer và Base Backbone
backbone_name = "vinai/phobert-large"
tokenizer = AutoTokenizer.from_pretrained(backbone_name)
backbone = XLMRobertaModel.from_pretrained(backbone_name)
backbone.resize_token_embeddings(len(tokenizer))
# 3. Tải file Weights (.pt) từ Hugging Face Hub
REPO_ID = "Minhtan210905/PhoBERT-BIO-Sequence-Labeling"
weights_path = hf_hub_download(repo_id=REPO_ID, filename="phobert_bio_best.pt")
# 4. Khởi tạo mô hình và nạp trọng số
model = PhoBERTForBIOTagging(backbone=backbone, num_labels=3)
model.load_state_dict(torch.load(weights_path, map_location=device))
model.eval().to(device)
def extract_toxic_spans(text):
inputs = tokenizer(text, return_tensors="pt", truncation=True, max_length=128).to(device)
with torch.no_grad():
logits = model(inputs["input_ids"], inputs["attention_mask"])
preds = logits.argmax(dim=-1)[0].cpu().numpy()
tokens = tokenizer.convert_ids_to_tokens(inputs["input_ids"][0])
real_len = int(inputs["attention_mask"][0].sum())
body_preds = preds[1 : real_len - 1]
body_tokens = tokens[1 : real_len - 1]
toxic_words = []
current_word = ""
for token, label in zip(body_tokens, body_preds):
clean_token = token.replace("@@", "").replace("_", " ")
if label == 1: # B-T
if current_word: toxic_words.append(current_word.strip())
current_word = clean_token
elif label == 2: # I-T
current_word += clean_token
else: # O
if current_word:
toxic_words.append(current_word.strip())
current_word = ""
if current_word: toxic_words.append(current_word.strip())
return toxic_words
# --- Chạy thử nghiệm ---
test_text = "thằng này là đồ ngu đần học dốt vl"
violation_words = extract_toxic_spans(test_text)
print(f"Câu gốc: {test_text}")
print(f"Các từ lóng vi phạm bị bắt: {violation_words}")
# Kì vọng Output: ['ngu đần', 'vl']