hoailebads/Qwen3-Embedding-0.6B-VLSP-Legal-Retrieval-LoRA
Qwen3-Embedding-0.6B — VLSP Legal Retrieval (Dual-LoRA)
Bi-encoder truy hồi điều luật tiếng Việt cho bài toán VLSP Legal Text Retrieval. Kiến trúc dual-LoRA: hai adapter LoRA riêng biệt dùng chung một base model đóng băng — query_adapter mã hoá câu hỏi, passage_adapter mã hoá điều luật.
Đây là checkpoint retrieval tốt nhất trong 22 lần train được đo trên cùng tập eval (train_synthetic_hoi_dap), dùng để sinh top-100 candidate cho pha rerank trong hoaileba/Qwen-Retrieval-Tuning.
Kết quả
Tập eval: 219 câu hỏi unique (VLSP eval.json, ground truth dedup theo aid). Corpus: 67,561 chunk / 59,628 điều luật. FAISS inner-product, dedup theo aid.
R@100 = 94.98 là trần recall cho pha rerank phía sau — ~5% câu hỏi không có đáp án đúng trong 100 candidate, và đó là giới hạn thật của pipeline chứ không phải của reranker.
So với các checkpoint khác (cùng tập eval 219 câu)
Hai điều đọc được từ bảng: dual-adapter hơn single-adapter (+4.8 R@1 so với train_single_vlsp_only), và augment câu hỏi dạng hỏi–đáp (hoi_dap) là biến thể synthetic cho lợi ích lớn nhất — cộng thêm +1.6 R@1 lên trên checkpoint cha train_synthetic_only_hn.
Số đo đầy đủ: `eval_results.json`.
Cách dùng
Model gồm hai adapter nên không load thẳng bằng AutoModel được — phải nạp cả hai và chuyển adapter theo loại text. File `modeling_dual_lora.py` trong repo này làm sẵn việc đó:
from modeling_dual_lora import DualLoRAEncoder
import numpy as np
enc = DualLoRAEncoder.from_pretrained("hoailebads/Qwen3-Embedding-0.6B-VLSP-Legal-Retrieval-LoRA")
questions = ["Người điều khiển xe máy không đội mũ bảo hiểm bị phạt bao nhiêu tiền?"]
articles = ["Điều 6. Xử phạt người điều khiển xe mô tô, xe gắn máy ... "]
q = enc.encode(questions, is_query=True) # (1, 1024), đã L2-normalize
d = enc.encode(articles, is_query=False) # (N, 1024)
scores = q @ d.T # inner product == cosine
top = np.argsort(-scores[0])[:10]Hoặc tự nạp bằng PEFT:
from transformers import AutoModel, AutoTokenizer
from peft import PeftModel
import torch
base = AutoModel.from_pretrained("Qwen/Qwen3-Embedding-0.6B",
torch_dtype=torch.bfloat16, trust_remote_code=True)
model = PeftModel.from_pretrained(base, "<repo>/query_adapter", adapter_name="query_adapter")
model.load_adapter("<repo>/passage_adapter", adapter_name="passage_adapter")
model.set_adapter("query_adapter") # trước khi encode câu hỏi
model.set_adapter("passage_adapter") # trước khi encode điều luậtQuy ước bắt buộc (phải khớp lúc train)
- Không có instruction prefix. Encode raw text — thêm
"Instruct: ..."sẽ lệch phân bố. - Pooling = hidden state của token thật cuối cùng, sau đó L2-normalize.
max_length = 1024, truncation bên phải (mặc định của tokenizer).- Passage text =
article_title + "\n" + content. - Encode query bằng `passage_adapter` (hoặc ngược lại) làm hỏng kết quả — đây là lỗi dễ mắc nhất khi dùng model này.
Huấn luyện
Model là kết quả của một chuỗi train nối tiếp, không phải một lần train từ base: mỗi pha mine lại hard negative bằng checkpoint ngay trước đó rồi train tiếp trên một biến thể synthetic mới. train_synthetic_hoi_dap là pha cuối của nhánh thắng.
Vị trí trong pipeline
câu hỏi → [RETRIEVAL: model này] → top-100 → [RERANK: Qwen3-Reranker-8B] → dynamic top-k → đáp ánModel liên quan:
- `hoailebads/Qwen3-Reranker-8B-VLSP-Legal-LoRA` — reranker chính
- `hoailebads/Qwen3-Reranker-0.6B-VLSP-Legal-LoRA` — reranker bản nhẹ
- `hoailebads/Qwen3-Embedding-0.6B-Zalo-Legal-Retrieval-LoRA` — bản retrieval cho corpus Zalo
Code + số đo đầy đủ: hoaileba/Qwen-Retrieval-Tuning
Giới hạn
- Chỉ đo trên văn bản pháp luật tiếng Việt; chưa đo trên domain khác hay ngôn ngữ khác.
- Tập eval 219 câu là nhỏ — chênh lệch <1 điểm R@1 giữa các checkpoint nằm trong nhiễu.
- Corpus VLSP có ~1.35 điều luật đúng/câu hỏi; metric ở đây là retrieval thuần, chưa phải F2MACRO của giải (cần thêm rerank + chọn top-k động).
License
Apache-2.0, theo base model Qwen/Qwen3-Embedding-0.6B.
