telen / inference.py
haidang2405's picture
first commit
e7cfc32 verified
Raw
History Blame Contribute Delete
3.35 kB
"""
TELEN Inference — encode legal texts to 768-dim embeddings.
Usage:
from inference import TELENInference
model = TELENInference()
embeddings = model.encode(["Điều 1: Thông tư này quy định về..."])
similarity = model.similarity(text1, text2)
"""
import sys; sys.path.insert(0, ".")
import torch
import torch.nn.functional as F
from pyvi import ViTokenizer
from src.telern.config import TELENConfig
from src.telern.model import create_model
class TELENInference:
def __init__(self, checkpoint_path: str = None):
self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
self.config = TELENConfig()
self.model = create_model(self.config).to(self.device)
if checkpoint_path is None:
checkpoint_path = self.config.output_dir + "/telen_best.pt"
ckpt = torch.load(checkpoint_path, map_location=self.device, weights_only=False)
self.model.hypernetwork.load_state_dict(ckpt["hypernetwork"])
self.model.state_encoder.load_state_dict(ckpt["state_encoder"])
self.model.base_projection.load_state_dict(ckpt["base_projection"])
self.model.attn_query.data.copy_(ckpt["attn_query"])
self.model.eval()
print(f"TELEN loaded on {self.device}")
print(f" HyperNetwork: {sum(p.numel() for p in self.model.hypernetwork.parameters()):,} params")
print(f" Ready for inference.")
def build_graph(self, df):
"""Build concept graph from a DataFrame with [id, title, text, law_id, law_type, year] columns."""
self.model.build_graph(df)
def encode(self, texts: list, batch_size: int = 64) -> torch.Tensor:
"""Encode a list of legal texts to 768-dim normalized embeddings."""
embeddings = []
for i in range(0, len(texts), batch_size):
batch = texts[i:i + batch_size]
with torch.no_grad():
result = self.model(batch, use_stochastic=False)
embeddings.append(result["embeddings"].cpu())
return torch.cat(embeddings, dim=0)
def similarity(self, text1: str, text2: str) -> float:
"""Compute cosine similarity between two texts."""
emb = self.encode([text1, text2])
return F.cosine_similarity(emb[0:1], emb[1:2]).item()
def retrieve(self, query: str, corpus: list, top_k: int = 10) -> list:
"""Retrieve top-k most similar documents from a corpus."""
query_emb = self.encode([query])
corpus_embs = self.encode(corpus)
sim = F.cosine_similarity(query_emb, corpus_embs).numpy()
top_indices = sim.argsort()[::-1][:top_k]
return [(int(i), float(sim[i])) for i in top_indices]
# ── Demo ──
if __name__ == "__main__":
model = TELENInference()
# Example queries
q1 = "Điều 1: Thông tư này quy định về quản lý thuế giá trị gia tăng đối với hàng hóa nhập khẩu"
q2 = "Điều 2: Đối tượng áp dụng là các tổ chức, cá nhân kinh doanh hàng hóa nhập khẩu"
q3 = "Điều 1: Nghị định này quy định về xử phạt vi phạm hành chính trong lĩnh vực giao thông"
print(f"\nSimilarity test:")
print(f" q1 vs q2 (same law): {model.similarity(q1, q2):.4f}")
print(f" q1 vs q3 (diff law): {model.similarity(q1, q3):.4f}")