nnlogging 0.1.0__py3-none-any.whl → 0.1.1__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.
Potentially problematic release.
This version of nnlogging might be problematic. Click here for more details.
- nnlogging/__init__.py +13 -4
- nnlogging/shell/__init__.py +8 -0
- nnlogging/shell/exception/__init__.py +11 -0
- nnlogging/shell/exception/branch_exists.py +49 -0
- nnlogging/shell/exception/branch_not_found.py +50 -0
- nnlogging/shell/exception/task_exists.py +54 -0
- nnlogging/shell/exception/task_not_found.py +50 -0
- nnlogging/shell/protocol.py +86 -0
- nnlogging/shell/shell.py +425 -0
- nnlogging/shell/utils/__init__.py +35 -0
- nnlogging/shell/utils/branch_funcs.py +163 -0
- nnlogging/shell/utils/logger_funcs.py +198 -0
- nnlogging/shell/utils/run_funcs.py +96 -0
- nnlogging/shell/utils/task_funcs.py +115 -0
- nnlogging/typings/__init__.py +41 -0
- nnlogging/typings/aliases.py +66 -0
- nnlogging/typings/exceptions.py +10 -0
- nnlogging/typings/generics.py +23 -0
- nnlogging/typings/protocols.py +14 -0
- nnlogging/utils/__init__.py +39 -0
- nnlogging/utils/helpers.py +39 -0
- nnlogging/utils/rich_factories.py +154 -0
- nnlogging/utils/shell_factories.py +192 -0
- nnlogging-0.1.1.dist-info/METADATA +181 -0
- nnlogging-0.1.1.dist-info/RECORD +26 -0
- nnlogging/shell.py +0 -307
- nnlogging/utils.py +0 -212
- nnlogging-0.1.0.dist-info/METADATA +0 -24
- nnlogging-0.1.0.dist-info/RECORD +0 -6
- {nnlogging-0.1.0.dist-info → nnlogging-0.1.1.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from collections.abc import Collection
|
|
3
|
+
from logging import Formatter as LoggingFormatter
|
|
4
|
+
from sys import stderr
|
|
5
|
+
from typing import Literal
|
|
6
|
+
|
|
7
|
+
from rich.console import Console as RichConsole
|
|
8
|
+
from rich.highlighter import (
|
|
9
|
+
Highlighter as RichHighlighter,
|
|
10
|
+
NullHighlighter as RichNullHighlighter,
|
|
11
|
+
)
|
|
12
|
+
from rich.logging import RichHandler
|
|
13
|
+
from rich.progress import Progress as RichProgress, ProgressColumn as RichProgressColumn
|
|
14
|
+
from rich.theme import Theme as RichTheme
|
|
15
|
+
|
|
16
|
+
from nnlogging.typings import FormatTimeCallable, Sink
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_rich_console(
|
|
20
|
+
sink: Sink | None = None,
|
|
21
|
+
/,
|
|
22
|
+
*,
|
|
23
|
+
width: int | None = None,
|
|
24
|
+
height: int | None = None,
|
|
25
|
+
markup: bool = True,
|
|
26
|
+
emoji: bool = True,
|
|
27
|
+
color_system: Literal["auto", "standard", "truecolor"] | None = "auto",
|
|
28
|
+
theme: RichTheme | None = None,
|
|
29
|
+
highlighter: RichHighlighter | None = None,
|
|
30
|
+
soft_wrap: bool = True,
|
|
31
|
+
force_terminal: bool | None = None,
|
|
32
|
+
force_jupyter: bool | None = None,
|
|
33
|
+
force_interactive: bool | None = None,
|
|
34
|
+
):
|
|
35
|
+
console = RichConsole(
|
|
36
|
+
file=sink or stderr, # pyright: ignore[reportArgumentType]
|
|
37
|
+
width=width,
|
|
38
|
+
height=height,
|
|
39
|
+
markup=markup,
|
|
40
|
+
emoji=emoji,
|
|
41
|
+
color_system=color_system,
|
|
42
|
+
theme=theme,
|
|
43
|
+
highlight=highlighter is not None
|
|
44
|
+
and not isinstance(highlighter, RichNullHighlighter),
|
|
45
|
+
highlighter=highlighter or RichNullHighlighter(),
|
|
46
|
+
soft_wrap=soft_wrap,
|
|
47
|
+
force_terminal=force_terminal,
|
|
48
|
+
force_jupyter=force_jupyter,
|
|
49
|
+
force_interactive=force_interactive,
|
|
50
|
+
)
|
|
51
|
+
return console
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def get_rich_handler(
|
|
55
|
+
console: RichConsole | None = None,
|
|
56
|
+
/,
|
|
57
|
+
*,
|
|
58
|
+
level: str | int = logging.NOTSET,
|
|
59
|
+
show_level: bool = True,
|
|
60
|
+
show_time: bool = True,
|
|
61
|
+
show_path: bool = True,
|
|
62
|
+
log_time_format: str | FormatTimeCallable = "[%x %X]",
|
|
63
|
+
omit_repeated_times: bool = True,
|
|
64
|
+
markup: bool = True,
|
|
65
|
+
highlighter: RichHighlighter | None = None,
|
|
66
|
+
rich_tracebacks: bool = True,
|
|
67
|
+
tracebacks_show_locals: bool = False,
|
|
68
|
+
log_message_format: str | LoggingFormatter = "%(message)s",
|
|
69
|
+
):
|
|
70
|
+
handler = RichHandler(
|
|
71
|
+
console=console or get_rich_console(),
|
|
72
|
+
level=level,
|
|
73
|
+
show_level=show_level,
|
|
74
|
+
show_time=show_time,
|
|
75
|
+
show_path=show_path,
|
|
76
|
+
log_time_format=log_time_format,
|
|
77
|
+
omit_repeated_times=omit_repeated_times,
|
|
78
|
+
markup=markup,
|
|
79
|
+
highlighter=highlighter or RichNullHighlighter(),
|
|
80
|
+
rich_tracebacks=rich_tracebacks,
|
|
81
|
+
tracebacks_show_locals=tracebacks_show_locals,
|
|
82
|
+
)
|
|
83
|
+
match log_message_format:
|
|
84
|
+
case str():
|
|
85
|
+
handler.setFormatter(LoggingFormatter(log_message_format))
|
|
86
|
+
case LoggingFormatter():
|
|
87
|
+
handler.setFormatter(log_message_format)
|
|
88
|
+
return handler
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def get_rich_progress_default_columns(
|
|
92
|
+
*,
|
|
93
|
+
markup: bool = True,
|
|
94
|
+
):
|
|
95
|
+
from rich.progress import (
|
|
96
|
+
BarColumn,
|
|
97
|
+
SpinnerColumn,
|
|
98
|
+
TaskProgressColumn,
|
|
99
|
+
TextColumn,
|
|
100
|
+
TimeRemainingColumn,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
spinner_column = SpinnerColumn(
|
|
104
|
+
spinner_name="dots",
|
|
105
|
+
style="progress.spinner",
|
|
106
|
+
finished_text=" ",
|
|
107
|
+
)
|
|
108
|
+
text_column = TextColumn(
|
|
109
|
+
text_format="{task.description}",
|
|
110
|
+
style="progress.description",
|
|
111
|
+
justify="left",
|
|
112
|
+
markup=markup,
|
|
113
|
+
)
|
|
114
|
+
bar_column = BarColumn(bar_width=40)
|
|
115
|
+
task_progress_column = TaskProgressColumn(
|
|
116
|
+
text_format="{task.percentage:>3.0f}%",
|
|
117
|
+
text_format_no_percentage="",
|
|
118
|
+
style="progress.percentage",
|
|
119
|
+
justify="right",
|
|
120
|
+
markup=markup,
|
|
121
|
+
show_speed=True,
|
|
122
|
+
)
|
|
123
|
+
time_remaining_column = TimeRemainingColumn(
|
|
124
|
+
compact=False,
|
|
125
|
+
elapsed_when_finished=True,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
return (
|
|
129
|
+
spinner_column,
|
|
130
|
+
text_column,
|
|
131
|
+
bar_column,
|
|
132
|
+
task_progress_column,
|
|
133
|
+
time_remaining_column,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def get_rich_progress(
|
|
138
|
+
console: RichConsole | None = None,
|
|
139
|
+
/,
|
|
140
|
+
*,
|
|
141
|
+
columns: Collection[str | RichProgressColumn] | None = None,
|
|
142
|
+
transient: bool = False,
|
|
143
|
+
refresh_per_second: float = 10,
|
|
144
|
+
speed_estimate_period: float = 3600,
|
|
145
|
+
default_column_markup: bool = True,
|
|
146
|
+
):
|
|
147
|
+
progress = RichProgress(
|
|
148
|
+
*(columns or get_rich_progress_default_columns(markup=default_column_markup)),
|
|
149
|
+
console=console,
|
|
150
|
+
transient=transient,
|
|
151
|
+
refresh_per_second=refresh_per_second,
|
|
152
|
+
speed_estimate_period=speed_estimate_period,
|
|
153
|
+
)
|
|
154
|
+
return progress
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from collections.abc import Collection
|
|
3
|
+
from dataclasses import asdict, dataclass, field
|
|
4
|
+
from logging import Formatter as LoggingFormatter
|
|
5
|
+
from typing import Literal
|
|
6
|
+
|
|
7
|
+
from aim import Repo as AimRepo, Run as AimRun
|
|
8
|
+
from rich.highlighter import Highlighter as RichHighlighter
|
|
9
|
+
from rich.progress import ProgressColumn as RichProgressColumn
|
|
10
|
+
from rich.theme import Theme as RichTheme
|
|
11
|
+
|
|
12
|
+
from nnlogging.typings import Branch, FormatTimeCallable, Omitable, Sink
|
|
13
|
+
from nnlogging.utils.helpers import evolve_, or_
|
|
14
|
+
from nnlogging.utils.rich_factories import (
|
|
15
|
+
get_rich_console,
|
|
16
|
+
get_rich_handler,
|
|
17
|
+
get_rich_progress_default_columns,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass(slots=True, kw_only=True)
|
|
22
|
+
class LoggerConfig:
|
|
23
|
+
name: str = "nnlogging"
|
|
24
|
+
level: int | str = logging.DEBUG
|
|
25
|
+
propagate: bool = False
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_logging_logger(
|
|
29
|
+
config: LoggerConfig | None = None,
|
|
30
|
+
/,
|
|
31
|
+
*,
|
|
32
|
+
name: Omitable[str] = ...,
|
|
33
|
+
level: Omitable[int | str] = ...,
|
|
34
|
+
propagate: Omitable[bool] = ...,
|
|
35
|
+
):
|
|
36
|
+
config_base = config or LoggerConfig()
|
|
37
|
+
config_evolved = evolve_(
|
|
38
|
+
config_base,
|
|
39
|
+
name=name,
|
|
40
|
+
level=level,
|
|
41
|
+
propagate=propagate,
|
|
42
|
+
)
|
|
43
|
+
logger = logging.getLogger(config_evolved.name)
|
|
44
|
+
logger.setLevel(config_evolved.level)
|
|
45
|
+
logger.propagate = config_evolved.propagate
|
|
46
|
+
return logger
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass(slots=True, kw_only=True)
|
|
50
|
+
class RunConfig:
|
|
51
|
+
experiment: str | None = None
|
|
52
|
+
repo: str | AimRepo | None = None
|
|
53
|
+
system_tracking_interval: float | None = 10
|
|
54
|
+
capture_terminal_logs: bool = False
|
|
55
|
+
log_system_params: bool = False
|
|
56
|
+
run_hash: str | None = None
|
|
57
|
+
read_only: bool = False
|
|
58
|
+
force_resume: bool = False
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def get_aim_run(
|
|
62
|
+
config: RunConfig | None = None,
|
|
63
|
+
/,
|
|
64
|
+
*,
|
|
65
|
+
experiment: Omitable[str | None] = ...,
|
|
66
|
+
repo: Omitable[str | AimRepo | None] = ...,
|
|
67
|
+
system_tracking_interval: Omitable[float | None] = ...,
|
|
68
|
+
capture_terminal_logs: Omitable[bool] = ...,
|
|
69
|
+
log_system_params: Omitable[bool] = ...,
|
|
70
|
+
run_hash: Omitable[str | None] = ...,
|
|
71
|
+
read_only: Omitable[bool] = ...,
|
|
72
|
+
force_resume: Omitable[bool] = ...,
|
|
73
|
+
):
|
|
74
|
+
config_base = config or RunConfig()
|
|
75
|
+
config_evolved = evolve_(
|
|
76
|
+
config_base,
|
|
77
|
+
experiment=experiment,
|
|
78
|
+
repo=repo,
|
|
79
|
+
system_tracking_interval=system_tracking_interval,
|
|
80
|
+
capture_terminal_logs=capture_terminal_logs,
|
|
81
|
+
log_system_params=log_system_params,
|
|
82
|
+
run_hash=run_hash,
|
|
83
|
+
read_only=read_only,
|
|
84
|
+
force_resume=force_resume,
|
|
85
|
+
)
|
|
86
|
+
run = AimRun(**asdict(config_evolved)) # pyright: ignore[reportAny]
|
|
87
|
+
return run
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@dataclass(slots=True, kw_only=True)
|
|
91
|
+
class BranchConfig:
|
|
92
|
+
# shared
|
|
93
|
+
markup: bool = True
|
|
94
|
+
highlighter: RichHighlighter | None = None
|
|
95
|
+
|
|
96
|
+
# console
|
|
97
|
+
width: int | None = None
|
|
98
|
+
height: int | None = None
|
|
99
|
+
emoji: bool = True
|
|
100
|
+
color_system: Literal["auto", "standard", "truecolor"] | None = "auto"
|
|
101
|
+
theme: RichTheme | None = None
|
|
102
|
+
soft_wrap: bool = True
|
|
103
|
+
force_terminal: bool | None = None
|
|
104
|
+
force_jupyter: bool | None = None
|
|
105
|
+
force_interactive: bool | None = None
|
|
106
|
+
|
|
107
|
+
# handler
|
|
108
|
+
level: str | int = logging.NOTSET
|
|
109
|
+
show_level: bool = True
|
|
110
|
+
show_time: bool = True
|
|
111
|
+
show_path: bool = True
|
|
112
|
+
log_time_format: str | FormatTimeCallable = "[%x %X]"
|
|
113
|
+
omit_repeated_times: bool = True
|
|
114
|
+
rich_tracebacks: bool = True
|
|
115
|
+
tracebacks_show_locals: bool = False
|
|
116
|
+
log_message_format: str | LoggingFormatter = "%(message)s"
|
|
117
|
+
|
|
118
|
+
# progress
|
|
119
|
+
columns: Collection[str | RichProgressColumn] = field(
|
|
120
|
+
default_factory=get_rich_progress_default_columns,
|
|
121
|
+
compare=False,
|
|
122
|
+
)
|
|
123
|
+
transient: bool = False
|
|
124
|
+
refresh_per_second: float = 10
|
|
125
|
+
speed_estimate_period: float = 3600
|
|
126
|
+
default_column_markup: bool = True
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def get_branch(
|
|
130
|
+
config: BranchConfig | None = None,
|
|
131
|
+
/,
|
|
132
|
+
sink: Sink | None = None,
|
|
133
|
+
*,
|
|
134
|
+
markup: Omitable[bool] = ...,
|
|
135
|
+
highlighter: Omitable[RichHighlighter | None] = ...,
|
|
136
|
+
width: Omitable[int | None] = ...,
|
|
137
|
+
height: Omitable[int | None] = ...,
|
|
138
|
+
emoji: Omitable[bool] = ...,
|
|
139
|
+
color_system: Omitable[Literal["auto", "standard", "truecolor"] | None] = ...,
|
|
140
|
+
theme: Omitable[RichTheme | None] = ...,
|
|
141
|
+
soft_wrap: Omitable[bool] = ...,
|
|
142
|
+
force_terminal: Omitable[bool | None] = ...,
|
|
143
|
+
force_jupyter: Omitable[bool | None] = ...,
|
|
144
|
+
force_interactive: Omitable[bool | None] = ...,
|
|
145
|
+
level: Omitable[str | int] = ...,
|
|
146
|
+
show_level: Omitable[bool] = ...,
|
|
147
|
+
show_time: Omitable[bool] = ...,
|
|
148
|
+
show_path: Omitable[bool] = ...,
|
|
149
|
+
log_time_format: Omitable[str | FormatTimeCallable] = ...,
|
|
150
|
+
omit_repeated_times: Omitable[bool] = ...,
|
|
151
|
+
rich_tracebacks: Omitable[bool] = ...,
|
|
152
|
+
tracebacks_show_locals: Omitable[bool] = ...,
|
|
153
|
+
log_message_format: Omitable[str | LoggingFormatter] = ...,
|
|
154
|
+
):
|
|
155
|
+
if config is None:
|
|
156
|
+
config = BranchConfig()
|
|
157
|
+
console = get_rich_console(
|
|
158
|
+
sink,
|
|
159
|
+
width=or_(width, config.width),
|
|
160
|
+
height=or_(height, config.height),
|
|
161
|
+
markup=or_(markup, config.markup),
|
|
162
|
+
emoji=or_(emoji, config.emoji),
|
|
163
|
+
color_system=or_(color_system, config.color_system),
|
|
164
|
+
theme=or_(theme, config.theme),
|
|
165
|
+
highlighter=or_(highlighter, config.highlighter),
|
|
166
|
+
soft_wrap=or_(soft_wrap, config.soft_wrap),
|
|
167
|
+
force_terminal=or_(force_terminal, config.force_terminal),
|
|
168
|
+
force_jupyter=or_(force_jupyter, config.force_jupyter),
|
|
169
|
+
force_interactive=or_(force_interactive, config.force_interactive),
|
|
170
|
+
)
|
|
171
|
+
handler = get_rich_handler(
|
|
172
|
+
console,
|
|
173
|
+
level=or_(level, config.level),
|
|
174
|
+
show_level=or_(show_level, config.show_level),
|
|
175
|
+
show_time=or_(show_time, config.show_time),
|
|
176
|
+
show_path=or_(show_path, config.show_path),
|
|
177
|
+
log_time_format=or_(log_time_format, config.log_time_format),
|
|
178
|
+
omit_repeated_times=or_(omit_repeated_times, config.omit_repeated_times),
|
|
179
|
+
markup=or_(markup, config.markup),
|
|
180
|
+
highlighter=or_(highlighter, config.highlighter),
|
|
181
|
+
rich_tracebacks=or_(rich_tracebacks, config.rich_tracebacks),
|
|
182
|
+
tracebacks_show_locals=or_(
|
|
183
|
+
tracebacks_show_locals, config.tracebacks_show_locals
|
|
184
|
+
),
|
|
185
|
+
log_message_format=or_(log_message_format, config.log_message_format),
|
|
186
|
+
)
|
|
187
|
+
return Branch(
|
|
188
|
+
console=console,
|
|
189
|
+
handler=handler,
|
|
190
|
+
tasks=dict(),
|
|
191
|
+
progress=None,
|
|
192
|
+
)
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nnlogging
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: A powerful and elegant logging library designed specifically for neural network and machine learning experiments. nnlogging seamlessly integrates [Rich](https://github.com/Textualize/rich) for beautiful terminal output and [Aim](https://github.com/aimhubio/aim) for comprehensive experiment tracking.
|
|
5
|
+
Requires-Python: <3.13,>=3.10
|
|
6
|
+
Requires-Dist: aim>=3.29.0
|
|
7
|
+
Requires-Dist: rich>=14.0.0
|
|
8
|
+
Provides-Extra: dev
|
|
9
|
+
Requires-Dist: faker>=37.11.0; extra == 'dev'
|
|
10
|
+
Requires-Dist: pytest-cov>=7.0.0; extra == 'dev'
|
|
11
|
+
Requires-Dist: pytest-html>=4.1.1; extra == 'dev'
|
|
12
|
+
Requires-Dist: pytest-repeat>=0.9.4; extra == 'dev'
|
|
13
|
+
Requires-Dist: pytest-sugar>=1.1.1; extra == 'dev'
|
|
14
|
+
Requires-Dist: pytest-xdist>=3.8.0; extra == 'dev'
|
|
15
|
+
Requires-Dist: pytest>=8.4.2; extra == 'dev'
|
|
16
|
+
Requires-Dist: twine>=6.2.0; extra == 'dev'
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# nnlogging
|
|
20
|
+
|
|
21
|
+
A powerful logging library for neural network and machine learning experiments
|
|
22
|
+
that combines [Rich](https://github.com/Textualize/rich) for beautiful terminal
|
|
23
|
+
output with [Aim](https://github.com/aimhubio/aim) for comprehensive experiment
|
|
24
|
+
tracking.
|
|
25
|
+
|
|
26
|
+
## ✨ Features
|
|
27
|
+
|
|
28
|
+
- 🎨 **Beautiful Console Output** - Rich-powered colorful logging with progress
|
|
29
|
+
bars
|
|
30
|
+
- 📊 **Experiment Tracking** - Built-in Aim integration for metrics and
|
|
31
|
+
hyperparameters
|
|
32
|
+
- 🔧 **Flexible Logging** - Multiple console handlers with customizable
|
|
33
|
+
formatting
|
|
34
|
+
- 📈 **Progress Tracking** - Advanced progress bars for long-running training
|
|
35
|
+
loops
|
|
36
|
+
- 🎯 **ML-Focused Design** - Purpose-built for machine learning workflows
|
|
37
|
+
- 🐍 **Modern Python** - Python 3.10+ with full type hints
|
|
38
|
+
|
|
39
|
+
## 🚀 Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install nnlogging
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Requirements:** Python 3.10-3.12
|
|
46
|
+
|
|
47
|
+
## ⚡ Quick Start
|
|
48
|
+
|
|
49
|
+
### Basic Logging
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from nnlogging import Shell
|
|
53
|
+
from nnlogging.utils import get_rich_console
|
|
54
|
+
import sys
|
|
55
|
+
|
|
56
|
+
# Initialize logger
|
|
57
|
+
shell = Shell(name="my_experiment")
|
|
58
|
+
shell.add_console({"main": get_rich_console(sys.stderr)})
|
|
59
|
+
shell.build_handler_from_console()
|
|
60
|
+
|
|
61
|
+
# Log messages
|
|
62
|
+
shell.info("Starting training...")
|
|
63
|
+
shell.warn("Learning rate is high")
|
|
64
|
+
shell.error("CUDA out of memory")
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Experiment Tracking
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
# Initialize Aim tracking
|
|
71
|
+
shell.add_aimrun(experiment="resnet_training")
|
|
72
|
+
|
|
73
|
+
# Track metrics during training
|
|
74
|
+
for epoch in range(100):
|
|
75
|
+
train_loss, train_acc = train_epoch()
|
|
76
|
+
shell.track(train_loss, name="train_loss", epoch=epoch)
|
|
77
|
+
shell.track(train_acc, name="train_accuracy", epoch=epoch)
|
|
78
|
+
|
|
79
|
+
shell.info(f"Epoch {epoch}: Loss={train_loss:.4f}, Acc={train_acc:.3f}")
|
|
80
|
+
|
|
81
|
+
# Track hyperparameters
|
|
82
|
+
shell.update_aimrun_metadata("config", {
|
|
83
|
+
"learning_rate": 0.001,
|
|
84
|
+
"batch_size": 32,
|
|
85
|
+
"model": "ResNet50"
|
|
86
|
+
})
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Progress Tracking
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
# Setup progress bars
|
|
93
|
+
shell.build_progress_from_console("main")
|
|
94
|
+
shell.add_task("training", description="Training", total=1000)
|
|
95
|
+
shell.start_progress()
|
|
96
|
+
|
|
97
|
+
# Update during training loop
|
|
98
|
+
for step in range(1000):
|
|
99
|
+
loss = train_step()
|
|
100
|
+
shell.update_task("training", advance=1)
|
|
101
|
+
|
|
102
|
+
if step % 100 == 0:
|
|
103
|
+
shell.info(f"Step {step}: Loss={loss:.4f}")
|
|
104
|
+
|
|
105
|
+
shell.stop_progress()
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Complete Training Example
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
from nnlogging import Shell
|
|
112
|
+
from nnlogging.utils import get_rich_console
|
|
113
|
+
import sys
|
|
114
|
+
|
|
115
|
+
# Setup logging with both console and experiment tracking
|
|
116
|
+
shell = Shell(name="training")
|
|
117
|
+
shell.add_console({"console": get_rich_console(sys.stdout)})
|
|
118
|
+
shell.build_handler_from_console()
|
|
119
|
+
shell.build_progress_from_console()
|
|
120
|
+
|
|
121
|
+
# Initialize experiment tracking
|
|
122
|
+
shell.add_aimrun(
|
|
123
|
+
experiment="mnist_cnn",
|
|
124
|
+
log_system_params=True,
|
|
125
|
+
capture_terminal_logs=True
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# Log hyperparameters
|
|
129
|
+
config = {"lr": 0.001, "batch_size": 64, "epochs": 10}
|
|
130
|
+
shell.update_aimrun_metadata("hparams", config)
|
|
131
|
+
shell.info(f"Starting training with config: {config}")
|
|
132
|
+
|
|
133
|
+
# Training loop with progress tracking
|
|
134
|
+
shell.add_task("epochs", description="Epochs", total=config["epochs"])
|
|
135
|
+
shell.start_progress()
|
|
136
|
+
|
|
137
|
+
for epoch in range(config["epochs"]):
|
|
138
|
+
# Training phase
|
|
139
|
+
train_loss, train_acc = train_model()
|
|
140
|
+
shell.track(train_loss, name="train_loss", epoch=epoch)
|
|
141
|
+
shell.track(train_acc, name="train_acc", epoch=epoch)
|
|
142
|
+
|
|
143
|
+
# Validation phase
|
|
144
|
+
val_loss, val_acc = validate_model()
|
|
145
|
+
shell.track(val_loss, name="val_loss", epoch=epoch)
|
|
146
|
+
shell.track(val_acc, name="val_acc", epoch=epoch)
|
|
147
|
+
|
|
148
|
+
shell.update_task("epochs", advance=1)
|
|
149
|
+
shell.info(f"Epoch {epoch}: Train Loss={train_loss:.3f}, Val Acc={val_acc:.3f}")
|
|
150
|
+
|
|
151
|
+
shell.stop_progress()
|
|
152
|
+
shell.info("Training completed! 🎉")
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## 🔄 Workflow
|
|
156
|
+
|
|
157
|
+

|
|
158
|
+
|
|
159
|
+
1. **Initialize** - Create Shell instance for your experiment
|
|
160
|
+
2. **Configure** - Add consoles and progress tracking
|
|
161
|
+
3. **Track** - Connect to Aim for experiment tracking
|
|
162
|
+
4. **Train & Log** - Use throughout your ML pipeline
|
|
163
|
+
5. **Visualize** - View results in Aim's web interface with `aim up`
|
|
164
|
+
|
|
165
|
+
## 🌍 Environments
|
|
166
|
+
|
|
167
|
+
nnlogging works seamlessly across different environments:
|
|
168
|
+
|
|
169
|
+
- **Local Development** - Full Rich terminal output with colors and formatting
|
|
170
|
+
- **Jupyter Notebooks** - Integrated display with notebook-friendly rendering
|
|
171
|
+
- **Remote Servers** - Automatic fallback for limited terminal capabilities
|
|
172
|
+
- **CI/CD Pipelines** - Clean text output when Rich features aren't supported
|
|
173
|
+
- **Docker Containers** - Optimized for containerized ML workloads
|
|
174
|
+
|
|
175
|
+
## 🤝 Contributing
|
|
176
|
+
|
|
177
|
+
Contributions welcome! Please open an issue for major changes.
|
|
178
|
+
|
|
179
|
+
## 📄 License
|
|
180
|
+
|
|
181
|
+
MIT License
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
nnlogging/__init__.py,sha256=sVUcI-0A0ID9W-l0FS9vNzoCngPnxQsDdMkXsFTsPOE,235
|
|
2
|
+
nnlogging/shell/__init__.py,sha256=tdcZDJuqlihYreih_jvgub0la_X8c3JWxnaNLR77u5c,128
|
|
3
|
+
nnlogging/shell/protocol.py,sha256=wVbdqBycfZqbj066HugmaCtQc9OdVxy47rvdLu5o5bc,1663
|
|
4
|
+
nnlogging/shell/shell.py,sha256=lN2aSzySnORGVI5DaljilfzDh7h-s9i4KqZs1mcH2rQ,11592
|
|
5
|
+
nnlogging/shell/exception/__init__.py,sha256=aFAbufsmio0Yndq6H7zEEoWGNA2kfO7F3ZL1p6iGYzQ,365
|
|
6
|
+
nnlogging/shell/exception/branch_exists.py,sha256=OpsZduL-vlOHn8RKmktw9J1Y-dlQI064zqJOb32wm_Y,1114
|
|
7
|
+
nnlogging/shell/exception/branch_not_found.py,sha256=r5RHg7DnP9VnraOJtioGi8BK7alhFLo7yKfaF13CD0g,1126
|
|
8
|
+
nnlogging/shell/exception/task_exists.py,sha256=m1ezYtxzdSR0MqFT2Qb1DkQUTIVMqt-AHN91punsP4g,1232
|
|
9
|
+
nnlogging/shell/exception/task_not_found.py,sha256=cydrhiRbnqP_ZvVMziF_iW7nY8lXUb7MnQgcIKfpxzo,1106
|
|
10
|
+
nnlogging/shell/utils/__init__.py,sha256=z70fg9IUfJOjXhJj3gi7U3RIJQGLWBfIV8vm5MkV_3w,675
|
|
11
|
+
nnlogging/shell/utils/branch_funcs.py,sha256=5UbPFDaHkfq9YRdMaGXW0bwwiufVQAUlkk-DnGe9abM,5559
|
|
12
|
+
nnlogging/shell/utils/logger_funcs.py,sha256=VdP7VpFQM_lwlFgdrkCJ9_tM90W9kX385LFNe-YCTGA,4611
|
|
13
|
+
nnlogging/shell/utils/run_funcs.py,sha256=9Q4SjftQIE4BCI_VzR2B1o5az27E37ey5yI0vBtVOpQ,2281
|
|
14
|
+
nnlogging/shell/utils/task_funcs.py,sha256=p76NvB-M5cNyTIqACDk7i_2qKNF1YOC6L_WDkt0qSeI,3222
|
|
15
|
+
nnlogging/typings/__init__.py,sha256=7ar5136odVB9vOj5MTQ6_AYuodoWOGduMSveEpVtF1Y,774
|
|
16
|
+
nnlogging/typings/aliases.py,sha256=EpLqeOss5u5-zpu-tbv6g-LZ21mFyKO0PpyXmDLrCUs,2080
|
|
17
|
+
nnlogging/typings/exceptions.py,sha256=rCmrwA599Uy7iOVnX12_Q8B0FMydyJX7zgOLBWxWDUM,174
|
|
18
|
+
nnlogging/typings/generics.py,sha256=olwknb77voWiIydEM62aMuU5kQPyS74zoyX7Ncr9cig,680
|
|
19
|
+
nnlogging/typings/protocols.py,sha256=osKmzyQ9Qzz_woxbd2eM9wDvPZ6hJZvupQ2cdkOM0H8,341
|
|
20
|
+
nnlogging/utils/__init__.py,sha256=cVr1eB99PAw_nSDlpMAopMGeQVI6Pouge5Bgkawo6fU,733
|
|
21
|
+
nnlogging/utils/helpers.py,sha256=8KTHeyQJR36Wnm8CRG7fZsx-IX6kXU4CsSkrTEgyZ0E,785
|
|
22
|
+
nnlogging/utils/rich_factories.py,sha256=RVI46Ncxk5aoMTbbQmf_mIB664IkYACXOiVOqwHLLt0,4473
|
|
23
|
+
nnlogging/utils/shell_factories.py,sha256=nGkQxhGZT19K4V_E94yqNTPlvnTGS245SrNYyc72B9o,6367
|
|
24
|
+
nnlogging-0.1.1.dist-info/METADATA,sha256=zUI3SPhYM9Q6pkEqx5vns07QuUmGrPBh_ryT6sA5k6w,5475
|
|
25
|
+
nnlogging-0.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
26
|
+
nnlogging-0.1.1.dist-info/RECORD,,
|