CreativeEngineer Claude Opus 4.6 commited on
Commit
2cb6617
Β·
1 Parent(s): 3b185f9

feat: upgrade notebook to Qwen3.5-4B with H100 hyperparams

Browse files

- Model: unsloth/Qwen3.5-4B (from Qwen3-0.6B)
- num_generations: 8 (from 4) for smoother GRPO advantages
- learning_rate: 5e-5 (from 2e-4) for more stable training
- per_device_train_batch_size: 8 (from 4)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

training/notebooks/fusion_design_lab_training.ipynb CHANGED
@@ -5,14 +5,14 @@
5
  "id": "7fb27b941602401d91542211134fc71a",
6
  "metadata": {},
7
  "source": [
8
- "# Fusion Design Lab \u2014 GRPO Training\n",
9
  "\n",
10
  "Train an LLM to optimize stellarator fusion reactor designs using **GRPO** (Group Relative Policy Optimization) with **Unsloth** and **TRL**.\n",
11
  "\n",
12
  "The agent interacts with a constrained optimization environment where it adjusts 4 geometric knobs of a stellarator boundary, aiming to **minimize max elongation** while satisfying 3 hard physics constraints:\n",
13
- "- `aspect_ratio \u2264 4.0`\n",
14
- "- `average_triangularity \u2264 -0.5`\n",
15
- "- `edge_iota_over_nfp \u2265 0.3`\n",
16
  "\n",
17
  "Each episode has **6 evaluations** budgeted. The agent produces a plan of actions and the environment scores it via the `constellaration` physics verifier.\n",
18
  "\n",
@@ -59,29 +59,7 @@
59
  "id": "72eea5119410473aa328ad9291626812",
60
  "metadata": {},
61
  "outputs": [],
62
- "source": [
63
- "from unsloth import FastLanguageModel\n",
64
- "\n",
65
- "MODEL_NAME = \"unsloth/Qwen3-0.6B\"\n",
66
- "MAX_SEQ_LENGTH = 2048\n",
67
- "\n",
68
- "model, tokenizer = FastLanguageModel.from_pretrained(\n",
69
- " model_name=MODEL_NAME,\n",
70
- " max_seq_length=MAX_SEQ_LENGTH,\n",
71
- " load_in_4bit=True,\n",
72
- " fast_inference=True,\n",
73
- ")\n",
74
- "\n",
75
- "model = FastLanguageModel.get_peft_model(\n",
76
- " model,\n",
77
- " r=32,\n",
78
- " target_modules=[\"q_proj\", \"k_proj\", \"v_proj\", \"o_proj\", \"gate_proj\", \"up_proj\", \"down_proj\"],\n",
79
- " lora_alpha=32,\n",
80
- " use_gradient_checkpointing=\"unsloth\",\n",
81
- ")\n",
82
- "\n",
83
- "print(f\"Model loaded: {MODEL_NAME}\")"
84
- ]
85
  },
86
  {
87
  "cell_type": "markdown",
@@ -220,7 +198,7 @@
220
  "source": [
221
  "## 6. Reward Function\n",
222
  "\n",
223
- "The environment reward executes each generated action plan in the stellarator environment and returns the cumulative low-fidelity Reward V0 from the live environment. The environment's built-in reward decomposes feasibility (+3/-3 crossing bonuses, feasibility progress), objective (max elongation improvement), step costs, and failure penalties \u2014 see `server/environment.py:_compute_reward_breakdown(...)`.\n",
224
  "\n",
225
  "For the current training workflow, the notebook ignores `submit` and does not auto-submit. GRPO therefore optimizes the low-fidelity `run` path only. The live observation telemetry still exposes `reward_breakdown` and `action_monitor` for debugging reward behavior.\n"
226
  ]
@@ -313,41 +291,7 @@
313
  "id": "8a65eabff63a45729fe45fb5ade58bdc",
314
  "metadata": {},
315
  "outputs": [],
316
- "source": [
317
- "from trl import GRPOConfig, GRPOTrainer\n",
318
- "\n",
319
- "MAX_PROMPT_LENGTH = 768\n",
320
- "MAX_COMPLETION_LENGTH = MAX_SEQ_LENGTH - MAX_PROMPT_LENGTH\n",
321
- "\n",
322
- "training_args = GRPOConfig(\n",
323
- " output_dir=\"./grpo_fusion_output\",\n",
324
- " learning_rate=2e-4,\n",
325
- " num_generations=4,\n",
326
- " max_completion_length=MAX_COMPLETION_LENGTH,\n",
327
- " max_prompt_length=MAX_PROMPT_LENGTH,\n",
328
- " per_device_train_batch_size=4,\n",
329
- " gradient_accumulation_steps=1,\n",
330
- " max_steps=60,\n",
331
- " temperature=1.0,\n",
332
- " logging_steps=1,\n",
333
- " save_steps=20,\n",
334
- " bf16=True,\n",
335
- " report_to=\"none\",\n",
336
- " seed=42,\n",
337
- ")\n",
338
- "\n",
339
- "trainer = GRPOTrainer(\n",
340
- " model=model,\n",
341
- " processing_class=tokenizer,\n",
342
- " reward_funcs=[environment_reward_fn],\n",
343
- " args=training_args,\n",
344
- " train_dataset=dataset,\n",
345
- ")\n",
346
- "\n",
347
- "print(\"Starting GRPO training...\")\n",
348
- "train_result = trainer.train()\n",
349
- "print(f\"Training complete. Total steps: {train_result.global_step}\")"
350
- ]
351
  },
352
  {
353
  "cell_type": "markdown",
@@ -401,7 +345,7 @@
401
  "else:\n",
402
  " axes[1].text(0.5, 0.5, \"Reward metrics not logged\", ha=\"center\", va=\"center\")\n",
403
  "\n",
404
- "plt.suptitle(\"Fusion Design Lab \u2014 GRPO Training Curves\", fontsize=14, fontweight=\"bold\")\n",
405
  "plt.tight_layout()\n",
406
  "plt.savefig(\"training_curves.png\", dpi=150, bbox_inches=\"tight\")\n",
407
  "plt.show()\n",
@@ -474,7 +418,7 @@
474
  " episode = run_episode_with_actions(actions, seed_idx=seed_idx)\n",
475
  " trace = [\n",
476
  " (\n",
477
- " f\"{step.action_label} \u2192 reward={step.reward:.3f} \"\n",
478
  " f\"score={step.p1_score:.4f} feasible={step.constraints_satisfied} \"\n",
479
  " f\"terms={reward_term_summary(step)}\"\n",
480
  " )\n",
@@ -497,7 +441,7 @@
497
  "for seed in range(len(RESET_SEEDS)):\n",
498
  " reward, trace = run_episode_with_model(seed)\n",
499
  " trained_rewards.append(reward)\n",
500
- " print(f\"\\nSeed {seed} \u2014 Total reward: {reward:.3f}\")\n",
501
  " for line in trace:\n",
502
  " print(f\" {line}\")\n",
503
  "\n",
@@ -511,7 +455,7 @@
511
  " seed_rewards = [run_random_episode(seed) for _ in range(10)]\n",
512
  " random_rewards.extend(seed_rewards)\n",
513
  " print(\n",
514
- " f\"Seed {seed} \u2014 Mean: {sum(seed_rewards) / len(seed_rewards):.3f}, Best: {max(seed_rewards):.3f}\"\n",
515
  " )\n",
516
  "\n",
517
  "print(f\"\\nMean random reward: {sum(random_rewards) / len(random_rewards):.3f}\")\n",
@@ -550,7 +494,7 @@
550
  "with FusionLabClient(base_url=HF_SPACE_URL) as env:\n",
551
  " reset_result = env.reset(seed=42)\n",
552
  " remote_obs = reset_result.observation\n",
553
- " print(f\"\\nRemote reset \u2014 max_elongation: {remote_obs.max_elongation:.4f}\")\n",
554
  " print(f\" aspect_ratio: {remote_obs.aspect_ratio:.4f}\")\n",
555
  " print(f\" constraints_satisfied: {remote_obs.constraints_satisfied}\")\n",
556
  " print(f\" budget_remaining: {remote_obs.budget_remaining}\")\n",
@@ -576,7 +520,7 @@
576
  " print(\n",
577
  " f\" Step {i}: {action.intent} {action.parameter or ''} \"\n",
578
  " f\"{action.direction or ''} {action.magnitude or ''} \"\n",
579
- " f\"\u2192 reward={reward:.3f}, score={step_obs.p1_score:.4f}, terms={reward_term_summary(step_obs)}\"\n",
580
  " )\n",
581
  " if result.done:\n",
582
  " print(f\" Episode done. Final score: {step_obs.p1_score:.4f}\")\n",
 
5
  "id": "7fb27b941602401d91542211134fc71a",
6
  "metadata": {},
7
  "source": [
8
+ "# Fusion Design Lab β€” GRPO Training\n",
9
  "\n",
10
  "Train an LLM to optimize stellarator fusion reactor designs using **GRPO** (Group Relative Policy Optimization) with **Unsloth** and **TRL**.\n",
11
  "\n",
12
  "The agent interacts with a constrained optimization environment where it adjusts 4 geometric knobs of a stellarator boundary, aiming to **minimize max elongation** while satisfying 3 hard physics constraints:\n",
13
+ "- `aspect_ratio ≀ 4.0`\n",
14
+ "- `average_triangularity ≀ -0.5`\n",
15
+ "- `edge_iota_over_nfp β‰₯ 0.3`\n",
16
  "\n",
17
  "Each episode has **6 evaluations** budgeted. The agent produces a plan of actions and the environment scores it via the `constellaration` physics verifier.\n",
18
  "\n",
 
59
  "id": "72eea5119410473aa328ad9291626812",
60
  "metadata": {},
61
  "outputs": [],
62
+ "source": "from unsloth import FastLanguageModel\n\nMODEL_NAME = \"unsloth/Qwen3.5-4B\"\nMAX_SEQ_LENGTH = 2048\n\nmodel, tokenizer = FastLanguageModel.from_pretrained(\n model_name=MODEL_NAME,\n max_seq_length=MAX_SEQ_LENGTH,\n load_in_4bit=True,\n fast_inference=True,\n)\n\nmodel = FastLanguageModel.get_peft_model(\n model,\n r=32,\n target_modules=[\"q_proj\", \"k_proj\", \"v_proj\", \"o_proj\", \"gate_proj\", \"up_proj\", \"down_proj\"],\n lora_alpha=32,\n use_gradient_checkpointing=\"unsloth\",\n)\n\nprint(f\"Model loaded: {MODEL_NAME}\")"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  },
64
  {
65
  "cell_type": "markdown",
 
198
  "source": [
199
  "## 6. Reward Function\n",
200
  "\n",
201
+ "The environment reward executes each generated action plan in the stellarator environment and returns the cumulative low-fidelity Reward V0 from the live environment. The environment's built-in reward decomposes feasibility (+3/-3 crossing bonuses, feasibility progress), objective (max elongation improvement), step costs, and failure penalties β€” see `server/environment.py:_compute_reward_breakdown(...)`.\n",
202
  "\n",
203
  "For the current training workflow, the notebook ignores `submit` and does not auto-submit. GRPO therefore optimizes the low-fidelity `run` path only. The live observation telemetry still exposes `reward_breakdown` and `action_monitor` for debugging reward behavior.\n"
204
  ]
 
291
  "id": "8a65eabff63a45729fe45fb5ade58bdc",
292
  "metadata": {},
293
  "outputs": [],
294
+ "source": "from trl import GRPOConfig, GRPOTrainer\n\nMAX_PROMPT_LENGTH = 768\nMAX_COMPLETION_LENGTH = MAX_SEQ_LENGTH - MAX_PROMPT_LENGTH\n\ntraining_args = GRPOConfig(\n output_dir=\"./grpo_fusion_output\",\n learning_rate=5e-5,\n num_generations=8,\n max_completion_length=MAX_COMPLETION_LENGTH,\n max_prompt_length=MAX_PROMPT_LENGTH,\n per_device_train_batch_size=8,\n gradient_accumulation_steps=1,\n max_steps=60,\n temperature=1.0,\n logging_steps=1,\n save_steps=20,\n bf16=True,\n report_to=\"none\",\n seed=42,\n)\n\ntrainer = GRPOTrainer(\n model=model,\n processing_class=tokenizer,\n reward_funcs=[environment_reward_fn],\n args=training_args,\n train_dataset=dataset,\n)\n\nprint(\"Starting GRPO training...\")\ntrain_result = trainer.train()\nprint(f\"Training complete. Total steps: {train_result.global_step}\")"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295
  },
296
  {
297
  "cell_type": "markdown",
 
345
  "else:\n",
346
  " axes[1].text(0.5, 0.5, \"Reward metrics not logged\", ha=\"center\", va=\"center\")\n",
347
  "\n",
348
+ "plt.suptitle(\"Fusion Design Lab β€” GRPO Training Curves\", fontsize=14, fontweight=\"bold\")\n",
349
  "plt.tight_layout()\n",
350
  "plt.savefig(\"training_curves.png\", dpi=150, bbox_inches=\"tight\")\n",
351
  "plt.show()\n",
 
418
  " episode = run_episode_with_actions(actions, seed_idx=seed_idx)\n",
419
  " trace = [\n",
420
  " (\n",
421
+ " f\"{step.action_label} β†’ reward={step.reward:.3f} \"\n",
422
  " f\"score={step.p1_score:.4f} feasible={step.constraints_satisfied} \"\n",
423
  " f\"terms={reward_term_summary(step)}\"\n",
424
  " )\n",
 
441
  "for seed in range(len(RESET_SEEDS)):\n",
442
  " reward, trace = run_episode_with_model(seed)\n",
443
  " trained_rewards.append(reward)\n",
444
+ " print(f\"\\nSeed {seed} β€” Total reward: {reward:.3f}\")\n",
445
  " for line in trace:\n",
446
  " print(f\" {line}\")\n",
447
  "\n",
 
455
  " seed_rewards = [run_random_episode(seed) for _ in range(10)]\n",
456
  " random_rewards.extend(seed_rewards)\n",
457
  " print(\n",
458
+ " f\"Seed {seed} β€” Mean: {sum(seed_rewards) / len(seed_rewards):.3f}, Best: {max(seed_rewards):.3f}\"\n",
459
  " )\n",
460
  "\n",
461
  "print(f\"\\nMean random reward: {sum(random_rewards) / len(random_rewards):.3f}\")\n",
 
494
  "with FusionLabClient(base_url=HF_SPACE_URL) as env:\n",
495
  " reset_result = env.reset(seed=42)\n",
496
  " remote_obs = reset_result.observation\n",
497
+ " print(f\"\\nRemote reset β€” max_elongation: {remote_obs.max_elongation:.4f}\")\n",
498
  " print(f\" aspect_ratio: {remote_obs.aspect_ratio:.4f}\")\n",
499
  " print(f\" constraints_satisfied: {remote_obs.constraints_satisfied}\")\n",
500
  " print(f\" budget_remaining: {remote_obs.budget_remaining}\")\n",
 
520
  " print(\n",
521
  " f\" Step {i}: {action.intent} {action.parameter or ''} \"\n",
522
  " f\"{action.direction or ''} {action.magnitude or ''} \"\n",
523
+ " f\"β†’ reward={reward:.3f}, score={step_obs.p1_score:.4f}, terms={reward_term_summary(step_obs)}\"\n",
524
  " )\n",
525
  " if result.done:\n",
526
  " print(f\" Episode done. Final score: {step_obs.p1_score:.4f}\")\n",