Files
wehub-resource-sync a203934033
Lint test / lint (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:34:58 +08:00

154 lines
5.6 KiB
Python

# Copyright (c) ModelScope Contributors. All rights reserved.
import inspect
import numpy as np
import os
import tempfile
from datasets import Dataset as HfDataset
from modelscope.hub.utils.utils import get_cache_dir
from torch.utils.data import Dataset
from typing import Any, Callable, Dict, Optional, Union
from swift.template import MaxLengthError, Template
from swift.utils import get_logger
from .preprocessor import RowPreprocessor
logger = get_logger()
def sample_dataset(
dataset: HfDataset,
dataset_sample: Optional[int],
shuffle: bool = True,
random_state: Optional[np.random.RandomState] = None,
shuffle_all: bool = False, # For compatibility, this defaults to False.
) -> HfDataset:
"""Sample dataset by a dataset_sample number
Args:
dataset: The dataset instance, iterable dataset is not supported
dataset_sample: The sample number
shuffle: Whether to perform random sampling on non-streaming datasets
random_state: The random state
Returns:
The sampled dataset
"""
if dataset_sample is None:
return dataset
n_repeat_sample = dataset_sample // len(dataset)
n_remain_sample = dataset_sample % len(dataset)
if n_repeat_sample >= 1 and n_remain_sample >= 1:
logger.warning(f'dataset_sample:{dataset_sample} is greater than len(dataset):{len(dataset)}, '
'repeated sampling will be performed.')
idx = np.tile(range(len(dataset)), n_repeat_sample)
if random_state is None:
random_state = np.random.RandomState()
if n_remain_sample >= 1:
if shuffle:
idx_remain = random_state.permutation(len(dataset))[:n_remain_sample]
else:
idx_remain = np.arange(n_remain_sample)
idx = np.concatenate([idx, idx_remain])
if n_repeat_sample >= 1 and shuffle and shuffle_all:
random_state.shuffle(idx)
dataset = dataset.select(idx)
return dataset
class LazyLLMDataset(Dataset):
"""This class if used to lazy tokenize the dataset, and skips bad ones when training"""
def __init__(self,
dataset: HfDataset,
encode_func: Callable[[Dict[str, Any]], Dict[str, Any]],
*,
n_try_fetch: int = 10,
strict: bool = False,
random_state: Optional[Union[np.random.RandomState, int]] = None,
traceback_limit: int = 10) -> None:
self.dataset = dataset
self.encode_func = encode_func
n_try_fetch = 1 if strict else min(n_try_fetch, len(self.dataset))
assert n_try_fetch >= 1
self.strict = strict
self.n_try_fetch = n_try_fetch
if not isinstance(random_state, np.random.RandomState):
random_state = np.random.RandomState(random_state)
self.random_state = random_state
self.traceback_limit = traceback_limit
self._traceback_counter = 0
self._idx = 0
self._idx_list = self.random_state.permutation(len(self.dataset)).tolist()
def __getitem__(self, idx: int) -> Dict[str, Any]:
if isinstance(idx, str):
return self.dataset[idx]
for i in range(self.n_try_fetch):
if i > 0:
idx = self._idx_list[self._idx]
self._idx = (self._idx + 1) % len(self.dataset)
data = self.dataset[idx]
try:
return self.encode_func(data, return_length=True)
except Exception as e:
if self.strict:
logger.warning('To avoid errors, you can pass `strict=False`.')
raise
if isinstance(e, MaxLengthError):
continue
if self.traceback_limit is not None and self._traceback_counter < self.traceback_limit:
import traceback
logger.info(traceback.format_exc())
logger.warning('👆👆👆There are errors in the template.encode, '
'and another piece of data will be randomly selected.')
self._traceback_counter += 1
raise ValueError('Failed to retrieve the dataset. You can avoid this issue by increasing `max_length` or '
'modifying the `truncation_strategy`.')
def __len__(self) -> int:
return len(self.dataset)
class EncodePreprocessor(RowPreprocessor):
def __init__(self, template: 'Template'):
super().__init__()
self.template = template
def preprocess(self, row: Dict[str, Any]) -> Optional[Dict[str, Any]]:
return self.template.encode(row, return_length=True)
class AddLengthPreprocessor(EncodePreprocessor):
def preprocess(self, row: Dict[str, Any]) -> Optional[Dict[str, Any]]:
encoded = super().preprocess(row)
row['lengths'] = encoded['lengths']
return row
TEMP_DIR_POOL = {}
def get_temporary_cache_files_directory(prefix=None):
if prefix is None:
import datasets.config
prefix = datasets.config.TEMP_CACHE_DIR_PREFIX
if prefix in TEMP_DIR_POOL:
TEMP_DIR = TEMP_DIR_POOL[prefix]
else:
tmp_dir = os.path.join(get_cache_dir(), 'tmp')
os.makedirs(tmp_dir, exist_ok=True)
kwargs = {}
parameters = inspect.signature(tempfile.TemporaryDirectory.__init__).parameters
if 'ignore_cleanup_errors' in parameters:
kwargs['ignore_cleanup_errors'] = True
TEMP_DIR = tempfile.TemporaryDirectory(prefix=prefix, dir=tmp_dir, **kwargs)
logger.info(f'create tmp_dir: {TEMP_DIR.name}')
TEMP_DIR_POOL[prefix] = TEMP_DIR
return TEMP_DIR.name