Skip to content

Commit 914dd6c

Browse files
authored
Merge pull request #172 from prashantgupta24/cpu-data-script
✨ add script to manually save CPU validation data
2 parents fc3a30f + 0a0c558 commit 914dd6c

3 files changed

Lines changed: 144 additions & 0 deletions

File tree

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import json
2+
from aiu_fms_testing_utils.testing.validation import (
3+
LogitsExtractorHook,
4+
extract_validation_information,
5+
)
6+
from fms.models import get_model
7+
from transformers import AutoTokenizer
8+
# from concurrent.futures import ThreadPoolExecutor
9+
# Ideally we want this script to fetch data in parallel
10+
# But it's proving harder than initially thought
11+
# Making it work for now, making it fast is second step
12+
13+
import argparse
14+
import torch
15+
16+
17+
def load_jsonl(path):
18+
"""
19+
Loads a JSONL file.
20+
- If field is None: returns a list of dicts (one per line).
21+
- If field is a string: returns a list of obj[field] (only non-None values).
22+
"""
23+
data = []
24+
with open(path, "r", encoding="utf-8") as f:
25+
for idx, line in enumerate(f):
26+
line = line.strip()
27+
if not line:
28+
continue
29+
try:
30+
obj = json.loads(line)
31+
except (ValueError, json.JSONDecodeError) as e:
32+
print(f"Failed to parse line {idx} in {path}: {e}")
33+
data.append(obj)
34+
return data
35+
36+
37+
parser = argparse.ArgumentParser(
38+
description="Script which will save CPU validation data"
39+
)
40+
parser.add_argument(
41+
"--attention_type",
42+
type=str,
43+
default="paged",
44+
choices=["paged", "paged_fp8"],
45+
help="The attention type to use",
46+
)
47+
parser.add_argument(
48+
"--model_variant",
49+
type=str,
50+
default="ibm-ai-platform/micro-g3.3-8b-instruct-1b",
51+
help="The model id or path to use for this test. Note: must be a huggingface format",
52+
)
53+
parser.add_argument(
54+
"--max_new_tokens",
55+
type=int,
56+
default=8,
57+
help="set this if you want to change the number of tokens generated per sequence (1 prefill + max_new_tokens-1 decodes). Note: If this value is larger than 64, this may result in switching decode programs mid generation",
58+
)
59+
parser.add_argument(
60+
"--max_workers",
61+
type=int,
62+
default=8,
63+
help="max workers to run in parallel",
64+
)
65+
parser.add_argument(
66+
"--dataset_path",
67+
type=str,
68+
help="path to dataset",
69+
)
70+
args = parser.parse_args()
71+
max_new_tokens = args.max_new_tokens
72+
is_fp8 = "fp8" in args.attention_type
73+
model_variant = args.model_variant
74+
tokenizer = AutoTokenizer.from_pretrained(model_variant)
75+
model_path_kwargs = {"variant": model_variant}
76+
validation_model = get_model(
77+
architecture="hf_pretrained",
78+
device_type="cpu",
79+
data_type=None if is_fp8 else torch.bfloat16,
80+
fused_weights=False,
81+
**model_path_kwargs,
82+
)
83+
84+
# get the input ids for the validation
85+
dataset = load_jsonl(args.dataset_path)
86+
87+
88+
def process_row(row):
89+
id = row["id"]
90+
prompt_text = row["prompt"]
91+
input_ids = tokenizer.encode(prompt_text)
92+
print("fetching cpu validation info for id: ", id)
93+
with torch.no_grad():
94+
cpu_validation_info = extract_validation_information(
95+
validation_model,
96+
torch.tensor(input_ids).unsqueeze(0),
97+
max_new_tokens,
98+
LogitsExtractorHook(),
99+
attn_algorithm="math",
100+
)
101+
return {"id": id, "input_ids": input_ids, "validation": cpu_validation_info}
102+
103+
104+
# See comment above
105+
# with ThreadPoolExecutor(max_workers=args.max_workers) as executor:
106+
# results = list(executor.map(process_row, dataset))
107+
108+
# save the results
109+
validation_info = {}
110+
for row in dataset:
111+
result = process_row(row)
112+
# for result in results:
113+
tokens = result["validation"].get_info("tokens")
114+
generated_tokens_tensor = tokens[0][-max_new_tokens:]
115+
generated_tokens = [token.item() for token in generated_tokens_tensor]
116+
logits = result["validation"].get_info("logits")
117+
top_logprobs = []
118+
for step_num, logits_for_step in enumerate(logits[0]):
119+
logprob_for_step = torch.nn.functional.log_softmax(logits_for_step, dim=-1)
120+
values, indices = torch.topk(logprob_for_step, k=100)
121+
# in case we want to save a new tensor?
122+
# but this will also take memory
123+
# top_logprobs = torch.full_like(logprobs, float('-inf'))
124+
# top_logprobs.scatter_(1, indices, values)
125+
top_logprob_dict = {
126+
int(idx): float(val) for idx, val in zip(indices[0], values[0])
127+
}
128+
top_logprobs.append(top_logprob_dict)
129+
validation_info[result["id"]] = {
130+
"logprobs": top_logprobs,
131+
"tokens": generated_tokens,
132+
"text": tokenizer.decode(generated_tokens),
133+
}
134+
with open(f"{result['id']}_cpu_validation_info.json", "w") as f:
135+
json.dump(validation_info, f, indent=4)
136+
print(f"Done for {result['id']}")
137+
138+
139+
# save the final result
140+
with open("cpu_validation_info.json", "w") as f:
141+
json.dump(validation_info, f, indent=4)
142+
print("all done!")

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ dependencies = [
4747
# the repo and navigate to the `scripts` folder.
4848
[project.scripts]
4949
drive_paged_programs = "aiu_fms_testing_utils.scripts.drive_paged_programs:__main__"
50+
save_cpu_data = "aiu_fms_testing_utils.scripts.save_cpu_data:__main__"
5051
generate_layers_metrics = "aiu_fms_testing_utils.scripts.generate_layers_metrics:__main__"
5152
generate_metrics = "aiu_fms_testing_utils.scripts.generate_metrics:__main__"
5253
inference = "aiu_fms_testing_utils.scripts.inference:__main__"

scripts/save_cpu_data.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../aiu_fms_testing_utils/scripts/save_cpu_data.py

0 commit comments

Comments
 (0)