DPDP-SSense / scripts /01_prepare_data.sh
PRiyanshu0-1's picture
Initial push: DPDP SLM Pipeline with comprehensive LFS
1f52672
Raw History Blame Contribute Delete
13.2 kB
#!/usr/bin/env bash
# ==============================================================================
# 01_prepare_data.sh – Stage 1: Synthetic Data Forge, Model Verification & Unsloth Preparation
# ==============================================================================
# ⚠️ SPECIALIZED PIPELINE NOTICE:
# This script is exclusively engineered for preparing data and downloading checkpoints for the Indian Digital Personal
# Data Protection (DPDP) Act 2023 & Rules 2025 specialized legal models on NVIDIA DGX Spark infrastructure (128 GB VRAM).
# It checks/downloads our Teacher Model (`Qwen2-72B-Instruct-FP8`) and Student Model (`Qwen2.5-7B-Instruct`), synthesizes
# statutory training data, and formats Unsloth SFT + DPO datasets. It is specialized for our DPDP law pipeline only.
#
# Prerequisites for DGX Spark Execution:
# - NVIDIA DGX / GPU environment (128 GB VRAM unified or split)
# - Python 3.10+ / 3.12 with CUDA 12.x/13.x support
# - Packages installed (`pip install -r ml/requirements.txt`): unsloth, trl, transformers, vllm, datasets, torch, huggingface_hub, chromadb, langchain-text-splitters, rank_bm25
#
# Usage:
# bash ml/scripts/01_prepare_data.sh [--skip-gan]
#
# Options:
# --skip-gan Skip running gan_forge.py (useful if raw GAN policy files exist)
# -h, --help Show help menu and exit
# ==============================================================================
set -euo pipefail
# Locate repository and ML root relative to this script
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ML_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
REPO_ROOT="$(cd "${ML_DIR}/.." && pwd)"
# Resolve Python binary
PYTHON_CMD="python"
if command -v python3 &> /dev/null; then
PYTHON_CMD="python3"
fi
SKIP_GAN=false
while [[ $# -gt 0 ]]; do
case $1 in
--skip-gan)
SKIP_GAN=true
shift
;;
-h|--help)
echo "Usage: bash ml/scripts/01_prepare_data.sh [options]"
echo "Options:"
echo " --skip-gan Skip running gan_forge.py and proceed directly to tree building and dataset formatting"
echo " -h, --help Show this help message and exit"
exit 0
;;
*)
echo "❌ Unknown option: $1"
echo "Use --help for available options."
exit 1
;;
esac
done
# Setup logging
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
export LOG_DIR="${REPO_ROOT}/logs"
export PYTHONUNBUFFERED=1
mkdir -p "${LOG_DIR}"
SCRIPT_NAME=$(basename "$0" .sh)
MASTER_LOG="${LOG_DIR}/${SCRIPT_NAME}_${TIMESTAMP}.log"
exec > >(tee -i "${MASTER_LOG}")
exec 2>&1
echo "════════════════════════════════════════════════════════════════════════════════"
echo "πŸš€ INITIATING STAGE 1: DGX SPARK MODEL VERIFICATION & DATA PREPARATION"
echo "════════════════════════════════════════════════════════════════════════════════"
echo " β€’ Repository Root: ${REPO_ROOT}"
echo " β€’ ML Root: ${ML_DIR}"
echo " β€’ Python Binary: $(command -v "${PYTHON_CMD}")"
echo " β€’ Logs Directory: ${LOG_DIR}"
echo " β€’ Skip GAN Forge: ${SKIP_GAN}"
echo " β€’ Target Domain: Digital Personal Data Protection (DPDP) Act 2023 & Rules 2025"
echo "════════════════════════════════════════════════════════════════════════════════"
# Terminate lingering vLLM API server processes from aborted jobs if any
echo -e "\n🧹 Cleaning up any orphaned vLLM API endpoints before starting..."
pkill -f vllm.entrypoints.openai.api_server 2>/dev/null || true
# ════════════════════════════════════════════════════════════════════════════════
# [PHASE 0.1]: PURGE CACHES (PRESERVING GENERATED DATA)
# ════════════════════════════════════════════════════════════════════════════════
echo -e "\n🧹 [PHASE 0.1]: Purging Caches..."
# 1. Purge Python Bytecode Cache
find "${REPO_ROOT}" -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
echo " βœ… Purged all __pycache__ directories."
# 2. Purge Vector DB Cache
rm -f "${ML_DIR}/data-forge/dpdp_hybrid_index.pkl" 2>/dev/null || true
echo " βœ… Purged Hybrid RAG Index cache."
# 3. Purge Aggregated JSONL data
rm -f "${ML_DIR}/slm-training/data"/*.jsonl 2>/dev/null || true
echo " βœ… Purged aggregated JSONL training files (Will be rebuilt in Phase 3)."
# ════════════════════════════════════════════════════════════════════════════════
# [PHASE 0.5/4]: MODEL VERIFICATION & DOWNLOAD (LOCAL CHECK & HUGGINGFACE FALLBACK)
# ════════════════════════════════════════════════════════════════════════════════
mkdir -p "${ML_DIR}/models"
echo -e "\n▢️ [PHASE 0.5/4]: Verifying Teacher ('Qwen2-72B') & Student ('Qwen2.5-7B-Instruct') Models in ml/models/..."
# 1. Check Student Model: Qwen2.5-7B-Instruct
if [ -d "${ML_DIR}/models/Qwen2.5-7B-Instruct" ] && [ -n "$(ls -A "${ML_DIR}/models/Qwen2.5-7B-Instruct" 2>/dev/null)" ]; then
echo " βœ… Student model ('Qwen2.5-7B-Instruct') found locally at ml/models/Qwen2.5-7B-Instruct. Skipping download."
elif [ -d "${ML_DIR}/models/Qwen3.5-9B" ] && [ -n "$(ls -A "${ML_DIR}/models/Qwen3.5-9B" 2>/dev/null)" ]; then
echo " βœ… Model found locally at ml/models/Qwen3.5-9B. Skipping download."
else
echo " πŸ“₯ Student model not found locally in ml/models/. Downloading unsloth/Qwen2.5-7B-Instruct via hf..."
if command -v hf &> /dev/null; then
hf download unsloth/Qwen2.5-7B-Instruct --local-dir "${ML_DIR}/models/Qwen2.5-7B-Instruct"
else
"${PYTHON_CMD}" -c "from huggingface_hub import snapshot_download; snapshot_download(repo_id='unsloth/Qwen2.5-7B-Instruct', local_dir='${ML_DIR}/models/Qwen2.5-7B-Instruct')"
fi
echo " βœ… Downloaded Qwen2.5-7B-Instruct successfully."
fi
# 2. Check Teacher Model: Qwen2-72B-Instruct-FP8
if [ -d "${ML_DIR}/models/Qwen2-72B-Instruct-FP8" ] && [ -n "$(ls -A "${ML_DIR}/models/Qwen2-72B-Instruct-FP8" 2>/dev/null)" ]; then
echo " βœ… Teacher model ('Qwen2-72B-Instruct-FP8') found locally at ml/models/Qwen2-72B-Instruct-FP8. Skipping download."
elif [ -d "${ML_DIR}/models/Qwen2.5-72B-Instruct-FP8" ] && [ -n "$(ls -A "${ML_DIR}/models/Qwen2.5-72B-Instruct-FP8" 2>/dev/null)" ]; then
echo " βœ… Teacher model found locally at ml/models/Qwen2.5-72B-Instruct-FP8. Skipping download."
else
echo " πŸ“₯ Teacher model not found locally in ml/models/. Downloading Qwen/Qwen2-72B-Instruct-FP8 via hf..."
if command -v hf &> /dev/null; then
hf download Qwen/Qwen2-72B-Instruct-FP8 --local-dir "${ML_DIR}/models/Qwen2-72B-Instruct-FP8"
else
"${PYTHON_CMD}" -c "from huggingface_hub import snapshot_download; snapshot_download(repo_id='Qwen/Qwen2-72B-Instruct-FP8', local_dir='${ML_DIR}/models/Qwen2-72B-Instruct-FP8')"
fi
echo " βœ… Downloaded teacher model successfully."
fi
# 3. Check RAG Models: BAAI/bge-small-en-v1.5 and BAAI/bge-reranker-v2-m3
if [ -d "${ML_DIR}/models/bge-small-en-v1.5" ] && [ -n "$(ls -A "${ML_DIR}/models/bge-small-en-v1.5" 2>/dev/null)" ]; then
echo " βœ… RAG Embedding model ('bge-small-en-v1.5') found locally in ml/models/. Skipping download."
else
echo " πŸ“₯ RAG Embedding model not found locally in ml/models/. Downloading BAAI/bge-small-en-v1.5..."
if command -v hf &> /dev/null; then
hf download BAAI/bge-small-en-v1.5 --local-dir "${ML_DIR}/models/bge-small-en-v1.5"
else
"${PYTHON_CMD}" -c "from huggingface_hub import snapshot_download; snapshot_download(repo_id='BAAI/bge-small-en-v1.5', local_dir='${ML_DIR}/models/bge-small-en-v1.5')"
fi
echo " βœ… Downloaded RAG embedding model successfully."
fi
if [ -d "${ML_DIR}/models/bge-reranker-v2-m3" ] && [ -n "$(ls -A "${ML_DIR}/models/bge-reranker-v2-m3" 2>/dev/null)" ]; then
echo " βœ… RAG Reranker model ('bge-reranker-v2-m3') found locally in ml/models/. Skipping download."
else
echo " πŸ“₯ RAG Reranker model not found locally in ml/models/. Downloading BAAI/bge-reranker-v2-m3..."
if command -v hf &> /dev/null; then
hf download BAAI/bge-reranker-v2-m3 --local-dir "${ML_DIR}/models/bge-reranker-v2-m3"
else
"${PYTHON_CMD}" -c "from huggingface_hub import snapshot_download; snapshot_download(repo_id='BAAI/bge-reranker-v2-m3', local_dir='${ML_DIR}/models/bge-reranker-v2-m3')"
fi
echo " βœ… Downloaded RAG reranker model successfully."
fi
# ════════════════════════════════════════════════════════════════════════════════
# [PHASE 0.7/4]: RAG DEPENDENCY RESOLUTION
# ════════════════════════════════════════════════════════════════════════════════
echo -e "\n▢️ [PHASE 0.7/4]: Verifying Data Forge & Vector DB Dependencies..."
"${PYTHON_CMD}" -m pip install -q chromadb langchain-text-splitters rank_bm25 sentence-transformers langchain
echo " βœ… Dependencies synchronized."
cd "${ML_DIR}/data-forge"
# ════════════════════════════════════════════════════════════════════════════════
# [PHASE 1/4]: SYNTHETIC DATA FORGE
# ════════════════════════════════════════════════════════════════════════════════
if [ "${SKIP_GAN}" = true ]; then
echo -e "\n⏭️ [PHASE 1/4]: Skipping Synthetic GAN Forge (--skip-gan enabled)."
else
echo -e "\n▢️ [PHASE 1/4(a)]: Building Vector Database (ChromaDB)..."
"${PYTHON_CMD}" -u build_vector_db.py
echo -e "\n▢️ [PHASE 1/4(b)]: Forging Synthetic Data (GAN Forge via vLLM)..."
"${PYTHON_CMD}" -u gan_forge.py
fi
# ════════════════════════════════════════════════════════════════════════════════
# [PHASE 2/4]: DETERMINISTIC RUST DECISION TREE
# ════════════════════════════════════════════════════════════════════════════════
echo -e "\n▢️ [PHASE 2/4]: Building Deterministic Rust Decision Tree..."
"${PYTHON_CMD}" -u build_dpdp_tree.py
# ════════════════════════════════════════════════════════════════════════════════
# [PHASE 3/4]: UNSLOTH DATASET ALIGNMENT & FORMATTING
# ════════════════════════════════════════════════════════════════════════════════
echo -e "\n▢️ [PHASE 3/4]: Aligning & Formatting Data Schemas for Unsloth..."
"${PYTHON_CMD}" -u prepare_unsloth_data.py
echo -e "\n════════════════════════════════════════════════════════════════════════════════"
echo "βœ… STAGE 1 COMPLETE: Models verified and Unsloth SFT & DPO training datasets synthesized."
echo "════════════════════════════════════════════════════════════════════════════════"
echo "πŸ“ Execution logs saved to: ${LOG_DIR}"
echo "πŸ‘‰ Next step: Run 'bash ml/scripts/02_train_models.sh' to fine-tune both DPDP SLMs on DGX Spark."