soonvalley04 commited on
Commit
2cb1b63
·
verified ·
1 Parent(s): c40b9d8

Delete inference_lora.py

Browse files
Files changed (1) hide show
  1. inference_lora.py +0 -210
inference_lora.py DELETED
@@ -1,210 +0,0 @@
1
- """
2
- inference_lora.py — Local LoRA Inference for Split-Brain Environment
3
- =====================================================================
4
- Loads the GRPO-trained LoRA adapter (openenv-split-brain-lora/) on top of
5
- Llama-3.2-3B-Instruct and runs it against the Split-Brain environment.
6
-
7
- Usage (requires GPU with >=6GB VRAM, or run on Colab):
8
- pip install unsloth peft transformers torch
9
- python inference_lora.py
10
-
11
- This script demonstrates the improvement of the fine-tuned model over
12
- the base model on the Split-Brain cascading_deadlock task (Task 4).
13
- """
14
-
15
- import os
16
- import json
17
- import re
18
- import torch
19
- from typing import List, Optional
20
-
21
- from agents.split_brain.environment import SplitBrainEnv
22
- from agents.split_brain.models import SplitBrainAction
23
-
24
- # ── 1. Load Model + LoRA Adapter ────────────────────────────────────────────
25
-
26
- LORA_PATH = os.path.join(os.path.dirname(__file__), "openenv-split-brain-lora")
27
- BASE_MODEL = "unsloth/Llama-3.2-3B-Instruct-bnb-4bit"
28
- MAX_STEPS = 15
29
-
30
- print(f"[INFO] Loading base model: {BASE_MODEL}")
31
- print(f"[INFO] Applying LoRA adapter from: {LORA_PATH}")
32
-
33
- try:
34
- from unsloth import FastLanguageModel
35
-
36
- model, tokenizer = FastLanguageModel.from_pretrained(
37
- model_name=BASE_MODEL,
38
- max_seq_length=1024,
39
- load_in_4bit=True,
40
- fast_inference=False,
41
- )
42
- # Load the trained LoRA weights on top
43
- model.load_adapter(LORA_PATH, adapter_name="split_brain_lora")
44
- FastLanguageModel.for_inference(model)
45
- print("[INFO] LoRA adapter loaded successfully via Unsloth.")
46
- USE_UNSLOTH = True
47
-
48
- except ImportError:
49
- # Fallback: use raw transformers + PEFT (no Unsloth needed)
50
- from transformers import AutoModelForCausalLM, AutoTokenizer
51
- from peft import PeftModel
52
-
53
- print("[INFO] Unsloth not available, falling back to transformers + PEFT...")
54
- tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL)
55
- base_model = AutoModelForCausalLM.from_pretrained(
56
- BASE_MODEL,
57
- torch_dtype=torch.float16,
58
- device_map="auto",
59
- )
60
- model = PeftModel.from_pretrained(base_model, LORA_PATH)
61
- model.eval()
62
- print("[INFO] LoRA adapter loaded successfully via PEFT.")
63
- USE_UNSLOTH = False
64
-
65
-
66
- # ── 2. Local Generation Function ────────────────────────────────────────────
67
-
68
- def generate_action(system_prompt: str, user_prompt: str) -> str:
69
- """Generate a single action using the local LoRA-tuned model."""
70
- messages = [
71
- {"role": "system", "content": system_prompt},
72
- {"role": "user", "content": user_prompt},
73
- ]
74
-
75
- input_text = tokenizer.apply_chat_template(
76
- messages, tokenize=False, add_generation_prompt=True
77
- )
78
- inputs = tokenizer(input_text, return_tensors="pt").to(model.device)
79
-
80
- with torch.no_grad():
81
- outputs = model.generate(
82
- **inputs,
83
- max_new_tokens=256,
84
- temperature=0.1,
85
- do_sample=True,
86
- top_p=0.9,
87
- pad_token_id=tokenizer.eos_token_id,
88
- )
89
-
90
- # Decode only the generated tokens (skip the prompt)
91
- generated = outputs[0][inputs["input_ids"].shape[1]:]
92
- return tokenizer.decode(generated, skip_special_tokens=True)
93
-
94
-
95
- # ── 3. Parse LLM Output into Action ─────────────────────────────────────────
96
-
97
- def parse_action(text: str) -> SplitBrainAction:
98
- """Extract a JSON action from the model's output text."""
99
- # Strip thinking blocks
100
- text = re.sub(r'<think>.*?</think>', '', text, flags=re.DOTALL).strip()
101
- text = text.replace("```json", "").replace("```", "").strip()
102
-
103
- match = re.search(r'\{.*\}', text, re.DOTALL)
104
- if match:
105
- try:
106
- data = json.loads(match.group(0))
107
- if "action_type" in data:
108
- return SplitBrainAction(**data)
109
- except Exception:
110
- pass
111
-
112
- # Fallback: noop
113
- return SplitBrainAction(action_type="noop")
114
-
115
-
116
- # ── 4. Run the Split-Brain Episode ──────────────────────────────────────────
117
-
118
- def run_episode(task_id: str = "cascading_deadlock") -> dict:
119
- """Run a full episode on the Split-Brain environment using the LoRA model."""
120
- env = SplitBrainEnv()
121
- obs = env.reset(task=task_id)
122
-
123
- rewards: List[float] = []
124
- actions_taken: List[str] = []
125
- total_reward = 0.0
126
-
127
- print(f"\n{'='*70}")
128
- print(f" SPLIT-BRAIN LORA INFERENCE — Task: {task_id}")
129
- print(f" Model: {BASE_MODEL} + LoRA ({LORA_PATH})")
130
- print(f"{'='*70}\n")
131
-
132
- for step in range(1, MAX_STEPS + 1):
133
- # Get prompts from the environment (multi-agent aware)
134
- system_prompt, user_prompt = env.get_llm_prompts()
135
- actor = env.state_data.current_actor
136
-
137
- # Generate action with the LoRA model
138
- raw_text = generate_action(system_prompt, user_prompt)
139
- action = parse_action(raw_text)
140
-
141
- # Step the environment
142
- result = env.step(action)
143
- reward = result.reward
144
- done = result.done
145
- msg = result.info.get("message", "")
146
-
147
- rewards.append(reward)
148
- total_reward += reward
149
- actions_taken.append(action.action_type)
150
-
151
- print(f"Step {step:2d} [{actor}] {action.action_type}"
152
- f"{(' → ' + action.target_id) if action.target_id else ''}")
153
- print(f" reward={reward:+.3f} | {msg}")
154
-
155
- if done:
156
- print(f"\n{'─'*70}")
157
- print(f" ✅ EPISODE COMPLETE at step {step}")
158
- break
159
- else:
160
- print(f"\n{'─'*70}")
161
- print(f" ⏱ MAX STEPS REACHED ({MAX_STEPS})")
162
-
163
- # Summary
164
- final_health = env.state_data.global_health
165
- success = final_health >= 1.0
166
-
167
- print(f" Final Health: {final_health:.2f}")
168
- print(f" Total Reward: {total_reward:.3f}")
169
- print(f" Success: {'YES ✅' if success else 'NO ❌'}")
170
- print(f" Actions: {' → '.join(actions_taken)}")
171
- print(f"{'='*70}\n")
172
-
173
- # Detect if the model got stuck in a loop
174
- diagnostic_count = actions_taken.count("run_diagnostic")
175
- if diagnostic_count > 2:
176
- print(f" ⚠️ WARNING: Model ran diagnostic {diagnostic_count} times (loop detected)")
177
- elif diagnostic_count <= 1:
178
- print(f" ✅ IMPROVEMENT: Model avoided the diagnostic loop!")
179
-
180
- return {
181
- "task": task_id,
182
- "success": success,
183
- "steps": len(rewards),
184
- "total_reward": total_reward,
185
- "final_health": final_health,
186
- "actions": actions_taken,
187
- "diagnostic_loops": diagnostic_count,
188
- }
189
-
190
-
191
- # ── 5. Main ─────────────────────────────────────────────────────────────────
192
-
193
- if __name__ == "__main__":
194
- # Run the task that was previously failing with the base 8B model
195
- result = run_episode("cascading_deadlock")
196
-
197
- print("\n" + "="*70)
198
- print(" COMPARISON SUMMARY")
199
- print("="*70)
200
- print(f" Before (base Llama 3.1 8B, no LoRA):")
201
- print(f" → Stuck in infinite run_diagnostic loop (10+ repeats)")
202
- print(f" → Never executed update_route, verify_routing, etc.")
203
- print(f" → Episode timed out with minimal reward")
204
- print(f"")
205
- print(f" After (Llama 3.2 3B + GRPO LoRA):")
206
- print(f" → Diagnostic loops: {result['diagnostic_loops']}")
207
- print(f" → Actions taken: {' → '.join(result['actions'])}")
208
- print(f" → Final health: {result['final_health']:.2f}")
209
- print(f" → Success: {'YES ✅' if result['success'] else 'NO ❌'}")
210
- print("="*70)