Đối với dữ liệu video, ngoài thông tin hình ảnh (frame, shot, OCR,... ) thì nội dung lời nói trong video là một dữ liệu quan trọng để phục vụ tìm kiếm. Trong bài viết này, mình sẽ giới thiệu về pipeline ASR mình đã áp dụng cho hệ thống Video Retrieval trong khuôn khổ cuộc thi AIC - HCMC2026
I. Pipeline tổng quan
Mình sử dụng một mô hình pre-trained ASR để thực hiện trích xuất nội dung lời nói trong video. Sau đó tiến hành kiểm tra lại, mặc dù mô hình đã cho hiệu suất rất tốt. Tuy nhiên đối với các dạng video phóng sự, quay trực tiếp,... thì khả năng âm thanh bị nhiễu là rất lớn. Vì vậy, mình tiến hành đưa qua thêm 1 lớp chuẩn hoá văn bản cuối cùng. Pipeline tổng quan được thể hiện trong sơ đồ dưới đây

II. PhoWhisper hay Whisper ?
PhoWhisper là model được fine-tune cho tiếng Việt. Được huấn luyện bởi dữ liệu video tiếng Việt lên tới hơn 800 giờ, với nhiều giọng vùng miền khác nhau. Vì vậy nó đặc biệt phù hợp cho ngôn ngữ Việt Nam. Đối với Whisper, đây là multilingual model - hỗ trợ đa ngôn ngữ, timestamp ổn định - đây là một ưu điểm rõ ràng so với PhoWhisper nếu chạy theo batch.
Để khởi tạo mô hình PhoWhisper, bạn có thể chạy đoạn code sau:
from transformers import AutoModelForSpeechSeq2Seq, AutoProcessor
def load_phowhisper(model_name: str = "vinai/PhoWhisper-large"):
"""Khởi tạo mô hình và processor PhoWhisper."""
device = "cuda:0" if torch.cuda.is_available() else "cpu"
dtype = torch.float16 if device.startswith("cuda") else torch.float32
print(f"Đang nạp mô hình {model_name} trên thiết bị: {device}...")
processor = AutoProcessor.from_pretrained(model_name)
model = AutoModelForSpeechSeq2Seq.from_pretrained(model_name, torch_dtype=dtype).to(device)
model.eval()
# Thiết lập cấu hình generate để lấy scores logprob
generation_config = model.generation_config
generation_config.return_dict_in_generate = True
generation_config.output_scores = True
return processor, model, device
# processor, model, device = load_phowhisper()III. Segment-level average logprob
Thay vì trích xuất 1 và đánh giá avg_logprob trên toàn bộ video, hệ thống mình đã thực hiện ở mức segment. Mỗi segment ASR có thể trả về các thông tin: start_ms, end_ms, text, avg_logprob. Đối với model mặc định từ openai-whisper, giá trị avg_logprob được trả về, còn model Phowhisper từ HuggingFace sẽ không trả về để tiết kiệm tại nguyên tính toán. Vì vậy, nếu dùng PhoWhisper, bạn có thể tham khảo đoạn code sau đây để tính avg_logprop
def average_logprob_from_segment(model: Any, generated_segment: dict[str, Any]) -> float | None:
"""Tính xác suất trung bình (avg_logprob) của các token sinh ra bởi Whisper."""
result = generated_segment.get("result", {})
scores = result.get("scores") if isinstance(result, dict) else None
tokens = generated_segment.get("tokens")
if not scores or not tokens:
return None
return float(model._retrieve_avg_logprobs(scores, tokens, temperature=0.0))
Trong đó model là mô hình PhoWhisper được sử dụng, generated_segment là một dict chứa thông tin segment lấy ra từ bước generate
IV. LLM chuẩn hoá text
Ngưỡng avg_logprob và mô hình mình sử dụng
Sau khi qua bước đầu tiên, đã có các thông tin về transcript và avg_logprob. Mình sẽ xét đối với ngưỡng avg_logprob = -1.0. Bản chất của logprob chính là hàm logarithm tự nhiên của xác suất dự đoán từ p, vì vậy khi xét logprob = -1.0 thì xác suất p ở ngưỡng 36.8%, đây là ngưỡng hợp lí để tránh tiêu tốn quá nhiều chi phí API và cũng là tiêu chuẩn mà OpenAI công bố. Vì vậy, khi nào cần chất lượng dự đoán cao hơn, bạn có thể giảm ngưỡng logprob này xuống.
Mô hình mình sử dụng trong bước này là DeepSeek-V4-Flash. Mình không nhớ chi tiết chi phí input-output-reasoning, nhưng mình thấy đây là một mô hình giá rẻ, hiệu năng ổn định, thậm chí rất tốt cho tác vụ này
Tại sao không sử dụng LLM để lấy transcript ngay?
Hiện nay đã có rất nhiều mô hình ASR vượt trội có thể truy cập thông qua API Key. Tuy nhiên mình vẫn chọn tiếp cận thông qua cách làm này bởi vì các mô hình như PhoWhisper đã làm rất tốt với bài toán tiếng Việt rồi, sử dụng LLM như một lớp dự phòng sẽ làm giảm chi phí đáng kể; Hơn là đẩy hàng trăm giờ video trực tiếp vào trong LLM để nhận ra text. Tuy nhiên cách làm này cũng có bất lợi là phải tốn chi phí thuê GPU. Nếu các bạn đang cần tìm chỗ thuê GPU rẻ hoặc cung cấp miễn phí thì có thể xem bài viết này: Các nền tảng cung cấp GPU cho người mới . Để tối ưu về phần chi phí này, mình đã tìm hiểu thêm về cách thiết lập n-worker, ép nhiều nhân CPU làm việc song song, từ đó tăng tốc độ và giảm chi phí đáng kể
Kết luận
Trên đây là pipeline ASR mà mình và cả nhóm đã cùng nhau thiết lập để phục vụ cho bài toán Video Retrieval trong hội thi AI Challenge của Thành Phố Hồ Chí Minh. Mong là nó sẽ hữu ích cho những bạn lần đầu tiếp cận. Và cũng mong nhận được góp ý để có thể cải thiện hơn trong tương lai. Xin cảm ơn

Thảo luận bài viết
Câu hỏi, ghi chú và góc nhìn của bạn về nội dung này.