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.
- {lmfuser-0.1.2 → lmfuser-0.2.0}/PKG-INFO +2 -2
- {lmfuser-0.1.2 → lmfuser-0.2.0}/pyproject.toml +2 -2
- {lmfuser-0.1.2 → lmfuser-0.2.0}/src/lmfuser/runners/ddp_runner.py +21 -4
- {lmfuser-0.1.2 → lmfuser-0.2.0}/src/lmfuser/task.py +38 -8
- {lmfuser-0.1.2 → lmfuser-0.2.0}/src/lmfuser/utils.py +5 -1
- {lmfuser-0.1.2 → lmfuser-0.2.0}/.github/workflows/python-publish.yml +0 -0
- {lmfuser-0.1.2 → lmfuser-0.2.0}/.gitignore +0 -0
- {lmfuser-0.1.2 → lmfuser-0.2.0}/.vscode/settings.json +0 -0
- {lmfuser-0.1.2 → lmfuser-0.2.0}/LICENSE +0 -0
- {lmfuser-0.1.2 → lmfuser-0.2.0}/README.md +0 -0
- {lmfuser-0.1.2 → lmfuser-0.2.0}/src/lmfuser/__init__.py +0 -0
- {lmfuser-0.1.2 → lmfuser-0.2.0}/src/lmfuser/model_loader.py +0 -0
- {lmfuser-0.1.2 → lmfuser-0.2.0}/src/lmfuser/optimizers.py +0 -0
- {lmfuser-0.1.2 → lmfuser-0.2.0}/src/lmfuser/runners/__init__.py +0 -0
- {lmfuser-0.1.2 → lmfuser-0.2.0}/src/lmfuser/runners/runner.py +0 -0
- {lmfuser-0.1.2 → lmfuser-0.2.0}/src/lmfuser/schedulers.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: LMFuser
|
|
3
|
-
Version: 0.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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'
|
|
124
|
+
assert dataloader_type in ('sharded', 'single file', 'batch', 'empty'), \
|
|
125
|
+
f'Unknown dataloader type: {dataloader_type}'
|
|
122
126
|
|
|
123
|
-
if dataloader_type == '
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|