fix: 修复 nl_id + BFD 按 group_size 分批打包(存盘不拆分文件)

This commit is contained in:
2026-07-03 17:07:26 +08:00
parent 598e1ce4ae
commit 06735b9cb3
2 changed files with 44 additions and 19 deletions
+43 -18
View File
@@ -117,14 +117,17 @@ def cache_jsonl(
) -> List[str]: ) -> List[str]:
"""Tokenize JSONL files and pack them into HDF5 storage. """Tokenize JSONL files and pack them into HDF5 storage.
BFD packs in group_size-bounded batches to avoid O(N²), then all
packed chunks are merged and saved as one HDF5 file per input file.
Args: Args:
files: List of JSONL file paths. files: List of JSONL file paths.
output_dir: H5 output directory. output_dir: H5 output directory.
processor: Initialized Processor instance. processor: Initialized Processor instance.
pack_size: Packing length, <=0 means no packing. pack_size: Packing length, <=0 means no packing.
pad_value: Padding value. pad_value: Padding value.
group_size: Merge every this many packed chunks into one tensor, group_size: BFD batch granularity (token count threshold for each
<=0 means no merging. packing batch) and merge granularity, <=0 means no merging.
pack_algo: Packing algorithm: 'bfd' (default), 'ffd', pack_algo: Packing algorithm: 'bfd' (default), 'ffd',
'greedy'. Only used when pack_size > 0. 'greedy'. Only used when pack_size > 0.
@@ -135,10 +138,21 @@ def cache_jsonl(
output_files: List[str] = [] output_files: List[str] = []
output_keys = processor.output_keys output_keys = processor.output_keys
dtypes = (
dict(processor.schema.output_fields)
if processor.schema is not None
else None
)
pad_values = {k: (0 if k == "position_ids" else (False if k.endswith("_mask") else pad_value)) for k in output_keys}
target_tokens = group_size * pack_size if group_size > 0 and pack_size > 0 else 0
for file_path in files: for file_path in files:
file_name = Path(file_path).stem file_name = Path(file_path).stem
arrows: Dict[str, List] = {key: [] for key in output_keys} all_packed: Dict[str, List[Tensor]] = {key: [] for key in output_keys}
arrows_batch: Dict[str, List] = {key: [] for key in output_keys}
batch_tokens: int = 0
with open(file_path, "r", encoding="utf-8") as f: with open(file_path, "r", encoding="utf-8") as f:
for line_num, line in enumerate( for line_num, line in enumerate(
@@ -148,7 +162,9 @@ def cache_jsonl(
result = processor.process(json.loads(line)) result = processor.process(json.loads(line))
if result is not None: if result is not None:
for key in output_keys: for key in output_keys:
arrows[key].append(result[key]) arrows_batch[key].append(result[key])
if target_tokens > 0:
batch_tokens += int(result[output_keys[0]].shape[0])
except json.JSONDecodeError as e: except json.JSONDecodeError as e:
logger.warning( logger.warning(
f"JSON decode error in {file_path} line {line_num}: {e}. Skipping line." f"JSON decode error in {file_path} line {line_num}: {e}. Skipping line."
@@ -160,26 +176,35 @@ def cache_jsonl(
) )
continue continue
if not arrows[output_keys[0]]: if target_tokens > 0 and batch_tokens >= target_tokens:
packed = pack_tensors(arrows_batch, pack_size, pad_value, dtypes, pad_values=pad_values, algo=pack_algo)
for key in output_keys:
all_packed[key].extend(packed[key])
arrows_batch[key] = []
batch_tokens = 0
if arrows_batch[output_keys[0]]:
if pack_size > 0:
packed = pack_tensors(arrows_batch, pack_size, pad_value, dtypes, pad_values=pad_values, algo=pack_algo)
for key in output_keys:
all_packed[key].extend(packed[key])
else:
for key in output_keys:
all_packed[key].extend(arrows_batch[key])
if not all_packed[output_keys[0]]:
logger.warning(f"No valid samples in {file_path}, skipping") logger.warning(f"No valid samples in {file_path}, skipping")
continue continue
if pack_size > 0: if pack_size <= 0:
dtypes = ( output = all_packed
dict(processor.schema.output_fields) elif group_size > 0 and all_packed[output_keys[0]]:
if processor.schema is not None
else None
)
pad_values = {k: (0 if k == "position_ids" else (False if k.endswith("_mask") else pad_value)) for k in output_keys}
output = pack_tensors(arrows, pack_size, pad_value, dtypes, pad_values=pad_values, algo=pack_algo)
else:
output = arrows
if group_size > 0 and output[output_keys[0]]:
output = { output = {
key: merge_tensors(tensors, group_size) key: merge_tensors(tensors, group_size)
for key, tensors in output.items() for key, tensors in all_packed.items()
} }
else:
output = all_packed
h5_path = HDF5Handler.save(output_dir, file_name, output) h5_path = HDF5Handler.save(output_dir, file_name, output)
output_files.append(h5_path) output_files.append(h5_path)
+1 -1
View File
@@ -20,7 +20,7 @@ class ChatMLStrategy(PromptStrategy):
assistant_end: str = "<im▁end>", assistant_end: str = "<im▁end>",
): ):
super().__init__(tokenizer) super().__init__(tokenizer)
nl_id = tokenizer.token_to_id("\n") nl_id = tokenizer.encode("a\nb", add_special_tokens=False)[1]
self._user_start_ids = self._encode_format(user_start) + [nl_id] self._user_start_ids = self._encode_format(user_start) + [nl_id]
self._user_end_ids = self._encode_format(user_end) + [nl_id] self._user_end_ids = self._encode_format(user_end) + [nl_id]