| import math |
| import os |
| from typing import Any, Dict, List |
|
|
| import torch |
| import torch.distributed as dist |
| from datasets import Dataset |
|
|
| from veomni.utils import helper |
| from veomni.utils.helper import get_cache_dir |
|
|
|
|
| logger = helper.create_logger(__name__) |
|
|
|
|
| class DummyDataset: |
| def __init__(self, size=100, num_shard=2, dataset_name: str = "test_dataset") -> None: |
| self.size = size |
| self.num_shard = num_shard |
|
|
| self.save_path = get_cache_dir(f"./{dataset_name}") |
|
|
| if not dist.is_initialized() or dist.get_rank() == 0: |
| self.build_dummy_dataset() |
|
|
| if dist.is_initialized(): |
| dist.barrier() |
|
|
| def generate_data(self, index_list: List): |
| for index in index_list: |
| input_ids = [index + 1] * (index + 1) |
| yield {"input_ids": input_ids, "attention_mask": [1] * len(input_ids), "labels": input_ids} |
|
|
| def build_dummy_dataset(self): |
| if not os.path.exists(self.save_path): |
| os.makedirs(self.save_path) |
|
|
| batch_len = math.ceil(self.size / self.num_shard) |
| print(f"Total length: {self.size}, batch length: {batch_len}") |
|
|
| index = 0 |
| for i in range(0, self.size, batch_len): |
| print(f"Generating {index}th parquet file") |
| ds = Dataset.from_generator( |
| self.generate_data, |
| gen_kwargs={"index_list": list(range(i + 1, i + batch_len + 1))}, |
| keep_in_memory=True, |
| num_proc=1, |
| ) |
| ds.to_parquet(os.path.join(self.save_path, f"{index}.parquet")) |
| index += 1 |
|
|
| def clean_cache(self): |
| if not dist.is_initialized() or dist.get_rank() == 0: |
| if os.path.exists(self.save_path): |
| os.system(f"rm -rf {self.save_path}") |
|
|
| def __del__(self): |
| self.clean_cache() |
|
|
|
|
| def process_dummy_example( |
| example: Dict[str, Any], |
| max_seq_len: int, |
| source_name: str = None, |
| ) -> List[Dict[str, "torch.Tensor"]]: |
| tokenized_example = {} |
| for k, v in example.items(): |
| if k == "ds_idx" or k == "source_name": |
| continue |
| else: |
| tokenized_example[k] = torch.tensor(v[:max_seq_len], dtype=torch.long) |
| return [tokenized_example] |
|
|
|
|
| class FakeModel: |
| def __init__(self) -> None: |
| pass |
|
|
| def state_dict(self): |
| return {} |
|
|
| def load_state_dict(self, *args, **kwargs): |
| pass |
|
|
|
|
| def compare_items(item, rank, group_size, group): |
| item = item.to("cuda") |
| item_list = [torch.empty_like(item) for _ in range(group_size)] |
|
|
| dist.all_gather(item_list, item, group=group) |
|
|
| for i in range(0, group_size): |
| if not torch.equal(item, item_list[i]): |
| logger.info(f"[rank{rank}]: group_rank {i} item is not equal to item {rank}") |
| return False |
|
|
| return True |
|
|
|
|
| def compare_global_batch(global_batch_list, global_batch_resume_list): |
| for global_batch, global_batch_resume in zip(global_batch_list, global_batch_resume_list): |
| for micro_batch, micro_batch_resume in zip(global_batch, global_batch_resume): |
| for key in micro_batch.keys(): |
| if torch.is_tensor(micro_batch[key]): |
| assert torch.all(micro_batch[key] == micro_batch_resume[key]) |
|
|
|
|
| def compare_metrics(metrics, metrics_resume): |
| assert metrics["consume_tokens(M)"] == metrics_resume["consume_tokens(M)"] |
|
|