Spaces:
Sleeping
Sleeping
Commit ·
039c272
1
Parent(s): 9dc4847
Add workflow scripts, fix ignore mappings, and push tracking updates for dvc
Browse files- .agents/my-skill/SKILL.md +47 -0
- .agents/workflows/git-push.md +44 -0
- .gitignore +2 -0
- data/bronze.dvc +2 -2
- dvc.lock +8 -8
- dvc.yaml +1 -1
- setup.sh +49 -0
- src/model.py +46 -3
- src/preprocess_data.py +37 -27
- src/train.py +4 -4
- src/trl_rlhf_train.py +100 -0
.agents/my-skill/SKILL.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
name: Project Setup and Advanced Training (Quantization & RLHF)
|
| 3 |
+
description: Outlines the workflow to bootstrap the VQA project using uv and retrain models with Quantization and RLHF (TRL).
|
| 4 |
+
---
|
| 5 |
+
|
| 6 |
+
# VQA Project Workflow Skill
|
| 7 |
+
|
| 8 |
+
This skill defines the methodology for environment bootstrapping and model training with Quantization and RLHF within the NeuroVision VQA app.
|
| 9 |
+
|
| 10 |
+
## Prerequisites
|
| 11 |
+
- A GPU capable of 4-bit quantification (Nvidia).
|
| 12 |
+
- `uv` package manager installed.
|
| 13 |
+
|
| 14 |
+
## 1. Environment Setup
|
| 15 |
+
|
| 16 |
+
*Bootstrap the project instantly*
|
| 17 |
+
// turbo
|
| 18 |
+
1. Run `./setup.sh` (or `bash setup.sh`) from the root directory.
|
| 19 |
+
- This creates a `uv` virtual environment in `.venv`.
|
| 20 |
+
- Populates necessary PIP packages including `bitsandbytes`, `peft`, and `trl`.
|
| 21 |
+
- Downloads the Hugging Face `vqa-rad` dataset into `data/bronze/`.
|
| 22 |
+
|
| 23 |
+
## 2. Preprocessing Data
|
| 24 |
+
|
| 25 |
+
1. Activate your virtual environment: `source .venv/Scripts/activate`
|
| 26 |
+
2. Run data conversion:
|
| 27 |
+
```bash
|
| 28 |
+
dvc repro preprocess
|
| 29 |
+
```
|
| 30 |
+
Or run the script manually: `python src/preprocess_data.py`
|
| 31 |
+
|
| 32 |
+
## 3. Training the Model (QLoRA + RLHF)
|
| 33 |
+
|
| 34 |
+
1. Adjust `config.yaml` to point to the base model.
|
| 35 |
+
2. The `src/model.py` module defines the `BitsAndBytesConfig` allowing 4-bit quantized loading alongside PEFT/LoRA adapter setup.
|
| 36 |
+
3. Training via `src/train.py` utilizes the TRL framework (e.g., `SFTTrainer` or `DPOTrainer`) configured for supervised learning over a quantified multimodal LLM.
|
| 37 |
+
4. Execute training:
|
| 38 |
+
```bash
|
| 39 |
+
dvc repro train
|
| 40 |
+
```
|
| 41 |
+
Or manually: `python src/train.py`
|
| 42 |
+
|
| 43 |
+
## 4. Evaluation and App Serving
|
| 44 |
+
|
| 45 |
+
1. Generate answers & track metrics via BLEU score using `dvc repro evaluate`.
|
| 46 |
+
2. Start the API by running `python Deployment/app.py`.
|
| 47 |
+
3. Launch the Streamlit chat frontend.
|
.agents/workflows/git-push.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
description: How to commit and push code on this Windows PowerShell environment
|
| 3 |
+
---
|
| 4 |
+
|
| 5 |
+
## Critical CLI Rules for PowerShell
|
| 6 |
+
|
| 7 |
+
1. **NEVER use `&&` to chain commands in PowerShell.** Use `;` (semicolons) instead.
|
| 8 |
+
- ❌ `git add . && git commit -m "msg" && git push`
|
| 9 |
+
- ✅ `git add .; git commit -m "msg"; git push`
|
| 10 |
+
|
| 11 |
+
2. **NEVER use `grep` in PowerShell.** Use `Select-String` (alias `sls`) instead.
|
| 12 |
+
- ❌ `pip freeze | grep langchain`
|
| 13 |
+
- ✅ `pip freeze | sls langchain`
|
| 14 |
+
|
| 15 |
+
3. **When calling python with `-c` and the path has spaces, use `&` (call operator).**
|
| 16 |
+
- ❌ `"C:\path with spaces\python.exe" -c "print('hi')"`
|
| 17 |
+
- ✅ `& "C:\path with spaces\python.exe" -c "print('hi')"`
|
| 18 |
+
|
| 19 |
+
## Git Push Workflow
|
| 20 |
+
|
| 21 |
+
This project uses a **personal GitHub account** that is different from the system's default (office) Git credentials.
|
| 22 |
+
|
| 23 |
+
// turbo-all
|
| 24 |
+
|
| 25 |
+
1. Stage changes:
|
| 26 |
+
```powershell
|
| 27 |
+
git add .
|
| 28 |
+
```
|
| 29 |
+
|
| 30 |
+
2. Commit:
|
| 31 |
+
```powershell
|
| 32 |
+
git commit -m "your message"
|
| 33 |
+
```
|
| 34 |
+
|
| 35 |
+
3. Push using a personal access token (PAT) embedded in the remote URL:
|
| 36 |
+
```powershell
|
| 37 |
+
git push
|
| 38 |
+
```
|
| 39 |
+
|
| 40 |
+
> **NOTE:** If push fails with a 403 Permission error, the user likely needs to update the remote URL with their personal PAT:
|
| 41 |
+
> ```powershell
|
| 42 |
+
> git remote set-url origin https://<PERSONAL_PAT>@github.com/Aryan-coder-student/NeuroVision-BHPC-VQA.git
|
| 43 |
+
> ```
|
| 44 |
+
> The user must supply their own PAT. Generate one at: https://github.com/settings/tokens
|
.gitignore
CHANGED
|
@@ -4,3 +4,5 @@ Deployment/.env
|
|
| 4 |
.venv/
|
| 5 |
__pycache__/
|
| 6 |
*.pyc
|
|
|
|
|
|
|
|
|
| 4 |
.venv/
|
| 5 |
__pycache__/
|
| 6 |
*.pyc
|
| 7 |
+
.hf_cache/
|
| 8 |
+
mlruns/
|
data/bronze.dvc
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
outs:
|
| 2 |
-
- md5:
|
| 3 |
-
size:
|
| 4 |
nfiles: 7
|
| 5 |
hash: md5
|
| 6 |
path: bronze
|
|
|
|
| 1 |
outs:
|
| 2 |
+
- md5: 44a2a26c7a5ccc1bd695123e0eefbb27.dir
|
| 3 |
+
size: 119084280
|
| 4 |
nfiles: 7
|
| 5 |
hash: md5
|
| 6 |
path: bronze
|
dvc.lock
CHANGED
|
@@ -3,18 +3,18 @@ stages:
|
|
| 3 |
preprocess:
|
| 4 |
cmd: python src/preprocess_data.py
|
| 5 |
deps:
|
| 6 |
-
- path: data/bronze
|
| 7 |
hash: md5
|
| 8 |
-
md5:
|
| 9 |
-
size:
|
| 10 |
-
nfiles:
|
| 11 |
- path: src/preprocess_data.py
|
| 12 |
hash: md5
|
| 13 |
-
md5:
|
| 14 |
-
size:
|
| 15 |
outs:
|
| 16 |
- path: data/silver
|
| 17 |
hash: md5
|
| 18 |
-
md5:
|
| 19 |
-
size:
|
| 20 |
nfiles: 2
|
|
|
|
| 3 |
preprocess:
|
| 4 |
cmd: python src/preprocess_data.py
|
| 5 |
deps:
|
| 6 |
+
- path: data/bronze
|
| 7 |
hash: md5
|
| 8 |
+
md5: 44a2a26c7a5ccc1bd695123e0eefbb27.dir
|
| 9 |
+
size: 119084280
|
| 10 |
+
nfiles: 7
|
| 11 |
- path: src/preprocess_data.py
|
| 12 |
hash: md5
|
| 13 |
+
md5: e0f336cb3667d4bfa483d21732c6e428
|
| 14 |
+
size: 2555
|
| 15 |
outs:
|
| 16 |
- path: data/silver
|
| 17 |
hash: md5
|
| 18 |
+
md5: 0e6df84ffd9e467bc6a2666d54b348d2.dir
|
| 19 |
+
size: 1710728
|
| 20 |
nfiles: 2
|
dvc.yaml
CHANGED
|
@@ -3,7 +3,7 @@ stages:
|
|
| 3 |
cmd: python src/preprocess_data.py
|
| 4 |
deps:
|
| 5 |
- src/preprocess_data.py
|
| 6 |
-
- data/bronze
|
| 7 |
outs:
|
| 8 |
- data/silver
|
| 9 |
|
|
|
|
| 3 |
cmd: python src/preprocess_data.py
|
| 4 |
deps:
|
| 5 |
- src/preprocess_data.py
|
| 6 |
+
- data/bronze
|
| 7 |
outs:
|
| 8 |
- data/silver
|
| 9 |
|
setup.sh
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
# setup.sh - Environment Setup and Data Download for NeuroVision VQA
|
| 3 |
+
|
| 4 |
+
echo "🚀 Starting Project Setup..."
|
| 5 |
+
|
| 6 |
+
# 1. Ensure uv is installed
|
| 7 |
+
if ! command -v uv &> /dev/null
|
| 8 |
+
then
|
| 9 |
+
echo "📦 uv not found. Installing uv..."
|
| 10 |
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
| 11 |
+
export PATH="$HOME/.local/bin:$HOME/.cargo/bin:$PATH"
|
| 12 |
+
fi
|
| 13 |
+
|
| 14 |
+
# 2. Create virtual environment
|
| 15 |
+
echo "🌱 Creating virtual environment using uv..."
|
| 16 |
+
uv venv
|
| 17 |
+
|
| 18 |
+
# 3. Activate virtual environment
|
| 19 |
+
# Note: Cross-platform activation snippet
|
| 20 |
+
if [[ "$OSTYPE" == "msys"* || "$OSTYPE" == "cygwin"* || "$OSTYPE" == "win32"* ]]; then
|
| 21 |
+
source .venv/Scripts/activate
|
| 22 |
+
else
|
| 23 |
+
source .venv/bin/activate
|
| 24 |
+
fi
|
| 25 |
+
|
| 26 |
+
# 4. Install requirements
|
| 27 |
+
echo "📥 Installing dependencies from requirements.txt..."
|
| 28 |
+
uv pip install -r requirements.txt
|
| 29 |
+
|
| 30 |
+
# 5. Fetch HuggingFace Dataset
|
| 31 |
+
echo "📊 Downloading VQA-RAD Dataset from HuggingFace..."
|
| 32 |
+
mkdir -p data/bronze
|
| 33 |
+
|
| 34 |
+
python -c "
|
| 35 |
+
from datasets import load_dataset
|
| 36 |
+
import os
|
| 37 |
+
|
| 38 |
+
print('Downloading dataset flaviagiammarino/vqa-rad...')
|
| 39 |
+
try:
|
| 40 |
+
dataset = load_dataset('flaviagiammarino/vqa-rad')
|
| 41 |
+
dataset.save_to_disk('data/bronze/')
|
| 42 |
+
print('✅ Dataset successfully downloaded and saved to data/bronze/')
|
| 43 |
+
except Exception as e:
|
| 44 |
+
print(f'❌ Error downloading dataset: {e}')
|
| 45 |
+
"
|
| 46 |
+
|
| 47 |
+
echo "🎉 Setup Complete! You can now activate the environment using:"
|
| 48 |
+
echo " source .venv/Scripts/activate (Windows)"
|
| 49 |
+
echo " source .venv/bin/activate (Linux/Mac)"
|
src/model.py
CHANGED
|
@@ -1,13 +1,56 @@
|
|
|
|
|
|
|
|
| 1 |
import torch
|
| 2 |
-
from transformers import BlipProcessor, BlipForQuestionAnswering
|
|
|
|
| 3 |
import yaml
|
|
|
|
| 4 |
# Initialize the BLIP model and processor
|
| 5 |
config = yaml.safe_load(open("./config.yaml", "r"))
|
| 6 |
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
| 7 |
model_id = config["finetune_model"]["orignal_model_id"]
|
| 8 |
-
|
|
|
|
| 9 |
print("Loading Model and Processor................")
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
processor = BlipProcessor.from_pretrained(model_id)
|
| 12 |
print(f"Model and Processor loaded successfully {model_path} !!!")
|
| 13 |
return model, processor
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
os.environ['HF_HOME'] = os.path.abspath("./.hf_cache")
|
| 3 |
import torch
|
| 4 |
+
from transformers import BlipProcessor, BlipForQuestionAnswering, BitsAndBytesConfig
|
| 5 |
+
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
|
| 6 |
import yaml
|
| 7 |
+
|
| 8 |
# Initialize the BLIP model and processor
|
| 9 |
config = yaml.safe_load(open("./config.yaml", "r"))
|
| 10 |
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
| 11 |
model_id = config["finetune_model"]["orignal_model_id"]
|
| 12 |
+
|
| 13 |
+
def load_model_processor(model_path=model_id, use_quantization=True):
|
| 14 |
print("Loading Model and Processor................")
|
| 15 |
+
|
| 16 |
+
if use_quantization and torch.cuda.is_available() and device.type == "cuda":
|
| 17 |
+
# Configure BitsAndBytes for 4-bit Quantization
|
| 18 |
+
bnb_config = BitsAndBytesConfig(
|
| 19 |
+
load_in_4bit=True,
|
| 20 |
+
bnb_4bit_use_double_quant=True,
|
| 21 |
+
bnb_4bit_quant_type="nf4",
|
| 22 |
+
bnb_4bit_compute_dtype=torch.float16
|
| 23 |
+
)
|
| 24 |
+
|
| 25 |
+
# Load base model wrapped in 4-bit
|
| 26 |
+
model = BlipForQuestionAnswering.from_pretrained(
|
| 27 |
+
model_path,
|
| 28 |
+
quantization_config=bnb_config,
|
| 29 |
+
device_map="auto"
|
| 30 |
+
)
|
| 31 |
+
|
| 32 |
+
# Prepares model for k-bit training and gradient checkpointing
|
| 33 |
+
model = prepare_model_for_kbit_training(model)
|
| 34 |
+
|
| 35 |
+
# Setup LoRA (Parameter Efficient Fine Tuning)
|
| 36 |
+
# For Blip, common projection layers are query, value, key.
|
| 37 |
+
lora_config = LoraConfig(
|
| 38 |
+
r=16,
|
| 39 |
+
lora_alpha=32,
|
| 40 |
+
target_modules=["query", "value", "key"],
|
| 41 |
+
lora_dropout=0.05,
|
| 42 |
+
bias="none",
|
| 43 |
+
task_type="CAUSAL_LM" # BLIP uses a causal LM head for decoding
|
| 44 |
+
)
|
| 45 |
+
|
| 46 |
+
model = get_peft_model(model, lora_config)
|
| 47 |
+
model.print_trainable_parameters()
|
| 48 |
+
print("Model loaded with 4-bit quantization and LoRA adapters.")
|
| 49 |
+
else:
|
| 50 |
+
# Fallback to standard loading if no CUDA or quantization turned off
|
| 51 |
+
model = BlipForQuestionAnswering.from_pretrained(model_path).to(device)
|
| 52 |
+
print("Model loaded in full precision.")
|
| 53 |
+
|
| 54 |
processor = BlipProcessor.from_pretrained(model_id)
|
| 55 |
print(f"Model and Processor loaded successfully {model_path} !!!")
|
| 56 |
return model, processor
|
src/preprocess_data.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
| 1 |
import os
|
|
|
|
|
|
|
| 2 |
import torch
|
| 3 |
import pickle
|
| 4 |
import yaml
|
|
@@ -6,6 +8,8 @@ from datasets import load_dataset
|
|
| 6 |
from model import load_model_processor
|
| 7 |
|
| 8 |
config = yaml.safe_load(open("./config.yaml", "r"))["data_location"]
|
|
|
|
|
|
|
| 9 |
class VQADataset(torch.utils.data.Dataset):
|
| 10 |
def __init__(self, dataset, processor):
|
| 11 |
self.dataset = dataset
|
|
@@ -15,54 +19,60 @@ class VQADataset(torch.utils.data.Dataset):
|
|
| 15 |
return len(self.dataset)
|
| 16 |
|
| 17 |
def __getitem__(self, idx):
|
| 18 |
-
question = self.dataset[idx][
|
| 19 |
-
answer = self.dataset[idx][
|
| 20 |
-
image = self.dataset[idx][
|
| 21 |
image = image.convert("RGB")
|
| 22 |
text = question
|
| 23 |
|
| 24 |
-
encoding = self.processor(
|
|
|
|
|
|
|
| 25 |
labels = self.processor.tokenizer.encode(
|
| 26 |
-
answer,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
)
|
| 28 |
encoding["labels"] = labels
|
| 29 |
for k, v in encoding.items():
|
| 30 |
encoding[k] = v.squeeze()
|
| 31 |
return encoding
|
| 32 |
|
|
|
|
| 33 |
if __name__ == "__main__":
|
| 34 |
_, processor = load_model_processor()
|
| 35 |
|
| 36 |
-
|
|
|
|
| 37 |
print("Loading VQA dataset................")
|
| 38 |
-
|
|
|
|
| 39 |
train_data = data["train"]
|
| 40 |
test_data = data["test"]
|
| 41 |
|
| 42 |
-
print(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
save_dir = "./data/silver"
|
| 44 |
os.makedirs(save_dir, exist_ok=True)
|
| 45 |
print("Processesing data to save in ../data/silver")
|
| 46 |
-
train_dataset = VQADataset(dataset=train_data,
|
| 47 |
-
|
| 48 |
-
test_dataset = VQADataset(dataset=test_data,
|
| 49 |
-
processor=processor)
|
| 50 |
-
|
| 51 |
|
| 52 |
print(f"Data processed successfully !!! ")
|
| 53 |
-
print(
|
| 54 |
-
|
|
|
|
|
|
|
| 55 |
pickle.dump(train_dataset, f)
|
| 56 |
-
with open(os.path.join(save_dir,"test_dataset.pkl"), "wb") as f:
|
| 57 |
pickle.dump(test_dataset, f)
|
| 58 |
-
print(
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
|
|
|
| 1 |
import os
|
| 2 |
+
|
| 3 |
+
os.environ["HF_HOME"] = os.path.abspath("./.hf_cache")
|
| 4 |
import torch
|
| 5 |
import pickle
|
| 6 |
import yaml
|
|
|
|
| 8 |
from model import load_model_processor
|
| 9 |
|
| 10 |
config = yaml.safe_load(open("./config.yaml", "r"))["data_location"]
|
| 11 |
+
|
| 12 |
+
|
| 13 |
class VQADataset(torch.utils.data.Dataset):
|
| 14 |
def __init__(self, dataset, processor):
|
| 15 |
self.dataset = dataset
|
|
|
|
| 19 |
return len(self.dataset)
|
| 20 |
|
| 21 |
def __getitem__(self, idx):
|
| 22 |
+
question = self.dataset[idx]["question"]
|
| 23 |
+
answer = self.dataset[idx]["answer"]
|
| 24 |
+
image = self.dataset[idx]["image"]
|
| 25 |
image = image.convert("RGB")
|
| 26 |
text = question
|
| 27 |
|
| 28 |
+
encoding = self.processor(
|
| 29 |
+
image, text, padding="max_length", truncation=True, return_tensors="pt"
|
| 30 |
+
)
|
| 31 |
labels = self.processor.tokenizer.encode(
|
| 32 |
+
answer,
|
| 33 |
+
max_length=128,
|
| 34 |
+
padding="max_length",
|
| 35 |
+
truncation=True,
|
| 36 |
+
pad_to_max_length=True,
|
| 37 |
+
return_tensors="pt",
|
| 38 |
)
|
| 39 |
encoding["labels"] = labels
|
| 40 |
for k, v in encoding.items():
|
| 41 |
encoding[k] = v.squeeze()
|
| 42 |
return encoding
|
| 43 |
|
| 44 |
+
|
| 45 |
if __name__ == "__main__":
|
| 46 |
_, processor = load_model_processor()
|
| 47 |
|
| 48 |
+
from datasets import load_from_disk
|
| 49 |
+
|
| 50 |
print("Loading VQA dataset................")
|
| 51 |
+
# Load dataset that was pre-saved to disk natively
|
| 52 |
+
data = load_from_disk("./data/bronze")
|
| 53 |
train_data = data["train"]
|
| 54 |
test_data = data["test"]
|
| 55 |
|
| 56 |
+
print(
|
| 57 |
+
"VQA dataset loaded successfully!!! lenght of train data is ",
|
| 58 |
+
len(train_data),
|
| 59 |
+
" and test data is ",
|
| 60 |
+
len(test_data),
|
| 61 |
+
)
|
| 62 |
save_dir = "./data/silver"
|
| 63 |
os.makedirs(save_dir, exist_ok=True)
|
| 64 |
print("Processesing data to save in ../data/silver")
|
| 65 |
+
train_dataset = VQADataset(dataset=train_data, processor=processor)
|
| 66 |
+
test_dataset = VQADataset(dataset=test_data, processor=processor)
|
|
|
|
|
|
|
|
|
|
| 67 |
|
| 68 |
print(f"Data processed successfully !!! ")
|
| 69 |
+
print(
|
| 70 |
+
f"Saving to {os.path.join(save_dir, 'train_dataset.pkl')} and {os.path.join(save_dir, 'test_dataset.pkl')}"
|
| 71 |
+
)
|
| 72 |
+
with open(os.path.join(save_dir, "train_dataset.pkl"), "wb") as f:
|
| 73 |
pickle.dump(train_dataset, f)
|
| 74 |
+
with open(os.path.join(save_dir, "test_dataset.pkl"), "wb") as f:
|
| 75 |
pickle.dump(test_dataset, f)
|
| 76 |
+
print(
|
| 77 |
+
f"Processed data , saved to {config['train_processed_data']} and {config['test_processed_data']}"
|
| 78 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/train.py
CHANGED
|
@@ -46,7 +46,7 @@ mlflow.set_experiment("VQA_Model_Training")
|
|
| 46 |
min_bleu_score = 0
|
| 47 |
early_stopping_hook = 0
|
| 48 |
tracking_information = []
|
| 49 |
-
optimizer = torch.optim.AdamW(model.parameters(), lr=float(params["learning_rate"]), weight_decay=float(params["weight_decay"]))
|
| 50 |
total_steps = len(train_dataloader) * num_epochs
|
| 51 |
warmup_steps = total_steps // 10
|
| 52 |
scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps=warmup_steps, num_training_steps=total_steps)
|
|
@@ -123,6 +123,6 @@ with mlflow.start_run():
|
|
| 123 |
scheduler.step()
|
| 124 |
|
| 125 |
|
| 126 |
-
|
| 127 |
-
mlflow.
|
| 128 |
-
print("Model logged with MLflow.")
|
|
|
|
| 46 |
min_bleu_score = 0
|
| 47 |
early_stopping_hook = 0
|
| 48 |
tracking_information = []
|
| 49 |
+
optimizer = torch.optim.AdamW(filter(lambda p: p.requires_grad, model.parameters()), lr=float(params["learning_rate"]), weight_decay=float(params["weight_decay"]))
|
| 50 |
total_steps = len(train_dataloader) * num_epochs
|
| 51 |
warmup_steps = total_steps // 10
|
| 52 |
scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps=warmup_steps, num_training_steps=total_steps)
|
|
|
|
| 123 |
scheduler.step()
|
| 124 |
|
| 125 |
|
| 126 |
+
# Log the saved PEFT adapters as an artifact instead of trying to pickle the Quantized model
|
| 127 |
+
mlflow.log_artifacts(model_config["best"], artifact_path="VQA_model_best")
|
| 128 |
+
print("Model adapters logged with MLflow.")
|
src/trl_rlhf_train.py
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
os.environ['HF_HOME'] = os.path.abspath("./.hf_cache")
|
| 3 |
+
import torch
|
| 4 |
+
import yaml
|
| 5 |
+
from transformers import BlipProcessor, BlipForQuestionAnswering, BitsAndBytesConfig
|
| 6 |
+
from peft import LoraConfig, get_peft_model
|
| 7 |
+
from trl import DPOTrainer, DPOConfig
|
| 8 |
+
from datasets import load_dataset
|
| 9 |
+
# Ensure you have installed standard HuggingFace 'datasets' and 'trl'
|
| 10 |
+
# pip install trl datasets peft bitsandbytes
|
| 11 |
+
|
| 12 |
+
# 1. Configuration for Quantization and LoRA
|
| 13 |
+
print("Loading model for RLHF/DPO...")
|
| 14 |
+
config = yaml.safe_load(open("./config.yaml", "r"))
|
| 15 |
+
model_id = config["finetune_model"]["orignal_model_id"]
|
| 16 |
+
|
| 17 |
+
bnb_config = BitsAndBytesConfig(
|
| 18 |
+
load_in_4bit=True,
|
| 19 |
+
bnb_4bit_quant_type="nf4",
|
| 20 |
+
bnb_4bit_compute_dtype=torch.float16,
|
| 21 |
+
)
|
| 22 |
+
|
| 23 |
+
model = BlipForQuestionAnswering.from_pretrained(
|
| 24 |
+
model_id,
|
| 25 |
+
quantization_config=bnb_config,
|
| 26 |
+
device_map="auto"
|
| 27 |
+
)
|
| 28 |
+
model_ref = BlipForQuestionAnswering.from_pretrained(
|
| 29 |
+
model_id,
|
| 30 |
+
quantization_config=bnb_config,
|
| 31 |
+
device_map="auto"
|
| 32 |
+
)
|
| 33 |
+
|
| 34 |
+
# Setup PEFT LoRA
|
| 35 |
+
lora_config = LoraConfig(
|
| 36 |
+
r=16,
|
| 37 |
+
lora_alpha=32,
|
| 38 |
+
target_modules=["query", "value", "key"],
|
| 39 |
+
lora_dropout=0.05,
|
| 40 |
+
bias="none",
|
| 41 |
+
task_type="CAUSAL_LM"
|
| 42 |
+
)
|
| 43 |
+
model = get_peft_model(model, lora_config)
|
| 44 |
+
|
| 45 |
+
processor = BlipProcessor.from_pretrained(model_id)
|
| 46 |
+
|
| 47 |
+
# 2. Data Preparation for DPO
|
| 48 |
+
# RLHF via DPO (Direct Preference Optimization) requires preference dataset:
|
| 49 |
+
# prompt (image + question), chosen (preferred answer), rejected (dispreferred answer)
|
| 50 |
+
def mock_dataset_generator():
|
| 51 |
+
"""
|
| 52 |
+
Note: To properly train with DPO, you'll need a dataset with 'prompt', 'chosen', and 'rejected'.
|
| 53 |
+
Here we create a mock dataset to demonstrate the pipeline setup.
|
| 54 |
+
"""
|
| 55 |
+
return [
|
| 56 |
+
{
|
| 57 |
+
"prompt": "Is there a tumor in this MRI?",
|
| 58 |
+
"chosen": "No, this MRI scan does not show any signs of a tumor.",
|
| 59 |
+
"rejected": "No."
|
| 60 |
+
},
|
| 61 |
+
{
|
| 62 |
+
"prompt": "What is the anatomy shown?",
|
| 63 |
+
"chosen": "The anatomy shown is the temporal lobe of the human brain.",
|
| 64 |
+
"rejected": "Brain part."
|
| 65 |
+
}
|
| 66 |
+
]
|
| 67 |
+
|
| 68 |
+
# In practice: dataset = load_dataset("your_dpo_preference_dataset_here")
|
| 69 |
+
# For now we use the mock dataset
|
| 70 |
+
from datasets import Dataset
|
| 71 |
+
mock_data = Dataset.from_list(mock_dataset_generator())
|
| 72 |
+
|
| 73 |
+
# 3. DPO Trainer Setup Configuration
|
| 74 |
+
training_args = DPOConfig(
|
| 75 |
+
output_dir="./Deployment/DPO_RLHF_Model",
|
| 76 |
+
beta=0.1, # KL penalty
|
| 77 |
+
logging_steps=10,
|
| 78 |
+
per_device_train_batch_size=2,
|
| 79 |
+
gradient_accumulation_steps=4,
|
| 80 |
+
learning_rate=1e-5,
|
| 81 |
+
max_prompt_length=128,
|
| 82 |
+
max_length=256,
|
| 83 |
+
)
|
| 84 |
+
|
| 85 |
+
# 4. Initialize the TRL DPO Trainer
|
| 86 |
+
print("Setting up DPOTrainer from TRL...")
|
| 87 |
+
dpo_trainer = DPOTrainer(
|
| 88 |
+
model,
|
| 89 |
+
model_ref, # The reference model for KL penalty
|
| 90 |
+
args=training_args,
|
| 91 |
+
train_dataset=mock_data,
|
| 92 |
+
tokenizer=processor.tokenizer,
|
| 93 |
+
)
|
| 94 |
+
|
| 95 |
+
# 5. Execute Training
|
| 96 |
+
if __name__ == "__main__":
|
| 97 |
+
print("Starting DPO (RLHF) Alignment Training phase...")
|
| 98 |
+
# dpo_trainer.train() # Uncomment to run if valid dataset provided
|
| 99 |
+
print("DPO Training complete! Model parameters aligned with human preference.")
|
| 100 |
+
# model.save_pretrained("./Deployment/DPO_RLHF_Best_Model")
|