Spaces:
Running
Running
Fix Space inference loading and switch evidence plots to SVG
Browse files- .gitignore +7 -0
- BLOG.md +57 -0
- README.md +79 -12
- TRAINING_EVIDENCE.md +69 -0
- artifacts/family_productivity.svg +3109 -0
- artifacts/pass_rate_by_difficulty.svg +0 -0
- artifacts/results_summary.json +46 -0
- artifacts/reward_curve.svg +0 -0
- artifacts/training_status_snapshot.json +59 -0
- requirements.txt +1 -0
- server/requirements.txt +1 -0
- server/runtime.py +60 -16
.gitignore
CHANGED
|
@@ -223,3 +223,10 @@ __marimo__/
|
|
| 223 |
|
| 224 |
# local codebase maps
|
| 225 |
CODEBASE_STRUCTURE_MAIN_V5.md
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 223 |
|
| 224 |
# local codebase maps
|
| 225 |
CODEBASE_STRUCTURE_MAIN_V5.md
|
| 226 |
+
|
| 227 |
+
# recovered local-only artifacts
|
| 228 |
+
artifacts/events.jsonl
|
| 229 |
+
artifacts/reward_curve.csv
|
| 230 |
+
artifacts/run_summary.json
|
| 231 |
+
artifacts/test_plot.png
|
| 232 |
+
artifacts/*.png
|
BLOG.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ADAPT: training a model to debug algorithm solutions instead of guessing once
|
| 2 |
+
|
| 3 |
+
ADAPT is an OpenEnv environment for reinforcement learning on algorithmic problem solving. The core idea is simple: instead of rewarding a model only for a perfect first answer, we make it solve a programming task, inspect verifier feedback, and repair its code over up to three attempts.
|
| 4 |
+
|
| 5 |
+
That makes the environment closer to real software work. The agent sees a problem statement, input format, constraints, and visible examples. It writes Python code, gets hidden-test feedback, and is rewarded for improving hidden correctness and eventually meeting an efficiency target.
|
| 6 |
+
|
| 7 |
+
## What we built
|
| 8 |
+
|
| 9 |
+
- an OpenEnv-compatible environment with `reset`, `step`, and `state`
|
| 10 |
+
- a verifier that executes submitted Python safely and scores hidden correctness, visible correctness, and efficiency
|
| 11 |
+
- a reward-aware curriculum that shifts toward the most educational problem families
|
| 12 |
+
- a GRPO training pipeline built with Unsloth + Hugging Face TRL
|
| 13 |
+
|
| 14 |
+
## Why this environment is interesting
|
| 15 |
+
|
| 16 |
+
Most code-generation tasks only ask whether a model can get the answer immediately. ADAPT focuses on a harder and more realistic behavior: can the model recover from failure, use feedback, and converge toward a correct solution?
|
| 17 |
+
|
| 18 |
+
The environment includes `20` DSA problem families across easy, medium, and hard tiers, hidden evaluation tests, efficiency-aware rewards, and a curriculum that adapts based on what seems to teach the agent the most.
|
| 19 |
+
|
| 20 |
+
## Real training run
|
| 21 |
+
|
| 22 |
+
We trained `Qwen/Qwen2.5-3B-Instruct` with the overnight preset:
|
| 23 |
+
|
| 24 |
+
- Run ID: `15940d1d-7d8c-4253-8810-2ea934bedee4`
|
| 25 |
+
- Optimizer steps: `950`
|
| 26 |
+
- Training episodes logged: `7,600`
|
| 27 |
+
- Wall-clock time: `8.96 hours`
|
| 28 |
+
- Uploaded model revision: `6c957e7c6bdb25ff086775fb8692570aee4501c9`
|
| 29 |
+
|
| 30 |
+
From the recovered training logs:
|
| 31 |
+
|
| 32 |
+
- average reward improved from `0.4441` in the first `500` episodes to `0.5951` in the last `500`
|
| 33 |
+
- average hidden pass rate improved from `0.4625` to `0.6488`
|
| 34 |
+
- completion rate improved from `43.6%` to `59.6%`
|
| 35 |
+
|
| 36 |
+
Late in training, the model was solving many easy and medium tasks reliably and was noticeably stronger on hard tasks as well:
|
| 37 |
+
|
| 38 |
+
| Difficulty | Avg reward | Avg hidden pass rate | Completion rate |
|
| 39 |
+
| --- | ---: | ---: | ---: |
|
| 40 |
+
| Easy | 0.8390 | 0.8477 | 84.38% |
|
| 41 |
+
| Medium | 0.7892 | 0.8425 | 78.85% |
|
| 42 |
+
| Hard | 0.5182 | 0.5759 | 51.92% |
|
| 43 |
+
|
| 44 |
+
## Evidence
|
| 45 |
+
|
| 46 |
+

|
| 47 |
+
|
| 48 |
+

|
| 49 |
+
|
| 50 |
+

|
| 51 |
+
|
| 52 |
+
## Links
|
| 53 |
+
|
| 54 |
+
- Environment Space: [Dishaaa25/meta-rl-dsa-solver](https://huggingface.co/spaces/Dishaaa25/meta-rl-dsa-solver)
|
| 55 |
+
- Live app: [Dishaaa25-meta-rl-dsa-solver.hf.space](https://Dishaaa25-meta-rl-dsa-solver.hf.space)
|
| 56 |
+
- Training notebook: [Qwen2.5_(3B)-GRPO.ipynb](https://huggingface.co/spaces/Dishaaa25/meta-rl-dsa-solver/blob/main/Qwen2.5_%283B%29-GRPO.ipynb)
|
| 57 |
+
- Trained model: [Dishaaa25/adapt-dsa-tutor-model](https://huggingface.co/Dishaaa25/adapt-dsa-tutor-model)
|
README.md
CHANGED
|
@@ -15,6 +15,17 @@ tags:
|
|
| 15 |
|
| 16 |
LLMs are getting better at one-shot code generation, but they still struggle with the thing real engineers do all day: read feedback, debug, and repair. ADAPT closes that gap by turning algorithm practice into a self-repair RL environment where the model must improve over multiple attempts instead of guessing once.
|
| 17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
## Why ADAPT exists
|
| 19 |
|
| 20 |
Most code-generation benchmarks test whether a model can land the answer immediately. They do not test whether the model can recover from partial failure, use examples productively, or adapt as the task distribution changes.
|
|
@@ -187,17 +198,70 @@ That makes ADAPT more than a static benchmark. The environment actively searches
|
|
| 187 |
|
| 188 |
## Results
|
| 189 |
|
| 190 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 191 |
|
| 192 |
-
|
| 193 |
|
| 194 |
-
|
| 195 |
|
| 196 |
-
-
|
| 197 |
-
- `
|
| 198 |
-
-
|
| 199 |
-
- `
|
| 200 |
-
- one before/after repair example from baseline vs trained evaluation
|
| 201 |
|
| 202 |
## How to run
|
| 203 |
|
|
@@ -302,7 +366,10 @@ openenv push --repo-id <your-hf-username>/adapt-dsa-tutor
|
|
| 302 |
|
| 303 |
## Links
|
| 304 |
|
| 305 |
-
-
|
| 306 |
-
-
|
| 307 |
-
-
|
| 308 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
LLMs are getting better at one-shot code generation, but they still struggle with the thing real engineers do all day: read feedback, debug, and repair. ADAPT closes that gap by turning algorithm practice into a self-repair RL environment where the model must improve over multiple attempts instead of guessing once.
|
| 17 |
|
| 18 |
+
## Submission links
|
| 19 |
+
|
| 20 |
+
- Hugging Face Space: [Dishaaa25/meta-rl-dsa-solver](https://huggingface.co/spaces/Dishaaa25/meta-rl-dsa-solver)
|
| 21 |
+
- Live environment: [Dishaaa25-meta-rl-dsa-solver.hf.space](https://Dishaaa25-meta-rl-dsa-solver.hf.space)
|
| 22 |
+
- Training repo URL: [Space repository root](https://huggingface.co/spaces/Dishaaa25/meta-rl-dsa-solver/tree/main)
|
| 23 |
+
- Training script: [training/train_grpo.py](https://huggingface.co/spaces/Dishaaa25/meta-rl-dsa-solver/blob/main/training/train_grpo.py)
|
| 24 |
+
- Training evidence: [TRAINING_EVIDENCE.md](https://huggingface.co/spaces/Dishaaa25/meta-rl-dsa-solver/blob/main/TRAINING_EVIDENCE.md)
|
| 25 |
+
- Mini blog / writeup: [BLOG.md](https://huggingface.co/spaces/Dishaaa25/meta-rl-dsa-solver/blob/main/BLOG.md)
|
| 26 |
+
- Trained adapter repo: [Dishaaa25/adapt-dsa-tutor-model](https://huggingface.co/Dishaaa25/adapt-dsa-tutor-model)
|
| 27 |
+
- Source repo mirror: [s-shah4/meta-rl-dsa-solver](https://github.com/s-shah4/meta-rl-dsa-solver)
|
| 28 |
+
|
| 29 |
## Why ADAPT exists
|
| 30 |
|
| 31 |
Most code-generation benchmarks test whether a model can land the answer immediately. They do not test whether the model can recover from partial failure, use examples productively, or adapt as the task distribution changes.
|
|
|
|
| 198 |
|
| 199 |
## Results
|
| 200 |
|
| 201 |
+
We ran a real overnight GRPO training job on `Qwen/Qwen2.5-3B-Instruct` and logged `7,600` training episodes over `950` optimizer steps.
|
| 202 |
+
|
| 203 |
+
Training run:
|
| 204 |
+
|
| 205 |
+
- Run ID: `15940d1d-7d8c-4253-8810-2ea934bedee4`
|
| 206 |
+
- Started: `2026-04-25 22:21 UTC`
|
| 207 |
+
- Finished: `2026-04-26 07:19 UTC`
|
| 208 |
+
- Wall-clock time: `8.96 hours`
|
| 209 |
+
- Train preset: `overnight`
|
| 210 |
+
- Curriculum mode: `reward_aware`
|
| 211 |
+
- Trained model revision: `6c957e7c6bdb25ff086775fb8692570aee4501c9`
|
| 212 |
+
|
| 213 |
+
Proof of learning from the actual run logs:
|
| 214 |
+
|
| 215 |
+
- Average reward improved from `0.4441` in the first `500` episodes to `0.5951` in the last `500` episodes.
|
| 216 |
+
- Average hidden pass rate improved from `0.4625` to `0.6488`.
|
| 217 |
+
- Completion rate improved from `43.6%` to `59.6%`.
|
| 218 |
+
|
| 219 |
+
Late-training performance over the final `500` episodes:
|
| 220 |
+
|
| 221 |
+
| Difficulty | Episodes | Avg reward | Avg hidden pass rate | Completion rate |
|
| 222 |
+
| --- | ---: | ---: | ---: | ---: |
|
| 223 |
+
| Easy | 32 | 0.8390 | 0.8477 | 84.38% |
|
| 224 |
+
| Medium | 104 | 0.7892 | 0.8425 | 78.85% |
|
| 225 |
+
| Hard | 364 | 0.5182 | 0.5759 | 51.92% |
|
| 226 |
+
|
| 227 |
+
### Reward curve
|
| 228 |
+
|
| 229 |
+

|
| 230 |
+
|
| 231 |
+
### Pass rate by difficulty
|
| 232 |
+
|
| 233 |
+

|
| 234 |
+
|
| 235 |
+
### Reward-aware family productivity
|
| 236 |
+
|
| 237 |
+

|
| 238 |
+
|
| 239 |
+
Top productive families near the end of training:
|
| 240 |
+
|
| 241 |
+
- `smallest_most_frequent`
|
| 242 |
+
- `merge_intervals`
|
| 243 |
+
- `matrix_diagonal_sum`
|
| 244 |
+
- `fizzbuzz_variant`
|
| 245 |
+
- `group_anagrams_count`
|
| 246 |
+
- `max_subarray_sum`
|
| 247 |
+
- `two_sum_count`
|
| 248 |
+
- `balanced_brackets`
|
| 249 |
+
|
| 250 |
+
### A concrete improvement story
|
| 251 |
+
|
| 252 |
+
This run did not include a separate baseline-eval sweep, so we do not claim a strict benchmark-style baseline-vs-trained score table. Instead, we show the model improving *inside the environment itself* over the same overnight run:
|
| 253 |
+
|
| 254 |
+
- early training is dominated by low-reward, low-pass-rate episodes and safety failures
|
| 255 |
+
- by the end of the run, the agent is regularly solving hard tasks like `reverse_words` with `reward=1.0`, `hidden pass rate=1.0`, and `efficiency score=1.0`
|
| 256 |
|
| 257 |
+
The raw summary used for the table above is stored in `artifacts/results_summary.json`.
|
| 258 |
|
| 259 |
+
For the hackathon submission form, the "Training Run Notebook URL" field can point to the public Hugging Face Space repository because this project trained directly on Hugging Face rather than from a separate Colab notebook. The repo includes:
|
| 260 |
|
| 261 |
+
- the full training entrypoint in `training/train_grpo.py`
|
| 262 |
+
- the recovered training evidence in `TRAINING_EVIDENCE.md`
|
| 263 |
+
- embedded reward / pass-rate plots committed as image files
|
| 264 |
+
- the lightweight structured summary in `artifacts/results_summary.json`
|
|
|
|
| 265 |
|
| 266 |
## How to run
|
| 267 |
|
|
|
|
| 366 |
|
| 367 |
## Links
|
| 368 |
|
| 369 |
+
- Hugging Face Space URL: [https://huggingface.co/spaces/Dishaaa25/meta-rl-dsa-solver](https://huggingface.co/spaces/Dishaaa25/meta-rl-dsa-solver)
|
| 370 |
+
- Live app URL: [https://Dishaaa25-meta-rl-dsa-solver.hf.space](https://Dishaaa25-meta-rl-dsa-solver.hf.space)
|
| 371 |
+
- Training repo URL: [https://huggingface.co/spaces/Dishaaa25/meta-rl-dsa-solver/tree/main](https://huggingface.co/spaces/Dishaaa25/meta-rl-dsa-solver/tree/main)
|
| 372 |
+
- Training script URL: [https://huggingface.co/spaces/Dishaaa25/meta-rl-dsa-solver/blob/main/training/train_grpo.py](https://huggingface.co/spaces/Dishaaa25/meta-rl-dsa-solver/blob/main/training/train_grpo.py)
|
| 373 |
+
- Training evidence URL: [https://huggingface.co/spaces/Dishaaa25/meta-rl-dsa-solver/blob/main/TRAINING_EVIDENCE.md](https://huggingface.co/spaces/Dishaaa25/meta-rl-dsa-solver/blob/main/TRAINING_EVIDENCE.md)
|
| 374 |
+
- Blog post URL: [https://huggingface.co/spaces/Dishaaa25/meta-rl-dsa-solver/blob/main/BLOG.md](https://huggingface.co/spaces/Dishaaa25/meta-rl-dsa-solver/blob/main/BLOG.md)
|
| 375 |
+
- Trained model URL: [https://huggingface.co/Dishaaa25/adapt-dsa-tutor-model](https://huggingface.co/Dishaaa25/adapt-dsa-tutor-model)
|
TRAINING_EVIDENCE.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Training Evidence
|
| 2 |
+
|
| 3 |
+
This project was trained directly on Hugging Face infrastructure rather than from a separate Colab notebook. For the hackathon submission form, the public Hugging Face Space repository can be used as the "Training Run Notebook URL" because it contains the runnable training script and the evidence artifacts below.
|
| 4 |
+
|
| 5 |
+
## Public training assets
|
| 6 |
+
|
| 7 |
+
- Space repository root: [Dishaaa25/meta-rl-dsa-solver](https://huggingface.co/spaces/Dishaaa25/meta-rl-dsa-solver/tree/main)
|
| 8 |
+
- Training entrypoint: [training/train_grpo.py](https://huggingface.co/spaces/Dishaaa25/meta-rl-dsa-solver/blob/main/training/train_grpo.py)
|
| 9 |
+
- Trained adapter repo: [Dishaaa25/adapt-dsa-tutor-model](https://huggingface.co/Dishaaa25/adapt-dsa-tutor-model)
|
| 10 |
+
- Model revision from this run: `6c957e7c6bdb25ff086775fb8692570aee4501c9`
|
| 11 |
+
|
| 12 |
+
## Confirmed run
|
| 13 |
+
|
| 14 |
+
- Run ID: `15940d1d-7d8c-4253-8810-2ea934bedee4`
|
| 15 |
+
- Status: `succeeded`
|
| 16 |
+
- Base model: `Qwen/Qwen2.5-3B-Instruct`
|
| 17 |
+
- Optimizer steps: `950`
|
| 18 |
+
- Logged training episodes: `7,600`
|
| 19 |
+
- Duration: `8.964 hours`
|
| 20 |
+
- Generator mode: `reward_aware`
|
| 21 |
+
- Dataset size: `1024`
|
| 22 |
+
- Checkpoint upload enabled: `true`
|
| 23 |
+
|
| 24 |
+
## Evidence that training actually happened
|
| 25 |
+
|
| 26 |
+
- Reward curve image committed to the repo: `artifacts/reward_curve.svg`
|
| 27 |
+
- Pass-rate-by-difficulty image committed to the repo: `artifacts/pass_rate_by_difficulty.svg`
|
| 28 |
+
- Family-productivity image committed to the repo: `artifacts/family_productivity.svg`
|
| 29 |
+
- Structured summary committed to the repo: `artifacts/results_summary.json`
|
| 30 |
+
|
| 31 |
+
## Key outcomes from the recovered run logs
|
| 32 |
+
|
| 33 |
+
- Average reward improved from `0.4441` over the first `500` episodes to `0.5951` over the last `500`.
|
| 34 |
+
- Average hidden pass rate improved from `0.4625` to `0.6488`.
|
| 35 |
+
- Completion rate improved from `43.6%` to `59.6%`.
|
| 36 |
+
|
| 37 |
+
Final-500-episode breakdown:
|
| 38 |
+
|
| 39 |
+
| Difficulty | Episodes | Avg reward | Avg hidden pass rate | Completion rate |
|
| 40 |
+
| --- | ---: | ---: | ---: | ---: |
|
| 41 |
+
| Easy | 32 | 0.8390 | 0.8477 | 84.38% |
|
| 42 |
+
| Medium | 104 | 0.7892 | 0.8425 | 78.85% |
|
| 43 |
+
| Hard | 364 | 0.5182 | 0.5759 | 51.92% |
|
| 44 |
+
|
| 45 |
+
## Plots
|
| 46 |
+
|
| 47 |
+

|
| 48 |
+
|
| 49 |
+

|
| 50 |
+
|
| 51 |
+

|
| 52 |
+
|
| 53 |
+
## Training configuration snapshot
|
| 54 |
+
|
| 55 |
+
The full lightweight snapshot is committed in `artifacts/training_status_snapshot.json`. Key settings:
|
| 56 |
+
|
| 57 |
+
- learning rate: `5e-6`
|
| 58 |
+
- batch size: `1`
|
| 59 |
+
- gradient accumulation steps: `8`
|
| 60 |
+
- num generations: `4`
|
| 61 |
+
- max prompt length: `1024`
|
| 62 |
+
- max completion length: `384`
|
| 63 |
+
- LoRA rank: `16`
|
| 64 |
+
- LoRA alpha: `32`
|
| 65 |
+
- 4-bit loading: `true`
|
| 66 |
+
|
| 67 |
+
## Why the repo URL is the right form entry
|
| 68 |
+
|
| 69 |
+
The hackathon form explicitly allows a public Hugging Face repository URL in place of a Colab notebook. Since this team trained on Hugging Face directly, the repository URL is the most accurate submission target: it contains the training code, the evidence plots, and the run summary in one public place.
|
artifacts/family_productivity.svg
ADDED
|
|
artifacts/pass_rate_by_difficulty.svg
ADDED
|
|
artifacts/results_summary.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"run_id": "15940d1d-7d8c-4253-8810-2ea934bedee4",
|
| 3 |
+
"episodes": 7600,
|
| 4 |
+
"train_steps_reported": 950,
|
| 5 |
+
"wall_clock_hours": 8.964,
|
| 6 |
+
"first_500": {
|
| 7 |
+
"avg_reward": 0.4441,
|
| 8 |
+
"avg_pass_rate": 0.4625,
|
| 9 |
+
"completion_rate": 0.436
|
| 10 |
+
},
|
| 11 |
+
"last_500": {
|
| 12 |
+
"avg_reward": 0.5951,
|
| 13 |
+
"avg_pass_rate": 0.6488,
|
| 14 |
+
"completion_rate": 0.596
|
| 15 |
+
},
|
| 16 |
+
"difficulty_last_500": {
|
| 17 |
+
"easy": {
|
| 18 |
+
"episodes": 32,
|
| 19 |
+
"avg_reward": 0.839,
|
| 20 |
+
"avg_pass_rate": 0.8477,
|
| 21 |
+
"completion_rate": 0.8438
|
| 22 |
+
},
|
| 23 |
+
"medium": {
|
| 24 |
+
"episodes": 104,
|
| 25 |
+
"avg_reward": 0.7892,
|
| 26 |
+
"avg_pass_rate": 0.8425,
|
| 27 |
+
"completion_rate": 0.7885
|
| 28 |
+
},
|
| 29 |
+
"hard": {
|
| 30 |
+
"episodes": 364,
|
| 31 |
+
"avg_reward": 0.5182,
|
| 32 |
+
"avg_pass_rate": 0.5759,
|
| 33 |
+
"completion_rate": 0.5192
|
| 34 |
+
}
|
| 35 |
+
},
|
| 36 |
+
"top_productive_families_final": [
|
| 37 |
+
"smallest_most_frequent",
|
| 38 |
+
"merge_intervals",
|
| 39 |
+
"matrix_diagonal_sum",
|
| 40 |
+
"fizzbuzz_variant",
|
| 41 |
+
"group_anagrams_count",
|
| 42 |
+
"max_subarray_sum",
|
| 43 |
+
"two_sum_count",
|
| 44 |
+
"balanced_brackets"
|
| 45 |
+
]
|
| 46 |
+
}
|
artifacts/reward_curve.svg
ADDED
|
|
artifacts/training_status_snapshot.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"status": "succeeded",
|
| 3 |
+
"run_id": "15940d1d-7d8c-4253-8810-2ea934bedee4",
|
| 4 |
+
"started_at": "2026-04-25T22:21:10.584881+00:00",
|
| 5 |
+
"finished_at": "2026-04-26T07:19:01.232852+00:00",
|
| 6 |
+
"model_repo_id": "Dishaaa25/adapt-dsa-tutor-model",
|
| 7 |
+
"uploaded_revision": "6c957e7c6bdb25ff086775fb8692570aee4501c9",
|
| 8 |
+
"phase": "completed",
|
| 9 |
+
"completed_steps": 950,
|
| 10 |
+
"total_steps": 950,
|
| 11 |
+
"train_episode_index": 7600,
|
| 12 |
+
"current_difficulty": "hard",
|
| 13 |
+
"last_problem_id": "reverse_words_8c8524b3",
|
| 14 |
+
"last_problem_family": "reverse_words",
|
| 15 |
+
"last_pass_rate": 1.0,
|
| 16 |
+
"last_visible_pass_rate": 1.0,
|
| 17 |
+
"last_reward": 1.0,
|
| 18 |
+
"last_execution_status": "completed",
|
| 19 |
+
"timing_summary": {
|
| 20 |
+
"wall_clock_seconds": 32254.3,
|
| 21 |
+
"wall_clock_minutes": 537.57,
|
| 22 |
+
"wall_clock_hours": 8.96,
|
| 23 |
+
"completed_steps": 950,
|
| 24 |
+
"train_episode_count": 7600,
|
| 25 |
+
"configured_dataset_size": 1024,
|
| 26 |
+
"configured_batch_size": 1,
|
| 27 |
+
"configured_gradient_accumulation_steps": 8,
|
| 28 |
+
"configured_num_generations": 4,
|
| 29 |
+
"avg_seconds_per_step": 33.95,
|
| 30 |
+
"steps_per_hour": 106.03,
|
| 31 |
+
"avg_seconds_per_episode": 4.24,
|
| 32 |
+
"episodes_per_hour": 848.26
|
| 33 |
+
},
|
| 34 |
+
"config": {
|
| 35 |
+
"model_name": "Qwen/Qwen2.5-3B-Instruct",
|
| 36 |
+
"dataset_size": 1024,
|
| 37 |
+
"max_steps": 950,
|
| 38 |
+
"batch_size": 1,
|
| 39 |
+
"gradient_accumulation_steps": 8,
|
| 40 |
+
"num_generations": 4,
|
| 41 |
+
"max_seq_length": 2048,
|
| 42 |
+
"max_prompt_length": 1024,
|
| 43 |
+
"max_completion_length": 384,
|
| 44 |
+
"learning_rate": 5e-6,
|
| 45 |
+
"lora_rank": 16,
|
| 46 |
+
"lora_alpha": 32,
|
| 47 |
+
"load_in_4bit": true,
|
| 48 |
+
"gradient_checkpointing": true,
|
| 49 |
+
"bf16": false,
|
| 50 |
+
"baseline_eval": false,
|
| 51 |
+
"evaluation_episodes": 20,
|
| 52 |
+
"disable_wandb": true,
|
| 53 |
+
"generator_mode": "reward_aware",
|
| 54 |
+
"trace_logging_enabled": true,
|
| 55 |
+
"save_steps": 50,
|
| 56 |
+
"save_total_limit": 3,
|
| 57 |
+
"upload_checkpoints_to_hub": true
|
| 58 |
+
}
|
| 59 |
+
}
|
requirements.txt
CHANGED
|
@@ -7,3 +7,4 @@ huggingface_hub>=0.34.0,<0.36
|
|
| 7 |
datasets>=2.18.0
|
| 8 |
transformers>=4.51.3,<5.7
|
| 9 |
peft>=0.18.0,<0.20
|
|
|
|
|
|
| 7 |
datasets>=2.18.0
|
| 8 |
transformers>=4.51.3,<5.7
|
| 9 |
peft>=0.18.0,<0.20
|
| 10 |
+
unsloth==2026.3.5
|
server/requirements.txt
CHANGED
|
@@ -6,3 +6,4 @@ httpx>=0.28.0
|
|
| 6 |
huggingface_hub>=0.34.0,<0.36
|
| 7 |
transformers>=4.51.3,<5.7
|
| 8 |
peft>=0.18.0,<0.20
|
|
|
|
|
|
| 6 |
huggingface_hub>=0.34.0,<0.36
|
| 7 |
transformers>=4.51.3,<5.7
|
| 8 |
peft>=0.18.0,<0.20
|
| 9 |
+
unsloth==2026.3.5
|
server/runtime.py
CHANGED
|
@@ -174,6 +174,32 @@ class SpaceModelRegistry:
|
|
| 174 |
) from exc
|
| 175 |
return torch, AutoPeftModelForCausalLM, (AutoModelForCausalLM, AutoTokenizer)
|
| 176 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 177 |
def _base_model_name(self) -> str:
|
| 178 |
return os.getenv("BASE_MODEL_NAME") or os.getenv("MODEL_NAME") or "Qwen/Qwen2.5-3B-Instruct"
|
| 179 |
|
|
@@ -264,15 +290,23 @@ class SpaceModelRegistry:
|
|
| 264 |
dtype = torch.float16
|
| 265 |
else:
|
| 266 |
dtype = torch.float32
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
base_model_name,
|
| 272 |
-
device_map="auto",
|
| 273 |
-
torch_dtype=dtype,
|
| 274 |
)
|
| 275 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 276 |
self._base_model = model
|
| 277 |
self._base_tokenizer = tokenizer
|
| 278 |
self._set_state(
|
|
@@ -307,17 +341,27 @@ class SpaceModelRegistry:
|
|
| 307 |
dtype = torch.float16
|
| 308 |
else:
|
| 309 |
dtype = torch.float32
|
| 310 |
-
tokenizer = AutoTokenizer.from_pretrained(str(artifact_dir))
|
| 311 |
-
if tokenizer.pad_token is None and tokenizer.eos_token is not None:
|
| 312 |
-
tokenizer.pad_token = tokenizer.eos_token
|
| 313 |
-
|
| 314 |
if (artifact_dir / "adapter_config.json").exists():
|
| 315 |
-
|
| 316 |
-
str(artifact_dir),
|
| 317 |
-
|
| 318 |
-
|
| 319 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 320 |
else:
|
|
|
|
|
|
|
|
|
|
| 321 |
model = AutoModelForCausalLM.from_pretrained(
|
| 322 |
str(artifact_dir),
|
| 323 |
device_map="auto",
|
|
|
|
| 174 |
) from exc
|
| 175 |
return torch, AutoPeftModelForCausalLM, (AutoModelForCausalLM, AutoTokenizer)
|
| 176 |
|
| 177 |
+
def _load_with_unsloth(
|
| 178 |
+
self,
|
| 179 |
+
*,
|
| 180 |
+
model_name: str,
|
| 181 |
+
dtype: Any,
|
| 182 |
+
load_in_4bit: bool,
|
| 183 |
+
max_seq_length: int = 2048,
|
| 184 |
+
) -> tuple[Any, Any] | None:
|
| 185 |
+
try:
|
| 186 |
+
from unsloth import FastLanguageModel
|
| 187 |
+
except ImportError:
|
| 188 |
+
return None
|
| 189 |
+
|
| 190 |
+
model, tokenizer = FastLanguageModel.from_pretrained(
|
| 191 |
+
model_name=model_name,
|
| 192 |
+
max_seq_length=max_seq_length,
|
| 193 |
+
dtype=dtype,
|
| 194 |
+
load_in_4bit=load_in_4bit,
|
| 195 |
+
)
|
| 196 |
+
if tokenizer.pad_token is None and tokenizer.eos_token is not None:
|
| 197 |
+
tokenizer.pad_token = tokenizer.eos_token
|
| 198 |
+
if hasattr(FastLanguageModel, "for_inference"):
|
| 199 |
+
FastLanguageModel.for_inference(model)
|
| 200 |
+
model.eval()
|
| 201 |
+
return model, tokenizer
|
| 202 |
+
|
| 203 |
def _base_model_name(self) -> str:
|
| 204 |
return os.getenv("BASE_MODEL_NAME") or os.getenv("MODEL_NAME") or "Qwen/Qwen2.5-3B-Instruct"
|
| 205 |
|
|
|
|
| 290 |
dtype = torch.float16
|
| 291 |
else:
|
| 292 |
dtype = torch.float32
|
| 293 |
+
unsloth_stack = self._load_with_unsloth(
|
| 294 |
+
model_name=base_model_name,
|
| 295 |
+
dtype=dtype,
|
| 296 |
+
load_in_4bit=torch.cuda.is_available(),
|
|
|
|
|
|
|
|
|
|
| 297 |
)
|
| 298 |
+
if unsloth_stack is not None:
|
| 299 |
+
model, tokenizer = unsloth_stack
|
| 300 |
+
else:
|
| 301 |
+
tokenizer = AutoTokenizer.from_pretrained(base_model_name)
|
| 302 |
+
if tokenizer.pad_token is None and tokenizer.eos_token is not None:
|
| 303 |
+
tokenizer.pad_token = tokenizer.eos_token
|
| 304 |
+
model = AutoModelForCausalLM.from_pretrained(
|
| 305 |
+
base_model_name,
|
| 306 |
+
device_map="auto",
|
| 307 |
+
torch_dtype=dtype,
|
| 308 |
+
)
|
| 309 |
+
model.eval()
|
| 310 |
self._base_model = model
|
| 311 |
self._base_tokenizer = tokenizer
|
| 312 |
self._set_state(
|
|
|
|
| 341 |
dtype = torch.float16
|
| 342 |
else:
|
| 343 |
dtype = torch.float32
|
|
|
|
|
|
|
|
|
|
|
|
|
| 344 |
if (artifact_dir / "adapter_config.json").exists():
|
| 345 |
+
unsloth_stack = self._load_with_unsloth(
|
| 346 |
+
model_name=str(artifact_dir),
|
| 347 |
+
dtype=dtype,
|
| 348 |
+
load_in_4bit=torch.cuda.is_available(),
|
| 349 |
)
|
| 350 |
+
if unsloth_stack is not None:
|
| 351 |
+
model, tokenizer = unsloth_stack
|
| 352 |
+
else:
|
| 353 |
+
tokenizer = AutoTokenizer.from_pretrained(str(artifact_dir))
|
| 354 |
+
if tokenizer.pad_token is None and tokenizer.eos_token is not None:
|
| 355 |
+
tokenizer.pad_token = tokenizer.eos_token
|
| 356 |
+
model = AutoPeftModelForCausalLM.from_pretrained(
|
| 357 |
+
str(artifact_dir),
|
| 358 |
+
device_map="auto",
|
| 359 |
+
torch_dtype=dtype,
|
| 360 |
+
)
|
| 361 |
else:
|
| 362 |
+
tokenizer = AutoTokenizer.from_pretrained(str(artifact_dir))
|
| 363 |
+
if tokenizer.pad_token is None and tokenizer.eos_token is not None:
|
| 364 |
+
tokenizer.pad_token = tokenizer.eos_token
|
| 365 |
model = AutoModelForCausalLM.from_pretrained(
|
| 366 |
str(artifact_dir),
|
| 367 |
device_map="auto",
|