data-centric-env / README.md
Aswini-Kumar's picture
Add Training Evidence: real plots, logs, updated README
29675aa verified
|
Raw
History Blame Contribute Delete
16.8 kB
metadata
title: Data-Centric AI RL Environment
emoji: 🧠
colorFrom: blue
colorTo: indigo
sdk: docker
pinned: false
app_port: 7860
short_description: LLM learns to fix data, not models β€” GRPO RL env.
tags:
  - openenv
  - reinforcement-learning
  - data-centric-ai
  - grpo
  - unsloth
  - curriculum-learning

🧠 Data-Centric AI β€” Multi-Agent RL Environment

What if the model is fine β€” but the data isn't? This OpenEnv environment uses GRPO reinforcement learning to teach a language model to act as a data surgery orchestrator: dispatching specialist sub-agents to impute, rebalance, and augment a corrupted ML dataset β€” boosting a frozen classifier's accuracy without touching a single model weight.


πŸ”— Links

Resource Link
πŸ€— HF Space (live env) https://huggingface.co/spaces/Aswini-Kumar/data-centric-env
πŸ““ Training Notebook Open In Colab
πŸ“ Blog Post BLOG.md
πŸ’» GitHub https://github.com/CelestialWorthyOfHeavenAndEarth/data-centric-env
🏷️ Theme #3.1 β€” World Modeling / Professional Tasks

πŸ“Š Training Evidence

Real plots and logs from a verified 50-step GRPO run on Google Colab (T4 GPU):

Artifact Link
πŸ“ˆ Reward Curve partial_run_reward_curve.png
🎯 Accuracy Gain partial_run_accuracy_gain.png
πŸ—‚οΈ Curriculum Trace partial_run_curriculum.png
πŸ“Š Training Dashboard partial_run_training_dashboard.png
πŸ“‹ Raw Training Log partial_run_training.jsonl
πŸ“‰ Baseline Comparison partial_run_baseline_comparison.png

Run summary: SFT warmup (350 steps, ~14 min) β†’ GRPO (50 steps, ~25 min). Reward climbed from βˆ’0.23 β†’ +1.00 peak, with format compliance improving 18% β†’ 67% over training. Extended run plots are in plots/full_run_* and logs/full_run_training.jsonl.


🎯 The Problem

ML practitioners spend 80% of their time on data quality β€” yet almost no RL infrastructure exists to train LLMs to do this work automatically.

Andrew Ng's Data-Centric AI movement shows that fixing the data consistently beats improving the model architecture. We built a reinforcement learning environment to train an agent to master exactly that skill.

The agent must improve a frozen classifier β€” it cannot change the model at all. Its only lever is the data.


🌍 What the Agent Sees, Does, and Gets Rewarded For

The Setup

Each episode: a noisy tabular dataset + frozen Random Forest classifier. The agent must push classifier accuracy above a target threshold within a step budget.

Action Space (12 commands)

Command Effect
inspect_dataset View shape, missing values, class distribution
inspect_model View RF + LR accuracy, F1, per-class metrics
query_analyst Holistic diagnosis + prioritised fix plan (costs 2 budget)
query_cleaner Missing-value / outlier recommendations with skewness analysis
query_augmenter [class] Synthetic row generation for underrepresented classes
query_balancer Class rebalancing (oversample / undersample) recommendations
query_validator Rule violation detection (costs 2 budget)
apply <N> Apply recommendation N
reject <N> Reject a recommendation
undo Revert last apply (max 3 levels deep)
validate Retrain classifier and score (cooldown enforced)
submit Finalise episode β€” triggers terminal reward

Observation Space

DataCentricObservation(
    response="...",              # Specialist agent text output
    current_accuracy=0.71,       # Last validated RF accuracy
    baseline_accuracy=0.62,      # Accuracy before any fixes
    target_accuracy=0.73,        # Threshold to beat
    estimated_quality=0.84,      # Lightweight quality score [0,1]
    rows_preserved_pct=0.97,     # Fraction of original rows remaining
    budget_remaining=22,         # Steps left before forced submit
    validate_calls_remaining=2,  # Free validates remaining
    done=False,
)

Reward Function β€” OpenEnv Composable Rubrics

Key design principle: reward must discriminate. An agent that trivially achieves 100% success on easy tasks with any strategy is not learning β€” it's saturating. Every rubric is tuned to punish inefficiency and reward surgical accuracy improvement.

Rubric Signal Range
AccuracyRubric Ξ”accΓ—2.5 mid-episode; at submit: base + efficiencyΓ—budget_fraction + stretch bonus [-1.0, +0.80]
ProcessRubric Correct queryβ†’applyβ†’validate workflow (blind apply = βˆ’0.08, submit w/o validate = βˆ’0.15) [-0.20, +0.13]
PreservationRubric Must keep β‰₯92% of rows (prevents delete-to-win cheating) [-0.50, +0.05]
EfficiencyRubric At submit: gain/budget_used Γ— 3.0 β€” hitting target in 5 steps beats 25 steps by 3Γ— [-0.10, +0.25]
StepRubric Dense per-apply proxy using lightweight quality score β€” no classifier retraining [-0.30, +0.15]

Total clamped to [-1.0, 1.0] by DataCentricRubric.forward(). Reward range is real β€” bad episodes regularly hit βˆ’0.4, good ones hit +0.8.

Anti-Exploit Hardening (9 protections)

  • Ground truth immutability asserted after every apply
  • validate cooldown β€” must take 2 actions between validates
  • Duplicate apply detection + session apply limit (max 3 per query)
  • Recommendation staleness β€” re-query required after each session
  • Catastrophic data loss (<50% rows) β†’ immediate episode termination
  • Episode wall-clock timeout (5 min β†’ forced submit with penalty)
  • Input truncation (>200 chars β†’ truncate + βˆ’0.01 penalty)
  • Repeated same query without apply β†’ βˆ’0.05 penalty
  • Redundant validate (two in a row) β†’ βˆ’0.08 penalty

πŸ“š Task Curriculum (4 Levels)

Task Rows Issues Baseline Target Budget
task_0_tutorial 100 Missing values only (20%) ~0.62 0.73 30
task_1_easy 200 Missing + class imbalance ~0.63 0.79 25
task_2_medium 500 Missing + duplicates + imbalance + type errors ~0.58 0.74 40
task_3_hard 900 6 issues: above + outliers + cross-column logic errors ~0.54 0.71 60

Curriculum advances automatically when success rate β‰₯ 70% over a 20-episode rolling window.


πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚               LLM Agent (Qwen2.5-1.5B-Instruct)                 β”‚
β”‚            SFT warmup β†’ GRPO live-environment training          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              β”‚  text commands                    β”‚  structured obs
              β–Ό                                   β–²
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              DataCentricEnvironment (OpenEnv)                    β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚ Cleaner  β”‚  β”‚Augmenter β”‚  β”‚ Balancer β”‚  β”‚  Analyst     β”‚    β”‚
β”‚  β”‚  Agent   β”‚  β”‚  Agent   β”‚  β”‚  Agent   β”‚  β”‚   Agent      β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                        Working Copy (mutable)                    β”‚
β”‚              ◄─── Snapshot stack Γ—3 (undo support)              β”‚
β”‚              ──► ModelEvaluator (RF + LR, cached, fast_mode)    β”‚
β”‚              ──► Ground Truth (frozen, immutability-asserted)    β”‚
β”‚                                                                  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  DataCentricRubric (OpenEnv composable rubric system)    β”‚   β”‚
β”‚  β”‚  β”œβ”€β”€ AccuracyRubric    β”œβ”€β”€ ProcessRubric                 β”‚   β”‚
β”‚  β”‚  β”œβ”€β”€ PreservationRubric β”œβ”€β”€ EfficiencyRubric             β”‚   β”‚
β”‚  β”‚  └── StepRubric (dense per-step proxy)                   β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“Š Results

Training Curves

The following plots are generated by plot_rewards.py from the GRPO training log. Run train_colab.ipynb to reproduce.

Reward over training (150 episodes, GRPO with curriculum):

GRPO training reward curve showing learning from episode 0 to 150, with curriculum advancement markers at Easy, Medium, and Hard levels

Rolling mean (blue) rises from βˆ’0.1 at episode 0 to +0.65 by episode 150. Vertical dashed lines mark automatic curriculum advancement as the agent masters each level.

Full training dashboard (success rate per level, accuracy gain, curriculum progression):

2x2 training dashboard showing success rate per curriculum level, accuracy gain over episodes, curriculum level progression, and reward component breakdown

Top-left: success rate per curriculum level β€” Easy masters first, Medium and Hard improve progressively. Top-right: accuracy gain above baseline rises from ~0.04 to ~0.12 per episode. Bottom-left: curriculum level advances through 3 levels across 150 episodes.

Trained Agent vs Baselines

Same tasks, same seeds, 10 episodes per task:

Bar chart comparing Random Agent vs Heuristic Baseline vs Trained GRPO Agent success rates across all 4 tasks

Agent Tutorial Easy Medium Hard Overall
Random Agent 30% 20% 10% 5% 16%
Heuristic Baseline 100% 80% 60% 40% 70%
Trained Agent (GRPO) 100% 95% 80% 55% 83%

The trained agent outperforms the heuristic on every task except tutorial (both 100%). On hard tasks it's +15% absolute improvement. The heuristic always uses the same fixed sequence regardless of data; the trained agent adapts its strategy to the actual data issues.

Qualitative Comparison

Random agent (before training):

inspect_dataset
apply 3          ← blind apply (no query)
validate
validate         ← redundant validate (cooldown triggers)
submit           ← submits without hitting target

Trained agent (after GRPO):

query_analyst    ← starts with diagnosis
inspect_dataset  ← orients to data shape
query_cleaner    ← targets identified issue
apply 1          ← applies top recommendation
validate         ← checks improvement
query_balancer   ← addresses secondary issue
apply 1
submit           ← submits after hitting target

The trained agent learns the correct workflow sequence β€” not because it was hardcoded, but because the reward function penalises blind applies (βˆ’0.08) and rewards the queryβ†’applyβ†’validate loop (+0.09 total).


πŸ€– Training Pipeline

Model: Qwen/Qwen2.5-1.5B-Instruct (4-bit QLoRA via Unsloth, r=8) Algorithm: SFT warmup (1 epoch, ~9,480 examples) β†’ GRPO (TRL GRPOTrainer) Tracking: TensorBoard (logs/sft/ and logs/grpo/) Hardware: Any CUDA GPU (tested on T4/A100)

Run Training

# Full training (Colab recommended)
# Open train_colab.ipynb β€” runs SFT + GRPO, auto-resumes on disconnect

Open In Colab


πŸš€ Quick Start β€” Use the Live Environment

pip install openenv-core requests

from client import DataCentricEnv
from models import DataCentricAction

with DataCentricEnv(base_url="https://aswini-kumar-data-centric-env.hf.space").sync() as env:
    result = env.reset(task="task_1_easy", seed=42)
    obs = result.observation
    print(f"Baseline: {obs.baseline_accuracy:.2f}  Target: {obs.target_accuracy:.2f}")

    # Query the analyst for a prioritised fix plan
    result = env.step(DataCentricAction(message="query_analyst"))
    print(result.observation.response)

    # Apply the top recommendation
    result = env.step(DataCentricAction(message="apply 1"))
    result = env.step(DataCentricAction(message="validate"))
    print(f"Accuracy: {result.observation.current_accuracy:.2f}")

πŸ§ͺ Tests

pytest tests/ -v          # 35 tests: grader + environment safety invariants
pytest tests/test_grader.py -v      # 22 reward component tests
pytest tests/test_environment.py -v # 13 anti-exploit + budget tests
python audit.py           # Full connectivity audit (imports + live env cycle)

πŸ“ Project Structure

data_centric_env/
β”œβ”€β”€ openenv.yaml              # OpenEnv manifest
β”œβ”€β”€ client.py                 # WebSocket client (never imports server internals)
β”œβ”€β”€ models.py                 # DataCentricAction + DataCentricObservation
β”œβ”€β”€ agent_utils.py            # SYSTEM_PROMPT, build_user_prompt, server helpers
β”œβ”€β”€ train_data_centric.py     # SFT β†’ GRPO training pipeline
β”œβ”€β”€ train_colab.ipynb         # Training notebook (11 steps, auto-resume)
β”œβ”€β”€ eval_data_centric.py      # Trained vs random vs heuristic evaluation
β”œβ”€β”€ plot_rewards.py           # 4 reward curve plots
β”œβ”€β”€ sft_generator.py          # Generates ~9,480 SFT warmup trajectories
β”œβ”€β”€ inference.py              # Heuristic baseline agent
β”œβ”€β”€ audit.py                  # Full connectivity audit script
β”œβ”€β”€ plots/                    # ← Committed training plots
β”‚   β”œβ”€β”€ reward_curve.png
β”‚   β”œβ”€β”€ baseline_comparison.png
β”‚   └── training_dashboard.png
β”œβ”€β”€ BLOG.md                   # Detailed writeup
β”œβ”€β”€ tests/
β”‚   β”œβ”€β”€ test_grader.py        # 22 reward rubric tests
β”‚   └── test_environment.py   # 13 environment safety tests
└── server/
    β”œβ”€β”€ app.py                # FastAPI server
    β”œβ”€β”€ data_centric_environment.py
    β”œβ”€β”€ grader.py             # DataCentricRubric + 5 composable child rubrics
    β”œβ”€β”€ specialist_agents.py  # Cleaner, Augmenter, Balancer, Validator, Analyst
    β”œβ”€β”€ anti_exploit.py       # 9 reward-hacking protections
    β”œβ”€β”€ model_evaluator.py    # RF + LR with hash-based caching
    └── dataset_generator.py  # 4-task synthetic dataset generation

πŸ’‘ Why It Matters

Data-Centric AI is the underexplored frontier of LLM training. Most RL environments train on fixed reasoning tasks (math, code). This environment trains adaptive judgment under uncertainty β€” exactly what distinguishes a senior data engineer.

A model trained here can, given a messy dataset: diagnose the issues, apply targeted fixes in order of impact, verify improvement, and back out bad decisions β€” autonomously.

This capability does not exist in pretrained LLMs today. This environment is the training ground for it.


Theme: #3.1 β€” World Modeling / Professional Tasks Stack: OpenEnv Β· Unsloth Β· TRL (GRPO) Β· FastAPI Β· scikit-learn Β· TensorBoard