sasukeUchiha123 commited on
Commit
930182d
·
verified ·
1 Parent(s): 8c15a3c

Upload tests/fixtures/cached_audit.json with huggingface_hub

Browse files
Files changed (1) hide show
  1. tests/fixtures/cached_audit.json +1263 -0
tests/fixtures/cached_audit.json ADDED
@@ -0,0 +1,1263 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "type": "thought",
4
+ "data": {
5
+ "text": "User uploaded a Qwen2.5 LoRA fine-tuning script. I'll start by parsing the configuration and redacting any secrets, then profile a short run on MI300X before consulting the ROCm playbook for known wins."
6
+ }
7
+ },
8
+ {
9
+ "type": "tool_call",
10
+ "data": {
11
+ "id": "tc-1",
12
+ "name": "parse_config",
13
+ "input": {
14
+ "file_path": "workloads/train_qwen_lora.py"
15
+ }
16
+ }
17
+ },
18
+ {
19
+ "type": "tool_result",
20
+ "data": {
21
+ "id": "tc-1",
22
+ "name": "parse_config",
23
+ "ok": true,
24
+ "result": {
25
+ "model_name": "Qwen/Qwen2.5-7B-Instruct",
26
+ "batch_size": 4,
27
+ "grad_accum_steps": 8,
28
+ "seq_len": 1024,
29
+ "precision": "fp16",
30
+ "optimizer": "adamw_torch",
31
+ "attention_impl": "eager",
32
+ "gradient_checkpointing": false,
33
+ "lora_rank": 16,
34
+ "dataloader_workers": 0,
35
+ "dataloader_pin_memory": false,
36
+ "dataloader_prefetch_factor": 2,
37
+ "dataloader_persistent_workers": false,
38
+ "torch_compile": false,
39
+ "lr": 0.0002,
40
+ "warmup_steps": 100,
41
+ "env_vars": {
42
+ "HF_TOKEN": "hf_aaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
43
+ "HSA_FORCE_FINE_GRAIN_PCIE": "1",
44
+ "MIOPEN_FIND_MODE": "3"
45
+ },
46
+ "extras": {
47
+ "lora.lora_alpha": 32,
48
+ "lora.target_modules": [
49
+ "q_proj",
50
+ "v_proj"
51
+ ],
52
+ "lora.lora_dropout": 0.05,
53
+ "lora.bias": "none",
54
+ "lora.task_type": "CAUSAL_LM",
55
+ "batch_size": 4,
56
+ "output_dir": "./out",
57
+ "num_train_epochs": 3,
58
+ "logging_steps": 10,
59
+ "save_steps": 500,
60
+ "report_to": "none",
61
+ "push_to_hub": false
62
+ },
63
+ "raw_source": "# GPU Goblin canonical demo workload.\n#\n# Qwen2.5-7B-Instruct + LoRA fine-tune on the alpaca-cleaned dataset, staged with\n# *deliberately* sub-optimal defaults so the goblin has something to fix in\n# the demo. This script does NOT need to actually execute on a host \u2014 it\n# exists so `parse_config` can extract a realistic WorkloadConfig from it.\n#\n# Expected findings when audited:\n# - precision.bf16_over_fp16_on_mi300x (fp16=True)\n# - attention.flash_rocm_over_eager (attn_implementation=\"eager\")\n# - data.dataloader_workers_zero (dataloader_num_workers=0)\n# - memory.batch_too_small_for_192gb (per_device_train_batch_size=4)\n\nimport os\n\nimport torch\nfrom datasets import load_dataset\nfrom peft import LoraConfig, get_peft_model\nfrom torch.utils.data import DataLoader\nfrom transformers import (\n AutoModelForCausalLM,\n AutoTokenizer,\n Trainer,\n TrainingArguments,\n)\n\n# A redactable secret so parse_config has something to scrub during the demo.\nos.environ[\"HF_TOKEN\"] = \"<REDACTED:hf_token>\"\nHF_TOKEN = os.environ[\"HF_TOKEN\"]\n\n# ROCm-flavored env knobs the agent should pick up into env_vars.\nos.environ[\"HSA_FORCE_FINE_GRAIN_PCIE\"] = \"1\"\nos.environ[\"MIOPEN_FIND_MODE\"] = \"3\"\n\nMODEL_ID = \"Qwen/Qwen2.5-7B-Instruct\"\n\ntokenizer = AutoTokenizer.from_pretrained(MODEL_ID, token=HF_TOKEN)\nmodel = AutoModelForCausalLM.from_pretrained(\n MODEL_ID,\n torch_dtype=torch.float16,\n attn_implementation=\"eager\", # naive attention -- goblin should swap to flash_rocm\n token=HF_TOKEN,\n)\n\n# LoRA \u2014 rank 16, attached to attention projections.\nlora_config = LoraConfig(\n r=16,\n lora_alpha=32,\n target_modules=[\"q_proj\", \"v_proj\"],\n lora_dropout=0.05,\n bias=\"none\",\n task_type=\"CAUSAL_LM\",\n)\nmodel = get_peft_model(model, lora_config)\n\ndataset = load_dataset(\"yahma/alpaca-cleaned\", split=\"train\")\n\n# Hand-rolled DataLoader so parse_config sees the dataloader kwargs explicitly.\ntrain_loader = DataLoader(\n dataset,\n batch_size=4,\n num_workers=0, # leaves the GPU starved during training -- data_wait waste\n pin_memory=False,\n prefetch_factor=2,\n persistent_workers=False,\n)\n\ntraining_args = TrainingArguments(\n output_dir=\"./out\",\n per_device_train_batch_size=4, # leaves HBM on the floor at 192 GB\n gradient_accumulation_steps=8,\n num_train_epochs=3,\n learning_rate=2e-4,\n warmup_steps=100,\n fp16=True, # bf16 is the right call on CDNA3\n optim=\"adamw_torch\",\n logging_steps=10,\n save_steps=500,\n dataloader_num_workers=0,\n dataloader_pin_memory=False,\n gradient_checkpointing=False,\n torch_compile=False,\n report_to=\"none\",\n push_to_hub=False,\n)\n\ntrainer = Trainer(\n model=model,\n args=training_args,\n train_dataset=dataset,\n tokenizer=tokenizer,\n)\n\nif __name__ == \"__main__\":\n trainer.train()\n",
64
+ "redactions": [
65
+ "hf_token"
66
+ ]
67
+ }
68
+ }
69
+ },
70
+ {
71
+ "type": "tool_call",
72
+ "data": {
73
+ "id": "tc-2",
74
+ "name": "profile_run",
75
+ "input": {
76
+ "config": {
77
+ "model_name": "Qwen/Qwen2.5-7B-Instruct",
78
+ "batch_size": 4,
79
+ "grad_accum_steps": 8,
80
+ "seq_len": 1024,
81
+ "precision": "fp16",
82
+ "optimizer": "adamw_torch",
83
+ "attention_impl": "eager",
84
+ "gradient_checkpointing": false,
85
+ "lora_rank": 16,
86
+ "dataloader_workers": 0,
87
+ "dataloader_pin_memory": false,
88
+ "dataloader_prefetch_factor": 2,
89
+ "dataloader_persistent_workers": false,
90
+ "torch_compile": false,
91
+ "lr": 0.0002,
92
+ "warmup_steps": 100,
93
+ "env_vars": {
94
+ "HF_TOKEN": "hf_aaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
95
+ "HSA_FORCE_FINE_GRAIN_PCIE": "1",
96
+ "MIOPEN_FIND_MODE": "3"
97
+ },
98
+ "extras": {
99
+ "lora.lora_alpha": 32,
100
+ "lora.target_modules": [
101
+ "q_proj",
102
+ "v_proj"
103
+ ],
104
+ "lora.lora_dropout": 0.05,
105
+ "lora.bias": "none",
106
+ "lora.task_type": "CAUSAL_LM",
107
+ "batch_size": 4,
108
+ "output_dir": "./out",
109
+ "num_train_epochs": 3,
110
+ "logging_steps": 10,
111
+ "save_steps": 500,
112
+ "report_to": "none",
113
+ "push_to_hub": false
114
+ },
115
+ "raw_source": "# GPU Goblin canonical demo workload.\n#\n# Qwen2.5-7B-Instruct + LoRA fine-tune on the alpaca-cleaned dataset, staged with\n# *deliberately* sub-optimal defaults so the goblin has something to fix in\n# the demo. This script does NOT need to actually execute on a host \u2014 it\n# exists so `parse_config` can extract a realistic WorkloadConfig from it.\n#\n# Expected findings when audited:\n# - precision.bf16_over_fp16_on_mi300x (fp16=True)\n# - attention.flash_rocm_over_eager (attn_implementation=\"eager\")\n# - data.dataloader_workers_zero (dataloader_num_workers=0)\n# - memory.batch_too_small_for_192gb (per_device_train_batch_size=4)\n\nimport os\n\nimport torch\nfrom datasets import load_dataset\nfrom peft import LoraConfig, get_peft_model\nfrom torch.utils.data import DataLoader\nfrom transformers import (\n AutoModelForCausalLM,\n AutoTokenizer,\n Trainer,\n TrainingArguments,\n)\n\n# A redactable secret so parse_config has something to scrub during the demo.\nos.environ[\"HF_TOKEN\"] = \"<REDACTED:hf_token>\"\nHF_TOKEN = os.environ[\"HF_TOKEN\"]\n\n# ROCm-flavored env knobs the agent should pick up into env_vars.\nos.environ[\"HSA_FORCE_FINE_GRAIN_PCIE\"] = \"1\"\nos.environ[\"MIOPEN_FIND_MODE\"] = \"3\"\n\nMODEL_ID = \"Qwen/Qwen2.5-7B-Instruct\"\n\ntokenizer = AutoTokenizer.from_pretrained(MODEL_ID, token=HF_TOKEN)\nmodel = AutoModelForCausalLM.from_pretrained(\n MODEL_ID,\n torch_dtype=torch.float16,\n attn_implementation=\"eager\", # naive attention -- goblin should swap to flash_rocm\n token=HF_TOKEN,\n)\n\n# LoRA \u2014 rank 16, attached to attention projections.\nlora_config = LoraConfig(\n r=16,\n lora_alpha=32,\n target_modules=[\"q_proj\", \"v_proj\"],\n lora_dropout=0.05,\n bias=\"none\",\n task_type=\"CAUSAL_LM\",\n)\nmodel = get_peft_model(model, lora_config)\n\ndataset = load_dataset(\"yahma/alpaca-cleaned\", split=\"train\")\n\n# Hand-rolled DataLoader so parse_config sees the dataloader kwargs explicitly.\ntrain_loader = DataLoader(\n dataset,\n batch_size=4,\n num_workers=0, # leaves the GPU starved during training -- data_wait waste\n pin_memory=False,\n prefetch_factor=2,\n persistent_workers=False,\n)\n\ntraining_args = TrainingArguments(\n output_dir=\"./out\",\n per_device_train_batch_size=4, # leaves HBM on the floor at 192 GB\n gradient_accumulation_steps=8,\n num_train_epochs=3,\n learning_rate=2e-4,\n warmup_steps=100,\n fp16=True, # bf16 is the right call on CDNA3\n optim=\"adamw_torch\",\n logging_steps=10,\n save_steps=500,\n dataloader_num_workers=0,\n dataloader_pin_memory=False,\n gradient_checkpointing=False,\n torch_compile=False,\n report_to=\"none\",\n push_to_hub=False,\n)\n\ntrainer = Trainer(\n model=model,\n args=training_args,\n train_dataset=dataset,\n tokenizer=tokenizer,\n)\n\nif __name__ == \"__main__\":\n trainer.train()\n",
116
+ "redactions": [
117
+ "hf_token"
118
+ ]
119
+ },
120
+ "steps": 10
121
+ }
122
+ }
123
+ },
124
+ {
125
+ "type": "tool_result",
126
+ "data": {
127
+ "id": "tc-2",
128
+ "name": "profile_run",
129
+ "ok": true,
130
+ "result": {
131
+ "steps": 10,
132
+ "tokens_per_sec": 142.0,
133
+ "mfu_pct": 24.0,
134
+ "hbm_peak_gb": 73.0,
135
+ "hbm_avg_gb": 61.0,
136
+ "gpu_util_pct": 46.0,
137
+ "top_kernels": [
138
+ {
139
+ "name": "aten::matmul (fp16)",
140
+ "pct_time": 38.0
141
+ },
142
+ {
143
+ "name": "aten::scaled_dot_product_attention (eager)",
144
+ "pct_time": 24.0
145
+ },
146
+ {
147
+ "name": "aten::layer_norm",
148
+ "pct_time": 8.0
149
+ },
150
+ {
151
+ "name": "aten::cross_entropy_loss",
152
+ "pct_time": 5.0
153
+ },
154
+ {
155
+ "name": "aten::copy_ (h2d)",
156
+ "pct_time": 11.0
157
+ }
158
+ ],
159
+ "attention_kernel_loaded": "eager",
160
+ "waste_budget": {
161
+ "useful_gpu": 0.42,
162
+ "data_wait": 0.21,
163
+ "host_gap": 0.06,
164
+ "comm_excess": 0.0,
165
+ "memory_headroom": 0.14,
166
+ "precision_path": 0.11,
167
+ "kernel_shape": 0.06
168
+ },
169
+ "warnings": [
170
+ "Attention kernel is 'eager'; flash_rocm or sdpa would be much faster.",
171
+ "HBM utilization 38% suggests batch_size is leaving memory on the floor."
172
+ ],
173
+ "rocm_version": "6.1.0",
174
+ "pytorch_version": "2.3.0+rocm6.1",
175
+ "runner_kind": "fake"
176
+ }
177
+ }
178
+ },
179
+ {
180
+ "type": "thought",
181
+ "data": {
182
+ "text": "Profile shows 142 tok/s at 24% MFU \u2014 the precision_path and kernel_shape buckets are heavy. Querying the ROCm KB for matching rules."
183
+ }
184
+ },
185
+ {
186
+ "type": "tool_call",
187
+ "data": {
188
+ "id": "tc-3",
189
+ "name": "query_rocm_kb",
190
+ "input": {
191
+ "symptom": "fp16 with eager attention and zero dataloader workers on MI300X",
192
+ "top_k": 6
193
+ }
194
+ }
195
+ },
196
+ {
197
+ "type": "tool_result",
198
+ "data": {
199
+ "id": "tc-3",
200
+ "name": "query_rocm_kb",
201
+ "ok": true,
202
+ "result": {
203
+ "rules": [
204
+ {
205
+ "id": "precision.bf16_over_fp16_on_mi300x",
206
+ "category": "precision",
207
+ "targets_bucket": "precision_path",
208
+ "symptom": "fp16 used on MI300X / CDNA3",
209
+ "detect": {
210
+ "precision": "fp16"
211
+ },
212
+ "transform": {
213
+ "precision": "bf16"
214
+ },
215
+ "expected_recovery_fraction": 0.85,
216
+ "expected_impact": "MI300X CDNA3 matrix cores execute bf16 at the same throughput as fp16 with strictly better numerical stability. Reduces NaN risk in long runs.",
217
+ "rocm_version_min": "6.0",
218
+ "citation": "ROCm MI300X Optimization Guide \u00a73.2 \u2014 bf16 vs fp16"
219
+ },
220
+ {
221
+ "id": "attention.flash_rocm_over_eager",
222
+ "category": "attention",
223
+ "targets_bucket": "kernel_shape",
224
+ "symptom": "naive (eager) attention on MI300X \u2014 no flash kernel loaded",
225
+ "detect": {
226
+ "attention_impl": "eager"
227
+ },
228
+ "transform": {
229
+ "attention_impl": "flash_rocm"
230
+ },
231
+ "expected_recovery_fraction": 0.7,
232
+ "expected_impact": "Use the ROCm-validated flash-attention kernel (via Optimum-AMD or PyTorch SDPA backend). Eliminates O(seq_len^2) attention memory; typically 2-3x faster on MI300X for seq_len >= 1024.",
233
+ "rocm_version_min": "6.0",
234
+ "citation": "AMD ROCm vLLM/Optimum-AMD docs \u2014 Flash Attention validated on MI300"
235
+ }
236
+ ]
237
+ }
238
+ }
239
+ },
240
+ {
241
+ "type": "tool_call",
242
+ "data": {
243
+ "id": "tc-4",
244
+ "name": "propose_patch",
245
+ "input": {
246
+ "config": {
247
+ "model_name": "Qwen/Qwen2.5-7B-Instruct",
248
+ "batch_size": 4,
249
+ "grad_accum_steps": 8,
250
+ "seq_len": 1024,
251
+ "precision": "fp16",
252
+ "optimizer": "adamw_torch",
253
+ "attention_impl": "eager",
254
+ "gradient_checkpointing": false,
255
+ "lora_rank": 16,
256
+ "dataloader_workers": 0,
257
+ "dataloader_pin_memory": false,
258
+ "dataloader_prefetch_factor": 2,
259
+ "dataloader_persistent_workers": false,
260
+ "torch_compile": false,
261
+ "lr": 0.0002,
262
+ "warmup_steps": 100,
263
+ "env_vars": {
264
+ "HF_TOKEN": "hf_aaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
265
+ "HSA_FORCE_FINE_GRAIN_PCIE": "1",
266
+ "MIOPEN_FIND_MODE": "3"
267
+ },
268
+ "extras": {
269
+ "lora.lora_alpha": 32,
270
+ "lora.target_modules": [
271
+ "q_proj",
272
+ "v_proj"
273
+ ],
274
+ "lora.lora_dropout": 0.05,
275
+ "lora.bias": "none",
276
+ "lora.task_type": "CAUSAL_LM",
277
+ "batch_size": 4,
278
+ "output_dir": "./out",
279
+ "num_train_epochs": 3,
280
+ "logging_steps": 10,
281
+ "save_steps": 500,
282
+ "report_to": "none",
283
+ "push_to_hub": false
284
+ },
285
+ "raw_source": "# GPU Goblin canonical demo workload.\n#\n# Qwen2.5-7B-Instruct + LoRA fine-tune on the alpaca-cleaned dataset, staged with\n# *deliberately* sub-optimal defaults so the goblin has something to fix in\n# the demo. This script does NOT need to actually execute on a host \u2014 it\n# exists so `parse_config` can extract a realistic WorkloadConfig from it.\n#\n# Expected findings when audited:\n# - precision.bf16_over_fp16_on_mi300x (fp16=True)\n# - attention.flash_rocm_over_eager (attn_implementation=\"eager\")\n# - data.dataloader_workers_zero (dataloader_num_workers=0)\n# - memory.batch_too_small_for_192gb (per_device_train_batch_size=4)\n\nimport os\n\nimport torch\nfrom datasets import load_dataset\nfrom peft import LoraConfig, get_peft_model\nfrom torch.utils.data import DataLoader\nfrom transformers import (\n AutoModelForCausalLM,\n AutoTokenizer,\n Trainer,\n TrainingArguments,\n)\n\n# A redactable secret so parse_config has something to scrub during the demo.\nos.environ[\"HF_TOKEN\"] = \"<REDACTED:hf_token>\"\nHF_TOKEN = os.environ[\"HF_TOKEN\"]\n\n# ROCm-flavored env knobs the agent should pick up into env_vars.\nos.environ[\"HSA_FORCE_FINE_GRAIN_PCIE\"] = \"1\"\nos.environ[\"MIOPEN_FIND_MODE\"] = \"3\"\n\nMODEL_ID = \"Qwen/Qwen2.5-7B-Instruct\"\n\ntokenizer = AutoTokenizer.from_pretrained(MODEL_ID, token=HF_TOKEN)\nmodel = AutoModelForCausalLM.from_pretrained(\n MODEL_ID,\n torch_dtype=torch.float16,\n attn_implementation=\"eager\", # naive attention -- goblin should swap to flash_rocm\n token=HF_TOKEN,\n)\n\n# LoRA \u2014 rank 16, attached to attention projections.\nlora_config = LoraConfig(\n r=16,\n lora_alpha=32,\n target_modules=[\"q_proj\", \"v_proj\"],\n lora_dropout=0.05,\n bias=\"none\",\n task_type=\"CAUSAL_LM\",\n)\nmodel = get_peft_model(model, lora_config)\n\ndataset = load_dataset(\"yahma/alpaca-cleaned\", split=\"train\")\n\n# Hand-rolled DataLoader so parse_config sees the dataloader kwargs explicitly.\ntrain_loader = DataLoader(\n dataset,\n batch_size=4,\n num_workers=0, # leaves the GPU starved during training -- data_wait waste\n pin_memory=False,\n prefetch_factor=2,\n persistent_workers=False,\n)\n\ntraining_args = TrainingArguments(\n output_dir=\"./out\",\n per_device_train_batch_size=4, # leaves HBM on the floor at 192 GB\n gradient_accumulation_steps=8,\n num_train_epochs=3,\n learning_rate=2e-4,\n warmup_steps=100,\n fp16=True, # bf16 is the right call on CDNA3\n optim=\"adamw_torch\",\n logging_steps=10,\n save_steps=500,\n dataloader_num_workers=0,\n dataloader_pin_memory=False,\n gradient_checkpointing=False,\n torch_compile=False,\n report_to=\"none\",\n push_to_hub=False,\n)\n\ntrainer = Trainer(\n model=model,\n args=training_args,\n train_dataset=dataset,\n tokenizer=tokenizer,\n)\n\nif __name__ == \"__main__\":\n trainer.train()\n",
286
+ "redactions": [
287
+ "hf_token"
288
+ ]
289
+ },
290
+ "rules": [
291
+ {
292
+ "id": "precision.bf16_over_fp16_on_mi300x",
293
+ "category": "precision",
294
+ "targets_bucket": "precision_path",
295
+ "symptom": "fp16 used on MI300X / CDNA3",
296
+ "detect": {
297
+ "precision": "fp16"
298
+ },
299
+ "transform": {
300
+ "precision": "bf16"
301
+ },
302
+ "expected_recovery_fraction": 0.85,
303
+ "expected_impact": "MI300X CDNA3 matrix cores execute bf16 at the same throughput as fp16 with strictly better numerical stability. Reduces NaN risk in long runs.",
304
+ "rocm_version_min": "6.0",
305
+ "citation": "ROCm MI300X Optimization Guide \u00a73.2 \u2014 bf16 vs fp16"
306
+ },
307
+ {
308
+ "id": "attention.flash_rocm_over_eager",
309
+ "category": "attention",
310
+ "targets_bucket": "kernel_shape",
311
+ "symptom": "naive (eager) attention on MI300X \u2014 no flash kernel loaded",
312
+ "detect": {
313
+ "attention_impl": "eager"
314
+ },
315
+ "transform": {
316
+ "attention_impl": "flash_rocm"
317
+ },
318
+ "expected_recovery_fraction": 0.7,
319
+ "expected_impact": "Use the ROCm-validated flash-attention kernel (via Optimum-AMD or PyTorch SDPA backend). Eliminates O(seq_len^2) attention memory; typically 2-3x faster on MI300X for seq_len >= 1024.",
320
+ "rocm_version_min": "6.0",
321
+ "citation": "AMD ROCm vLLM/Optimum-AMD docs \u2014 Flash Attention validated on MI300"
322
+ }
323
+ ],
324
+ "metrics": {
325
+ "steps": 10,
326
+ "tokens_per_sec": 142.0,
327
+ "mfu_pct": 24.0,
328
+ "hbm_peak_gb": 73.0,
329
+ "hbm_avg_gb": 61.0,
330
+ "gpu_util_pct": 46.0,
331
+ "top_kernels": [
332
+ {
333
+ "name": "aten::matmul (fp16)",
334
+ "pct_time": 38.0
335
+ },
336
+ {
337
+ "name": "aten::scaled_dot_product_attention (eager)",
338
+ "pct_time": 24.0
339
+ },
340
+ {
341
+ "name": "aten::layer_norm",
342
+ "pct_time": 8.0
343
+ },
344
+ {
345
+ "name": "aten::cross_entropy_loss",
346
+ "pct_time": 5.0
347
+ },
348
+ {
349
+ "name": "aten::copy_ (h2d)",
350
+ "pct_time": 11.0
351
+ }
352
+ ],
353
+ "attention_kernel_loaded": "eager",
354
+ "waste_budget": {
355
+ "useful_gpu": 0.42,
356
+ "data_wait": 0.21,
357
+ "host_gap": 0.06,
358
+ "comm_excess": 0.0,
359
+ "memory_headroom": 0.14,
360
+ "precision_path": 0.11,
361
+ "kernel_shape": 0.06
362
+ },
363
+ "warnings": [
364
+ "Attention kernel is 'eager'; flash_rocm or sdpa would be much faster.",
365
+ "HBM utilization 38% suggests batch_size is leaving memory on the floor."
366
+ ],
367
+ "rocm_version": "6.1.0",
368
+ "pytorch_version": "2.3.0+rocm6.1",
369
+ "runner_kind": "fake"
370
+ }
371
+ }
372
+ }
373
+ },
374
+ {
375
+ "type": "tool_result",
376
+ "data": {
377
+ "id": "tc-4",
378
+ "name": "propose_patch",
379
+ "ok": true,
380
+ "result": {
381
+ "new_config": {
382
+ "model_name": "Qwen/Qwen2.5-7B-Instruct",
383
+ "batch_size": 4,
384
+ "grad_accum_steps": 8,
385
+ "seq_len": 1024,
386
+ "precision": "bf16",
387
+ "optimizer": "adamw_torch",
388
+ "attention_impl": "flash_rocm",
389
+ "gradient_checkpointing": false,
390
+ "lora_rank": 16,
391
+ "dataloader_workers": 0,
392
+ "dataloader_pin_memory": false,
393
+ "dataloader_prefetch_factor": 2,
394
+ "dataloader_persistent_workers": false,
395
+ "torch_compile": false,
396
+ "lr": 0.0002,
397
+ "warmup_steps": 100,
398
+ "env_vars": {
399
+ "HF_TOKEN": "hf_aaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
400
+ "HSA_FORCE_FINE_GRAIN_PCIE": "1",
401
+ "MIOPEN_FIND_MODE": "3"
402
+ },
403
+ "extras": {
404
+ "lora.lora_alpha": 32,
405
+ "lora.target_modules": [
406
+ "q_proj",
407
+ "v_proj"
408
+ ],
409
+ "lora.lora_dropout": 0.05,
410
+ "lora.bias": "none",
411
+ "lora.task_type": "CAUSAL_LM",
412
+ "batch_size": 4,
413
+ "output_dir": "./out",
414
+ "num_train_epochs": 3,
415
+ "logging_steps": 10,
416
+ "save_steps": 500,
417
+ "report_to": "none",
418
+ "push_to_hub": false
419
+ },
420
+ "raw_source": "# GPU Goblin canonical demo workload.\n#\n# Qwen2.5-7B-Instruct + LoRA fine-tune on the alpaca-cleaned dataset, staged with\n# *deliberately* sub-optimal defaults so the goblin has something to fix in\n# the demo. This script does NOT need to actually execute on a host \u2014 it\n# exists so `parse_config` can extract a realistic WorkloadConfig from it.\n#\n# Expected findings when audited:\n# - precision.bf16_over_fp16_on_mi300x (fp16=True)\n# - attention.flash_rocm_over_eager (attn_implementation=\"eager\")\n# - data.dataloader_workers_zero (dataloader_num_workers=0)\n# - memory.batch_too_small_for_192gb (per_device_train_batch_size=4)\n\nimport os\n\nimport torch\nfrom datasets import load_dataset\nfrom peft import LoraConfig, get_peft_model\nfrom torch.utils.data import DataLoader\nfrom transformers import (\n AutoModelForCausalLM,\n AutoTokenizer,\n Trainer,\n TrainingArguments,\n)\n\n# A redactable secret so parse_config has something to scrub during the demo.\nos.environ[\"HF_TOKEN\"] = \"<REDACTED:hf_token>\"\nHF_TOKEN = os.environ[\"HF_TOKEN\"]\n\n# ROCm-flavored env knobs the agent should pick up into env_vars.\nos.environ[\"HSA_FORCE_FINE_GRAIN_PCIE\"] = \"1\"\nos.environ[\"MIOPEN_FIND_MODE\"] = \"3\"\n\nMODEL_ID = \"Qwen/Qwen2.5-7B-Instruct\"\n\ntokenizer = AutoTokenizer.from_pretrained(MODEL_ID, token=HF_TOKEN)\nmodel = AutoModelForCausalLM.from_pretrained(\n MODEL_ID,\n torch_dtype=torch.float16,\n attn_implementation=\"eager\", # naive attention -- goblin should swap to flash_rocm\n token=HF_TOKEN,\n)\n\n# LoRA \u2014 rank 16, attached to attention projections.\nlora_config = LoraConfig(\n r=16,\n lora_alpha=32,\n target_modules=[\"q_proj\", \"v_proj\"],\n lora_dropout=0.05,\n bias=\"none\",\n task_type=\"CAUSAL_LM\",\n)\nmodel = get_peft_model(model, lora_config)\n\ndataset = load_dataset(\"yahma/alpaca-cleaned\", split=\"train\")\n\n# Hand-rolled DataLoader so parse_config sees the dataloader kwargs explicitly.\ntrain_loader = DataLoader(\n dataset,\n batch_size=4,\n num_workers=0, # leaves the GPU starved during training -- data_wait waste\n pin_memory=False,\n prefetch_factor=2,\n persistent_workers=False,\n)\n\ntraining_args = TrainingArguments(\n output_dir=\"./out\",\n per_device_train_batch_size=4, # leaves HBM on the floor at 192 GB\n gradient_accumulation_steps=8,\n num_train_epochs=3,\n learning_rate=2e-4,\n warmup_steps=100,\n fp16=True, # bf16 is the right call on CDNA3\n optim=\"adamw_torch\",\n logging_steps=10,\n save_steps=500,\n dataloader_num_workers=0,\n dataloader_pin_memory=False,\n gradient_checkpointing=False,\n torch_compile=False,\n report_to=\"none\",\n push_to_hub=False,\n)\n\ntrainer = Trainer(\n model=model,\n args=training_args,\n train_dataset=dataset,\n tokenizer=tokenizer,\n)\n\nif __name__ == \"__main__\":\n trainer.train()\n",
421
+ "redactions": [
422
+ "hf_token"
423
+ ]
424
+ },
425
+ "diff": "- attention_impl: 'eager'\n+ attention_impl: 'flash_rocm'\n- precision: 'fp16'\n+ precision: 'bf16'",
426
+ "rationale": [
427
+ {
428
+ "rule_id": "precision.bf16_over_fp16_on_mi300x",
429
+ "rationale": "MI300X CDNA3 matrix cores execute bf16 at the same throughput as fp16 with strictly better numerical stability. Reduces NaN risk in long runs.",
430
+ "citation": "ROCm MI300X Optimization Guide \u00a73.2 \u2014 bf16 vs fp16",
431
+ "targets_bucket": "precision_path",
432
+ "estimated_recovery_seconds": 0.0935
433
+ },
434
+ {
435
+ "rule_id": "attention.flash_rocm_over_eager",
436
+ "rationale": "Use the ROCm-validated flash-attention kernel (via Optimum-AMD or PyTorch SDPA backend). Eliminates O(seq_len^2) attention memory; typically 2-3x faster on MI300X for seq_len >= 1024.",
437
+ "citation": "AMD ROCm vLLM/Optimum-AMD docs \u2014 Flash Attention validated on MI300",
438
+ "targets_bucket": "kernel_shape",
439
+ "estimated_recovery_seconds": 0.041999999999999996
440
+ }
441
+ ],
442
+ "expected_speedup_low": 1.04,
443
+ "expected_speedup_high": 1.31,
444
+ "confidence": 0.85
445
+ }
446
+ }
447
+ },
448
+ {
449
+ "type": "tool_call",
450
+ "data": {
451
+ "id": "tc-5",
452
+ "name": "benchmark",
453
+ "input": {
454
+ "config": {
455
+ "model_name": "Qwen/Qwen2.5-7B-Instruct",
456
+ "batch_size": 4,
457
+ "grad_accum_steps": 8,
458
+ "seq_len": 1024,
459
+ "precision": "fp16",
460
+ "optimizer": "adamw_torch",
461
+ "attention_impl": "eager",
462
+ "gradient_checkpointing": false,
463
+ "lora_rank": 16,
464
+ "dataloader_workers": 0,
465
+ "dataloader_pin_memory": false,
466
+ "dataloader_prefetch_factor": 2,
467
+ "dataloader_persistent_workers": false,
468
+ "torch_compile": false,
469
+ "lr": 0.0002,
470
+ "warmup_steps": 100,
471
+ "env_vars": {
472
+ "HF_TOKEN": "hf_aaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
473
+ "HSA_FORCE_FINE_GRAIN_PCIE": "1",
474
+ "MIOPEN_FIND_MODE": "3"
475
+ },
476
+ "extras": {
477
+ "lora.lora_alpha": 32,
478
+ "lora.target_modules": [
479
+ "q_proj",
480
+ "v_proj"
481
+ ],
482
+ "lora.lora_dropout": 0.05,
483
+ "lora.bias": "none",
484
+ "lora.task_type": "CAUSAL_LM",
485
+ "batch_size": 4,
486
+ "output_dir": "./out",
487
+ "num_train_epochs": 3,
488
+ "logging_steps": 10,
489
+ "save_steps": 500,
490
+ "report_to": "none",
491
+ "push_to_hub": false
492
+ },
493
+ "raw_source": "# GPU Goblin canonical demo workload.\n#\n# Qwen2.5-7B-Instruct + LoRA fine-tune on the alpaca-cleaned dataset, staged with\n# *deliberately* sub-optimal defaults so the goblin has something to fix in\n# the demo. This script does NOT need to actually execute on a host \u2014 it\n# exists so `parse_config` can extract a realistic WorkloadConfig from it.\n#\n# Expected findings when audited:\n# - precision.bf16_over_fp16_on_mi300x (fp16=True)\n# - attention.flash_rocm_over_eager (attn_implementation=\"eager\")\n# - data.dataloader_workers_zero (dataloader_num_workers=0)\n# - memory.batch_too_small_for_192gb (per_device_train_batch_size=4)\n\nimport os\n\nimport torch\nfrom datasets import load_dataset\nfrom peft import LoraConfig, get_peft_model\nfrom torch.utils.data import DataLoader\nfrom transformers import (\n AutoModelForCausalLM,\n AutoTokenizer,\n Trainer,\n TrainingArguments,\n)\n\n# A redactable secret so parse_config has something to scrub during the demo.\nos.environ[\"HF_TOKEN\"] = \"<REDACTED:hf_token>\"\nHF_TOKEN = os.environ[\"HF_TOKEN\"]\n\n# ROCm-flavored env knobs the agent should pick up into env_vars.\nos.environ[\"HSA_FORCE_FINE_GRAIN_PCIE\"] = \"1\"\nos.environ[\"MIOPEN_FIND_MODE\"] = \"3\"\n\nMODEL_ID = \"Qwen/Qwen2.5-7B-Instruct\"\n\ntokenizer = AutoTokenizer.from_pretrained(MODEL_ID, token=HF_TOKEN)\nmodel = AutoModelForCausalLM.from_pretrained(\n MODEL_ID,\n torch_dtype=torch.float16,\n attn_implementation=\"eager\", # naive attention -- goblin should swap to flash_rocm\n token=HF_TOKEN,\n)\n\n# LoRA \u2014 rank 16, attached to attention projections.\nlora_config = LoraConfig(\n r=16,\n lora_alpha=32,\n target_modules=[\"q_proj\", \"v_proj\"],\n lora_dropout=0.05,\n bias=\"none\",\n task_type=\"CAUSAL_LM\",\n)\nmodel = get_peft_model(model, lora_config)\n\ndataset = load_dataset(\"yahma/alpaca-cleaned\", split=\"train\")\n\n# Hand-rolled DataLoader so parse_config sees the dataloader kwargs explicitly.\ntrain_loader = DataLoader(\n dataset,\n batch_size=4,\n num_workers=0, # leaves the GPU starved during training -- data_wait waste\n pin_memory=False,\n prefetch_factor=2,\n persistent_workers=False,\n)\n\ntraining_args = TrainingArguments(\n output_dir=\"./out\",\n per_device_train_batch_size=4, # leaves HBM on the floor at 192 GB\n gradient_accumulation_steps=8,\n num_train_epochs=3,\n learning_rate=2e-4,\n warmup_steps=100,\n fp16=True, # bf16 is the right call on CDNA3\n optim=\"adamw_torch\",\n logging_steps=10,\n save_steps=500,\n dataloader_num_workers=0,\n dataloader_pin_memory=False,\n gradient_checkpointing=False,\n torch_compile=False,\n report_to=\"none\",\n push_to_hub=False,\n)\n\ntrainer = Trainer(\n model=model,\n args=training_args,\n train_dataset=dataset,\n tokenizer=tokenizer,\n)\n\nif __name__ == \"__main__\":\n trainer.train()\n",
494
+ "redactions": [
495
+ "hf_token"
496
+ ]
497
+ },
498
+ "steps": 50
499
+ }
500
+ }
501
+ },
502
+ {
503
+ "type": "tool_result",
504
+ "data": {
505
+ "id": "tc-5",
506
+ "name": "benchmark",
507
+ "ok": true,
508
+ "result": {
509
+ "steps": 50,
510
+ "tokens_per_sec": 142.0,
511
+ "mfu_pct": 24.0,
512
+ "hbm_peak_gb": 73.0,
513
+ "hbm_avg_gb": 61.0,
514
+ "gpu_util_pct": 46.0,
515
+ "top_kernels": [
516
+ {
517
+ "name": "aten::matmul (fp16)",
518
+ "pct_time": 38.0
519
+ },
520
+ {
521
+ "name": "aten::scaled_dot_product_attention (eager)",
522
+ "pct_time": 24.0
523
+ },
524
+ {
525
+ "name": "aten::layer_norm",
526
+ "pct_time": 8.0
527
+ },
528
+ {
529
+ "name": "aten::cross_entropy_loss",
530
+ "pct_time": 5.0
531
+ },
532
+ {
533
+ "name": "aten::copy_ (h2d)",
534
+ "pct_time": 11.0
535
+ }
536
+ ],
537
+ "attention_kernel_loaded": "eager",
538
+ "waste_budget": {
539
+ "useful_gpu": 0.42,
540
+ "data_wait": 0.21,
541
+ "host_gap": 0.06,
542
+ "comm_excess": 0.0,
543
+ "memory_headroom": 0.14,
544
+ "precision_path": 0.11,
545
+ "kernel_shape": 0.06
546
+ },
547
+ "warnings": [
548
+ "Attention kernel is 'eager'; flash_rocm or sdpa would be much faster.",
549
+ "HBM utilization 38% suggests batch_size is leaving memory on the floor."
550
+ ],
551
+ "rocm_version": "6.1.0",
552
+ "pytorch_version": "2.3.0+rocm6.1",
553
+ "runner_kind": "fake"
554
+ }
555
+ }
556
+ },
557
+ {
558
+ "type": "tool_call",
559
+ "data": {
560
+ "id": "tc-6",
561
+ "name": "benchmark",
562
+ "input": {
563
+ "config": {
564
+ "model_name": "Qwen/Qwen2.5-7B-Instruct",
565
+ "batch_size": 4,
566
+ "grad_accum_steps": 8,
567
+ "seq_len": 1024,
568
+ "precision": "bf16",
569
+ "optimizer": "adamw_torch",
570
+ "attention_impl": "flash_rocm",
571
+ "gradient_checkpointing": false,
572
+ "lora_rank": 16,
573
+ "dataloader_workers": 0,
574
+ "dataloader_pin_memory": false,
575
+ "dataloader_prefetch_factor": 2,
576
+ "dataloader_persistent_workers": false,
577
+ "torch_compile": false,
578
+ "lr": 0.0002,
579
+ "warmup_steps": 100,
580
+ "env_vars": {
581
+ "HF_TOKEN": "hf_aaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
582
+ "HSA_FORCE_FINE_GRAIN_PCIE": "1",
583
+ "MIOPEN_FIND_MODE": "3"
584
+ },
585
+ "extras": {
586
+ "lora.lora_alpha": 32,
587
+ "lora.target_modules": [
588
+ "q_proj",
589
+ "v_proj"
590
+ ],
591
+ "lora.lora_dropout": 0.05,
592
+ "lora.bias": "none",
593
+ "lora.task_type": "CAUSAL_LM",
594
+ "batch_size": 4,
595
+ "output_dir": "./out",
596
+ "num_train_epochs": 3,
597
+ "logging_steps": 10,
598
+ "save_steps": 500,
599
+ "report_to": "none",
600
+ "push_to_hub": false
601
+ },
602
+ "raw_source": "# GPU Goblin canonical demo workload.\n#\n# Qwen2.5-7B-Instruct + LoRA fine-tune on the alpaca-cleaned dataset, staged with\n# *deliberately* sub-optimal defaults so the goblin has something to fix in\n# the demo. This script does NOT need to actually execute on a host \u2014 it\n# exists so `parse_config` can extract a realistic WorkloadConfig from it.\n#\n# Expected findings when audited:\n# - precision.bf16_over_fp16_on_mi300x (fp16=True)\n# - attention.flash_rocm_over_eager (attn_implementation=\"eager\")\n# - data.dataloader_workers_zero (dataloader_num_workers=0)\n# - memory.batch_too_small_for_192gb (per_device_train_batch_size=4)\n\nimport os\n\nimport torch\nfrom datasets import load_dataset\nfrom peft import LoraConfig, get_peft_model\nfrom torch.utils.data import DataLoader\nfrom transformers import (\n AutoModelForCausalLM,\n AutoTokenizer,\n Trainer,\n TrainingArguments,\n)\n\n# A redactable secret so parse_config has something to scrub during the demo.\nos.environ[\"HF_TOKEN\"] = \"<REDACTED:hf_token>\"\nHF_TOKEN = os.environ[\"HF_TOKEN\"]\n\n# ROCm-flavored env knobs the agent should pick up into env_vars.\nos.environ[\"HSA_FORCE_FINE_GRAIN_PCIE\"] = \"1\"\nos.environ[\"MIOPEN_FIND_MODE\"] = \"3\"\n\nMODEL_ID = \"Qwen/Qwen2.5-7B-Instruct\"\n\ntokenizer = AutoTokenizer.from_pretrained(MODEL_ID, token=HF_TOKEN)\nmodel = AutoModelForCausalLM.from_pretrained(\n MODEL_ID,\n torch_dtype=torch.float16,\n attn_implementation=\"eager\", # naive attention -- goblin should swap to flash_rocm\n token=HF_TOKEN,\n)\n\n# LoRA \u2014 rank 16, attached to attention projections.\nlora_config = LoraConfig(\n r=16,\n lora_alpha=32,\n target_modules=[\"q_proj\", \"v_proj\"],\n lora_dropout=0.05,\n bias=\"none\",\n task_type=\"CAUSAL_LM\",\n)\nmodel = get_peft_model(model, lora_config)\n\ndataset = load_dataset(\"yahma/alpaca-cleaned\", split=\"train\")\n\n# Hand-rolled DataLoader so parse_config sees the dataloader kwargs explicitly.\ntrain_loader = DataLoader(\n dataset,\n batch_size=4,\n num_workers=0, # leaves the GPU starved during training -- data_wait waste\n pin_memory=False,\n prefetch_factor=2,\n persistent_workers=False,\n)\n\ntraining_args = TrainingArguments(\n output_dir=\"./out\",\n per_device_train_batch_size=4, # leaves HBM on the floor at 192 GB\n gradient_accumulation_steps=8,\n num_train_epochs=3,\n learning_rate=2e-4,\n warmup_steps=100,\n fp16=True, # bf16 is the right call on CDNA3\n optim=\"adamw_torch\",\n logging_steps=10,\n save_steps=500,\n dataloader_num_workers=0,\n dataloader_pin_memory=False,\n gradient_checkpointing=False,\n torch_compile=False,\n report_to=\"none\",\n push_to_hub=False,\n)\n\ntrainer = Trainer(\n model=model,\n args=training_args,\n train_dataset=dataset,\n tokenizer=tokenizer,\n)\n\nif __name__ == \"__main__\":\n trainer.train()\n",
603
+ "redactions": [
604
+ "hf_token"
605
+ ]
606
+ },
607
+ "steps": 50
608
+ }
609
+ }
610
+ },
611
+ {
612
+ "type": "tool_result",
613
+ "data": {
614
+ "id": "tc-6",
615
+ "name": "benchmark",
616
+ "ok": true,
617
+ "result": {
618
+ "steps": 50,
619
+ "tokens_per_sec": 318.0,
620
+ "mfu_pct": 51.0,
621
+ "hbm_peak_gb": 168.0,
622
+ "hbm_avg_gb": 152.0,
623
+ "gpu_util_pct": 86.0,
624
+ "top_kernels": [
625
+ {
626
+ "name": "aten::matmul (bf16)",
627
+ "pct_time": 46.0
628
+ },
629
+ {
630
+ "name": "flash_attn_rocm_fwd",
631
+ "pct_time": 19.0
632
+ },
633
+ {
634
+ "name": "flash_attn_rocm_bwd",
635
+ "pct_time": 14.0
636
+ },
637
+ {
638
+ "name": "aten::layer_norm",
639
+ "pct_time": 7.0
640
+ },
641
+ {
642
+ "name": "aten::cross_entropy_loss",
643
+ "pct_time": 4.0
644
+ }
645
+ ],
646
+ "attention_kernel_loaded": "flash_rocm",
647
+ "waste_budget": {
648
+ "useful_gpu": 0.78,
649
+ "data_wait": 0.04,
650
+ "host_gap": 0.05,
651
+ "comm_excess": 0.0,
652
+ "memory_headroom": 0.04,
653
+ "precision_path": 0.02,
654
+ "kernel_shape": 0.03
655
+ },
656
+ "warnings": [],
657
+ "rocm_version": "6.1.0",
658
+ "pytorch_version": "2.3.0+rocm6.1",
659
+ "runner_kind": "fake"
660
+ }
661
+ }
662
+ },
663
+ {
664
+ "type": "tool_call",
665
+ "data": {
666
+ "id": "tc-7",
667
+ "name": "compare_runs",
668
+ "input": {
669
+ "workload_name": "Qwen2.5-7B LoRA fine-tune",
670
+ "before": {
671
+ "steps": 50,
672
+ "tokens_per_sec": 142.0,
673
+ "mfu_pct": 24.0,
674
+ "hbm_peak_gb": 73.0,
675
+ "hbm_avg_gb": 61.0,
676
+ "gpu_util_pct": 46.0,
677
+ "top_kernels": [
678
+ {
679
+ "name": "aten::matmul (fp16)",
680
+ "pct_time": 38.0
681
+ },
682
+ {
683
+ "name": "aten::scaled_dot_product_attention (eager)",
684
+ "pct_time": 24.0
685
+ },
686
+ {
687
+ "name": "aten::layer_norm",
688
+ "pct_time": 8.0
689
+ },
690
+ {
691
+ "name": "aten::cross_entropy_loss",
692
+ "pct_time": 5.0
693
+ },
694
+ {
695
+ "name": "aten::copy_ (h2d)",
696
+ "pct_time": 11.0
697
+ }
698
+ ],
699
+ "attention_kernel_loaded": "eager",
700
+ "waste_budget": {
701
+ "useful_gpu": 0.42,
702
+ "data_wait": 0.21,
703
+ "host_gap": 0.06,
704
+ "comm_excess": 0.0,
705
+ "memory_headroom": 0.14,
706
+ "precision_path": 0.11,
707
+ "kernel_shape": 0.06
708
+ },
709
+ "warnings": [
710
+ "Attention kernel is 'eager'; flash_rocm or sdpa would be much faster.",
711
+ "HBM utilization 38% suggests batch_size is leaving memory on the floor."
712
+ ],
713
+ "rocm_version": "6.1.0",
714
+ "pytorch_version": "2.3.0+rocm6.1",
715
+ "runner_kind": "fake"
716
+ },
717
+ "after": {
718
+ "steps": 50,
719
+ "tokens_per_sec": 318.0,
720
+ "mfu_pct": 51.0,
721
+ "hbm_peak_gb": 168.0,
722
+ "hbm_avg_gb": 152.0,
723
+ "gpu_util_pct": 86.0,
724
+ "top_kernels": [
725
+ {
726
+ "name": "aten::matmul (bf16)",
727
+ "pct_time": 46.0
728
+ },
729
+ {
730
+ "name": "flash_attn_rocm_fwd",
731
+ "pct_time": 19.0
732
+ },
733
+ {
734
+ "name": "flash_attn_rocm_bwd",
735
+ "pct_time": 14.0
736
+ },
737
+ {
738
+ "name": "aten::layer_norm",
739
+ "pct_time": 7.0
740
+ },
741
+ {
742
+ "name": "aten::cross_entropy_loss",
743
+ "pct_time": 4.0
744
+ }
745
+ ],
746
+ "attention_kernel_loaded": "flash_rocm",
747
+ "waste_budget": {
748
+ "useful_gpu": 0.78,
749
+ "data_wait": 0.04,
750
+ "host_gap": 0.05,
751
+ "comm_excess": 0.0,
752
+ "memory_headroom": 0.04,
753
+ "precision_path": 0.02,
754
+ "kernel_shape": 0.03
755
+ },
756
+ "warnings": [],
757
+ "rocm_version": "6.1.0",
758
+ "pytorch_version": "2.3.0+rocm6.1",
759
+ "runner_kind": "fake"
760
+ },
761
+ "patch": {
762
+ "new_config": {
763
+ "model_name": "Qwen/Qwen2.5-7B-Instruct",
764
+ "batch_size": 4,
765
+ "grad_accum_steps": 8,
766
+ "seq_len": 1024,
767
+ "precision": "bf16",
768
+ "optimizer": "adamw_torch",
769
+ "attention_impl": "flash_rocm",
770
+ "gradient_checkpointing": false,
771
+ "lora_rank": 16,
772
+ "dataloader_workers": 0,
773
+ "dataloader_pin_memory": false,
774
+ "dataloader_prefetch_factor": 2,
775
+ "dataloader_persistent_workers": false,
776
+ "torch_compile": false,
777
+ "lr": 0.0002,
778
+ "warmup_steps": 100,
779
+ "env_vars": {
780
+ "HF_TOKEN": "hf_aaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
781
+ "HSA_FORCE_FINE_GRAIN_PCIE": "1",
782
+ "MIOPEN_FIND_MODE": "3"
783
+ },
784
+ "extras": {
785
+ "lora.lora_alpha": 32,
786
+ "lora.target_modules": [
787
+ "q_proj",
788
+ "v_proj"
789
+ ],
790
+ "lora.lora_dropout": 0.05,
791
+ "lora.bias": "none",
792
+ "lora.task_type": "CAUSAL_LM",
793
+ "batch_size": 4,
794
+ "output_dir": "./out",
795
+ "num_train_epochs": 3,
796
+ "logging_steps": 10,
797
+ "save_steps": 500,
798
+ "report_to": "none",
799
+ "push_to_hub": false
800
+ },
801
+ "raw_source": "# GPU Goblin canonical demo workload.\n#\n# Qwen2.5-7B-Instruct + LoRA fine-tune on the alpaca-cleaned dataset, staged with\n# *deliberately* sub-optimal defaults so the goblin has something to fix in\n# the demo. This script does NOT need to actually execute on a host \u2014 it\n# exists so `parse_config` can extract a realistic WorkloadConfig from it.\n#\n# Expected findings when audited:\n# - precision.bf16_over_fp16_on_mi300x (fp16=True)\n# - attention.flash_rocm_over_eager (attn_implementation=\"eager\")\n# - data.dataloader_workers_zero (dataloader_num_workers=0)\n# - memory.batch_too_small_for_192gb (per_device_train_batch_size=4)\n\nimport os\n\nimport torch\nfrom datasets import load_dataset\nfrom peft import LoraConfig, get_peft_model\nfrom torch.utils.data import DataLoader\nfrom transformers import (\n AutoModelForCausalLM,\n AutoTokenizer,\n Trainer,\n TrainingArguments,\n)\n\n# A redactable secret so parse_config has something to scrub during the demo.\nos.environ[\"HF_TOKEN\"] = \"<REDACTED:hf_token>\"\nHF_TOKEN = os.environ[\"HF_TOKEN\"]\n\n# ROCm-flavored env knobs the agent should pick up into env_vars.\nos.environ[\"HSA_FORCE_FINE_GRAIN_PCIE\"] = \"1\"\nos.environ[\"MIOPEN_FIND_MODE\"] = \"3\"\n\nMODEL_ID = \"Qwen/Qwen2.5-7B-Instruct\"\n\ntokenizer = AutoTokenizer.from_pretrained(MODEL_ID, token=HF_TOKEN)\nmodel = AutoModelForCausalLM.from_pretrained(\n MODEL_ID,\n torch_dtype=torch.float16,\n attn_implementation=\"eager\", # naive attention -- goblin should swap to flash_rocm\n token=HF_TOKEN,\n)\n\n# LoRA \u2014 rank 16, attached to attention projections.\nlora_config = LoraConfig(\n r=16,\n lora_alpha=32,\n target_modules=[\"q_proj\", \"v_proj\"],\n lora_dropout=0.05,\n bias=\"none\",\n task_type=\"CAUSAL_LM\",\n)\nmodel = get_peft_model(model, lora_config)\n\ndataset = load_dataset(\"yahma/alpaca-cleaned\", split=\"train\")\n\n# Hand-rolled DataLoader so parse_config sees the dataloader kwargs explicitly.\ntrain_loader = DataLoader(\n dataset,\n batch_size=4,\n num_workers=0, # leaves the GPU starved during training -- data_wait waste\n pin_memory=False,\n prefetch_factor=2,\n persistent_workers=False,\n)\n\ntraining_args = TrainingArguments(\n output_dir=\"./out\",\n per_device_train_batch_size=4, # leaves HBM on the floor at 192 GB\n gradient_accumulation_steps=8,\n num_train_epochs=3,\n learning_rate=2e-4,\n warmup_steps=100,\n fp16=True, # bf16 is the right call on CDNA3\n optim=\"adamw_torch\",\n logging_steps=10,\n save_steps=500,\n dataloader_num_workers=0,\n dataloader_pin_memory=False,\n gradient_checkpointing=False,\n torch_compile=False,\n report_to=\"none\",\n push_to_hub=False,\n)\n\ntrainer = Trainer(\n model=model,\n args=training_args,\n train_dataset=dataset,\n tokenizer=tokenizer,\n)\n\nif __name__ == \"__main__\":\n trainer.train()\n",
802
+ "redactions": [
803
+ "hf_token"
804
+ ]
805
+ },
806
+ "diff": "- attention_impl: 'eager'\n+ attention_impl: 'flash_rocm'\n- precision: 'fp16'\n+ precision: 'bf16'",
807
+ "rationale": [
808
+ {
809
+ "rule_id": "precision.bf16_over_fp16_on_mi300x",
810
+ "rationale": "MI300X CDNA3 matrix cores execute bf16 at the same throughput as fp16 with strictly better numerical stability. Reduces NaN risk in long runs.",
811
+ "citation": "ROCm MI300X Optimization Guide \u00a73.2 \u2014 bf16 vs fp16",
812
+ "targets_bucket": "precision_path",
813
+ "estimated_recovery_seconds": 0.0935
814
+ },
815
+ {
816
+ "rule_id": "attention.flash_rocm_over_eager",
817
+ "rationale": "Use the ROCm-validated flash-attention kernel (via Optimum-AMD or PyTorch SDPA backend). Eliminates O(seq_len^2) attention memory; typically 2-3x faster on MI300X for seq_len >= 1024.",
818
+ "citation": "AMD ROCm vLLM/Optimum-AMD docs \u2014 Flash Attention validated on MI300",
819
+ "targets_bucket": "kernel_shape",
820
+ "estimated_recovery_seconds": 0.041999999999999996
821
+ }
822
+ ],
823
+ "expected_speedup_low": 1.04,
824
+ "expected_speedup_high": 1.31,
825
+ "confidence": 0.85
826
+ }
827
+ }
828
+ }
829
+ },
830
+ {
831
+ "type": "tool_result",
832
+ "data": {
833
+ "id": "tc-7",
834
+ "name": "compare_runs",
835
+ "ok": true,
836
+ "result": {
837
+ "workload_name": "Qwen2.5-7B LoRA fine-tune",
838
+ "before": {
839
+ "steps": 50,
840
+ "tokens_per_sec": 142.0,
841
+ "mfu_pct": 24.0,
842
+ "hbm_peak_gb": 73.0,
843
+ "hbm_avg_gb": 61.0,
844
+ "gpu_util_pct": 46.0,
845
+ "top_kernels": [
846
+ {
847
+ "name": "aten::matmul (fp16)",
848
+ "pct_time": 38.0
849
+ },
850
+ {
851
+ "name": "aten::scaled_dot_product_attention (eager)",
852
+ "pct_time": 24.0
853
+ },
854
+ {
855
+ "name": "aten::layer_norm",
856
+ "pct_time": 8.0
857
+ },
858
+ {
859
+ "name": "aten::cross_entropy_loss",
860
+ "pct_time": 5.0
861
+ },
862
+ {
863
+ "name": "aten::copy_ (h2d)",
864
+ "pct_time": 11.0
865
+ }
866
+ ],
867
+ "attention_kernel_loaded": "eager",
868
+ "waste_budget": {
869
+ "useful_gpu": 0.42,
870
+ "data_wait": 0.21,
871
+ "host_gap": 0.06,
872
+ "comm_excess": 0.0,
873
+ "memory_headroom": 0.14,
874
+ "precision_path": 0.11,
875
+ "kernel_shape": 0.06
876
+ },
877
+ "warnings": [
878
+ "Attention kernel is 'eager'; flash_rocm or sdpa would be much faster.",
879
+ "HBM utilization 38% suggests batch_size is leaving memory on the floor."
880
+ ],
881
+ "rocm_version": "6.1.0",
882
+ "pytorch_version": "2.3.0+rocm6.1",
883
+ "runner_kind": "fake"
884
+ },
885
+ "after": {
886
+ "steps": 50,
887
+ "tokens_per_sec": 318.0,
888
+ "mfu_pct": 51.0,
889
+ "hbm_peak_gb": 168.0,
890
+ "hbm_avg_gb": 152.0,
891
+ "gpu_util_pct": 86.0,
892
+ "top_kernels": [
893
+ {
894
+ "name": "aten::matmul (bf16)",
895
+ "pct_time": 46.0
896
+ },
897
+ {
898
+ "name": "flash_attn_rocm_fwd",
899
+ "pct_time": 19.0
900
+ },
901
+ {
902
+ "name": "flash_attn_rocm_bwd",
903
+ "pct_time": 14.0
904
+ },
905
+ {
906
+ "name": "aten::layer_norm",
907
+ "pct_time": 7.0
908
+ },
909
+ {
910
+ "name": "aten::cross_entropy_loss",
911
+ "pct_time": 4.0
912
+ }
913
+ ],
914
+ "attention_kernel_loaded": "flash_rocm",
915
+ "waste_budget": {
916
+ "useful_gpu": 0.78,
917
+ "data_wait": 0.04,
918
+ "host_gap": 0.05,
919
+ "comm_excess": 0.0,
920
+ "memory_headroom": 0.04,
921
+ "precision_path": 0.02,
922
+ "kernel_shape": 0.03
923
+ },
924
+ "warnings": [],
925
+ "rocm_version": "6.1.0",
926
+ "pytorch_version": "2.3.0+rocm6.1",
927
+ "runner_kind": "fake"
928
+ },
929
+ "patch": {
930
+ "new_config": {
931
+ "model_name": "Qwen/Qwen2.5-7B-Instruct",
932
+ "batch_size": 4,
933
+ "grad_accum_steps": 8,
934
+ "seq_len": 1024,
935
+ "precision": "bf16",
936
+ "optimizer": "adamw_torch",
937
+ "attention_impl": "flash_rocm",
938
+ "gradient_checkpointing": false,
939
+ "lora_rank": 16,
940
+ "dataloader_workers": 0,
941
+ "dataloader_pin_memory": false,
942
+ "dataloader_prefetch_factor": 2,
943
+ "dataloader_persistent_workers": false,
944
+ "torch_compile": false,
945
+ "lr": 0.0002,
946
+ "warmup_steps": 100,
947
+ "env_vars": {
948
+ "HF_TOKEN": "hf_aaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
949
+ "HSA_FORCE_FINE_GRAIN_PCIE": "1",
950
+ "MIOPEN_FIND_MODE": "3"
951
+ },
952
+ "extras": {
953
+ "lora.lora_alpha": 32,
954
+ "lora.target_modules": [
955
+ "q_proj",
956
+ "v_proj"
957
+ ],
958
+ "lora.lora_dropout": 0.05,
959
+ "lora.bias": "none",
960
+ "lora.task_type": "CAUSAL_LM",
961
+ "batch_size": 4,
962
+ "output_dir": "./out",
963
+ "num_train_epochs": 3,
964
+ "logging_steps": 10,
965
+ "save_steps": 500,
966
+ "report_to": "none",
967
+ "push_to_hub": false
968
+ },
969
+ "raw_source": "# GPU Goblin canonical demo workload.\n#\n# Qwen2.5-7B-Instruct + LoRA fine-tune on the alpaca-cleaned dataset, staged with\n# *deliberately* sub-optimal defaults so the goblin has something to fix in\n# the demo. This script does NOT need to actually execute on a host \u2014 it\n# exists so `parse_config` can extract a realistic WorkloadConfig from it.\n#\n# Expected findings when audited:\n# - precision.bf16_over_fp16_on_mi300x (fp16=True)\n# - attention.flash_rocm_over_eager (attn_implementation=\"eager\")\n# - data.dataloader_workers_zero (dataloader_num_workers=0)\n# - memory.batch_too_small_for_192gb (per_device_train_batch_size=4)\n\nimport os\n\nimport torch\nfrom datasets import load_dataset\nfrom peft import LoraConfig, get_peft_model\nfrom torch.utils.data import DataLoader\nfrom transformers import (\n AutoModelForCausalLM,\n AutoTokenizer,\n Trainer,\n TrainingArguments,\n)\n\n# A redactable secret so parse_config has something to scrub during the demo.\nos.environ[\"HF_TOKEN\"] = \"<REDACTED:hf_token>\"\nHF_TOKEN = os.environ[\"HF_TOKEN\"]\n\n# ROCm-flavored env knobs the agent should pick up into env_vars.\nos.environ[\"HSA_FORCE_FINE_GRAIN_PCIE\"] = \"1\"\nos.environ[\"MIOPEN_FIND_MODE\"] = \"3\"\n\nMODEL_ID = \"Qwen/Qwen2.5-7B-Instruct\"\n\ntokenizer = AutoTokenizer.from_pretrained(MODEL_ID, token=HF_TOKEN)\nmodel = AutoModelForCausalLM.from_pretrained(\n MODEL_ID,\n torch_dtype=torch.float16,\n attn_implementation=\"eager\", # naive attention -- goblin should swap to flash_rocm\n token=HF_TOKEN,\n)\n\n# LoRA \u2014 rank 16, attached to attention projections.\nlora_config = LoraConfig(\n r=16,\n lora_alpha=32,\n target_modules=[\"q_proj\", \"v_proj\"],\n lora_dropout=0.05,\n bias=\"none\",\n task_type=\"CAUSAL_LM\",\n)\nmodel = get_peft_model(model, lora_config)\n\ndataset = load_dataset(\"yahma/alpaca-cleaned\", split=\"train\")\n\n# Hand-rolled DataLoader so parse_config sees the dataloader kwargs explicitly.\ntrain_loader = DataLoader(\n dataset,\n batch_size=4,\n num_workers=0, # leaves the GPU starved during training -- data_wait waste\n pin_memory=False,\n prefetch_factor=2,\n persistent_workers=False,\n)\n\ntraining_args = TrainingArguments(\n output_dir=\"./out\",\n per_device_train_batch_size=4, # leaves HBM on the floor at 192 GB\n gradient_accumulation_steps=8,\n num_train_epochs=3,\n learning_rate=2e-4,\n warmup_steps=100,\n fp16=True, # bf16 is the right call on CDNA3\n optim=\"adamw_torch\",\n logging_steps=10,\n save_steps=500,\n dataloader_num_workers=0,\n dataloader_pin_memory=False,\n gradient_checkpointing=False,\n torch_compile=False,\n report_to=\"none\",\n push_to_hub=False,\n)\n\ntrainer = Trainer(\n model=model,\n args=training_args,\n train_dataset=dataset,\n tokenizer=tokenizer,\n)\n\nif __name__ == \"__main__\":\n trainer.train()\n",
970
+ "redactions": [
971
+ "hf_token"
972
+ ]
973
+ },
974
+ "diff": "- attention_impl: 'eager'\n+ attention_impl: 'flash_rocm'\n- precision: 'fp16'\n+ precision: 'bf16'",
975
+ "rationale": [
976
+ {
977
+ "rule_id": "precision.bf16_over_fp16_on_mi300x",
978
+ "rationale": "MI300X CDNA3 matrix cores execute bf16 at the same throughput as fp16 with strictly better numerical stability. Reduces NaN risk in long runs.",
979
+ "citation": "ROCm MI300X Optimization Guide \u00a73.2 \u2014 bf16 vs fp16",
980
+ "targets_bucket": "precision_path",
981
+ "estimated_recovery_seconds": 0.0935
982
+ },
983
+ {
984
+ "rule_id": "attention.flash_rocm_over_eager",
985
+ "rationale": "Use the ROCm-validated flash-attention kernel (via Optimum-AMD or PyTorch SDPA backend). Eliminates O(seq_len^2) attention memory; typically 2-3x faster on MI300X for seq_len >= 1024.",
986
+ "citation": "AMD ROCm vLLM/Optimum-AMD docs \u2014 Flash Attention validated on MI300",
987
+ "targets_bucket": "kernel_shape",
988
+ "estimated_recovery_seconds": 0.041999999999999996
989
+ }
990
+ ],
991
+ "expected_speedup_low": 1.04,
992
+ "expected_speedup_high": 1.31,
993
+ "confidence": 0.85
994
+ },
995
+ "metric_deltas": [
996
+ {
997
+ "name": "tokens_per_sec",
998
+ "before": 142.0,
999
+ "after": 318.0,
1000
+ "unit": "tok/s"
1001
+ },
1002
+ {
1003
+ "name": "mfu_pct",
1004
+ "before": 24.0,
1005
+ "after": 51.0,
1006
+ "unit": "%"
1007
+ },
1008
+ {
1009
+ "name": "hbm_peak_gb",
1010
+ "before": 73.0,
1011
+ "after": 168.0,
1012
+ "unit": "GB"
1013
+ },
1014
+ {
1015
+ "name": "gpu_util_pct",
1016
+ "before": 46.0,
1017
+ "after": 86.0,
1018
+ "unit": "%"
1019
+ }
1020
+ ],
1021
+ "waste_budget_before": {
1022
+ "useful_gpu": 0.42,
1023
+ "data_wait": 0.21,
1024
+ "host_gap": 0.06,
1025
+ "comm_excess": 0.0,
1026
+ "memory_headroom": 0.14,
1027
+ "precision_path": 0.11,
1028
+ "kernel_shape": 0.06
1029
+ },
1030
+ "waste_budget_after": {
1031
+ "useful_gpu": 0.78,
1032
+ "data_wait": 0.04,
1033
+ "host_gap": 0.05,
1034
+ "comm_excess": 0.0,
1035
+ "memory_headroom": 0.04,
1036
+ "precision_path": 0.02,
1037
+ "kernel_shape": 0.03
1038
+ },
1039
+ "speedup_actual": 2.24,
1040
+ "speedup_predicted_low": 1.04,
1041
+ "speedup_predicted_high": 1.31,
1042
+ "confidence": 0.85,
1043
+ "summary_line": "Tokens/sec: 142 \u2192 318 (2.24\u00d7). MFU: 24% \u2192 51%.",
1044
+ "validity_footer": "Recommendations validated against MI300X with the observed ROCm and PyTorch versions. Re-run the audit if you change model, hardware, or framework version."
1045
+ }
1046
+ }
1047
+ },
1048
+ {
1049
+ "type": "final_report",
1050
+ "data": {
1051
+ "report": {
1052
+ "workload_name": "Qwen2.5-7B LoRA fine-tune",
1053
+ "before": {
1054
+ "steps": 50,
1055
+ "tokens_per_sec": 142.0,
1056
+ "mfu_pct": 24.0,
1057
+ "hbm_peak_gb": 73.0,
1058
+ "hbm_avg_gb": 61.0,
1059
+ "gpu_util_pct": 46.0,
1060
+ "top_kernels": [
1061
+ {
1062
+ "name": "aten::matmul (fp16)",
1063
+ "pct_time": 38.0
1064
+ },
1065
+ {
1066
+ "name": "aten::scaled_dot_product_attention (eager)",
1067
+ "pct_time": 24.0
1068
+ },
1069
+ {
1070
+ "name": "aten::layer_norm",
1071
+ "pct_time": 8.0
1072
+ },
1073
+ {
1074
+ "name": "aten::cross_entropy_loss",
1075
+ "pct_time": 5.0
1076
+ },
1077
+ {
1078
+ "name": "aten::copy_ (h2d)",
1079
+ "pct_time": 11.0
1080
+ }
1081
+ ],
1082
+ "attention_kernel_loaded": "eager",
1083
+ "waste_budget": {
1084
+ "useful_gpu": 0.42,
1085
+ "data_wait": 0.21,
1086
+ "host_gap": 0.06,
1087
+ "comm_excess": 0.0,
1088
+ "memory_headroom": 0.14,
1089
+ "precision_path": 0.11,
1090
+ "kernel_shape": 0.06
1091
+ },
1092
+ "warnings": [
1093
+ "Attention kernel is 'eager'; flash_rocm or sdpa would be much faster.",
1094
+ "HBM utilization 38% suggests batch_size is leaving memory on the floor."
1095
+ ],
1096
+ "rocm_version": "6.1.0",
1097
+ "pytorch_version": "2.3.0+rocm6.1",
1098
+ "runner_kind": "fake"
1099
+ },
1100
+ "after": {
1101
+ "steps": 50,
1102
+ "tokens_per_sec": 318.0,
1103
+ "mfu_pct": 51.0,
1104
+ "hbm_peak_gb": 168.0,
1105
+ "hbm_avg_gb": 152.0,
1106
+ "gpu_util_pct": 86.0,
1107
+ "top_kernels": [
1108
+ {
1109
+ "name": "aten::matmul (bf16)",
1110
+ "pct_time": 46.0
1111
+ },
1112
+ {
1113
+ "name": "flash_attn_rocm_fwd",
1114
+ "pct_time": 19.0
1115
+ },
1116
+ {
1117
+ "name": "flash_attn_rocm_bwd",
1118
+ "pct_time": 14.0
1119
+ },
1120
+ {
1121
+ "name": "aten::layer_norm",
1122
+ "pct_time": 7.0
1123
+ },
1124
+ {
1125
+ "name": "aten::cross_entropy_loss",
1126
+ "pct_time": 4.0
1127
+ }
1128
+ ],
1129
+ "attention_kernel_loaded": "flash_rocm",
1130
+ "waste_budget": {
1131
+ "useful_gpu": 0.78,
1132
+ "data_wait": 0.04,
1133
+ "host_gap": 0.05,
1134
+ "comm_excess": 0.0,
1135
+ "memory_headroom": 0.04,
1136
+ "precision_path": 0.02,
1137
+ "kernel_shape": 0.03
1138
+ },
1139
+ "warnings": [],
1140
+ "rocm_version": "6.1.0",
1141
+ "pytorch_version": "2.3.0+rocm6.1",
1142
+ "runner_kind": "fake"
1143
+ },
1144
+ "patch": {
1145
+ "new_config": {
1146
+ "model_name": "Qwen/Qwen2.5-7B-Instruct",
1147
+ "batch_size": 4,
1148
+ "grad_accum_steps": 8,
1149
+ "seq_len": 1024,
1150
+ "precision": "bf16",
1151
+ "optimizer": "adamw_torch",
1152
+ "attention_impl": "flash_rocm",
1153
+ "gradient_checkpointing": false,
1154
+ "lora_rank": 16,
1155
+ "dataloader_workers": 0,
1156
+ "dataloader_pin_memory": false,
1157
+ "dataloader_prefetch_factor": 2,
1158
+ "dataloader_persistent_workers": false,
1159
+ "torch_compile": false,
1160
+ "lr": 0.0002,
1161
+ "warmup_steps": 100,
1162
+ "env_vars": {
1163
+ "HF_TOKEN": "hf_aaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
1164
+ "HSA_FORCE_FINE_GRAIN_PCIE": "1",
1165
+ "MIOPEN_FIND_MODE": "3"
1166
+ },
1167
+ "extras": {
1168
+ "lora.lora_alpha": 32,
1169
+ "lora.target_modules": [
1170
+ "q_proj",
1171
+ "v_proj"
1172
+ ],
1173
+ "lora.lora_dropout": 0.05,
1174
+ "lora.bias": "none",
1175
+ "lora.task_type": "CAUSAL_LM",
1176
+ "batch_size": 4,
1177
+ "output_dir": "./out",
1178
+ "num_train_epochs": 3,
1179
+ "logging_steps": 10,
1180
+ "save_steps": 500,
1181
+ "report_to": "none",
1182
+ "push_to_hub": false
1183
+ },
1184
+ "raw_source": "# GPU Goblin canonical demo workload.\n#\n# Qwen2.5-7B-Instruct + LoRA fine-tune on the alpaca-cleaned dataset, staged with\n# *deliberately* sub-optimal defaults so the goblin has something to fix in\n# the demo. This script does NOT need to actually execute on a host \u2014 it\n# exists so `parse_config` can extract a realistic WorkloadConfig from it.\n#\n# Expected findings when audited:\n# - precision.bf16_over_fp16_on_mi300x (fp16=True)\n# - attention.flash_rocm_over_eager (attn_implementation=\"eager\")\n# - data.dataloader_workers_zero (dataloader_num_workers=0)\n# - memory.batch_too_small_for_192gb (per_device_train_batch_size=4)\n\nimport os\n\nimport torch\nfrom datasets import load_dataset\nfrom peft import LoraConfig, get_peft_model\nfrom torch.utils.data import DataLoader\nfrom transformers import (\n AutoModelForCausalLM,\n AutoTokenizer,\n Trainer,\n TrainingArguments,\n)\n\n# A redactable secret so parse_config has something to scrub during the demo.\nos.environ[\"HF_TOKEN\"] = \"<REDACTED:hf_token>\"\nHF_TOKEN = os.environ[\"HF_TOKEN\"]\n\n# ROCm-flavored env knobs the agent should pick up into env_vars.\nos.environ[\"HSA_FORCE_FINE_GRAIN_PCIE\"] = \"1\"\nos.environ[\"MIOPEN_FIND_MODE\"] = \"3\"\n\nMODEL_ID = \"Qwen/Qwen2.5-7B-Instruct\"\n\ntokenizer = AutoTokenizer.from_pretrained(MODEL_ID, token=HF_TOKEN)\nmodel = AutoModelForCausalLM.from_pretrained(\n MODEL_ID,\n torch_dtype=torch.float16,\n attn_implementation=\"eager\", # naive attention -- goblin should swap to flash_rocm\n token=HF_TOKEN,\n)\n\n# LoRA \u2014 rank 16, attached to attention projections.\nlora_config = LoraConfig(\n r=16,\n lora_alpha=32,\n target_modules=[\"q_proj\", \"v_proj\"],\n lora_dropout=0.05,\n bias=\"none\",\n task_type=\"CAUSAL_LM\",\n)\nmodel = get_peft_model(model, lora_config)\n\ndataset = load_dataset(\"yahma/alpaca-cleaned\", split=\"train\")\n\n# Hand-rolled DataLoader so parse_config sees the dataloader kwargs explicitly.\ntrain_loader = DataLoader(\n dataset,\n batch_size=4,\n num_workers=0, # leaves the GPU starved during training -- data_wait waste\n pin_memory=False,\n prefetch_factor=2,\n persistent_workers=False,\n)\n\ntraining_args = TrainingArguments(\n output_dir=\"./out\",\n per_device_train_batch_size=4, # leaves HBM on the floor at 192 GB\n gradient_accumulation_steps=8,\n num_train_epochs=3,\n learning_rate=2e-4,\n warmup_steps=100,\n fp16=True, # bf16 is the right call on CDNA3\n optim=\"adamw_torch\",\n logging_steps=10,\n save_steps=500,\n dataloader_num_workers=0,\n dataloader_pin_memory=False,\n gradient_checkpointing=False,\n torch_compile=False,\n report_to=\"none\",\n push_to_hub=False,\n)\n\ntrainer = Trainer(\n model=model,\n args=training_args,\n train_dataset=dataset,\n tokenizer=tokenizer,\n)\n\nif __name__ == \"__main__\":\n trainer.train()\n",
1185
+ "redactions": [
1186
+ "hf_token"
1187
+ ]
1188
+ },
1189
+ "diff": "- attention_impl: 'eager'\n+ attention_impl: 'flash_rocm'\n- precision: 'fp16'\n+ precision: 'bf16'",
1190
+ "rationale": [
1191
+ {
1192
+ "rule_id": "precision.bf16_over_fp16_on_mi300x",
1193
+ "rationale": "MI300X CDNA3 matrix cores execute bf16 at the same throughput as fp16 with strictly better numerical stability. Reduces NaN risk in long runs.",
1194
+ "citation": "ROCm MI300X Optimization Guide \u00a73.2 \u2014 bf16 vs fp16",
1195
+ "targets_bucket": "precision_path",
1196
+ "estimated_recovery_seconds": 0.0935
1197
+ },
1198
+ {
1199
+ "rule_id": "attention.flash_rocm_over_eager",
1200
+ "rationale": "Use the ROCm-validated flash-attention kernel (via Optimum-AMD or PyTorch SDPA backend). Eliminates O(seq_len^2) attention memory; typically 2-3x faster on MI300X for seq_len >= 1024.",
1201
+ "citation": "AMD ROCm vLLM/Optimum-AMD docs \u2014 Flash Attention validated on MI300",
1202
+ "targets_bucket": "kernel_shape",
1203
+ "estimated_recovery_seconds": 0.041999999999999996
1204
+ }
1205
+ ],
1206
+ "expected_speedup_low": 1.04,
1207
+ "expected_speedup_high": 1.31,
1208
+ "confidence": 0.85
1209
+ },
1210
+ "metric_deltas": [
1211
+ {
1212
+ "name": "tokens_per_sec",
1213
+ "before": 142.0,
1214
+ "after": 318.0,
1215
+ "unit": "tok/s"
1216
+ },
1217
+ {
1218
+ "name": "mfu_pct",
1219
+ "before": 24.0,
1220
+ "after": 51.0,
1221
+ "unit": "%"
1222
+ },
1223
+ {
1224
+ "name": "hbm_peak_gb",
1225
+ "before": 73.0,
1226
+ "after": 168.0,
1227
+ "unit": "GB"
1228
+ },
1229
+ {
1230
+ "name": "gpu_util_pct",
1231
+ "before": 46.0,
1232
+ "after": 86.0,
1233
+ "unit": "%"
1234
+ }
1235
+ ],
1236
+ "waste_budget_before": {
1237
+ "useful_gpu": 0.42,
1238
+ "data_wait": 0.21,
1239
+ "host_gap": 0.06,
1240
+ "comm_excess": 0.0,
1241
+ "memory_headroom": 0.14,
1242
+ "precision_path": 0.11,
1243
+ "kernel_shape": 0.06
1244
+ },
1245
+ "waste_budget_after": {
1246
+ "useful_gpu": 0.78,
1247
+ "data_wait": 0.04,
1248
+ "host_gap": 0.05,
1249
+ "comm_excess": 0.0,
1250
+ "memory_headroom": 0.04,
1251
+ "precision_path": 0.02,
1252
+ "kernel_shape": 0.03
1253
+ },
1254
+ "speedup_actual": 2.24,
1255
+ "speedup_predicted_low": 1.04,
1256
+ "speedup_predicted_high": 1.31,
1257
+ "confidence": 0.85,
1258
+ "summary_line": "Tokens/sec: 142 \u2192 318 (2.24\u00d7). MFU: 24% \u2192 51%.",
1259
+ "validity_footer": "Recommendations validated against MI300X with the observed ROCm and PyTorch versions. Re-run the audit if you change model, hardware, or framework version."
1260
+ }
1261
+ }
1262
+ }
1263
+ ]