halib 0.2.7__tar.gz → 0.2.8__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.
Files changed (56) hide show
  1. {halib-0.2.7 → halib-0.2.8}/PKG-INFO +2 -2
  2. {halib-0.2.7 → halib-0.2.8}/README.md +1 -1
  3. halib-0.2.8/halib/exp/core/base_exp.py +147 -0
  4. {halib-0.2.7 → halib-0.2.8}/halib.egg-info/PKG-INFO +2 -2
  5. {halib-0.2.7 → halib-0.2.8}/setup.py +1 -1
  6. halib-0.2.7/halib/exp/core/base_exp.py +0 -168
  7. {halib-0.2.7 → halib-0.2.8}/.gitignore +0 -0
  8. {halib-0.2.7 → halib-0.2.8}/GDriveFolder.txt +0 -0
  9. {halib-0.2.7 → halib-0.2.8}/LICENSE.txt +0 -0
  10. {halib-0.2.7 → halib-0.2.8}/MANIFEST.in +0 -0
  11. {halib-0.2.7 → halib-0.2.8}/halib/__init__.py +0 -0
  12. {halib-0.2.7 → halib-0.2.8}/halib/common/__init__.py +0 -0
  13. {halib-0.2.7 → halib-0.2.8}/halib/common/common.py +0 -0
  14. {halib-0.2.7 → halib-0.2.8}/halib/common/rich_color.py +0 -0
  15. {halib-0.2.7 → halib-0.2.8}/halib/exp/__init__.py +0 -0
  16. {halib-0.2.7 → halib-0.2.8}/halib/exp/core/__init__.py +0 -0
  17. {halib-0.2.7 → halib-0.2.8}/halib/exp/core/base_config.py +0 -0
  18. {halib-0.2.7 → halib-0.2.8}/halib/exp/core/param_gen.py +0 -0
  19. {halib-0.2.7 → halib-0.2.8}/halib/exp/core/wandb_op.py +0 -0
  20. {halib-0.2.7 → halib-0.2.8}/halib/exp/data/__init__.py +0 -0
  21. {halib-0.2.7 → halib-0.2.8}/halib/exp/data/dataclass_util.py +0 -0
  22. {halib-0.2.7 → halib-0.2.8}/halib/exp/data/dataset.py +0 -0
  23. {halib-0.2.7 → halib-0.2.8}/halib/exp/data/torchloader.py +0 -0
  24. {halib-0.2.7 → halib-0.2.8}/halib/exp/perf/__init__.py +0 -0
  25. {halib-0.2.7 → halib-0.2.8}/halib/exp/perf/flop_calc.py +0 -0
  26. {halib-0.2.7 → halib-0.2.8}/halib/exp/perf/gpu_mon.py +0 -0
  27. {halib-0.2.7 → halib-0.2.8}/halib/exp/perf/perfcalc.py +0 -0
  28. {halib-0.2.7 → halib-0.2.8}/halib/exp/perf/perfmetrics.py +0 -0
  29. {halib-0.2.7 → halib-0.2.8}/halib/exp/perf/perftb.py +0 -0
  30. {halib-0.2.7 → halib-0.2.8}/halib/exp/perf/profiler.py +0 -0
  31. {halib-0.2.7 → halib-0.2.8}/halib/exp/viz/__init__.py +0 -0
  32. {halib-0.2.7 → halib-0.2.8}/halib/exp/viz/plot.py +0 -0
  33. {halib-0.2.7 → halib-0.2.8}/halib/filetype/__init__.py +0 -0
  34. {halib-0.2.7 → halib-0.2.8}/halib/filetype/csvfile.py +0 -0
  35. {halib-0.2.7 → halib-0.2.8}/halib/filetype/ipynb.py +0 -0
  36. {halib-0.2.7 → halib-0.2.8}/halib/filetype/jsonfile.py +0 -0
  37. {halib-0.2.7 → halib-0.2.8}/halib/filetype/textfile.py +0 -0
  38. {halib-0.2.7 → halib-0.2.8}/halib/filetype/videofile.py +0 -0
  39. {halib-0.2.7 → halib-0.2.8}/halib/filetype/yamlfile.py +0 -0
  40. {halib-0.2.7 → halib-0.2.8}/halib/online/__init__.py +0 -0
  41. {halib-0.2.7 → halib-0.2.8}/halib/online/gdrive.py +0 -0
  42. {halib-0.2.7 → halib-0.2.8}/halib/online/gdrive_mkdir.py +0 -0
  43. {halib-0.2.7 → halib-0.2.8}/halib/online/projectmake.py +0 -0
  44. {halib-0.2.7 → halib-0.2.8}/halib/online/tele_noti.py +0 -0
  45. {halib-0.2.7 → halib-0.2.8}/halib/system/__init__.py +0 -0
  46. {halib-0.2.7 → halib-0.2.8}/halib/system/cmd.py +0 -0
  47. {halib-0.2.7 → halib-0.2.8}/halib/system/filesys.py +0 -0
  48. {halib-0.2.7 → halib-0.2.8}/halib/system/path.py +0 -0
  49. {halib-0.2.7 → halib-0.2.8}/halib/utils/__init__.py +0 -0
  50. {halib-0.2.7 → halib-0.2.8}/halib/utils/dict.py +0 -0
  51. {halib-0.2.7 → halib-0.2.8}/halib/utils/list.py +0 -0
  52. {halib-0.2.7 → halib-0.2.8}/halib.egg-info/SOURCES.txt +0 -0
  53. {halib-0.2.7 → halib-0.2.8}/halib.egg-info/dependency_links.txt +0 -0
  54. {halib-0.2.7 → halib-0.2.8}/halib.egg-info/requires.txt +0 -0
  55. {halib-0.2.7 → halib-0.2.8}/halib.egg-info/top_level.txt +0 -0
  56. {halib-0.2.7 → halib-0.2.8}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: halib
3
- Version: 0.2.7
3
+ Version: 0.2.8
4
4
  Summary: Small library for common tasks
5
5
  Author: Hoang Van Ha
6
6
  Author-email: hoangvanhauit@gmail.com
@@ -53,7 +53,7 @@ Dynamic: summary
53
53
 
54
54
  # Helper package for coding and automation
55
55
 
56
- **Version 0.2.7**
56
+ **Version 0.2.8**
57
57
  + reorganize packages with most changes in `research` package; also rename `research` to `exp` (package for experiment management and utilities)
58
58
  + update `exp/perfcalc.py` to allow save computed performance to csv file (without explicit calling method `calc_perfs`)
59
59
 
@@ -1,6 +1,6 @@
1
1
  # Helper package for coding and automation
2
2
 
3
- **Version 0.2.7**
3
+ **Version 0.2.8**
4
4
  + reorganize packages with most changes in `research` package; also rename `research` to `exp` (package for experiment management and utilities)
5
5
  + update `exp/perfcalc.py` to allow save computed performance to csv file (without explicit calling method `calc_perfs`)
6
6
 
@@ -0,0 +1,147 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Tuple, Any, Optional
3
+ from .base_config import ExpBaseCfg
4
+ from ..perf.perfcalc import PerfCalc
5
+ from ..perf.perfmetrics import MetricsBackend
6
+
7
+
8
+ class ExpHook:
9
+ """Base interface for all experiment hooks."""
10
+ def on_before_run(self, exp): pass
11
+ def on_after_run(self, exp, results): pass
12
+
13
+
14
+ # ! SEE https://github.com/hahv/base_exp for sample usage
15
+ class BaseExp(PerfCalc, ABC):
16
+ """
17
+ Base class for experiments.
18
+ Orchestrates the experiment pipeline using a pluggable metrics backend.
19
+ """
20
+
21
+ def __init__(self, config: ExpBaseCfg):
22
+ self.config = config
23
+ self.metric_backend = None
24
+ # Flag to track if init_general/prepare_dataset has run
25
+ self._is_env_ready = False
26
+ self.hooks = []
27
+
28
+ def register_hook(self, hook: ExpHook):
29
+ self.hooks.append(hook)
30
+
31
+ def _trigger_hooks(self, method_name: str, *args, **kwargs):
32
+ for hook in self.hooks:
33
+ method = getattr(hook, method_name, None)
34
+ if callable(method):
35
+ method(*args, **kwargs)
36
+
37
+ # -----------------------
38
+ # PerfCalc Required Methods
39
+ # -----------------------
40
+ def get_dataset_name(self):
41
+ return self.config.get_dataset_cfg().get_name()
42
+
43
+ def get_experiment_name(self):
44
+ return self.config.get_cfg_name()
45
+
46
+ def get_metric_backend(self):
47
+ if not self.metric_backend:
48
+ self.metric_backend = self.prepare_metrics(self.config.get_metric_cfg())
49
+ return self.metric_backend
50
+
51
+ # -----------------------
52
+ # Abstract Experiment Steps
53
+ # -----------------------
54
+ @abstractmethod
55
+ def init_general(self, general_cfg):
56
+ """Setup general settings like SEED, logging, env variables."""
57
+ pass
58
+
59
+ @abstractmethod
60
+ def prepare_dataset(self, dataset_cfg):
61
+ """Load/prepare dataset."""
62
+ pass
63
+
64
+ @abstractmethod
65
+ def prepare_metrics(self, metric_cfg) -> MetricsBackend:
66
+ """
67
+ Prepare the metrics for the experiment.
68
+ This method should be implemented in subclasses.
69
+ """
70
+ pass
71
+
72
+ @abstractmethod
73
+ def exec_exp(self, *args, **kwargs) -> Optional[Tuple[Any, Any]]:
74
+ """Run experiment process, e.g.: training/evaluation loop.
75
+ Return: either `None` or a tuple of (raw_metrics_data, extra_data) for calc_and_save_exp_perfs
76
+ """
77
+ pass
78
+
79
+ # -----------------------
80
+ # Internal Helpers
81
+ # -----------------------
82
+ def _validate_and_unpack(self, results):
83
+ if results is None:
84
+ return None
85
+ if not isinstance(results, (tuple, list)) or len(results) != 2:
86
+ raise ValueError("exec must return (metrics_data, extra_data)")
87
+ return results[0], results[1]
88
+
89
+ def _prepare_environment(self, force_reload: bool = False):
90
+ """
91
+ Common setup. Skips if already initialized, unless force_reload is True.
92
+ """
93
+ if self._is_env_ready and not force_reload:
94
+ # Environment is already prepared, skipping setup.
95
+ return
96
+
97
+ # 1. Run Setup
98
+ self.init_general(self.config.get_general_cfg())
99
+ self.prepare_dataset(self.config.get_dataset_cfg())
100
+
101
+ # 2. Update metric backend (refresh if needed)
102
+ self.metric_backend = self.prepare_metrics(self.config.get_metric_cfg())
103
+
104
+ # 3. Mark as ready
105
+ self._is_env_ready = True
106
+
107
+ # -----------------------
108
+ # Main Experiment Runner
109
+ # -----------------------
110
+ def run_exp(self, should_calc_metrics=True, reload_env=False, *args, **kwargs):
111
+ """
112
+ Run the whole experiment pipeline.
113
+ :param reload_env: If True, forces dataset/general init to run again.
114
+ :param should_calc_metrics: Whether to calculate and save metrics after execution.
115
+ :kwargs Params:
116
+ + 'outfile' to save csv file results,
117
+ + 'outdir' to set output directory for experiment results.
118
+ + 'return_df' to return a DataFrame of results instead of a dictionary.
119
+
120
+ Full pipeline:
121
+ 1. Init
122
+ 2. Prepare Environment (General + Dataset + Metrics)
123
+ 3. Save Config
124
+ 4. Execute
125
+ 5. Calculate & Save Metrics
126
+ """
127
+ self._prepare_environment(force_reload=reload_env)
128
+
129
+ self._trigger_hooks("before_run", self)
130
+
131
+ # Save config before running
132
+ self.config.save_to_outdir()
133
+
134
+ # Execute experiment
135
+ results = self.exec_exp(*args, **kwargs)
136
+
137
+ if should_calc_metrics and results is not None:
138
+ metrics_data, extra_data = self._validate_and_unpack(results)
139
+ # Calculate & Save metrics
140
+ perf_results = self.calc_perfs(
141
+ raw_metrics_data=metrics_data, extra_data=extra_data, *args, **kwargs
142
+ )
143
+ self._trigger_hooks("after_run", self, perf_results)
144
+ return perf_results
145
+ else:
146
+ self._trigger_hooks("after_run", self, results)
147
+ return results
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: halib
3
- Version: 0.2.7
3
+ Version: 0.2.8
4
4
  Summary: Small library for common tasks
5
5
  Author: Hoang Van Ha
6
6
  Author-email: hoangvanhauit@gmail.com
@@ -53,7 +53,7 @@ Dynamic: summary
53
53
 
54
54
  # Helper package for coding and automation
55
55
 
56
- **Version 0.2.7**
56
+ **Version 0.2.8**
57
57
  + reorganize packages with most changes in `research` package; also rename `research` to `exp` (package for experiment management and utilities)
58
58
  + update `exp/perfcalc.py` to allow save computed performance to csv file (without explicit calling method `calc_perfs`)
59
59
 
@@ -8,7 +8,7 @@ with open("requirements.txt") as f:
8
8
 
9
9
  setuptools.setup(
10
10
  name="halib",
11
- version="0.2.7",
11
+ version="0.2.8",
12
12
  author="Hoang Van Ha",
13
13
  author_email="hoangvanhauit@gmail.com",
14
14
  description="Small library for common tasks",
@@ -1,168 +0,0 @@
1
- import os
2
- from rich.pretty import pprint
3
- from abc import ABC, abstractmethod
4
- from typing import List, Optional, TypeVar, Generic
5
-
6
- from abc import ABC, abstractmethod
7
- from dataclasses import dataclass
8
- from dataclass_wizard import YAMLWizard
9
-
10
-
11
- class NamedCfg(ABC):
12
- """
13
- Base class for named configurations.
14
- All configurations should have a name.
15
- """
16
-
17
- @abstractmethod
18
- def get_name(self):
19
- """
20
- Get the name of the configuration.
21
- This method should be implemented in subclasses.
22
- """
23
- pass
24
-
25
-
26
- @dataclass
27
- class AutoNamedCfg(YAMLWizard, NamedCfg):
28
- """
29
- Mixin that automatically implements get_name() by returning self.name.
30
- Classes using this MUST have a 'name' field.
31
- """
32
-
33
- name: Optional[str] = None
34
-
35
- def get_name(self):
36
- return self.name
37
-
38
- def __post_init__(self):
39
- # Enforce the "MUST" rule here
40
- if self.name is None:
41
- # We allow None during initial load, but it must be set before usage
42
- # or handled by the loader.
43
- pass
44
-
45
-
46
- T = TypeVar("T", bound=AutoNamedCfg)
47
-
48
-
49
- class BaseSelectorCfg(Generic[T]):
50
- """
51
- Base class to handle the logic of selecting an item from a list by name.
52
- """
53
-
54
- def _resolve_selection(self, items: List[T], selected_name: str, context: str) -> T:
55
- if selected_name is None:
56
- raise ValueError(f"No {context} selected in the configuration.")
57
-
58
- # Create a lookup dict for O(1) access, or just iterate if list is short
59
- for item in items:
60
- if item.name == selected_name:
61
- return item
62
-
63
- raise ValueError(
64
- f"{context.capitalize()} '{selected_name}' not found in the configuration list."
65
- )
66
-
67
-
68
- class ExpBaseCfg(ABC, YAMLWizard):
69
- """
70
- Base class for configuration objects.
71
- What a cfg class must have:
72
- 1 - a dataset cfg
73
- 2 - a metric cfg
74
- 3 - a method cfg
75
- """
76
-
77
- cfg_name: Optional[str] = None
78
-
79
- # Save to yaml fil
80
- def save_to_outdir(
81
- self, filename: str = "__config.yaml", outdir=None, override: bool = False
82
- ) -> None:
83
- """
84
- Save the configuration to the output directory.
85
- """
86
- if outdir is not None:
87
- output_dir = outdir
88
- else:
89
- output_dir = self.get_outdir()
90
- os.makedirs(output_dir, exist_ok=True)
91
- assert (output_dir is not None) and (
92
- os.path.isdir(output_dir)
93
- ), f"Output directory '{output_dir}' does not exist or is not a directory."
94
- file_path = os.path.join(output_dir, filename)
95
- if os.path.exists(file_path) and not override:
96
- pprint(
97
- f"File '{file_path}' already exists. Use 'override=True' to overwrite."
98
- )
99
- else:
100
- # method of YAMLWizard to_yaml_file
101
- self.to_yaml_file(file_path)
102
-
103
- @classmethod
104
- @abstractmethod
105
- # load from a custom YAML file
106
- def from_custom_yaml_file(cls, yaml_file: str):
107
- """Load a configuration from a custom YAML file."""
108
- pass
109
-
110
- def get_cfg_name(self, sep: str = "__", *args, **kwargs) -> str:
111
- if self.cfg_name is None:
112
- # auto get the config name from dataset, method, metric
113
- # 2. Generate the canonical Config Name
114
- name_parts = []
115
- general_info = self.get_general_cfg().get_name()
116
- dataset_info = self.get_dataset_cfg().get_name()
117
- method_info = self.get_method_cfg().get_name()
118
- name_parts = [
119
- general_info,
120
- f"ds_{dataset_info}",
121
- f"mt_{method_info}",
122
- ]
123
- if "extra" in kwargs:
124
- extra_info = kwargs["extra"]
125
- assert isinstance(extra_info, str), "'extra' kwarg must be a string."
126
- name_parts.append(extra_info)
127
- self.cfg_name = sep.join(name_parts)
128
- return self.cfg_name
129
-
130
- @abstractmethod
131
- def get_outdir(self):
132
- """
133
- Get the output directory for the configuration.
134
- This method should be implemented in subclasses.
135
- """
136
- return None
137
-
138
- @abstractmethod
139
- def get_general_cfg(self) -> NamedCfg:
140
- """
141
- Get the general configuration like output directory, log settings, SEED, etc.
142
- This method should be implemented in subclasses.
143
- """
144
- pass
145
-
146
- @abstractmethod
147
- def get_dataset_cfg(self) -> NamedCfg:
148
- """
149
- Get the dataset configuration.
150
- This method should be implemented in subclasses.
151
- """
152
- pass
153
-
154
- @abstractmethod
155
- def get_method_cfg(self) -> NamedCfg:
156
- """
157
- Get the method configuration.
158
- This method should be implemented in subclasses.
159
- """
160
- pass
161
-
162
- @abstractmethod
163
- def get_metric_cfg(self) -> NamedCfg:
164
- """
165
- Get the metric configuration.
166
- This method should be implemented in subclasses.
167
- """
168
- pass
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
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
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
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