nhdang117/legal-nli-demo
Legal NLI Demo
Web demo (Gradio) so sánh hành vi 3 model NLI trên văn bản pháp luật Việt Nam: TF-IDF + LogReg, TF-IDF + Linear SVM, PhoBERT.
Chức năng
Tab "Dự đoán & giải thích": nhập premise + hypothesis.
- Nhãn và độ tự tin của 3 model, kèm cờ khi các model bất đồng.
- ① TF-IDF: tô màu từng từ theo mức đóng góp, biểu đồ waterfall (bias / khối premise / khối hypothesis / cosine / chênh độ dài / jaccard), bảng top đặc trưng, danh sách từ ngoài từ điển. Giải thích này chính xác vì model tuyến tính.
- ② PhoBERT: câu sau tách từ VnCoreNLP, chuỗi subword thực sự đưa vào model, cảnh báo cắt cụt hoặc
<unk>; nút “⚙ Cách model tính” mở panel từng bước PhoBERT. - ③ Thử nghiệm đối chứng: đảo phủ định, đổi số, đổi và/hoặc, đổi lượng từ, bỏ premise, đổi chỗ P↔H; xem model nào lật nhãn.
- ④ Mẫu train gần nhất: kiểm tra model có đang học thuộc không.
Tab "Phân tích tập test" (695 cặp): accuracy theo loại hypothesis, theo mức trùng từ, theo lĩnh vực; độ tự tin khi đúng và khi sai; ma trận đúng/sai chéo giữa các model và kiểm định McNemar; bảng mẫu sai, bấm vào một dòng để mở ở tab 1.
Chạy local (Windows)
Yêu cầu: uv. Weights nằm ở ../Weights (mặc định).
cd webapp
uv venv -p 3.13 .venv
uv pip install -p .venv --index-strategy unsafe-best-match `
--extra-index-url https://download.pytorch.org/whl/cpu -r requirements.txt
.venv\Scripts\python scripts\precompute.py # chỉ cần khi dataset/weights thay đổi
.venv\Scripts\python app.py # mở http://127.0.0.1:7860- Java: VnCoreNLP cần Java. Nếu máy không có
JAVA_HOME, app tự tìm JRE portable trongwebapp/.runtime/. Có thể tải Temurin JRE 17 dạng zip từ adoptium.net rồi giải nén vào đó. Lần chạy đầu app tự tải phần tách từ của VnCoreNLP (~30MB) vào.runtime/vncorenlp. - Không có Java thì PhoBERT chạy không tách từ và kết quả sai lệch rất nhiều (đã đo: lệch tới 0.99 xác suất). Giao diện sẽ hiện cảnh báo.
- Chỉ muốn chạy nhanh 2 model TF-IDF:
set NLI_DISABLE_PHOBERT=1.
Ràng buộc khi load weights
Deploy Hugging Face Space (Docker)
Weights (~520MB) không đi kèm Space — để ở model repo riêng, app tự tải lúc chạy.
1. Đẩy weights lên HF model repo
hf auth login
hf repo create vn-legal-nli-tfidf --repo-type model
hf upload vn-legal-nli-tfidf ../Weights/tfidf_lr_final.joblib tfidf_lr_final.joblib
hf upload vn-legal-nli-tfidf ../Weights/tfidf_svm_final.joblib tfidf_svm_final.joblib
hf repo create vn-legal-nli-phobert --repo-type model
hf upload vn-legal-nli-phobert ../Weights/phobert-nli-out . \
--exclude "*.xlsx" --exclude "*.parquet" --exclude "history.csv"Repo phobert chỉ cần: model.safetensors, config.json, vocab.txt, bpe.codes, added_tokens.json, tokenizer_config.json.
2. Tạo Space và push
hf repo create legal-nli-demo --repo-type space --space_sdk docker
git clone https://huggingface.co/spaces/<user>/legal-nli-demo hf-space
cp -r webapp/* webapp/.dockerignore webapp/.gitignore hf-space/
cd hf-space && git add -A && git commit -m "deploy" && git pushFront matter YAML ở đầu file README này là thứ Space đọc để biết sdk: docker và app_port: 7860 — giữ nguyên, đừng xóa.
3. Settings → Variables and secrets
Free tier (2 vCPU / 16GB RAM) đủ chạy: PhoBERT fp32 + torch CPU ≈ 2GB RAM. Space ngủ sau 48h không ai truy cập; lần đánh thức đầu phải tải lại 515MB nên khởi động chậm.
Cấu trúc
app.py giao diện Gradio + event
features.py class PairTfidfFeatures (pickle của LR cần)
nli_demo/config.py đường dẫn, biến môi trường
nli_demo/text.py chuẩn hóa NFC, sinh biến thể đối chứng
nli_demo/segment.py VnCoreNLP (tự tìm JRE portable, tự tải wseg)
nli_demo/tfidf_model.py load + giải thích tuyến tính chính xác
nli_demo/phobert_model.py load + predict
nli_demo/neighbors.py mẫu train gần nhất
nli_demo/viz.py HTML tô màu + biểu đồ plotly
scripts/precompute.py sinh data/*.parquet