6from typing
import Union, Callable, List, Optional
7from shutil
import rmtree
15from pathlib
import Path
16from .preprocess
import preproc_builder
17from .utils_calib
import (
19 list_np_files_in_json,
20 get_balanced_ids_coco,
23 save_calib_to_msgpack,
30def get_yaml(yaml_path: str):
32 isinstance(yaml_path, str)
33 and os.path.isfile(yaml_path)
34 and yaml_path.endswith(
".yaml")
35 ), f
"Got wrong yaml path: {yaml_path}."
36 with open(yaml_path)
as f:
37 cfg = yaml.load(f, Loader=yaml.FullLoader)
46 anno_json: str =
None,
47 file_format: str =
"%012d.jpg",
49 remove_npy: bool =
False,
51 save_calib_msg: bool =
False,
55 @brief From images and a user-provided preprocessing function, generate calibration NumPy files and a manifest.
57 @param pre_ftn Callable. Pre-processing function that accepts an image path and returns a NumPy array.
58 @param data_dir string. Directory containing the raw calibration images.
59 @param save_dir string. Directory in which to store the generated NumPy files and metadata text file.
60 @param save_name string. Basename for the saved assets. NumPy files are written to
61 @c {save_dir}/{save_name}_npy and the manifest to @c {save_dir}/{save_name}.txt. Defaults to the basename of
62 @p data_dir when omitted.
63 @param anno_json string. Optional COCO-style annotation file. When provided, samples are randomly selected while
64 maintaining class balance.
65 @param file_format string. Filename format that uses @c image_idx (for example "%012d.jpg").
66 @param max_size int. Maximum number of calibration samples. A value of -1 disables the limit.
67 @param remove_npy bool. Remove existing NumPy outputs before generating new data.
68 @param seed int. Random seed applied to sampling and class-balanced selection. Defaults to 2023.
69 @param save_calib_msg bool. Persist the calibration metadata as an MSGpack file in addition to the manifest.
70 @param msg_path string. Explicit MSGpack output path. When omitted, the path is auto-generated by dataset name and
72 @return string. Path to the generated text file that lists the preprocessed NumPy samples.
74 @note Calibration samples are written as float32 NumPy arrays derived from the @p pre_ftn output. When
75 @p max_size is positive and the dataset is larger, a random subset is used. COCO annotations override this sampling
76 to balance categories.
80 ), f
"Expected a function for pre_ftn, but got type={type(pre_ftn)}."
83 save_name = os.path.basename(data_dir)
84 save_npy_dir = os.path.join(save_dir, f
"{save_name}")
85 save_txt_dir = os.path.join(save_dir, f
"{save_name}.txt")
88 if (remove_npy)
and (os.path.isdir(save_dir))
and (os.path.isdir(save_npy_dir)):
89 tmp_np_list = [x
for x
in os.listdir(save_npy_dir)
if x.endswith(
"npy")]
90 print(f
"There are {len(tmp_np_list)} npy files in {save_npy_dir}.")
92 os.makedirs(save_dir, exist_ok=
True)
93 os.makedirs(save_npy_dir, exist_ok=
True)
95 img_path_list = read_structure(data_dir)
102 if anno_json
is not None:
103 img_path_list, ids_list = get_balanced_ids_coco(
104 anno_json, img_path_list, max_size, fname_format=file_format, seed=seed
107 elif max_size > 0
and len(img_path_list) > max_size:
108 img_path_list = random.sample(img_path_list, max_size)
109 dataname =
"any_sampled"
114 for img_path
in tqdm(img_path_list, desc=
"Making Numpy File"):
115 out = pre_ftn(img_path)
118 if not isinstance(out, np.ndarray):
119 raise AssertionError(f
"Got unexpected tensor type: {type(out)}.", out)
121 save_npy = out.astype(np.float32)
122 fname = os.path.basename(img_path)
123 fname_list.append(fname)
124 npy_list.append(save_npy)
125 img_name = Path(fname).stem
126 save_path = os.path.join(save_npy_dir, img_name +
".npy")
127 np.save(save_path, save_npy)
130 calib_dict = make_calib_dict(
131 img_path_list, fname_list, npy_list, dataname, ids_list
133 save_calib_to_msgpack(calib_dict, msg_path)
136 list_np_files_in_txt(save_npy_dir, save_txt_dir)
141 args_pre: Union[str, dict],
144 save_name: str =
None,
145 anno_json: str =
None,
146 file_format: str =
"%012d.jpg",
148 remove_npy: bool =
False,
150 save_calib_msg: bool =
False,
151 msg_path: str =
None,
154 @brief Create calibration NumPy files and a manifest using a YAML or dict preprocessing configuration.
156 @param args_pre string or dict. Path to a YAML file or an in-memory dictionary describing the preprocessing
157 pipeline. See the preproc_builder class for all supported operators and parameters.
158 @param data_dir string. Directory of calibration images.
159 @param save_dir string. Directory where the generated NumPy files and manifest text file are stored.
160 @param save_name string. Optional basename for outputs. Defaults to the basename of @p data_dir.
161 @param anno_json string. Optional COCO-format annotation file used to sample images with class balance.
162 @param file_format string. Filename template built from @c image_idx (defaults to "%012d.jpg").
163 @param max_size int. Maximum number of calibration samples to generate; -1 keeps all available items.
164 @param remove_npy bool. Remove existing NumPy outputs before running preprocessing.
165 @param seed int. Random seed used for sampling. Defaults to 2023.
166 @param save_calib_msg bool. Save calibration metadata as MSGpack alongside NumPy and text outputs.
167 @param msg_path string. Explicit MSGpack output path. Auto-generated from dataset name and sample count when
169 @return string. Path to the manifest text file that lists the generated NumPy samples.
171 @note The preprocessing pipeline is constructed through @c preproc_builder and executed via @c make_calib_man. Use
172 the YAML schema to combine primitives such as GetImage, Resize, Normalize, Pad, CenterCrop, and SetOrder in a
175 if isinstance(args_pre, str):
176 args_pre = get_yaml(args_pre)
177 elif isinstance(args_pre, dict):
181 f
"Expected yaml path (str) or cfg dictionary, but got type={type(args_pre)}."
184 pre_process_ftn = preproc_builder(args_pre, to_tensor=
False)
185 save_txt_dir = make_calib_man(
202 args_pre: Union[str, dict],
204 subset_list: Union[List[str], str],
208 max_calib: int = 512,
209 save_prefix: Optional[str] =
None,
211 """Generate calibration embeddings for LLM models using Hugging Face datasets.
214 args_pre: YAML path or preprocessing configuration dictionary. Must set
216 dataset_name: Name of the Hugging Face dataset to load.
217 subset_list: List of dataset subsets (e.g. language splits) to iterate.
218 split: HF dataset split to use.
219 text_field: Key containing text in dataset entries.
220 save_dir: Root directory where calibration samples are stored.
221 max_calib: Maximum number of calibration samples per subset.
222 save_prefix: Override prefix used in output directory naming. If None,
223 derives from tokenizer directory name when available.
226 List of paths to generated calibration txt files, one per subset.
229 from datasets
import load_dataset
231 if isinstance(args_pre, str):
232 args_pre = get_yaml(args_pre)
233 elif not isinstance(args_pre, dict):
235 f
"Expected yaml path (str) or cfg dictionary, but got type={type(args_pre)}."
238 pre_process_ftn = preproc_builder(args_pre, to_tensor=
False)
239 if getattr(pre_process_ftn,
"datatype",
None) !=
"LLM":
241 "LLM calibration requires Datatype='LLM' in preprocessing config."
244 embedding_stage = next(
245 (fnc
for fnc
in pre_process_ftn.preprocess
if hasattr(fnc,
"model_name")),
248 model_name = getattr(embedding_stage,
"model_name",
None)
249 if save_prefix
is None:
250 save_prefix = model_name
or "llm"
252 os.makedirs(save_dir, exist_ok=
True)
253 generated_txt_paths: List[str] = []
255 if isinstance(subset_list, str):
256 subset_list = [subset_list]
258 for subset_name
in subset_list:
259 dataset = load_dataset(dataset_name, subset_name, split=split)
260 lang_suffix = subset_name.split(
".")[-1]
if "." in subset_name
else subset_name
262 f
"{save_prefix}-{dataset_name.replace('/', '_')}-{lang_suffix}"
264 target_dir = os.path.join(save_dir, target_dir_name)
265 os.makedirs(target_dir, exist_ok=
True)
268 for idx, sample
in enumerate(dataset):
269 if isinstance(sample, dict):
270 if text_field
not in sample:
272 f
"Key '{text_field}' not found in dataset sample for subset {subset_name}."
274 sample_input = sample[text_field]
276 sample_input = sample
279 embedded_text = pre_process_ftn(sample_input)
280 except Exception
as err:
281 print(f
"Skipping dataset item {idx} due to error: {err}")
284 if embedded_text
is None:
287 if not isinstance(embedded_text, np.ndarray):
288 raise AssertionError(
289 f
"LLM preprocessing should return numpy.ndarray, got {type(embedded_text)}."
292 save_path = os.path.join(target_dir, f
"inputs_embeds_{cur_num_calib}.npy")
293 np.save(save_path, embedded_text)
296 if cur_num_calib >= max_calib:
299 if cur_num_calib == 0:
301 f
"No calibration samples were generated for subset {subset_name}; check preprocessing constraints."
305 txt_path = os.path.join(save_dir, f
"{target_dir_name}.txt")
306 list_np_files_in_txt(target_dir, txt_path)
307 generated_txt_paths.append(txt_path)
309 return generated_txt_paths