Spaces:
Paused
Paused
File size: 10,847 Bytes
1e8f431 5551585 375083c 5551585 375083c 5551585 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | ---
title: Medical VQA
emoji: 🩺
colorFrom: blue
colorTo: green
sdk: docker
app_port: 7860
pinned: false
license: mit
---
<p align="center">
<img src="https://img.shields.io/badge/Maintained%3F-yes-green.svg" alt="Maintained">
<img src="https://img.shields.io/badge/Python-3.9%2B-blue.svg" alt="Python">
<img src="https://img.shields.io/badge/Framework-PyTorch-red.svg" alt="PyTorch">
<img src="https://img.shields.io/badge/SOTA-Medical--VQA-orange.svg" alt="SOTA">
</p>
## 👥 Nhóm thực hiện
* **Võ Xuân Quang** (MSSV: 523H0173)
* **Hoàng Xuân Thành** (MSSV: 523H0178)
Hệ thống **Visual Question Answering (VQA) Y tế** sử dụng tiếng Việt, xây dựng trên tập dữ liệu **SLAKE + VQA-RAD** đã được dịch sang tiếng Việt bằng kỹ thuật **Dictionary-Enhanced Prompting** (SOTA En→Vi, arXiv 2509.15640).
## 🏗️ Kiến trúc
| Cấu hình | Image Encoder | Text Encoder | Answer Decoder | Ghi chú |
|---|---|---|---|---|
| **A1** | **DenseNet-121 (XRV)** | PhoBERT | LSTM + Bahdanau | So sánh Decoder (1) |
| **A2** | **DenseNet-121 (XRV)** | PhoBERT | **Transformer Decoder** | So sánh Decoder (2) |
| **B1** | **LLaVA-Med-7B** | — | — | Zero-shot (Multimodal Pretrained) |
| **B2** | **LLaVA-Med-7B** | — | — | Fine-tuned (QLoRA 4-bit) + DPO |
> [!NOTE]
> **Sự khác biệt về chiến lược giải mã:**
> - **Hướng A (Closed-Vocab):** Sử dụng bộ từ vựng cố định được xây dựng từ tập huấn luyện. Phù hợp cho các câu trả lời ngắn, chuẩn hóa nhưng giới hạn khả năng sinh từ mới cho các câu hỏi mở (Open-ended).
> - **Hướng B (Open-Vocabulary):** Sử dụng cơ chế Generative (LLM-based), cho phép sinh các câu trả lời linh hoạt, mô tả chi tiết và có khả năng suy luận vượt ra ngoài các cụm từ có sẵn trong tập train.
**Cải tiến SOTA tích hợp:**
1. **Medical Backbone:** Sử dụng `torchxrayvision` (DenseNet-121) pretrained trên 200K+ ảnh X-ray.
2. **Custom Dual-Head:** Tối ưu hóa bằng cách tách nhánh Classifier (Yes/No) và Generator (LSTM/Transformer).
3. **Image Enhancement:** Thuật toán CLAHE tăng cường độ tương phản y tế.
4. **RLHF/DPO:** Huấn luyện bổ sung với 200 cặp dữ liệu preference.
5. **Đánh giá đa tầng:** Kết hợp tự động + LLM-as-a-judge + **Human Evaluation (Bắt buộc)**.
---
## 📁 Cấu trúc báo cáo & Sản phẩm
- **Báo cáo (15-20 trang):** Gồm các chương độc lập về Dữ liệu, Kiến trúc, Phương pháp đánh giá và Thực nghiệm.
- **GitHub:** Mã nguồn sạch, kèm README hướng dẫn.
- **HuggingFace:** Dataset sạch (`judge_results.json`) và Model Checkpoints.
- **Demo:** Giao diện Web tương tác bằng Gradio/Streamlit.
---
## 📁 Cấu trúc thư mục (Final)
```text
DL_MedicalVQA_Project/
├── configs/
│ └── medical_vqa.yaml # Toàn bộ cấu hình (dataset, model, training, eval)
├── data/ # Dữ liệu (KHÔNG commit lên git)
│ ├── merged_vqa_vi.json # Output sau dịch thuật (Train/Val/Test ID)
│ ├── test_in_domain.json # Test Set 1 (In-Distribution): Trích từ SLAKE + VQA-RAD
│ ├── test_ood_vqamed.json # Test Set 2 (Out-of-Distribution): Trích từ VQA-MED
│ └── preference_data_slake.json # DPO preference data
├── checkpoints/ # Model weights (KHÔNG commit)
├── logs/ # Training logs
├── scripts/
│ ├── data_pipeline.py # Sinh dữ liệu, Paraphrase, Test Set 1 (ID)
│ ├── prepare_ood_test.py # Tạo Test Set 2 (OOD) từ tập VQA-MED
│ └── llm_judge_eval.py # Chấm điểm Semantic QA bằng Qwen-Plus API
├── src/
│ ├── config.py # Dataclass config loader
│ ├── data/
│ │ ├── medical_dataset.py # PyTorch Dataset cho SLAKE+VQA-RAD
│ │ └── translate_med_vqa.py # Pipeline dịch thuật 6 bước
│ ├── engine/
│ │ ├── trainer.py # Training loop (A1/A2)
│ │ ├── medical_eval.py # VQA Acc, BLEU, ROUGE, BERTScore, LLM-judge
│ │ └── dpo_trainer.py # DPO training + preference data generator
│ ├── models/
│ │ ├── encoder.py # CNNEncoder (DenseNet)
│ │ ├── phobert_encoder.py # ViHealthBERT Text Encoder
│ │ ├── attention.py # BahdanauAttention + SpatialAttention
│ │ ├── medical_vqa_model.py # MedicalVQAModelA + CoAttentionFusion
│ │ ├── transformer_decoder.py # Transformer Decoder + Beam Search
│ │ └── multimodal_vqa.py # Hướng B: LLaVA-Med wrapper
│ └── utils/
│ ├── metrics.py # BLEU, ROUGE, METEOR, BERTScore
│ ├── helpers.py # Tiện ích chung
│ └── visualization.py # GradCAM, Radar chart, Confusion Matrix
├── app.py # File chạy giao diện Demo Web
└── train_medical.py # Entry point: train A1/A2/B1/B2/all
```
---
## 🎯 Chiến lược Đánh giá Chéo (Cross-Dataset Evaluation)
Để chứng minh khả năng tổng quát hóa của mô hình và bám sát yêu cầu "Tập test chuẩn bị thủ công", hệ thống sử dụng 2 tập Test riêng biệt:
1. **Test Set 1 (In-Distribution):** Trích xuất ~60 ảnh (Image-disjoint) từ SLAKE + VQA-RAD để đảm bảo bảo toàn điểm số an toàn (Baseline).
2. **Test Set 2 (Out-of-Distribution):** Trích xuất ~50 ảnh thủ công từ **VQA-MED** (chỉ lấy X-Quang, MRI, CT). Dùng để kiểm tra khả năng chống chịu sự dịch chuyển miền dữ liệu (Domain Shift), được đánh giá tự động bằng **LLM-as-a-judge (Qwen-Plus API)**.
## 📏 Phương pháp đánh giá
Trong Medical VQA, đặc biệt với **Hướng B (LLaVA-Med)**, mô hình thường sinh ra câu trả lời tự do dưới dạng câu mô tả đầy đủ thay vì chỉ một nhãn ngắn như `có` hoặc `không`. Nếu dùng trực tiếp các câu mô tả này để tính exact-match hoặc accuracy, nhiều trường hợp đúng về mặt ngữ nghĩa vẫn sẽ bị tính là sai do không trùng bề mặt với ground truth ngắn.
Vì vậy, hệ thống đánh giá được tách thành hai lớp:
- **Raw prediction:** câu trả lời gốc sau giải mã và hậu xử lý tối thiểu. Bản này được dùng cho các chỉ số ngữ nghĩa như **BERTScore** và **Semantic Score**, vì các chỉ số này cần giữ nguyên nội dung diễn đạt của mô hình.
- **Normalized prediction:** phiên bản chuẩn hóa của dự đoán, trong đó các câu trả lời mô tả cho câu hỏi đóng sẽ được ánh xạ về nhãn chuẩn như `có/không`. Bản này được dùng cho các chỉ số yêu cầu so khớp trực tiếp như **Accuracy, Exact Match, F1, BLEU**.
Ví dụ, với câu hỏi `Hình ảnh này có bình thường không?`, mô hình có thể sinh ra câu tiếng Anh như `The image appears to be normal, with no significant abnormalities detected`. Sau khi dịch và chuẩn hóa:
- **Raw prediction (Vi):** giữ câu mô tả đầy đủ để phục vụ semantic metrics.
- **Normalized prediction (Vi):** được ánh xạ về `có` để chấm Accuracy theo schema nhãn của dataset.
Thiết kế này giúp kết quả công bằng hơn ở cả hai góc nhìn: khả năng tuân thủ định dạng đáp án của bài toán và khả năng diễn đạt đúng ý nghĩa y khoa của mô hình.
---
## 🚀 Hướng dẫn chạy
### Yêu cầu Phần cứng
* **Hướng A:** Khả thi trên GPU phổ thông (T4 16GB VRAM, RTX 3060/4060) hoặc CPU (thời gian huấn luyện dài hơn).
* **Hướng B & DPO:** Yêu cầu GPU tối thiểu 16GB VRAM (Khuyến nghị sử dụng Kaggle P100/T4x2 hoặc Google Colab Pro) để chạy mô hình đa phương thức cùng kỹ thuật lượng tử hóa QLoRA 4-bit.
### 1. Cài đặt môi trường
```bash
pip install -r requirements.txt
```
### 2. Dịch thuật dataset (SLAKE + VQA-RAD → Tiếng Việt)
```bash
# Dịch VQA-RAD
python src/data/translate_med_vqa.py \
--api_key "YOUR_GEMINI_API_KEY" \
--dataset vqa-rad \
--output data/translated_vqa_rad.json
# Dịch SLAKE
python src/data/translate_med_vqa.py \
--api_key "YOUR_GEMINI_API_KEY" \
--dataset slake \
--output data/translated_slake.json
# Merge 2 file lại thành merged_vqa_vi.json (thủ công hoặc dùng script)
```
### 3. Tạo tập test thủ công (bắt buộc theo đề bài)
```bash
python scripts/create_manual_test.py \
--input data/merged_vqa_vi.json \
--output data/manual_test_set.json \
--n_images 60
```
### 4. Huấn luyện 4 cấu hình bắt buộc
```bash
# Hướng A — Kiến trúc rời rạc
python train_medical.py --config configs/medical_vqa.yaml --variant A1
python train_medical.py --config configs/medical_vqa.yaml --variant A2
# Hướng B — Multimodal Pretrained
python train_medical.py --config configs/medical_vqa.yaml --variant B1 # Zero-shot
python train_medical.py --config configs/medical_vqa.yaml --variant B2 # LoRA fine-tune
```
### 5. Tạo DPO Preference Data & huấn luyện DPO
```bash
# Tạo preference data từ SLAKE format
python src/engine/dpo_trainer.py \
--input data/merged_vqa_vi.json \
--output data/preference_data_slake.json \
--num_pairs 200
# DPO training (chạy sau B2)
python train_medical.py --config configs/medical_vqa.yaml --variant DPO
```
### 6. Khởi động Web Demo
```bash
python app.py
```
---
## 📊 Kết quả kỳ vọng
| Model | VQA-RAD Closed | VQA-RAD Open | SLAKE Acc |
|---|---|---|---|
| A1 (LSTM) | ~65–68% | ~50–53% | ~74–76% |
| A2 (Transformer + Beam Search) | ~68–72% | ~53–57% | ~76–79% |
| B1 (LLaVA-Med-7B Zero-shot) | ~62–68% | ~40–48% | ~70–75% |
| B2 (LLaVA-Med-7B + LoRA) | ~82–88% | ~62–70% | ~85–92% |
---
## 📚 Tài liệu tham khảo
- SLAKE Dataset: [PolyU, ACL 2021](https://arxiv.org/abs/2102.09542)
- VQA-RAD: [Lau et al., Nature Scientific Data 2018](https://www.nature.com/articles/sdata2018189)
- Dictionary-Enhanced Prompting: arXiv 2509.15640
- Co-Attention Fusion: [Kim et al., NeurIPS 2018](https://arxiv.org/abs/1805.07932)
- DPO: [Rafailov et al., NeurIPS 2023](https://arxiv.org/abs/2305.18290)
- PhoBERT: [Nguyen & Nguyen, EMNLP 2020](https://arxiv.org/abs/2003.00744)
```
|