Coverage for  / home / jenkins / .local / lib / python3.10 / site-packages / hyper_parallel / data / indexed / indexed_dataset.py: 81%

83 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-11-15 07:18 +0800

1# Copyright 2026 Huawei Technologies Co., Ltd 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"); 

4# you may not use this file except in compliance with the License. 

5# You may obtain a copy of the License at 

6# 

7# http://www.apache.org/licenses/LICENSE-2.0 

8# 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, 

11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

12# See the License for the specific language governing permissions and 

13# limitations under the License. 

14# ============================================================================ 

15"""Indexed pretraining LLM datasets stored in ``.idx/.bin`` files.""" 

16 

17from __future__ import annotations 

18 

19from collections.abc import Callable, Mapping, Sequence 

20from functools import partial 

21from typing import Any, TypeAlias 

22 

23from hyper_parallel.data.dataset_logging import get_dataset_logger 

24from hyper_parallel.data.indexed.indexed_data_config import ( 

25 GPTDatasetConfig, 

26 build_gpt_dataset_config, 

27 resolve_data_paths, 

28 resolve_dataset_type, 

29) 

30from hyper_parallel.data.indexed.indexed_pretrain_dataset import SFTFromMRDataset 

31from hyper_parallel.data.indexed.indexed_split_builder import IndexedDatasetSplitBuilder 

32from hyper_parallel.data.parallel import DataLoaderParallelContext 

33 

34DataPath: TypeAlias = str | Sequence[str] 

35DatasetSplits: TypeAlias = tuple[Any | None, Any | None, Any | None] 

36SplitBuilder: TypeAlias = Callable[..., DatasetSplits] 

37InstructionSplitBuilder: TypeAlias = Callable[..., Sequence[Any | None]] 

38logger = get_dataset_logger(__name__) 

39 

40 

41class IndexedPretrainDatasetBuilder: 

42 """Build GPT pretraining datasets from indexed token files. 

43 

44 Its ``build`` method keeps the indexed provider flow visible while each 

45 private step can be implemented and reviewed independently. 

46 """ 

47 

48 def __init__( 

49 self, 

50 *, 

51 data_path: DataPath, 

52 data_config: Mapping[str, Any], 

53 train_valid_test_num_samples: Sequence[int], 

54 dataloader_context: DataLoaderParallelContext | None = None, 

55 ) -> None: 

56 """Store the inputs required by the indexed pretraining build. 

57 

58 Args: 

59 data_path: Indexed prefix, directory, or weighted paths. May be 

60 omitted when mock data is enabled. 

61 data_config: Indexed pretraining build options. 

62 train_valid_test_num_samples: Trainer-derived target sizes. 

63 dataloader_context: DataLoader ownership and synchronization policy. 

64 """ 

65 self.data_path = data_path 

66 self.data_config = data_config 

67 self.train_valid_test_num_samples = train_valid_test_num_samples 

68 self.dataloader_context = dataloader_context or DataLoaderParallelContext( 

69 data_index_cache=bool(data_config.get("data_index_cache", False)) 

70 ) 

71 self.split_builder = IndexedDatasetSplitBuilder(self.dataloader_context) 

72 

73 def build(self) -> DatasetSplits: 

74 """Build train, validation, and test indexed datasets. 

75 

76 Returns: 

77 Train, validation, and test datasets. 

78 """ 

79 # Discover indexed files and add their default blend weights. 

80 # Mock Datasets generate their samples and do not need filesystem 

81 # discovery. Real indexed Datasets still require an explicit path. 

82 mock_data = bool(self.data_config.get("mock_data", False)) 

83 logger.debug("Building indexed Dataset: mock=%s, data_path=%s", mock_data, self.data_path) 

84 if mock_data: 

85 data_paths = [] 

86 else: 

87 if self.data_path is None: 

88 raise ValueError("data_path is required when mock_data is false") 

89 

90 data_paths = self._resolve_data_paths() 

91 

92 # Normalize Dataset options. Sample counts remain separate and are 

93 # passed directly to the split builder. 

94 config = self._build_gpt_dataset_config(data_paths) 

95 logger.debug( 

96 "Indexed Dataset config: simple_blend=%s, lazy=%s, shared_blend=%s, independent_blends=%s", 

97 config.simple_blend, config.data_lazy_load, bool(config.blend), bool(config.blend_per_split), 

98 ) 

99 

100 # Follow the Provider boundary: instruction and pretraining datasets 

101 # share one public entry but own separate construction pipelines. 

102 dataset_splits = self._build_dataset_splits(config) 

103 split_types = tuple(type(split).__name__ if split is not None else None for split in dataset_splits) 

104 logger.debug("Built indexed Dataset splits=%s", split_types) 

105 return dataset_splits 

106 

107 def _build_dataset_splits(self, config: GPTDatasetConfig) -> DatasetSplits: 

108 """Select the instruction or indexed-pretraining Dataset pipeline.""" 

109 if bool(self.data_config.get("is_instruction_dataset", False)): 

110 logger.debug("Selecting instruction Dataset pipeline") 

111 dataset_splits = self._build_instruction_dataset_splits(config) 

112 return dataset_splits 

113 

114 dataset_splits = self._build_pretrain_dataset_splits(config) 

115 return dataset_splits 

116 

117 def _build_pretrain_dataset_splits(self, config: GPTDatasetConfig) -> DatasetSplits: 

118 """Build GPT pretraining splits through the selected Dataset and blend types.""" 

119 # Select GPTDataset / MockGPTDataset / GPTFromMRDataset. 

120 dataset_type = self._select_dataset_type(config) 

121 

122 # Select the standard or simple blended Dataset builder. 

123 split_builder = self._select_split_builder(config) 

124 logger.debug("Selected indexed Dataset: type=%s, split_mode=%s", dataset_type.__name__, config.simple_blend) 

125 

126 # Build train, validation, and test datasets. 

127 datasets = split_builder( 

128 dataset_type=dataset_type, 

129 train_valid_test_num_samples=self.train_valid_test_num_samples, 

130 config=config, 

131 ) 

132 return datasets 

133 

134 def _build_instruction_dataset_splits(self, config: GPTDatasetConfig) -> DatasetSplits: 

135 """Build packed instruction splits through the configured implementation. 

136 

137 The concrete packed-dataset implementation remains outside this provider. 

138 

139 Raises: 

140 NotImplementedError: If no instruction Dataset builder is configured. 

141 ValueError: If the configured builder does not return three splits. 

142 """ 

143 instruction_builder = self.data_config.get("instruction_dataset_builder") 

144 if not callable(instruction_builder): 

145 raise NotImplementedError( 

146 "is_instruction_dataset=True requires an instruction_dataset_builder" 

147 ) 

148 

149 instruction_split_builder: InstructionSplitBuilder = instruction_builder 

150 

151 data_prefix = config.blend if config.blend is not None else self.data_path 

152 datasets = instruction_split_builder( 

153 data_prefix=data_prefix, 

154 splits_string=config.split, 

155 train_valid_test_num_samples=self.train_valid_test_num_samples, 

156 seq_length=config.sequence_length, 

157 seed=config.random_seed, 

158 tokenizer=config.tokenizer, 

159 ) 

160 if not isinstance(datasets, Sequence) or len(datasets) != 3: 

161 raise ValueError("instruction_dataset_builder must return train, validation, and test") 

162 

163 dataset_splits = (datasets[0], datasets[1], datasets[2]) 

164 return dataset_splits 

165 

166 def _resolve_data_paths(self) -> list[str]: 

167 """Delegate indexed path discovery to the config build module.""" 

168 if self.data_path is None: 

169 raise ValueError("data_path is required when mock_data is false") 

170 

171 dataset_type = resolve_dataset_type(self.data_config["low_level_dataset"]) 

172 data_paths = resolve_data_paths( 

173 self.data_path, 

174 distributed_walk=bool(self.data_config["distributed_walk"]), 

175 file_suffix=".arrow" if issubclass(dataset_type, SFTFromMRDataset) else ".bin", 

176 ) 

177 return data_paths 

178 

179 def _build_gpt_dataset_config(self, data_paths: Sequence[str]) -> GPTDatasetConfig: 

180 """Delegate GPT Dataset option normalization.""" 

181 config = build_gpt_dataset_config(data_paths, self.data_config) 

182 return config 

183 

184 @staticmethod 

185 def _select_dataset_type(config: GPTDatasetConfig) -> type: 

186 """Select GPT, Mock GPT, or MR GPT Dataset.""" 

187 return config.low_level_dataset 

188 

189 def _select_split_builder(self, config: GPTDatasetConfig) -> SplitBuilder: 

190 """ 

191 Select the standard or simple train/valid/test builder. 

192 "no": BlendedDataset 

193 "inter/intra": SimpleBlendedDataset 

194 """ 

195 if config.simple_blend == "no": 

196 split_builder = partial(self.split_builder.build, blend_mode="no") 

197 return split_builder 

198 

199 if config.simple_blend not in {"inter", "intra"}: 

200 raise ValueError("simple_blend must be one of 'no', 'inter', or 'intra'; " 

201 f"got {config.simple_blend!r}" 

202 ) 

203 

204 split_builder = partial(self.split_builder.build, blend_mode=config.simple_blend) 

205 return split_builder 

206 

207 

208def build_indexed_dataset( 

209 *, 

210 data_path: DataPath = None, 

211 data_config: Mapping[str, Any], 

212 train_valid_test_num_samples: Sequence[int], 

213 dataloader_context: DataLoaderParallelContext | None = None, 

214) -> DatasetSplits: 

215 """Build indexed pretraining datasets through the dedicated builder. 

216 

217 Args: 

218 data_path: Indexed prefix, directory, or weighted paths. May be omitted 

219 when mock data is enabled. 

220 data_config: Indexed pretraining build options. 

221 train_valid_test_num_samples: Trainer-derived target sizes. 

222 dataloader_context: DataLoader ownership and synchronization policy. 

223 

224 Returns: 

225 Train, validation, and test datasets. 

226 """ 

227 builder = IndexedPretrainDatasetBuilder( 

228 data_path=data_path, 

229 data_config=data_config, 

230 train_valid_test_num_samples=train_valid_test_num_samples, 

231 dataloader_context=dataloader_context, 

232 ) 

233 datasets = builder.build() 

234 return datasets