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

88 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-10-25 05:45 +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) 

29from hyper_parallel.data.indexed.indexed_pretrain_dataset import ( 

30 GPTDataset, 

31 GPTFromMRDataset, 

32 MockGPTDataset, 

33) 

34from hyper_parallel.data.indexed.indexed_split_builder import IndexedDatasetSplitBuilder 

35from hyper_parallel.data.parallel import DataLoaderParallelContext 

36 

37DataPath: TypeAlias = str | Sequence[str] 

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

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

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

41logger = get_dataset_logger(__name__) 

42 

43 

44class IndexedPretrainDatasetBuilder: 

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

46 

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

48 private step can be implemented and reviewed independently. 

49 """ 

50 

51 def __init__( 

52 self, 

53 *, 

54 data_path: DataPath, 

55 data_config: Mapping[str, Any], 

56 train_valid_test_num_samples: Sequence[int], 

57 dataloader_context: DataLoaderParallelContext | None = None, 

58 ) -> None: 

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

60 

61 Args: 

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

63 omitted when mock data is enabled. 

64 data_config: Indexed pretraining build options. 

65 train_valid_test_num_samples: Trainer-derived target sizes. 

66 dataloader_context: DataLoader ownership and synchronization policy. 

67 """ 

68 self.data_path = data_path 

69 self.data_config = data_config 

70 self.train_valid_test_num_samples = train_valid_test_num_samples 

71 self.dataloader_context = dataloader_context or DataLoaderParallelContext( 

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

73 ) 

74 self.split_builder = IndexedDatasetSplitBuilder(self.dataloader_context) 

75 

76 def build(self) -> DatasetSplits: 

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

78 

79 Returns: 

80 Train, validation, and test datasets. 

81 """ 

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

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

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

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

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

87 if mock_data: 

88 data_paths = [] 

89 else: 

90 if self.data_path is None: 

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

92 

93 data_paths = self._resolve_data_paths() 

94 

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

96 # passed directly to the split builder. 

97 config = self._build_gpt_dataset_config(data_paths) 

98 logger.debug( 

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

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

101 ) 

102 

103 # Follow the Provider boundary: instruction and pretraining datasets 

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

105 dataset_splits = self._build_dataset_splits(config) 

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

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

108 return dataset_splits 

109 

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

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

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

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

114 dataset_splits = self._build_instruction_dataset_splits(config) 

115 return dataset_splits 

116 

117 dataset_splits = self._build_pretrain_dataset_splits(config) 

118 return dataset_splits 

119 

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

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

122 # Select GPTDataset / MockGPTDataset / GPTFromMRDataset. 

123 dataset_type = self._select_dataset_type(config) 

124 

125 # Select the standard or simple blended Dataset builder. 

126 split_builder = self._select_split_builder(config) 

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

128 

129 # Build train, validation, and test datasets. 

130 datasets = split_builder( 

131 dataset_type=dataset_type, 

132 train_valid_test_num_samples=self.train_valid_test_num_samples, 

133 config=config, 

134 ) 

135 return datasets 

136 

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

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

139 

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

141 

142 Raises: 

143 NotImplementedError: If no instruction Dataset builder is configured. 

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

145 """ 

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

147 if not callable(instruction_builder): 

148 raise NotImplementedError( 

149 "is_instruction_dataset=True requires an instruction_dataset_builder" 

150 ) 

151 

152 instruction_split_builder: InstructionSplitBuilder = instruction_builder 

153 

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

155 datasets = instruction_split_builder( 

156 data_prefix=data_prefix, 

157 splits_string=config.split, 

158 train_valid_test_num_samples=self.train_valid_test_num_samples, 

159 seq_length=config.sequence_length, 

160 seed=config.random_seed, 

161 tokenizer=config.tokenizer, 

162 ) 

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

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

165 

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

167 return dataset_splits 

168 

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

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

171 if self.data_path is None: 

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

173 

174 data_paths = resolve_data_paths( 

175 self.data_path, 

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

177 ) 

178 return data_paths 

179 

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

181 """Delegate GPT Dataset option normalization.""" 

182 config = build_gpt_dataset_config(data_paths, self.data_config) 

183 return config 

184 

185 @staticmethod 

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

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

188 if config.mock: 

189 return MockGPTDataset 

190 

191 if config.is_dataset_from_mr: 

192 return GPTFromMRDataset 

193 

194 return GPTDataset 

195 

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

197 """ 

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

199 "no": BlendedDataset 

200 "inter/intra": SimpleBlendedDataset 

201 """ 

202 if config.simple_blend == "no": 

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

204 return split_builder 

205 

206 if not config.is_dataset_from_mr: 

207 raise ValueError("simple_blend values other than 'no' require is_dataset_from_mr=True") 

208 

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

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

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

212 ) 

213 

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

215 return split_builder 

216 

217 

218def build_indexed_dataset( 

219 *, 

220 data_path: DataPath = None, 

221 data_config: Mapping[str, Any], 

222 train_valid_test_num_samples: Sequence[int], 

223 dataloader_context: DataLoaderParallelContext | None = None, 

224) -> DatasetSplits: 

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

226 

227 Args: 

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

229 when mock data is enabled. 

230 data_config: Indexed pretraining build options. 

231 train_valid_test_num_samples: Trainer-derived target sizes. 

232 dataloader_context: DataLoader ownership and synchronization policy. 

233 

234 Returns: 

235 Train, validation, and test datasets. 

236 """ 

237 builder = IndexedPretrainDatasetBuilder( 

238 data_path=data_path, 

239 data_config=data_config, 

240 train_valid_test_num_samples=train_valid_test_num_samples, 

241 dataloader_context=dataloader_context, 

242 ) 

243 datasets = builder.build() 

244 return datasets