melog 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.
- melog/__init__.py +63 -0
- melog/api/__init__.py +122 -0
- melog/cli/__init__.py +97 -0
- melog/core.py +521 -0
- melog/metrics/__init__.py +38 -0
- melog/metrics/base.py +206 -0
- melog/metrics/basic.py +79 -0
- melog/metrics/classification.py +319 -0
- melog/metrics/group.py +146 -0
- melog/storage/journal.py +59 -0
- melog/storage/media.py +164 -0
- melog/storage/media_log.py +57 -0
- melog/storage/melog_file.py +412 -0
- melog/storage/mirror.py +235 -0
- melog/tracking/axis.py +89 -0
- melog/tracking/console.py +125 -0
- melog/tracking/steps_bar.py +195 -0
- melog/utils/__init__.py +1 -0
- melog/utils/bar_stack.py +98 -0
- melog/utils/distributed.py +99 -0
- melog/utils/downsample.py +44 -0
- melog/utils/epoch_end_iterable.py +52 -0
- melog/utils/tqdm.py +392 -0
- melog/web/__init__.py +0 -0
- melog/web/app.py +161 -0
- melog/web/fs.py +72 -0
- melog/web/loader.py +108 -0
- melog/web/media_store.py +53 -0
- melog/web/media_view.py +76 -0
- melog/web/server.py +185 -0
- melog/web/static/css/style.css +123 -0
- melog/web/static/echarts.min.js +45 -0
- melog/web/static/index.html +72 -0
- melog/web/static/js/charts.js +281 -0
- melog/web/static/js/downsample.js +27 -0
- melog/web/static/js/filebrowser.js +223 -0
- melog/web/static/js/main.js +55 -0
- melog/web/static/js/media.js +233 -0
- melog/web/static/js/theme.js +24 -0
- melog/web/static/js/ws.js +17 -0
- melog/web/static/logo.svg +25 -0
- melog/web/store.py +55 -0
- melog/web/view.py +62 -0
- melog/web/ws.py +50 -0
- melog-0.1.0.dist-info/METADATA +435 -0
- melog-0.1.0.dist-info/RECORD +49 -0
- melog-0.1.0.dist-info/WHEEL +5 -0
- melog-0.1.0.dist-info/entry_points.txt +2 -0
- melog-0.1.0.dist-info/top_level.txt +1 -0
melog/__init__.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Melog 包入口。"""
|
|
2
|
+
|
|
3
|
+
from .api import (
|
|
4
|
+
StepsBar,
|
|
5
|
+
audio,
|
|
6
|
+
current,
|
|
7
|
+
current_bar,
|
|
8
|
+
error,
|
|
9
|
+
image,
|
|
10
|
+
init,
|
|
11
|
+
log,
|
|
12
|
+
scalar,
|
|
13
|
+
set_colors,
|
|
14
|
+
stepsbar,
|
|
15
|
+
success,
|
|
16
|
+
tqdm,
|
|
17
|
+
warn,
|
|
18
|
+
)
|
|
19
|
+
from .metrics import (
|
|
20
|
+
Accuracy,
|
|
21
|
+
AUC,
|
|
22
|
+
ConfusionMatrix,
|
|
23
|
+
Count,
|
|
24
|
+
F1,
|
|
25
|
+
Last,
|
|
26
|
+
Mean,
|
|
27
|
+
Metric,
|
|
28
|
+
MetricGroup,
|
|
29
|
+
Precision,
|
|
30
|
+
Recall,
|
|
31
|
+
Sum,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
__version__ = "0.1.0"
|
|
35
|
+
__all__ = [
|
|
36
|
+
"init",
|
|
37
|
+
"current",
|
|
38
|
+
"current_bar",
|
|
39
|
+
"tqdm",
|
|
40
|
+
"StepsBar",
|
|
41
|
+
"stepsbar",
|
|
42
|
+
"scalar",
|
|
43
|
+
"log",
|
|
44
|
+
"image",
|
|
45
|
+
"audio",
|
|
46
|
+
"success",
|
|
47
|
+
"error",
|
|
48
|
+
"warn",
|
|
49
|
+
"set_colors",
|
|
50
|
+
"Metric",
|
|
51
|
+
"MetricGroup",
|
|
52
|
+
"Mean",
|
|
53
|
+
"Sum",
|
|
54
|
+
"Last",
|
|
55
|
+
"Count",
|
|
56
|
+
"Accuracy",
|
|
57
|
+
"Precision",
|
|
58
|
+
"Recall",
|
|
59
|
+
"F1",
|
|
60
|
+
"AUC",
|
|
61
|
+
"ConfusionMatrix",
|
|
62
|
+
"__version__",
|
|
63
|
+
]
|
melog/api/__init__.py
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""全局入口与模块级便捷接口。
|
|
2
|
+
|
|
3
|
+
melog.init() 创建并激活全局共享实例(不返回);之后项目任意位置
|
|
4
|
+
直接使用本模块定义的模块级接口(melog.scalar / melog.log 等),
|
|
5
|
+
无需持有实例。需要实例本身时用 melog.current() 取回。
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any, Dict, Iterable, Optional, Union
|
|
12
|
+
|
|
13
|
+
from ..core import Melog, current
|
|
14
|
+
from ..metrics import MetricGroup
|
|
15
|
+
from ..tracking.steps_bar import StepsBar
|
|
16
|
+
from ..utils.tqdm import tqdm
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"init",
|
|
20
|
+
"current",
|
|
21
|
+
"current_bar",
|
|
22
|
+
"tqdm",
|
|
23
|
+
"StepsBar",
|
|
24
|
+
"stepsbar",
|
|
25
|
+
"scalar",
|
|
26
|
+
"log",
|
|
27
|
+
"image",
|
|
28
|
+
"audio",
|
|
29
|
+
"success",
|
|
30
|
+
"error",
|
|
31
|
+
"warn",
|
|
32
|
+
"set_colors",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def init(log_dir: str = "./melog_runs", web_port: Optional[int] = None, **kwargs: Any) -> None:
|
|
37
|
+
"""创建并激活全局共享的 Melog 实例(melog 的唯一公开入口)。
|
|
38
|
+
|
|
39
|
+
不返回实例:入口处调用一次后,项目任意位置直接使用模块级
|
|
40
|
+
melog.scalar() 等接口(需要实例本身时用 melog.current() 取回)。
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
log_dir: 日志保存路径(即 run 目录):指标 / 媒体 / console.log
|
|
44
|
+
直接落在其中;重跑同一目录即断点续训(历史曲线接续,
|
|
45
|
+
重新训练的 epoch 自动覆盖上次中断的重叠数据)。
|
|
46
|
+
web_port: Web 监听端口;缺省自动选择一个空闲端口。
|
|
47
|
+
**kwargs: 其余高级参数(enable_web / enable_progress / reduce_op /
|
|
48
|
+
flush_every / max_plot_points,以及 project 覆盖项目名等)。
|
|
49
|
+
|
|
50
|
+
再次调用会用新实例替换当前活动实例。
|
|
51
|
+
"""
|
|
52
|
+
log_dir = Path(log_dir)
|
|
53
|
+
kwargs.setdefault("project", log_dir.name)
|
|
54
|
+
Melog(output_dir=str(log_dir.parent), web_port=web_port, **kwargs)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def stepsbar(
|
|
58
|
+
iterable: Iterable,
|
|
59
|
+
total: Optional[float] = None,
|
|
60
|
+
epoch: Optional[int] = None,
|
|
61
|
+
metrics: Optional[MetricGroup] = None,
|
|
62
|
+
**kwargs: Any,
|
|
63
|
+
) -> StepsBar:
|
|
64
|
+
"""模块级便捷接口:等价于 ``StepsBar(iterable, ...)``。"""
|
|
65
|
+
return StepsBar(iterable, total=total, epoch=epoch, metrics=metrics, **kwargs)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def scalar(
|
|
69
|
+
metrics: Union[Dict[str, Any], MetricGroup],
|
|
70
|
+
advance: int = 0,
|
|
71
|
+
) -> Dict[str, float]:
|
|
72
|
+
"""模块级便捷接口:等价于 ``current().scalar(...)``。"""
|
|
73
|
+
return current().scalar(metrics, advance=advance)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def log(*values: Any, sep: str = " ", end: str = "\n", flush: bool = False) -> None:
|
|
77
|
+
"""模块级便捷接口:等价于 ``current().log(...)``。"""
|
|
78
|
+
current().log(*values, sep=sep, end=end, flush=flush)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def success(*values: Any, sep: str = " ", end: str = "\n", flush: bool = False) -> None:
|
|
82
|
+
"""模块级便捷接口:等价于 ``current().success(...)``。"""
|
|
83
|
+
current().success(*values, sep=sep, end=end, flush=flush)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def error(*values: Any, sep: str = " ", end: str = "\n", flush: bool = False) -> None:
|
|
87
|
+
"""模块级便捷接口:等价于 ``current().error(...)``。"""
|
|
88
|
+
current().error(*values, sep=sep, end=end, flush=flush)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def warn(*values: Any, sep: str = " ", end: str = "\n", flush: bool = False) -> None:
|
|
92
|
+
"""模块级便捷接口:等价于 ``current().warn(...)``。"""
|
|
93
|
+
current().warn(*values, sep=sep, end=end, flush=flush)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def current_bar() -> Optional[tqdm]:
|
|
97
|
+
"""模块级便捷接口:等价于 ``current().current_bar()``。"""
|
|
98
|
+
return current().current_bar()
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def image(
|
|
102
|
+
name: str,
|
|
103
|
+
data: Any,
|
|
104
|
+
caption: Optional[str] = None,
|
|
105
|
+
) -> None:
|
|
106
|
+
"""模块级便捷接口:等价于 ``current().image(...)``。"""
|
|
107
|
+
current().image(name, data, caption=caption)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def audio(
|
|
111
|
+
name: str,
|
|
112
|
+
data: Any,
|
|
113
|
+
sr: int = 22050,
|
|
114
|
+
caption: Optional[str] = None,
|
|
115
|
+
) -> None:
|
|
116
|
+
"""模块级便捷接口:等价于 ``current().audio(...)``。"""
|
|
117
|
+
current().audio(name, data, sr=sr, caption=caption)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def set_colors(colors: Dict[str, str]) -> None:
|
|
121
|
+
"""模块级便捷接口:等价于 ``current().set_colors(...)``。"""
|
|
122
|
+
current().set_colors(colors)
|
melog/cli/__init__.py
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""命令行入口:melog <path> 快速查看训练日志。
|
|
2
|
+
|
|
3
|
+
用法:
|
|
4
|
+
melog runs/exp1/metrics-20260903_101010.melog # 指定日志文件
|
|
5
|
+
melog runs/exp1 # 指定目录(合并全部会话文件)
|
|
6
|
+
melog # 缺省在 ./melog_runs 中查找
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import argparse
|
|
12
|
+
import sys
|
|
13
|
+
import time
|
|
14
|
+
import webbrowser
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
from ..web.fs import FileBrowser
|
|
18
|
+
from ..web.loader import LogLoader
|
|
19
|
+
from ..web.server import WebServer
|
|
20
|
+
from ..web.store import MetricStore
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _resolve_log_file(path: Path) -> Path:
|
|
24
|
+
"""文件直接用;目录取其中最新的 .melog 日志。"""
|
|
25
|
+
if path.is_file():
|
|
26
|
+
return path
|
|
27
|
+
return FileBrowser.find_latest_log(path)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _load_into_store(store: MetricStore, log_file: Path) -> int:
|
|
31
|
+
"""把日志(同 run 目录的会话文件合并)灌入内存 store,作为静态视图数据源。"""
|
|
32
|
+
series = LogLoader.parse(log_file)
|
|
33
|
+
count = 0
|
|
34
|
+
for name, pts in series.items():
|
|
35
|
+
for step, value, epoch in pts:
|
|
36
|
+
store.add(step, {name: value}, epoch)
|
|
37
|
+
count += 1
|
|
38
|
+
return count
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def main(argv=None) -> int:
|
|
42
|
+
parser = argparse.ArgumentParser(
|
|
43
|
+
prog="melog",
|
|
44
|
+
description="Melog 训练日志可视化:melog <.melog 日志文件或目录>",
|
|
45
|
+
)
|
|
46
|
+
parser.add_argument(
|
|
47
|
+
"path", nargs="?", default=None,
|
|
48
|
+
help=".melog 日志文件或包含它的目录;缺省时在 ./melog_runs 中查找",
|
|
49
|
+
)
|
|
50
|
+
parser.add_argument("--host", default="127.0.0.1", help="监听地址(默认 127.0.0.1)")
|
|
51
|
+
parser.add_argument("--port", type=int, default=8666, help="监听端口(默认 8666)")
|
|
52
|
+
parser.add_argument("--no-browser", action="store_true", help="不自动打开浏览器")
|
|
53
|
+
args = parser.parse_args(argv)
|
|
54
|
+
|
|
55
|
+
if args.path:
|
|
56
|
+
target = Path(args.path)
|
|
57
|
+
if not target.exists():
|
|
58
|
+
print(f"路径不存在: {target}", file=sys.stderr)
|
|
59
|
+
return 1
|
|
60
|
+
else:
|
|
61
|
+
target = Path("melog_runs")
|
|
62
|
+
if not target.exists():
|
|
63
|
+
print("未指定路径,且当前目录下没有 melog_runs/", file=sys.stderr)
|
|
64
|
+
return 1
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
log_file = _resolve_log_file(target)
|
|
68
|
+
except FileNotFoundError as e:
|
|
69
|
+
print(str(e), file=sys.stderr)
|
|
70
|
+
return 1
|
|
71
|
+
|
|
72
|
+
store = MetricStore()
|
|
73
|
+
if _load_into_store(store, log_file) == 0:
|
|
74
|
+
print("文件中没有可解析的指标", file=sys.stderr)
|
|
75
|
+
return 1
|
|
76
|
+
|
|
77
|
+
server = WebServer(store, host=args.host, port=args.port, log_file=str(log_file))
|
|
78
|
+
server.start()
|
|
79
|
+
|
|
80
|
+
print(f"Melog 可视化: {server.url}")
|
|
81
|
+
print(f"日志文件: {log_file}")
|
|
82
|
+
print("Ctrl+C 退出")
|
|
83
|
+
if not args.no_browser:
|
|
84
|
+
webbrowser.open(server.url)
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
while True:
|
|
88
|
+
time.sleep(1)
|
|
89
|
+
except KeyboardInterrupt:
|
|
90
|
+
pass
|
|
91
|
+
finally:
|
|
92
|
+
server.stop()
|
|
93
|
+
return 0
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
if __name__ == "__main__":
|
|
97
|
+
sys.exit(main())
|