vanishingradient commited on
Commit
7ca973d
·
verified ·
1 Parent(s): 5ee5b9f

Add kaggle/train_grpo.py

Browse files
Files changed (1) hide show
  1. kaggle/train_grpo.py +51 -15
kaggle/train_grpo.py CHANGED
@@ -173,11 +173,13 @@ _TOOL_CALL_RE = re.compile(
173
 
174
 
175
  def _env_tool_callables(env: Any) -> list[Callable[..., str]]:
176
- return [
177
- getattr(env, name)
 
178
  for name, _ in inspect.getmembers(type(env), predicate=inspect.isfunction)
179
  if name not in ("reset", "get_reward") and not name.startswith("_")
180
  ]
 
181
 
182
 
183
  def _parse_tool_calls(text: str) -> list[dict[str, Any]]:
@@ -227,7 +229,8 @@ def run_heldout_agent_eval(
227
  messages = [{"role": "user", "content": str(prompt or "")}]
228
 
229
  final_text = ""
230
- for _turn in range(max_turns):
 
231
  try:
232
  prompt_text = tokenizer.apply_chat_template(
233
  messages,
@@ -242,19 +245,40 @@ def run_heldout_agent_eval(
242
  except Exception:
243
  prompt_text = messages[-1]["content"] if messages else ""
244
 
245
- inputs = tokenizer(prompt_text, return_tensors="pt")
246
- inputs = {k: v.to(model.device) for k, v in inputs.items()}
247
- with torch.no_grad():
248
- out = model.generate(
249
- **inputs,
250
- max_new_tokens=max_new_tokens,
251
- do_sample=False,
252
- pad_token_id=tokenizer.eos_token_id,
253
- )
254
- gen = out[0][inputs["input_ids"].shape[-1] :]
255
- completion = tokenizer.decode(gen, skip_special_tokens=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
256
  final_text = completion
257
- calls = _parse_tool_calls(completion)
258
  messages.append({"role": "assistant", "content": completion})
259
  if not calls:
260
  break
@@ -295,6 +319,11 @@ def run_heldout_agent_eval(
295
  "reward_total": reward,
296
  "resolved": bool(report.get("resolved")),
297
  "resolution": report.get("resolution"),
 
 
 
 
 
298
  }
299
  )
300
  except Exception as e: # noqa: BLE001
@@ -311,6 +340,10 @@ def run_heldout_agent_eval(
311
  }
312
  )
313
  finally:
 
 
 
 
314
  try:
315
  env._cleanup()
316
  except Exception:
@@ -373,6 +406,9 @@ def langfuse_log_ckpt_eval(
373
  "pass_frac": r.get("pass_frac"),
374
  "reward_total": r.get("reward_total"),
375
  "resolved": r.get("resolved"),
 
 
 
376
  }
377
  )
378
  summary = {
 
173
 
174
 
175
  def _env_tool_callables(env: Any) -> list[Callable[..., str]]:
176
+ # Bound methods so held-out eval can call fn(**kwargs); TRL uses class functions itself.
177
+ names = [
178
+ name
179
  for name, _ in inspect.getmembers(type(env), predicate=inspect.isfunction)
180
  if name not in ("reset", "get_reward") and not name.startswith("_")
181
  ]
182
+ return [getattr(env, name) for name in names]
183
 
184
 
185
  def _parse_tool_calls(text: str) -> list[dict[str, Any]]:
 
229
  messages = [{"role": "user", "content": str(prompt or "")}]
230
 
231
  final_text = ""
232
+ lf = getattr(env, "_lf", None)
233
+ for turn in range(max_turns):
234
  try:
235
  prompt_text = tokenizer.apply_chat_template(
236
  messages,
 
245
  except Exception:
246
  prompt_text = messages[-1]["content"] if messages else ""
247
 
248
+ def _generate_once() -> str:
249
+ inputs_local = tokenizer(prompt_text, return_tensors="pt")
250
+ inputs_local = {k: v.to(model.device) for k, v in inputs_local.items()}
251
+ with torch.no_grad():
252
+ out_ids = model.generate(
253
+ **inputs_local,
254
+ max_new_tokens=max_new_tokens,
255
+ do_sample=False,
256
+ pad_token_id=tokenizer.eos_token_id,
257
+ )
258
+ gen_ids = out_ids[0][inputs_local["input_ids"].shape[-1] :]
259
+ return tokenizer.decode(gen_ids, skip_special_tokens=True)
260
+
261
+ if lf is not None and getattr(env, "_root", None) is not None:
262
+ with lf.start_as_current_observation(
263
+ name=f"llm-turn-{turn}",
264
+ as_type="generation",
265
+ input={"messages_tail": messages[-2:], "turn": turn},
266
+ metadata={"phase": "ckpt_eval", "turn": turn},
267
+ ) as gen_span:
268
+ completion = _generate_once()
269
+ calls = _parse_tool_calls(completion)
270
+ gen_span.update(
271
+ output={
272
+ "completion": completion[:4000],
273
+ "n_tool_calls": len(calls),
274
+ "tool_names": [c["name"] for c in calls],
275
+ }
276
+ )
277
+ else:
278
+ completion = _generate_once()
279
+ calls = _parse_tool_calls(completion)
280
+
281
  final_text = completion
 
282
  messages.append({"role": "assistant", "content": completion})
283
  if not calls:
284
  break
 
319
  "reward_total": reward,
320
  "resolved": bool(report.get("resolved")),
321
  "resolution": report.get("resolution"),
322
+ "n_tool_calls": len(getattr(env, "_tool_calls", []) or []),
323
+ "tools_used": [
324
+ c.get("name") for c in (getattr(env, "_tool_calls", []) or [])
325
+ ],
326
+ "langfuse_trace_id": getattr(env, "_trace_id", "") or "",
327
  }
328
  )
329
  except Exception as e: # noqa: BLE001
 
340
  }
341
  )
342
  finally:
343
+ try:
344
+ env._end_trace()
345
+ except Exception:
346
+ pass
347
  try:
348
  env._cleanup()
349
  except Exception:
 
406
  "pass_frac": r.get("pass_frac"),
407
  "reward_total": r.get("reward_total"),
408
  "resolved": r.get("resolved"),
409
+ "n_tool_calls": r.get("n_tool_calls"),
410
+ "tools_used": r.get("tools_used"),
411
+ "rollout_trace_id": r.get("langfuse_trace_id"),
412
  }
413
  )
414
  summary = {