torchsystem 0.1.0__py3-none-any.whl
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.
- torchsystem/__init__.py +7 -0
- torchsystem/aggregate.py +46 -0
- torchsystem/callbacks/average.py +51 -0
- torchsystem/callbacks/metrics.py +19 -0
- torchsystem/commands.py +89 -0
- torchsystem/compiler.py +43 -0
- torchsystem/events.py +41 -0
- torchsystem/loaders.py +53 -0
- torchsystem/settings.py +26 -0
- torchsystem/storage.py +88 -0
- torchsystem/weights.py +51 -0
- torchsystem-0.1.0.dist-info/LICENSE +21 -0
- torchsystem-0.1.0.dist-info/METADATA +19 -0
- torchsystem-0.1.0.dist-info/RECORD +15 -0
- torchsystem-0.1.0.dist-info/WHEEL +4 -0
torchsystem/__init__.py
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
from torchsystem.aggregate import Aggregate
|
|
2
|
+
from torchsystem.loaders import Loaders
|
|
3
|
+
from torchsystem.storage import Models, Criterions, Optimizer, Datasets
|
|
4
|
+
from torchsystem.compiler import Compiler
|
|
5
|
+
from pybondi import Event, Command
|
|
6
|
+
from pybondi.session import Session
|
|
7
|
+
from pybondi.repository import Repository
|
torchsystem/aggregate.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Any
|
|
3
|
+
from typing import Iterator
|
|
4
|
+
from typing import Protocol
|
|
5
|
+
from typing import overload
|
|
6
|
+
from typing import Callable
|
|
7
|
+
from torch import Tensor
|
|
8
|
+
from torch.nn import Module
|
|
9
|
+
from torch.utils.data import Dataset
|
|
10
|
+
from pybondi.aggregate import Root
|
|
11
|
+
|
|
12
|
+
class Loader(Protocol):
|
|
13
|
+
'''
|
|
14
|
+
Interface for the DataLoader class.
|
|
15
|
+
'''
|
|
16
|
+
dataset: Dataset
|
|
17
|
+
|
|
18
|
+
def __iter__(self) -> Iterator[Any]:...
|
|
19
|
+
|
|
20
|
+
@overload
|
|
21
|
+
def __iter__(self) -> Iterator[tuple[Tensor, Tensor]]:...
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Aggregate(Module, ABC):
|
|
25
|
+
|
|
26
|
+
def __init__(self, id: Any):
|
|
27
|
+
super().__init__()
|
|
28
|
+
self.root = Root(id=id)
|
|
29
|
+
self.epoch = 0
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def phase(self) -> str:
|
|
33
|
+
return 'train' if self.training else 'evaluation'
|
|
34
|
+
|
|
35
|
+
@phase.setter
|
|
36
|
+
def phase(self, value: str):
|
|
37
|
+
self.train() if value == 'train' else self.eval()
|
|
38
|
+
|
|
39
|
+
@abstractmethod
|
|
40
|
+
def fit(self, data: Loader, callback: Callable): ...
|
|
41
|
+
|
|
42
|
+
@abstractmethod
|
|
43
|
+
def evaluate(self, data: Loader, callback: Callable): ...
|
|
44
|
+
|
|
45
|
+
def iterate(self, data: Loader, callback: Callable):
|
|
46
|
+
self.fit(data, callback) if self.training else self.evaluate(data, callback)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from torch import Tensor
|
|
2
|
+
from pybondi.callbacks import Callback
|
|
3
|
+
from torchsystem.callbacks.metrics import Metric, accuracy, predictions
|
|
4
|
+
|
|
5
|
+
class Average:
|
|
6
|
+
def __init__(self):
|
|
7
|
+
self.value = 0.0
|
|
8
|
+
|
|
9
|
+
def update(self, sample: int, value: float) -> float:
|
|
10
|
+
self.value = (self.value * (sample - 1) + value) / sample
|
|
11
|
+
return self.value
|
|
12
|
+
|
|
13
|
+
def reset(self):
|
|
14
|
+
self.value = 0.0
|
|
15
|
+
|
|
16
|
+
class Loss(Callback):
|
|
17
|
+
def __init__(self):
|
|
18
|
+
super().__init__()
|
|
19
|
+
self.epoch = 0
|
|
20
|
+
self.phase = None
|
|
21
|
+
self.average = Average()
|
|
22
|
+
|
|
23
|
+
def __call__(self, batch: int, loss: float, *args, **kwargs):
|
|
24
|
+
self.batch = batch
|
|
25
|
+
self.average.update(batch, loss)
|
|
26
|
+
|
|
27
|
+
def flush(self):
|
|
28
|
+
self.publisher.publish('result', Metric('loss', self.average.value, self.batch, self.epoch, self.phase))
|
|
29
|
+
self.average.reset()
|
|
30
|
+
|
|
31
|
+
def reset(self):
|
|
32
|
+
self.average.reset()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class Accuracy(Callback):
|
|
36
|
+
def __init__(self):
|
|
37
|
+
super().__init__()
|
|
38
|
+
self.epoch = 0
|
|
39
|
+
self.phase = None
|
|
40
|
+
self.average = Average()
|
|
41
|
+
|
|
42
|
+
def __call__(self, batch: int, _, output: Tensor, target: Tensor, *args, **kwargs):
|
|
43
|
+
self.batch = batch
|
|
44
|
+
self.average.update(batch, accuracy(predictions(output), target))
|
|
45
|
+
|
|
46
|
+
def flush(self):
|
|
47
|
+
self.publisher.publish('result', Metric('accuracy', self.average.value, self.batch, self.epoch, self.phase))
|
|
48
|
+
self.average.reset()
|
|
49
|
+
|
|
50
|
+
def reset(self):
|
|
51
|
+
self.average.reset()
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Any
|
|
3
|
+
from typing import Any
|
|
4
|
+
from torch import Tensor
|
|
5
|
+
from torch import argmax
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class Metric:
|
|
9
|
+
name: str
|
|
10
|
+
value: Any
|
|
11
|
+
batch: int
|
|
12
|
+
epoch: int
|
|
13
|
+
phase: str
|
|
14
|
+
|
|
15
|
+
def accuracy(predictions: Tensor, target: Tensor) -> float:
|
|
16
|
+
return (predictions == target).float().mean().item()
|
|
17
|
+
|
|
18
|
+
def predictions(output: Tensor) -> Tensor:
|
|
19
|
+
return argmax(output, dim=1)
|
torchsystem/commands.py
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
from typing import Sequence
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from datetime import datetime, timezone
|
|
4
|
+
from pybondi import Command
|
|
5
|
+
from pybondi.callbacks import Callback
|
|
6
|
+
from torchsystem.aggregate import Aggregate
|
|
7
|
+
from torchsystem.aggregate import Loader
|
|
8
|
+
from torchsystem.events import Trained, Evaluated, Iterated
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class Train(Command):
|
|
12
|
+
'''
|
|
13
|
+
The Train command is used to train the aggregate using the sequence of loaders provided.
|
|
14
|
+
It bumps the epoch after training the aggregate.
|
|
15
|
+
'''
|
|
16
|
+
aggregate: Aggregate
|
|
17
|
+
loaders: Sequence[Loader]
|
|
18
|
+
callback: Callback
|
|
19
|
+
|
|
20
|
+
def execute(self):
|
|
21
|
+
self.aggregate.phase = 'train'
|
|
22
|
+
self.callback.set('phase', self.aggregate.phase)
|
|
23
|
+
self.callback.set('epoch', self.aggregate.epoch)
|
|
24
|
+
start = datetime.now(timezone.utc)
|
|
25
|
+
for loader in self.loaders:
|
|
26
|
+
self.aggregate.fit(loader, self.callback)
|
|
27
|
+
end = datetime.now(timezone.utc)
|
|
28
|
+
self.aggregate.root.publish(event=Trained(
|
|
29
|
+
epoch=self.aggregate.epoch,
|
|
30
|
+
start=start,
|
|
31
|
+
end=end,
|
|
32
|
+
loaders=self.loaders,
|
|
33
|
+
aggregate=self.aggregate
|
|
34
|
+
))
|
|
35
|
+
self.aggregate.epoch += 1
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class Evaluate(Command):
|
|
39
|
+
'''
|
|
40
|
+
The Evaluate command is used to evaluate the aggregate using the sequence of loaders provided.
|
|
41
|
+
The aggregate is put on evaluation mode. It does not bump the epoch since it is not training the aggregate.
|
|
42
|
+
'''
|
|
43
|
+
aggregate: Aggregate
|
|
44
|
+
loaders: Sequence[Loader]
|
|
45
|
+
callback: Callback
|
|
46
|
+
|
|
47
|
+
def execute(self):
|
|
48
|
+
self.aggregate.phase = 'evaluation'
|
|
49
|
+
self.callback.set('phase', self.aggregate.phase)
|
|
50
|
+
self.callback.set('epoch', self.aggregate.epoch)
|
|
51
|
+
start = datetime.now(timezone.utc)
|
|
52
|
+
for loader in self.loaders:
|
|
53
|
+
self.aggregate.evaluate(loader, self.callback)
|
|
54
|
+
end = datetime.now(timezone.utc)
|
|
55
|
+
self.aggregate.root.publish(event=Evaluated(
|
|
56
|
+
epoch=self.aggregate.epoch,
|
|
57
|
+
start=start,
|
|
58
|
+
end=end,
|
|
59
|
+
loaders=self.loaders,
|
|
60
|
+
aggregate=self.aggregate
|
|
61
|
+
))
|
|
62
|
+
|
|
63
|
+
@dataclass
|
|
64
|
+
class Iterate(Command):
|
|
65
|
+
'''
|
|
66
|
+
The Iterate command is used to iterate over the sequence of loaders provided.
|
|
67
|
+
It determines the phase of the aggregate and calls the fit or evaluate method accordingly.
|
|
68
|
+
After iterating over the loaders, it bumps the epoch.
|
|
69
|
+
'''
|
|
70
|
+
aggregate: Aggregate
|
|
71
|
+
loaders: Sequence[tuple[str, Loader]]
|
|
72
|
+
callback: Callback
|
|
73
|
+
|
|
74
|
+
def execute(self):
|
|
75
|
+
self.callback.set('epoch', self.aggregate.epoch)
|
|
76
|
+
start = datetime.now(timezone.utc)
|
|
77
|
+
for phase, loader in self.loaders:
|
|
78
|
+
self.aggregate.phase = phase
|
|
79
|
+
self.callback.set('phase', self.aggregate.phase )
|
|
80
|
+
self.aggregate.iterate(loader, self.callback)
|
|
81
|
+
end = datetime.now(timezone.utc)
|
|
82
|
+
self.aggregate.root.publish(event=Iterated(
|
|
83
|
+
epoch=self.aggregate.epoch,
|
|
84
|
+
start=start,
|
|
85
|
+
end=end,
|
|
86
|
+
loaders=self.loaders,
|
|
87
|
+
aggregate=self.aggregate
|
|
88
|
+
))
|
|
89
|
+
self.aggregate.epoch += 1
|
torchsystem/compiler.py
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from typing import Callable
|
|
2
|
+
from torch import compile
|
|
3
|
+
from pybondi.aggregate import Factory
|
|
4
|
+
from torchsystem.aggregate import Aggregate
|
|
5
|
+
from torchsystem.settings import Settings
|
|
6
|
+
from logging import getLogger
|
|
7
|
+
|
|
8
|
+
logger = getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
class Compiler:
|
|
11
|
+
'''
|
|
12
|
+
The Compiler class is used to compile several modules into a single aggregate.
|
|
13
|
+
|
|
14
|
+
Parameters:
|
|
15
|
+
factory (Callable): A callable that returns an aggregate. Could be the aggregate's type
|
|
16
|
+
a function that initializes and returns an aggregate or a callable instance of a factory.
|
|
17
|
+
'''
|
|
18
|
+
|
|
19
|
+
def __init__(self, factory: Factory, settings: Settings = None):
|
|
20
|
+
self.settings = settings or Settings()
|
|
21
|
+
self.factory = factory
|
|
22
|
+
|
|
23
|
+
def compile(self, *args, **kwargs) -> Aggregate:
|
|
24
|
+
'''
|
|
25
|
+
Builds and compiles the aggregate using the factory provided.
|
|
26
|
+
|
|
27
|
+
Parameters:
|
|
28
|
+
*args: The positional arguments to pass to the factory.
|
|
29
|
+
**kwargs: The keyword arguments to pass to the factory.
|
|
30
|
+
'''
|
|
31
|
+
logger.info(f'Building and compiling the aggregate')
|
|
32
|
+
aggregate = self.factory(*args, **kwargs)
|
|
33
|
+
try:
|
|
34
|
+
compiled = compile(aggregate)
|
|
35
|
+
logger.info(f'Aggregate compiled successfully')
|
|
36
|
+
logger.info(f'Aggregate: {compiled}')
|
|
37
|
+
return compiled
|
|
38
|
+
except Exception as error:
|
|
39
|
+
logger.error(f'Error compiling the aggregate: {error}')
|
|
40
|
+
if self.settings.compilation.raise_on_error:
|
|
41
|
+
raise error
|
|
42
|
+
logger.info(f'Returning the uncompiled aggregate')
|
|
43
|
+
return aggregate
|
torchsystem/events.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from typing import Sequence
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from pybondi import Event
|
|
5
|
+
from torchsystem.aggregate import Aggregate, Loader
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class Trained(Event):
|
|
9
|
+
'''
|
|
10
|
+
The Trained event is used to signal that the aggregate has been trained.
|
|
11
|
+
over a sequence of loaders.
|
|
12
|
+
'''
|
|
13
|
+
epoch: int
|
|
14
|
+
start: datetime
|
|
15
|
+
end: datetime
|
|
16
|
+
loaders: Sequence[Loader]
|
|
17
|
+
aggregate: Aggregate
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class Evaluated(Event):
|
|
21
|
+
'''
|
|
22
|
+
The Evaluated event is used to signal that the aggregate has been evaluated
|
|
23
|
+
over a sequence of loaders.
|
|
24
|
+
'''
|
|
25
|
+
epoch: int
|
|
26
|
+
start: datetime
|
|
27
|
+
end: datetime
|
|
28
|
+
loaders: Sequence[Loader]
|
|
29
|
+
aggregate: Aggregate
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class Iterated(Event):
|
|
33
|
+
'''
|
|
34
|
+
The Iterated event is used to signal that the aggregate has been iterated
|
|
35
|
+
over a sequence of loaders.
|
|
36
|
+
'''
|
|
37
|
+
epoch: int
|
|
38
|
+
start: datetime
|
|
39
|
+
end: datetime
|
|
40
|
+
loaders: Sequence[tuple[str, Loader]]
|
|
41
|
+
aggregate: Aggregate
|
torchsystem/loaders.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from typing import Iterator
|
|
2
|
+
from torch.utils.data import DataLoader
|
|
3
|
+
from torch.utils.data import Dataset
|
|
4
|
+
from torchsystem.aggregate import Loader
|
|
5
|
+
from torchsystem.settings import Settings
|
|
6
|
+
from mlregistry import Registry
|
|
7
|
+
|
|
8
|
+
INFRASTRUCTURE_PARAMETERS = {'dataset', 'pin_memory', 'pin_memory_device' ,'num_workers'}
|
|
9
|
+
|
|
10
|
+
class Loaders:
|
|
11
|
+
'''
|
|
12
|
+
This class acts as an iterable container for the data loaders. It allows decoupling the infrastructure
|
|
13
|
+
settings like devices from the domain settings of the dataloaders like batch size, shuffling, etc. When
|
|
14
|
+
you add a dataset to the loaders it will automatically register the dataset and it's dataloader in the
|
|
15
|
+
registry and add metadata to them.
|
|
16
|
+
'''
|
|
17
|
+
|
|
18
|
+
def __init__(self, settings: Settings = None, exclude_parameters: set[str] = INFRASTRUCTURE_PARAMETERS):
|
|
19
|
+
self.settings = settings or Settings()
|
|
20
|
+
self.registry = Registry(excluded_positions=[0], exclude_parameters=exclude_parameters)
|
|
21
|
+
self.registry.register(DataLoader, 'loader')
|
|
22
|
+
self.list = list[tuple[str, Loader]]()
|
|
23
|
+
|
|
24
|
+
def add(self, phase: str, dataset: Dataset, batch_size: int, shuffle: bool = False, settings: Settings | None = None, **kwargs):
|
|
25
|
+
'''
|
|
26
|
+
Add a dataset to the loaders. The dataset is added with the phase, batch size, and shuffle settings.
|
|
27
|
+
|
|
28
|
+
Parameters:
|
|
29
|
+
phase: str: The phase of the dataset. It can be 'train', 'validation', or 'test'.
|
|
30
|
+
dataset: Dataset: The dataset to be added to the loaders.
|
|
31
|
+
batch_size: int: The batch size of the dataset.
|
|
32
|
+
shuffle: bool: Whether to shuffle the dataset or not.
|
|
33
|
+
settings: Settings: The settings to be used for the dataloader. If None, the default settings are used.
|
|
34
|
+
**kwargs: Any: Additional keyword arguments to be passed to the DataLoader.
|
|
35
|
+
'''
|
|
36
|
+
|
|
37
|
+
settings = settings or self.settings
|
|
38
|
+
loader = DataLoader(
|
|
39
|
+
dataset,
|
|
40
|
+
batch_size=batch_size,
|
|
41
|
+
shuffle=shuffle,
|
|
42
|
+
pin_memory=self.settings.loaders.pin_memory,
|
|
43
|
+
pin_memory_device=self.settings.loaders.pin_memory_device,
|
|
44
|
+
num_workers=self.settings.loaders.num_of_workers,
|
|
45
|
+
**kwargs
|
|
46
|
+
)
|
|
47
|
+
self.list.append((phase, loader))
|
|
48
|
+
|
|
49
|
+
def __iter__(self) -> Iterator[tuple[str, Loader]]:
|
|
50
|
+
return iter(self.list)
|
|
51
|
+
|
|
52
|
+
def clear(self):
|
|
53
|
+
self.list.clear()
|
torchsystem/settings.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from pydantic import Field
|
|
2
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
3
|
+
|
|
4
|
+
class ModelSettings(BaseSettings):
|
|
5
|
+
device: str = Field(default='cpu')
|
|
6
|
+
model_config = SettingsConfigDict(env_prefix='MODEL_')
|
|
7
|
+
|
|
8
|
+
class CompilerSettings(BaseSettings):
|
|
9
|
+
raise_on_error: bool = Field(default=False)
|
|
10
|
+
model_config = SettingsConfigDict(env_prefix='COMPILATION_')
|
|
11
|
+
|
|
12
|
+
class LoaderSettings(BaseSettings):
|
|
13
|
+
pin_memory: bool = Field(default=False)
|
|
14
|
+
pin_memory_device: str = Field(default='')
|
|
15
|
+
num_of_workers: int = Field(default=0)
|
|
16
|
+
model_config = SettingsConfigDict(env_prefix='LOADER_')
|
|
17
|
+
|
|
18
|
+
class WeightsSettings(BaseSettings):
|
|
19
|
+
directory: str = Field(default='data/weights')
|
|
20
|
+
model_config = SettingsConfigDict(env_prefix='WEIGHTS_')
|
|
21
|
+
|
|
22
|
+
class Settings(BaseSettings):
|
|
23
|
+
model: BaseSettings = Field(default_factory=ModelSettings)
|
|
24
|
+
loaders: LoaderSettings = Field(default_factory=LoaderSettings)
|
|
25
|
+
compilation: CompilerSettings = Field(default_factory=CompilerSettings)
|
|
26
|
+
weights: WeightsSettings = Field(default_factory=WeightsSettings)
|
torchsystem/storage.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from os import path
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from torch.nn import Module
|
|
4
|
+
from torch.optim import Optimizer
|
|
5
|
+
from torch.utils.data import Dataset
|
|
6
|
+
from torchsystem.settings import Settings
|
|
7
|
+
from torchsystem.weights import Weights
|
|
8
|
+
from mlregistry import Registry
|
|
9
|
+
from mlregistry import get_hash
|
|
10
|
+
|
|
11
|
+
class Storage[T]:
|
|
12
|
+
'''
|
|
13
|
+
Base class for storage classes. It is responsible for coordinating the registry and weights of objects.
|
|
14
|
+
'''
|
|
15
|
+
registry: Registry[T]
|
|
16
|
+
weights: Weights[T]
|
|
17
|
+
category: str
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def register(cls, type: type):
|
|
21
|
+
return cls.registry.register(type, cls.category)
|
|
22
|
+
|
|
23
|
+
def get(self, name: str, *args, **kwargs) -> Optional[T]:
|
|
24
|
+
'''
|
|
25
|
+
Get an object from the registry and restore it's weights if available.
|
|
26
|
+
|
|
27
|
+
Parameters:
|
|
28
|
+
name (str): The name of the object.
|
|
29
|
+
*args: Positional arguments for initializing the object.
|
|
30
|
+
**kwargs: Keyword arguments for initializing the object.
|
|
31
|
+
'''
|
|
32
|
+
|
|
33
|
+
if not name in self.registry.keys():
|
|
34
|
+
return None
|
|
35
|
+
object = self.registry.get(name)(*args, **kwargs)
|
|
36
|
+
if hasattr(self, 'weights'):
|
|
37
|
+
self.weights.restore(object, f'{self.category}:{get_hash(object)}')
|
|
38
|
+
return object
|
|
39
|
+
|
|
40
|
+
def store(self, object: T):
|
|
41
|
+
'''
|
|
42
|
+
Store the weights of an object in a given category, an assertion error is raised if the object is not registered.
|
|
43
|
+
|
|
44
|
+
Parameters:
|
|
45
|
+
object (T): The object to store.
|
|
46
|
+
'''
|
|
47
|
+
assert object.__class__.__name__ in self.registry.keys(), f'{object.__class__.__name__} not registered in {self.category}'
|
|
48
|
+
if hasattr(self, 'weights'):
|
|
49
|
+
self.weights.store(object, f'{self.category}:{get_hash(object)}')
|
|
50
|
+
|
|
51
|
+
def restore(self, object: T):
|
|
52
|
+
'''
|
|
53
|
+
Restore the weights of an object from a given category, an assertion error is raised if the object is not registered.
|
|
54
|
+
|
|
55
|
+
Parameters:
|
|
56
|
+
object (T): The object to restore.
|
|
57
|
+
'''
|
|
58
|
+
assert object.__class__.__name__ in self.registry.keys(), f'{object.__class__.__name__} not registered in {self.category}'
|
|
59
|
+
if hasattr(self, 'weights'):
|
|
60
|
+
self.weights.restore(object, f'{self.category}:{get_hash(object)}')
|
|
61
|
+
|
|
62
|
+
class Models(Storage[Module]):
|
|
63
|
+
category = 'model'
|
|
64
|
+
registry = Registry()
|
|
65
|
+
|
|
66
|
+
def __init__(self, folder: str | None = None, settings: Settings = None):
|
|
67
|
+
self.settings = settings or Settings()
|
|
68
|
+
self.weights = Weights(path.join(self.settings.weights.directory, folder) if folder else self.settings.weights.directory)
|
|
69
|
+
|
|
70
|
+
class Criterions(Storage[Module]):
|
|
71
|
+
category = 'criterion'
|
|
72
|
+
registry = Registry()
|
|
73
|
+
|
|
74
|
+
def __init__(self, folder: str | None = None, settings: Settings = None):
|
|
75
|
+
self.settings = settings or Settings()
|
|
76
|
+
self.weights = Weights(path.join(self.settings.weights.directory, folder) if folder else self.settings.weights.directory)
|
|
77
|
+
|
|
78
|
+
class Optimizers(Storage[Optimizer]):
|
|
79
|
+
category = 'optimizer'
|
|
80
|
+
registry = Registry(excluded_positions=[0], exclude_parameters={'params'})
|
|
81
|
+
|
|
82
|
+
def __init__(self, folder: str | None = None, settings: Settings = None):
|
|
83
|
+
self.settings = settings or Settings()
|
|
84
|
+
self.weights = Weights(path.join(self.settings.weights.directory, folder) if folder else self.settings.weights.directory)
|
|
85
|
+
|
|
86
|
+
class Datasets(Storage[Dataset]):
|
|
87
|
+
category = 'dataset'
|
|
88
|
+
registry = Registry(exclude_parameters={'root', 'download'})
|
torchsystem/weights.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from os import makedirs
|
|
2
|
+
from os import path, makedirs
|
|
3
|
+
from logging import getLogger
|
|
4
|
+
from torch import save, load
|
|
5
|
+
from torch.nn import Module
|
|
6
|
+
|
|
7
|
+
logger = getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
class Weights[T: Module]:
|
|
10
|
+
'''
|
|
11
|
+
Weights class is responsible for storing and restoring the weights of a module.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
directory (str): The directory to store the weights.
|
|
15
|
+
'''
|
|
16
|
+
def __init__(self, directory: str):
|
|
17
|
+
self.location = directory
|
|
18
|
+
if not path.exists(self.location):
|
|
19
|
+
makedirs(self.location)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def store(self, module: T, filename: str):
|
|
23
|
+
'''
|
|
24
|
+
Store the weights of a module.
|
|
25
|
+
|
|
26
|
+
Parameters:
|
|
27
|
+
module (Module): The module to store the weights.
|
|
28
|
+
folder (str): The folder to store the weights.
|
|
29
|
+
filename (str): The filename to store the
|
|
30
|
+
'''
|
|
31
|
+
logger.info(f'Storing weights of {module.__class__.__name__} in {filename}.pth')
|
|
32
|
+
save(module.state_dict(), path.join(self.location, filename + '.pth'))
|
|
33
|
+
logger.info(f'Weights stored successfully')
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def restore(self, module: T, filename: str):
|
|
37
|
+
'''
|
|
38
|
+
Restore the weights of a module.
|
|
39
|
+
|
|
40
|
+
Parameters:
|
|
41
|
+
module (Module): The module to restore the weights.
|
|
42
|
+
folder (str): The folder to restore the weights.
|
|
43
|
+
filename (str): The filename to restore the weights.
|
|
44
|
+
'''
|
|
45
|
+
logger.info(f'Restoring weights of {module.__class__.__name__} from {filename}.pth')
|
|
46
|
+
try:
|
|
47
|
+
state_dict = load(path.join(self.location, filename + '.pth'), weights_only=True)
|
|
48
|
+
module.load_state_dict(state_dict)
|
|
49
|
+
logger.info(f'Weights restored successfully')
|
|
50
|
+
except FileNotFoundError as error:
|
|
51
|
+
logger.warning(f'Error restoring weights: {error}')
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Mapache Software
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: torchsystem
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: An IA training system, based on domain driven design and an event driven architecture, created on top of the pybondi library.
|
|
5
|
+
License: MIT
|
|
6
|
+
Author: Eric Cardozo
|
|
7
|
+
Author-email: eric.m.cardozo@mi.unc.edu.ar
|
|
8
|
+
Requires-Python: >=3.12,<4.0
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Requires-Dist: mlregistry (>=1.0.0,<2.0.0)
|
|
14
|
+
Requires-Dist: pybondi (>=0.2.3,<0.3.0)
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
# torch-system
|
|
18
|
+
An IA training system, created using domain driven design and an event driven architecture.
|
|
19
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
torchsystem/__init__.py,sha256=-_IuDIA71zFptbspHgN5gWW4zPsCAAe1AThw9G4EqnE,310
|
|
2
|
+
torchsystem/aggregate.py,sha256=YVNK3pqcyhMiRxhdwQmbZkMphfEigk5i43auKmyTwLo,1199
|
|
3
|
+
torchsystem/callbacks/average.py,sha256=1p06GBZl3uIBF87DvKa5CLoajHTBdMkVEpXN8ivKqdM,1498
|
|
4
|
+
torchsystem/callbacks/metrics.py,sha256=GanvN2_zHxucOvVWpB5YFlkS_lsS8rKos3vqdIs8-tM,429
|
|
5
|
+
torchsystem/commands.py,sha256=9DnC3czK3ngPfz-_6iXAKYS4-OlQ1fsZrZ0zAO60P2E,3130
|
|
6
|
+
torchsystem/compiler.py,sha256=fmUgkA7m3HTxc8cDWOk5OtHG8kiVAHbMVMlDqBsCeXY,1605
|
|
7
|
+
torchsystem/events.py,sha256=Tm8BEGjrBIDVX06pkemD-b4BM14hzvWfXzNW2bpPyU0,993
|
|
8
|
+
torchsystem/loaders.py,sha256=e2QtQ79Nc30Zm-DGxfwmO8ZfjJoOEyWhyt01AHMYsZM,2408
|
|
9
|
+
torchsystem/settings.py,sha256=3--h06nWc0GcW3ehNDv9HLxW56GHxUtc9W7s20sYITY,1064
|
|
10
|
+
torchsystem/storage.py,sha256=8USWlA3M8B1JShUBXBQUsxoLkees-u-1ftfIMW1EVlM,3474
|
|
11
|
+
torchsystem/weights.py,sha256=6zoITMkjl9WC5BdH5L890-lwppoydRNRsGTnMii60q4,1806
|
|
12
|
+
torchsystem-0.1.0.dist-info/LICENSE,sha256=xaMmSaui1itQNp2WE6mT7zoqwyhLqqObOA5YW7BqXnc,1073
|
|
13
|
+
torchsystem-0.1.0.dist-info/METADATA,sha256=IsCJxZ9l5rCrlJqAldSwnWKYK9yl4Kft14t7YsUtlgQ,729
|
|
14
|
+
torchsystem-0.1.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
15
|
+
torchsystem-0.1.0.dist-info/RECORD,,
|