LMFuser 0.1.2__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: LMFuser
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: The LMFuser training framework.
5
5
  Project-URL: Homepage, https://github.com/TYTTYTTYT/LMFuser
6
6
  Project-URL: Documentation, https://github.com/TYTTYTTYT/LMFuser
@@ -17,7 +17,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
17
17
  Classifier: Topic :: Utilities
18
18
  Requires-Python: >=3.11
19
19
  Requires-Dist: hyperargs>=0.1.3
20
- Requires-Dist: lmfuser-data>=0.1.1
20
+ Requires-Dist: lmfuser-data>=0.2.0
21
21
  Requires-Dist: numpy
22
22
  Requires-Dist: pandas
23
23
  Requires-Dist: pyarrow
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "LMFuser"
7
- version = "0.1.2"
7
+ version = "0.2.0"
8
8
  requires-python = ">= 3.11"
9
9
  description = "The LMFuser training framework."
10
10
  readme = "README.md"
@@ -20,7 +20,7 @@ dependencies = [
20
20
  "pandas",
21
21
  "pyarrow",
22
22
  "torch>=2.4.0",
23
- "LMFuser-data>=0.1.1",
23
+ "LMFuser-data>=0.2.0",
24
24
  "tqdm",
25
25
  "wandb",
26
26
  "HyperArgs>=0.1.3",
@@ -66,11 +66,19 @@ class Wrapper(nn.Module):
66
66
  self.module = model.to(get_default_device())
67
67
  self.forward = model.forward
68
68
 
69
+ def no_sync(self):
70
+ # duck-type DDP for the accumulation path: a single process has no
71
+ # gradient sync to skip (latent crash: single GPU + grad accumulation)
72
+ from contextlib import nullcontext
73
+ return nullcontext()
74
+
69
75
  def __getattr__(self, name: str) -> Any:
70
76
  try:
71
77
  return super().__getattr__(name)
72
- except:
73
- return self.module.__getattr__(name)
78
+ except AttributeError:
79
+ # full lookup (instance dict included) — nn.Module.__getattr__ alone
80
+ # misses plain attributes like `.config`
81
+ return getattr(self.module, name)
74
82
 
75
83
 
76
84
  class DDPWraper(nn.Module):
@@ -85,8 +93,8 @@ class DDPWraper(nn.Module):
85
93
  def __getattr__(self, name: str) -> Any:
86
94
  try:
87
95
  return super().__getattr__(name)
88
- except:
89
- return self.model.module.__getattr__(name)
96
+ except AttributeError:
97
+ return getattr(self.model.module, name)
90
98
 
91
99
 
92
100
  class FSDP2Wrapper(nn.Module):
@@ -141,6 +149,11 @@ class DDPRunnerConfig(RunerConf):
141
149
  shuffle_dataset = BoolArg(default=True)
142
150
  row_prefetch = IntArg(0, min_value=0)
143
151
  num_row_workers = IntArg(1, min_value=1)
152
+ # batch-mode loader (train_dataloader_type: batch): TOTAL workers per rank,
153
+ # shared-memory ring depth, and per-slot capacity
154
+ num_batch_workers = IntArg(4, min_value=1)
155
+ batch_queue_depth = IntArg(4, min_value=2)
156
+ batch_slot_mb = IntArg(128, min_value=1)
144
157
 
145
158
  resume_training = BoolArg(default=False)
146
159
  resume_path = StrArg(default=None, allow_none=True)
@@ -202,6 +215,9 @@ class DDPRunner(Runner[DDPRunnerConfig]):
202
215
  worker_timeout=config.worker_timeout.value(), # type: ignore
203
216
  world_size=get_world_size(),
204
217
  rank=get_global_rank(),
218
+ num_batch_workers=config.num_batch_workers.value(), # type: ignore
219
+ batch_queue_depth=config.batch_queue_depth.value(), # type: ignore
220
+ batch_slot_mb=config.batch_slot_mb.value(), # type: ignore
205
221
  )
206
222
 
207
223
  self.eval_data_loaders = config.task_conf.get_eval_dataloaders(
@@ -772,6 +788,7 @@ class DDPRunner(Runner[DDPRunnerConfig]):
772
788
  self.model_loader.model_path = test_model_path
773
789
  self._model = None
774
790
 
791
+ self.model.eval() # ensure eval mode after potential model reload
775
792
  batch_list: list[dict[str, list[Any]]] = []
776
793
  with ExitStack() as stack:
777
794
  stack.enter_context(torch.no_grad())
@@ -5,7 +5,7 @@ import torch
5
5
  from torch import nn
6
6
  from lmfuser_data.interfaces import Batch, Row
7
7
  from lmfuser_data.scanners import Scanner
8
- from lmfuser_data import DataLoader, PyTorchDataLoader
8
+ from lmfuser_data import DataLoader, PyTorchDataLoader, BatchDataLoader
9
9
  from lmfuser_data.interfaces import SubclassTracer
10
10
  from hyperargs import Conf, StrArg, FloatArg, IntArg, OptionArg, add_dependency, monitor_on
11
11
 
@@ -53,7 +53,7 @@ class TaskBase(Conf, SubclassTracer):
53
53
 
54
54
  scanner_type = OptionArg(default='C4Scanner', option_fn=scanner_type_list)
55
55
 
56
- train_dataloader_type = OptionArg(default='single file', options=['single file', 'sharded', 'empty'])
56
+ train_dataloader_type = OptionArg(default='single file', options=['single file', 'sharded', 'batch', 'empty'])
57
57
  eval_dataloader_type = OptionArg(default='single file', options=['single file', 'sharded', 'empty'])
58
58
  test_dataloader_type = OptionArg(default='single file', options=['single file', 'sharded', 'empty'])
59
59
 
@@ -106,8 +106,11 @@ class TaskBase(Conf, SubclassTracer):
106
106
  worker_timeout: float,
107
107
  num_workers: int,
108
108
  rank: int,
109
- world_size: int
110
- ) -> None | DataLoader | PyTorchDataLoader | EmptyDataLoader:
109
+ world_size: int,
110
+ num_batch_workers: int = 4,
111
+ batch_queue_depth: int = 4,
112
+ batch_slot_mb: int = 128,
113
+ ) -> None | DataLoader | PyTorchDataLoader | BatchDataLoader | EmptyDataLoader:
111
114
  if self.num_train_data_path.value() == 0:
112
115
  return None
113
116
  if self._train_dataloader is not None:
@@ -118,9 +121,30 @@ class TaskBase(Conf, SubclassTracer):
118
121
  assert scanner_type is not None, 'scanner_type is None'
119
122
 
120
123
  dataloader_type = self.train_dataloader_type.value()
121
- assert dataloader_type in ('sharded', 'single file'), f'Unknown dataloader type: {dataloader_type}'
124
+ assert dataloader_type in ('sharded', 'single file', 'batch', 'empty'), \
125
+ f'Unknown dataloader type: {dataloader_type}'
122
126
 
123
- if dataloader_type == 'sharded':
127
+ if dataloader_type == 'batch':
128
+ self._train_dataloader = BatchDataLoader(
129
+ batch_size=batch_size,
130
+ path_list=path_list, # type: ignore
131
+ distributor_weights=weight_list, # type: ignore
132
+ scanner_type=Scanner.get_subclass(scanner_type),
133
+ seed=seed,
134
+ shuffle=shuffle,
135
+ map_fn=self.get_row_processor(),
136
+ flow_fn=self.get_flow_processor(),
137
+ collate_fn=self.get_collate_fn(),
138
+ batch_map_fn=self.get_batch_processor(),
139
+ ignore_error=ignore_error,
140
+ num_workers=num_batch_workers,
141
+ queue_depth=batch_queue_depth,
142
+ slot_mb=batch_slot_mb,
143
+ num_ranks=world_size,
144
+ rank_idx=rank,
145
+ worker_timeout=worker_timeout,
146
+ )
147
+ elif dataloader_type == 'sharded':
124
148
  self._train_dataloader = DataLoader(
125
149
  batch_size=batch_size,
126
150
  path_list=path_list, # type: ignore
@@ -402,8 +426,11 @@ class Tasks(Conf):
402
426
  worker_timeout: float,
403
427
  num_workers: int,
404
428
  rank: int,
405
- world_size: int
406
- ) -> list[DataLoader | None | PyTorchDataLoader | EmptyDataLoader]:
429
+ world_size: int,
430
+ num_batch_workers: int = 4,
431
+ batch_queue_depth: int = 4,
432
+ batch_slot_mb: int = 128,
433
+ ) -> list[DataLoader | None | PyTorchDataLoader | BatchDataLoader | EmptyDataLoader]:
407
434
  return [
408
435
  task.conf._get_train_dataloader(
409
436
  batch_size=batch_size,
@@ -417,6 +444,9 @@ class Tasks(Conf):
417
444
  num_workers=num_workers,
418
445
  rank=rank,
419
446
  world_size=world_size,
447
+ num_batch_workers=num_batch_workers,
448
+ batch_queue_depth=batch_queue_depth,
449
+ batch_slot_mb=batch_slot_mb,
420
450
  )
421
451
  for task in self.tasks
422
452
  ]
@@ -42,7 +42,11 @@ def dist_init() -> None:
42
42
  device_type = get_default_device_type()
43
43
 
44
44
  if device_type == 'cuda':
45
- dist.init_process_group(backend='nccl')
45
+ import datetime as _dt
46
+ # 1h timeout: a transient data stall on one rank (e.g. a shard
47
+ # download hang) must not nuke the whole DDP group (default 10min
48
+ # killed a pretrain run mid-flight)
49
+ dist.init_process_group(backend='nccl', timeout=_dt.timedelta(seconds=3600))
46
50
  torch.cuda.set_device(get_local_rank())
47
51
  elif device_type == 'npu':
48
52
  dist.init_process_group(backend='hccl')
File without changes
File without changes
File without changes
File without changes
File without changes