6from typing
import Union, Callable, List, Optional
7from shutil
import rmtree
15from pathlib
import Path
16from .preprocess
import preproc_builder
17from .utils_calib
import (
18 list_calib_files_in_txt,
19 get_balanced_ids_coco,
22 save_calib_to_msgpack,
29def get_yaml(yaml_path: str):
31 isinstance(yaml_path, str)
32 and os.path.isfile(yaml_path)
33 and yaml_path.endswith(
".yaml")
34 ), f
"Got wrong yaml path: {yaml_path}."
35 with open(yaml_path)
as f:
36 cfg = yaml.load(f, Loader=yaml.FullLoader)
45 anno_json: str =
None,
46 file_format: str =
"%012d.jpg",
48 remove_npy: bool =
False,
50 save_calib_msg: bool =
False,
54 @brief From images and a user-provided preprocessing function, generate calibration NumPy files and a manifest.
56 @param pre_ftn Callable. Pre-processing function that accepts an image path and returns a NumPy array.
57 @param data_dir string. Directory containing the raw calibration images.
58 @param save_dir string. Directory in which to store the generated NumPy files and metadata text file.
59 @param save_name string. Basename for the saved assets. NumPy files are written to
60 @c {save_dir}/{save_name}_npy and the manifest to @c {save_dir}/{save_name}.txt. Defaults to the basename of
61 @p data_dir when omitted.
62 @param anno_json string. Optional COCO-style annotation file. When provided, samples are randomly selected while
63 maintaining class balance.
64 @param file_format string. Filename format that uses @c image_idx (for example "%012d.jpg").
65 @param max_size int. Maximum number of calibration samples. A value of -1 disables the limit.
66 @param remove_npy bool. Remove existing NumPy outputs before generating new data.
67 @param seed int. Random seed applied to sampling and class-balanced selection. Defaults to 2023.
68 @param save_calib_msg bool. Persist the calibration metadata as an MSGpack file in addition to the manifest.
69 @param msg_path string. Explicit MSGpack output path. When omitted, the path is auto-generated by dataset name and
71 @return string. Path to the generated text file that lists the preprocessed NumPy samples.
73 @note Calibration samples are written as float32 NumPy arrays derived from the @p pre_ftn output. When
74 @p max_size is positive and the dataset is larger, a random subset is used. COCO annotations override this sampling
75 to balance categories.
79 ), f
"Expected a function for pre_ftn, but got type={type(pre_ftn)}."
82 save_name = os.path.basename(data_dir)
83 save_npy_dir = os.path.join(save_dir, f
"{save_name}")
84 save_txt_dir = os.path.join(save_dir, f
"{save_name}.txt")
87 if (remove_npy)
and (os.path.isdir(save_dir))
and (os.path.isdir(save_npy_dir)):
88 tmp_np_list = [x
for x
in os.listdir(save_npy_dir)
if x.endswith(
"npy")]
89 print(f
"There are {len(tmp_np_list)} npy files in {save_npy_dir}.")
91 os.makedirs(save_dir, exist_ok=
True)
92 os.makedirs(save_npy_dir, exist_ok=
True)
94 img_path_list = read_structure(data_dir)
101 if anno_json
is not None:
102 img_path_list, ids_list = get_balanced_ids_coco(
103 anno_json, img_path_list, max_size, fname_format=file_format, seed=seed
106 elif max_size > 0
and len(img_path_list) > max_size:
107 img_path_list = random.sample(img_path_list, max_size)
108 dataname =
"any_sampled"
113 for img_path
in tqdm(img_path_list, desc=
"Making Numpy File"):
114 out = pre_ftn(img_path)
117 if not isinstance(out, np.ndarray):
118 raise AssertionError(f
"Got unexpected tensor type: {type(out)}.", out)
120 save_npy = out.astype(np.float32)
121 fname = os.path.basename(img_path)
122 fname_list.append(fname)
123 npy_list.append(save_npy)
124 img_name = Path(fname).stem
125 save_path = os.path.join(save_npy_dir, img_name +
".npy")
126 np.save(save_path, save_npy)
129 calib_dict = make_calib_dict(
130 img_path_list, fname_list, npy_list, dataname, ids_list
132 save_calib_to_msgpack(calib_dict, msg_path)
135 list_calib_files_in_txt(save_npy_dir, save_txt_dir)
140 args_pre: Union[str, dict],
143 save_name: str =
None,
144 anno_json: str =
None,
145 file_format: str =
"%012d.jpg",
147 remove_npy: bool =
False,
149 save_calib_msg: bool =
False,
150 msg_path: str =
None,
153 @brief Create calibration NumPy files and a manifest using a YAML or dict preprocessing configuration.
155 @param args_pre string or dict. Path to a YAML file or an in-memory dictionary describing the preprocessing
156 pipeline. See the preproc_builder class for all supported operators and parameters.
157 @param data_dir string. Directory of calibration images.
158 @param save_dir string. Directory where the generated NumPy files and manifest text file are stored.
159 @param save_name string. Optional basename for outputs. Defaults to the basename of @p data_dir.
160 @param anno_json string. Optional COCO-format annotation file used to sample images with class balance.
161 @param file_format string. Filename template built from @c image_idx (defaults to "%012d.jpg").
162 @param max_size int. Maximum number of calibration samples to generate; -1 keeps all available items.
163 @param remove_npy bool. Remove existing NumPy outputs before running preprocessing.
164 @param seed int. Random seed used for sampling. Defaults to 2023.
165 @param save_calib_msg bool. Save calibration metadata as MSGpack alongside NumPy and text outputs.
166 @param msg_path string. Explicit MSGpack output path. Auto-generated from dataset name and sample count when
168 @return string. Path to the manifest text file that lists the generated NumPy samples.
170 @note The preprocessing pipeline is constructed through @c preproc_builder and executed via @c make_calib_man. Use
171 the YAML schema to combine primitives such as GetImage, Resize, Normalize, Pad, CenterCrop, and SetOrder in a
174 if isinstance(args_pre, str):
175 args_pre = get_yaml(args_pre)
176 elif isinstance(args_pre, dict):
180 f
"Expected yaml path (str) or cfg dictionary, but got type={type(args_pre)}."
183 pre_process_ftn = preproc_builder(args_pre, to_tensor=
False)
184 save_txt_dir = make_calib_man(
201 args_pre: Union[str, dict],
203 subset_list: Union[List[str], str],
207 max_calib: int = 512,
208 save_prefix: Optional[str] =
None,
210 """Generate calibration embeddings for LLM models using Hugging Face datasets.
213 args_pre: YAML path or preprocessing configuration dictionary. Must set
215 dataset_name: Name of the Hugging Face dataset to load.
216 subset_list: List of dataset subsets (e.g. language splits) to iterate.
217 split: HF dataset split to use.
218 text_field: Key containing text in dataset entries.
219 save_dir: Root directory where calibration samples are stored.
220 max_calib: Maximum number of calibration samples per subset.
221 save_prefix: Override prefix used in output directory naming. If None,
222 derives from tokenizer directory name when available.
225 List of paths to generated calibration txt files, one per subset.
228 from datasets
import load_dataset
230 if isinstance(args_pre, str):
231 args_pre = get_yaml(args_pre)
232 elif not isinstance(args_pre, dict):
234 f
"Expected yaml path (str) or cfg dictionary, but got type={type(args_pre)}."
237 pre_process_ftn = preproc_builder(args_pre, to_tensor=
False)
238 if getattr(pre_process_ftn,
"datatype",
None) !=
"LLM":
240 "LLM calibration requires Datatype='LLM' in preprocessing config."
243 embedding_stage = next(
244 (fnc
for fnc
in pre_process_ftn.preprocess
if hasattr(fnc,
"model_name")),
247 model_name = getattr(embedding_stage,
"model_name",
None)
248 if save_prefix
is None:
249 save_prefix = model_name
or "llm"
251 os.makedirs(save_dir, exist_ok=
True)
252 generated_txt_paths: List[str] = []
254 if isinstance(subset_list, str):
255 subset_list = [subset_list]
257 for subset_name
in subset_list:
258 dataset = load_dataset(dataset_name, subset_name, split=split)
259 lang_suffix = subset_name.split(
".")[-1]
if "." in subset_name
else subset_name
261 f
"{save_prefix}-{dataset_name.replace('/', '_')}-{lang_suffix}"
263 target_dir = os.path.join(save_dir, target_dir_name)
264 os.makedirs(target_dir, exist_ok=
True)
267 for idx, sample
in enumerate(dataset):
268 if isinstance(sample, dict):
269 if text_field
not in sample:
271 f
"Key '{text_field}' not found in dataset sample for subset {subset_name}."
273 sample_input = sample[text_field]
275 sample_input = sample
278 embedded_text = pre_process_ftn(sample_input)
279 except Exception
as err:
280 print(f
"Skipping dataset item {idx} due to error: {err}")
283 if embedded_text
is None:
286 if not isinstance(embedded_text, np.ndarray):
287 raise AssertionError(
288 f
"LLM preprocessing should return numpy.ndarray, got {type(embedded_text)}."
291 save_path = os.path.join(target_dir, f
"inputs_embeds_{cur_num_calib}.npy")
292 np.save(save_path, embedded_text)
295 if cur_num_calib >= max_calib:
298 if cur_num_calib == 0:
300 f
"No calibration samples were generated for subset {subset_name}; check preprocessing constraints."
304 txt_path = os.path.join(save_dir, f
"{target_dir_name}.txt")
305 list_calib_files_in_txt(target_dir, txt_path)
306 generated_txt_paths.append(txt_path)
308 return generated_txt_paths