sasukeUchiha123 commited on
Commit
ae1180d
·
verified ·
1 Parent(s): 5b2e2d7

Upload workloads/_runtime.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. workloads/_runtime.py +129 -0
workloads/_runtime.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Shared runtime helpers for the GPU Goblin workload scripts.
2
+
3
+ Why this exists: ``goblin_runner.sh`` invokes user scripts with
4
+ ``--max_steps=<N>`` and ``--torch_profile_out=<path>`` so rocprofv3 can
5
+ capture only a handful of training steps and ``profile_parser`` can read
6
+ real metrics back. Without ``--max_steps`` honored, scripts run for hours
7
+ and trip LiveRunner's timeout. Without the profile JSON, profile_parser
8
+ zeroes out ``tokens_per_sec`` / ``step_time_seconds`` and the agent has
9
+ nothing to reason about beyond config-shape alone.
10
+
11
+ Each workload script (``train_qwen_lora.py`` and the scenarios under
12
+ ``scenarios/``) imports this module rather than copy-pasting the
13
+ argparse + profile-write boilerplate.
14
+
15
+ Usage:
16
+
17
+ from workloads._runtime import parse_runtime_args, emit_torch_profile
18
+
19
+ runtime_args = parse_runtime_args()
20
+
21
+ ta_kwargs = dict(...)
22
+ if runtime_args.max_steps > 0:
23
+ ta_kwargs["max_steps"] = runtime_args.max_steps
24
+ ta_kwargs["num_train_epochs"] = 1 # max_steps wins, but be explicit
25
+ training_args = TrainingArguments(**ta_kwargs)
26
+
27
+ if __name__ == "__main__":
28
+ import time
29
+ t0 = time.time()
30
+ trainer.train()
31
+ emit_torch_profile(
32
+ runtime_args.torch_profile_out,
33
+ elapsed=time.time() - t0,
34
+ n_steps=int(trainer.state.global_step or runtime_args.max_steps),
35
+ per_device_batch=training_args.per_device_train_batch_size,
36
+ grad_accum=training_args.gradient_accumulation_steps,
37
+ seq_len_cap=512,
38
+ )
39
+ """
40
+
41
+ from __future__ import annotations
42
+
43
+ import argparse
44
+ import json
45
+ from dataclasses import dataclass
46
+
47
+
48
+ @dataclass
49
+ class RuntimeArgs:
50
+ max_steps: int
51
+ torch_profile_out: str
52
+
53
+
54
+ def parse_runtime_args() -> RuntimeArgs:
55
+ """Parse ``--max_steps`` and ``--torch_profile_out`` from sys.argv.
56
+
57
+ Uses ``parse_known_args`` so unrelated flags from libraries (HF Trainer,
58
+ accelerate, deepspeed) pass through untouched.
59
+ """
60
+ parser = argparse.ArgumentParser(add_help=False)
61
+ parser.add_argument(
62
+ "--max_steps",
63
+ type=int,
64
+ default=0,
65
+ help=(
66
+ "When >0, override TrainingArguments.max_steps so the script "
67
+ "stops after this many optimization steps. Passed in by "
68
+ "goblin_runner.sh — without it, profiling runs train for "
69
+ "hours and time out."
70
+ ),
71
+ )
72
+ parser.add_argument(
73
+ "--torch_profile_out",
74
+ type=str,
75
+ default="",
76
+ help=(
77
+ "Path to write a minimal torch_profile.json (tokens/sec + step "
78
+ "time) so runner/profile_parser populates RunMetrics with real "
79
+ "numbers."
80
+ ),
81
+ )
82
+ args, _ = parser.parse_known_args()
83
+ return RuntimeArgs(
84
+ max_steps=args.max_steps,
85
+ torch_profile_out=args.torch_profile_out,
86
+ )
87
+
88
+
89
+ def emit_torch_profile(
90
+ path: str,
91
+ *,
92
+ elapsed: float,
93
+ n_steps: int,
94
+ per_device_batch: int,
95
+ grad_accum: int = 1,
96
+ seq_len_cap: int = 512,
97
+ ) -> None:
98
+ """Write the smallest torch_profile-shape JSON profile_parser will read.
99
+
100
+ profile_parser._read_torch_profile looks for these top-level fields under
101
+ ``metadata``: tokens_per_sec, mfu_pct, step_time_seconds, pytorch_version.
102
+ We supply the first three and pytorch_version (mfu_pct is optional and
103
+ estimated downstream).
104
+
105
+ No-ops when ``path`` is empty (script run outside goblin_runner.sh) or
106
+ when ``n_steps`` is 0 (training crashed before finishing a step).
107
+ """
108
+ if not path or n_steps <= 0:
109
+ return
110
+ try:
111
+ import torch # local import — workload owns its own torch
112
+
113
+ global_batch = max(1, per_device_batch) * max(1, grad_accum)
114
+ approx_tokens = n_steps * global_batch * seq_len_cap
115
+ tokens_per_sec = approx_tokens / elapsed if elapsed > 0 else 0.0
116
+ payload = {
117
+ "metadata": {
118
+ "tokens_per_sec": round(tokens_per_sec, 2),
119
+ "step_time_seconds": round(elapsed / n_steps, 4),
120
+ "pytorch_version": torch.__version__,
121
+ "n_steps": n_steps,
122
+ }
123
+ }
124
+ with open(path, "w") as f:
125
+ json.dump(payload, f)
126
+ except Exception as exc: # pragma: no cover — diagnostic only
127
+ # Don't tank the run on a profile-emit failure; the agent will
128
+ # just see "fake" metrics for this step instead of "live".
129
+ print(f"[workloads._runtime] failed to write {path}: {exc}")