mikon 0.0.1__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.
- mikon-0.0.1/.gitignore +16 -0
- mikon-0.0.1/LICENSE +21 -0
- mikon-0.0.1/PKG-INFO +138 -0
- mikon-0.0.1/README-ja.md +98 -0
- mikon-0.0.1/README.md +98 -0
- mikon-0.0.1/mikon/__init__.py +8 -0
- mikon-0.0.1/mikon/_runner.py +146 -0
- mikon-0.0.1/mikon/cli.py +220 -0
- mikon-0.0.1/mikon/sdk/__init__.py +40 -0
- mikon-0.0.1/mikon/sdk/config.py +7 -0
- mikon-0.0.1/mikon/sdk/context.py +163 -0
- mikon-0.0.1/mikon/sdk/datasets.py +177 -0
- mikon-0.0.1/mikon/sdk/job.py +94 -0
- mikon-0.0.1/mikon/sdk/module.py +325 -0
- mikon-0.0.1/mikon/server/__init__.py +1 -0
- mikon-0.0.1/mikon/server/api.py +450 -0
- mikon-0.0.1/mikon/server/app.py +131 -0
- mikon-0.0.1/mikon/server/discovery.py +412 -0
- mikon-0.0.1/mikon/server/docs.py +536 -0
- mikon-0.0.1/mikon/server/models.py +361 -0
- mikon-0.0.1/mikon/server/problems.py +32 -0
- mikon-0.0.1/mikon/server/registry.py +96 -0
- mikon-0.0.1/mikon/server/resources.py +709 -0
- mikon-0.0.1/mikon/server/runner.py +284 -0
- mikon-0.0.1/mikon/server/schema.py +51 -0
- mikon-0.0.1/mikon/server/settings.py +43 -0
- mikon-0.0.1/mikon/server/store.py +1050 -0
- mikon-0.0.1/mikon/templates/docs/USAGE-ja.md +924 -0
- mikon-0.0.1/mikon/templates/docs/USAGE.md +924 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- mikon-0.0.1/mikon/web/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- mikon-0.0.1/mikon/web/assets/index-DVrEHM_2.css +2 -0
- mikon-0.0.1/mikon/web/assets/index-WIx9l7H5.js +372 -0
- mikon-0.0.1/mikon/web/index.html +13 -0
- mikon-0.0.1/pyproject.toml +88 -0
mikon-0.0.1/.gitignore
ADDED
mikon-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 miko-misa
|
|
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.
|
mikon-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mikon
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Self-hosted AI development manager for GPU job execution on your own servers
|
|
5
|
+
Project-URL: Homepage, https://github.com/miko-misa/mikon
|
|
6
|
+
Project-URL: Repository, https://github.com/miko-misa/mikon
|
|
7
|
+
Project-URL: Issues, https://github.com/miko-misa/mikon/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/miko-misa/mikon/releases
|
|
9
|
+
Author-email: miko-misa <hacnosuke@gmail.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: amd,deep-learning,experiment-tracking,gpu,job-management,machine-learning,mlops,nvidia
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
+
Classifier: Topic :: System :: Monitoring
|
|
25
|
+
Requires-Python: >=3.11
|
|
26
|
+
Requires-Dist: bleach<7,>=6.1
|
|
27
|
+
Requires-Dist: fastapi<1,>=0.115
|
|
28
|
+
Requires-Dist: httpx<1,>=0.27
|
|
29
|
+
Requires-Dist: markdown<4,>=3.6
|
|
30
|
+
Requires-Dist: nvidia-ml-py<13,>=12.550
|
|
31
|
+
Requires-Dist: psutil<8,>=5.9
|
|
32
|
+
Requires-Dist: pydantic<3,>=2.8
|
|
33
|
+
Requires-Dist: pygments<3,>=2.18
|
|
34
|
+
Requires-Dist: pymdown-extensions<11,>=10.11
|
|
35
|
+
Requires-Dist: sse-starlette<4,>=2.1
|
|
36
|
+
Requires-Dist: typer<1,>=0.12
|
|
37
|
+
Requires-Dist: uvicorn[standard]<1,>=0.30
|
|
38
|
+
Requires-Dist: watchfiles<2,>=0.22
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
|
|
41
|
+
# mikon
|
|
42
|
+
|
|
43
|
+
> 日本語版: [README-ja.md](README-ja.md)
|
|
44
|
+
|
|
45
|
+
A self-hosted tool for managing AI development (training and evaluation jobs) on GPU servers from a browser.
|
|
46
|
+
|
|
47
|
+
**Write Python the way you normally would, and just add a decorator to your functions.** mikon automatically discovers your jobs, generates config forms, allocates GPUs, launches runs, and displays metrics, logs, and artifacts in real time.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Features
|
|
52
|
+
|
|
53
|
+
- **Decorator-only discovery** — Just add `@mikon.job`. No registration step, no code changes required.
|
|
54
|
+
- **Auto-generated config UI** — Pydantic fields on `class Config(mikon.Config)` become form widgets automatically (sliders, selects, checkboxes, etc.)
|
|
55
|
+
- **NVIDIA and AMD support** — Specify GPUs in unified `nvidia:0` / `amd:0` format. `CUDA_VISIBLE_DEVICES` / `ROCR_VISIBLE_DEVICES` are set automatically.
|
|
56
|
+
- **Live monitoring** — Metric charts and log streams update every few seconds via SSE.
|
|
57
|
+
- **Artifact management** — Call `ctx.log_artifact()` to make files downloadable from the browser.
|
|
58
|
+
- **Lineage tracking** — `ctx.use_dataset()` / `ctx.use_artifact()` automatically build an upstream/downstream graph.
|
|
59
|
+
- **Module system** — Register swappable components with `@mikon.module`; the UI generates a module-selection form automatically.
|
|
60
|
+
- **Dataset management** — Register existing paths or create datasets with a builder function.
|
|
61
|
+
- **Document viewer** — Markdown, Typst, and TypMark files placed in `docs/` are viewable in the dashboard.
|
|
62
|
+
- **File-based persistence** — No SQL database required. Everything is stored as text files under `.mikon/`.
|
|
63
|
+
- **Independent processes** — Jobs keep running even if the dashboard is restarted.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Requirements
|
|
68
|
+
|
|
69
|
+
- Python 3.11+
|
|
70
|
+
- GPU server with NVIDIA drivers or AMD ROCm installed
|
|
71
|
+
- `typst` CLI (optional, for Typst document rendering)
|
|
72
|
+
- `typmark-cli` CLI (optional, for TypMark document rendering)
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Quick Start
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Install
|
|
80
|
+
uv add mikon # or: pip install mikon
|
|
81
|
+
|
|
82
|
+
# Initialize project
|
|
83
|
+
mikon init
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
# src/train.py
|
|
88
|
+
import mikon
|
|
89
|
+
from mikon import Config, RunContext
|
|
90
|
+
from pydantic import Field
|
|
91
|
+
from typing import Literal
|
|
92
|
+
|
|
93
|
+
class TrainConfig(Config):
|
|
94
|
+
lr: float = Field(1e-3, gt=0, le=1)
|
|
95
|
+
epochs: int = Field(10, ge=1, le=1000)
|
|
96
|
+
optimizer: Literal["adam", "sgd"] = "adam"
|
|
97
|
+
|
|
98
|
+
@mikon.job
|
|
99
|
+
def train(config: TrainConfig, ctx: RunContext) -> None:
|
|
100
|
+
for epoch in range(config.epochs):
|
|
101
|
+
loss = 1.0 / (epoch + 1)
|
|
102
|
+
ctx.log_metric("loss", loss, step=epoch)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# Start the server on the GPU machine
|
|
107
|
+
mikon serve
|
|
108
|
+
|
|
109
|
+
# Launch a job from the CLI
|
|
110
|
+
mikon run train --gpu nvidia:0
|
|
111
|
+
|
|
112
|
+
# Access the dashboard from your local machine via SSH port forwarding
|
|
113
|
+
ssh -L 8000:localhost:8000 you@gpu-server
|
|
114
|
+
# → Open http://localhost:8000 in your browser
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Installation
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
uv add mikon # recommended
|
|
123
|
+
pip install mikon
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Dependencies (`pynvml`, `psutil`, `watchfiles`, `fastapi`, etc.) are installed automatically.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Documentation
|
|
131
|
+
|
|
132
|
+
For the full usage guide, SDK reference, CLI options, and API error model, see [USAGE.md](USAGE.md).
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## License
|
|
137
|
+
|
|
138
|
+
MIT
|
mikon-0.0.1/README-ja.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# mikon
|
|
2
|
+
|
|
3
|
+
> English: [README.md](README.md)
|
|
4
|
+
|
|
5
|
+
GPUサーバー上のAI開発(学習・評価ジョブ)をブラウザで管理するセルフホスト型ツール。
|
|
6
|
+
|
|
7
|
+
**あなたは普段どおりPythonでコードを書き、関数にデコレータを付けるだけ。** ツールが自動でジョブを認識し、コンフィグのフォームを生成し、GPUを割り当てて起動し、メトリクス・ログ・成果物をリアルタイムで表示します。
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 特徴
|
|
12
|
+
|
|
13
|
+
- **デコレータだけで認識** — `@mikon.job` を付けるだけ。登録作業やコード変更は不要
|
|
14
|
+
- **コンフィグUIの自動生成** — `class Config(mikon.Config)` の Pydantic フィールドがそのままフォームになる(スライダ・セレクト・チェックボックスなど)
|
|
15
|
+
- **NVIDIA / AMD 両対応** — `nvidia:0` / `amd:0` の統一形式でGPUを指定。`CUDA_VISIBLE_DEVICES` / `ROCR_VISIBLE_DEVICES` を自動設定
|
|
16
|
+
- **ライブモニタリング** — メトリクスチャート・ログストリームが数秒更新(SSE)
|
|
17
|
+
- **成果物管理** — `ctx.log_artifact()` でブラウザからダウンロード可能
|
|
18
|
+
- **リネージュ追跡** — `ctx.use_dataset()` / `ctx.use_artifact()` で上流/下流グラフを自動構築
|
|
19
|
+
- **モジュールシステム** — 差し替え可能なコンポーネントを `@mikon.module` で登録、UIでモジュール選択フォームが自動生成
|
|
20
|
+
- **データセット管理** — 既存パスの登録、ビルダーによる自動作成
|
|
21
|
+
- **ドキュメント閲覧** — `docs/` に置いた Markdown / Typst / TypMark をダッシュボードで表示
|
|
22
|
+
- **ファイルベース永続化** — SQLデータベース不要。すべて `.mikon/` 以下のテキストファイルに保存
|
|
23
|
+
- **独立プロセス** — ダッシュボードを再起動してもジョブは生き続ける
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 要件
|
|
28
|
+
|
|
29
|
+
- Python 3.11+
|
|
30
|
+
- GPUサーバー(NVIDIA ドライバ or AMD ROCm 導入済み)
|
|
31
|
+
- Typst ドキュメントを使う場合は `typst` CLI(任意)
|
|
32
|
+
- TypMark ドキュメントを使う場合は `typmark-cli` CLI(任意)
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## クイックスタート
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# インストール
|
|
40
|
+
uv add mikon # または pip install mikon
|
|
41
|
+
|
|
42
|
+
# プロジェクト初期化
|
|
43
|
+
mikon init
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
# src/train.py
|
|
48
|
+
import mikon
|
|
49
|
+
from mikon import Config, RunContext
|
|
50
|
+
from pydantic import Field
|
|
51
|
+
from typing import Literal
|
|
52
|
+
|
|
53
|
+
class TrainConfig(Config):
|
|
54
|
+
lr: float = Field(1e-3, gt=0, le=1)
|
|
55
|
+
epochs: int = Field(10, ge=1, le=1000)
|
|
56
|
+
optimizer: Literal["adam", "sgd"] = "adam"
|
|
57
|
+
|
|
58
|
+
@mikon.job
|
|
59
|
+
def train(config: TrainConfig, ctx: RunContext) -> None:
|
|
60
|
+
for epoch in range(config.epochs):
|
|
61
|
+
loss = 1.0 / (epoch + 1)
|
|
62
|
+
ctx.log_metric("loss", loss, step=epoch)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# サーバー起動(GPUサーバー上で)
|
|
67
|
+
mikon serve
|
|
68
|
+
|
|
69
|
+
# CLIから起動
|
|
70
|
+
mikon run train --gpu nvidia:0
|
|
71
|
+
|
|
72
|
+
# 手元PCからはSSHポートフォワードで
|
|
73
|
+
ssh -L 8000:localhost:8000 you@gpu-server
|
|
74
|
+
# → ブラウザで http://localhost:8000
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## インストール
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
uv add mikon # 推奨
|
|
83
|
+
pip install mikon
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
依存ライブラリ(`pynvml`・`psutil`・`watchfiles`・`fastapi` など)は自動でインストールされます。
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## ドキュメント
|
|
91
|
+
|
|
92
|
+
詳細な使い方・SDK リファレンス・CLI オプション・API エラーモデルは [USAGE-ja.md](USAGE-ja.md) を参照してください。
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## ライセンス
|
|
97
|
+
|
|
98
|
+
MIT
|
mikon-0.0.1/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# mikon
|
|
2
|
+
|
|
3
|
+
> 日本語版: [README-ja.md](README-ja.md)
|
|
4
|
+
|
|
5
|
+
A self-hosted tool for managing AI development (training and evaluation jobs) on GPU servers from a browser.
|
|
6
|
+
|
|
7
|
+
**Write Python the way you normally would, and just add a decorator to your functions.** mikon automatically discovers your jobs, generates config forms, allocates GPUs, launches runs, and displays metrics, logs, and artifacts in real time.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Decorator-only discovery** — Just add `@mikon.job`. No registration step, no code changes required.
|
|
14
|
+
- **Auto-generated config UI** — Pydantic fields on `class Config(mikon.Config)` become form widgets automatically (sliders, selects, checkboxes, etc.)
|
|
15
|
+
- **NVIDIA and AMD support** — Specify GPUs in unified `nvidia:0` / `amd:0` format. `CUDA_VISIBLE_DEVICES` / `ROCR_VISIBLE_DEVICES` are set automatically.
|
|
16
|
+
- **Live monitoring** — Metric charts and log streams update every few seconds via SSE.
|
|
17
|
+
- **Artifact management** — Call `ctx.log_artifact()` to make files downloadable from the browser.
|
|
18
|
+
- **Lineage tracking** — `ctx.use_dataset()` / `ctx.use_artifact()` automatically build an upstream/downstream graph.
|
|
19
|
+
- **Module system** — Register swappable components with `@mikon.module`; the UI generates a module-selection form automatically.
|
|
20
|
+
- **Dataset management** — Register existing paths or create datasets with a builder function.
|
|
21
|
+
- **Document viewer** — Markdown, Typst, and TypMark files placed in `docs/` are viewable in the dashboard.
|
|
22
|
+
- **File-based persistence** — No SQL database required. Everything is stored as text files under `.mikon/`.
|
|
23
|
+
- **Independent processes** — Jobs keep running even if the dashboard is restarted.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Requirements
|
|
28
|
+
|
|
29
|
+
- Python 3.11+
|
|
30
|
+
- GPU server with NVIDIA drivers or AMD ROCm installed
|
|
31
|
+
- `typst` CLI (optional, for Typst document rendering)
|
|
32
|
+
- `typmark-cli` CLI (optional, for TypMark document rendering)
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Install
|
|
40
|
+
uv add mikon # or: pip install mikon
|
|
41
|
+
|
|
42
|
+
# Initialize project
|
|
43
|
+
mikon init
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
# src/train.py
|
|
48
|
+
import mikon
|
|
49
|
+
from mikon import Config, RunContext
|
|
50
|
+
from pydantic import Field
|
|
51
|
+
from typing import Literal
|
|
52
|
+
|
|
53
|
+
class TrainConfig(Config):
|
|
54
|
+
lr: float = Field(1e-3, gt=0, le=1)
|
|
55
|
+
epochs: int = Field(10, ge=1, le=1000)
|
|
56
|
+
optimizer: Literal["adam", "sgd"] = "adam"
|
|
57
|
+
|
|
58
|
+
@mikon.job
|
|
59
|
+
def train(config: TrainConfig, ctx: RunContext) -> None:
|
|
60
|
+
for epoch in range(config.epochs):
|
|
61
|
+
loss = 1.0 / (epoch + 1)
|
|
62
|
+
ctx.log_metric("loss", loss, step=epoch)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Start the server on the GPU machine
|
|
67
|
+
mikon serve
|
|
68
|
+
|
|
69
|
+
# Launch a job from the CLI
|
|
70
|
+
mikon run train --gpu nvidia:0
|
|
71
|
+
|
|
72
|
+
# Access the dashboard from your local machine via SSH port forwarding
|
|
73
|
+
ssh -L 8000:localhost:8000 you@gpu-server
|
|
74
|
+
# → Open http://localhost:8000 in your browser
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Installation
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
uv add mikon # recommended
|
|
83
|
+
pip install mikon
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Dependencies (`pynvml`, `psutil`, `watchfiles`, `fastapi`, etc.) are installed automatically.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Documentation
|
|
91
|
+
|
|
92
|
+
For the full usage guide, SDK reference, CLI options, and API error model, see [USAGE.md](USAGE.md).
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## License
|
|
97
|
+
|
|
98
|
+
MIT
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
from mikon.sdk.config import Config
|
|
2
|
+
from mikon.sdk.context import RunContext
|
|
3
|
+
from mikon.sdk import datasets
|
|
4
|
+
from mikon.sdk.datasets import DatasetContext, dataset
|
|
5
|
+
from mikon.sdk.job import job
|
|
6
|
+
from mikon.sdk.module import ModuleFactory, ModuleRef, module
|
|
7
|
+
|
|
8
|
+
__all__ = ["Config", "DatasetContext", "ModuleFactory", "ModuleRef", "RunContext", "dataset", "datasets", "job", "module"]
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import json
|
|
5
|
+
import signal
|
|
6
|
+
import sys
|
|
7
|
+
import threading
|
|
8
|
+
import time
|
|
9
|
+
import traceback
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import TextIO
|
|
12
|
+
|
|
13
|
+
from mikon.sdk.datasets import DatasetContext, get_dataset_registry
|
|
14
|
+
from mikon.sdk.context import RunContext
|
|
15
|
+
from mikon.sdk.job import get_registry
|
|
16
|
+
from mikon.sdk.module import instantiate_config_modules, validate_module_nest_depth
|
|
17
|
+
from mikon.server.discovery import import_project
|
|
18
|
+
from mikon.server.models import RunStatus
|
|
19
|
+
from mikon.server.settings import load_settings
|
|
20
|
+
from mikon.server.store import Store
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def main(argv: list[str] | None = None) -> int:
|
|
24
|
+
parser = argparse.ArgumentParser()
|
|
25
|
+
parser.add_argument("--run-dir", required=True)
|
|
26
|
+
args = parser.parse_args(argv)
|
|
27
|
+
run_dir = Path(args.run_dir).resolve()
|
|
28
|
+
store = Store(run_dir.parents[1])
|
|
29
|
+
meta = store.read_json(run_dir / "meta.json")
|
|
30
|
+
run_id = meta["run_id"]
|
|
31
|
+
|
|
32
|
+
stop_event = threading.Event()
|
|
33
|
+
heartbeat = threading.Thread(
|
|
34
|
+
target=_heartbeat_loop, args=(run_dir, stop_event), name="mikon-heartbeat", daemon=True
|
|
35
|
+
)
|
|
36
|
+
heartbeat.start()
|
|
37
|
+
|
|
38
|
+
def _handle_signal(signum: int, frame: object) -> None:
|
|
39
|
+
raise KeyboardInterrupt(f"received signal {signum}")
|
|
40
|
+
|
|
41
|
+
signal.signal(signal.SIGTERM, _handle_signal)
|
|
42
|
+
signal.signal(signal.SIGINT, _handle_signal)
|
|
43
|
+
|
|
44
|
+
status = RunStatus.completed
|
|
45
|
+
exit_code = 0
|
|
46
|
+
error: str | None = None
|
|
47
|
+
event_logger = _LogEventWriter(run_dir / "logs" / "events.jsonl")
|
|
48
|
+
original_stdout = sys.stdout
|
|
49
|
+
original_stderr = sys.stderr
|
|
50
|
+
sys.stdout = _TeeLineWriter(original_stdout, event_logger, "stdout")
|
|
51
|
+
sys.stderr = _TeeLineWriter(original_stderr, event_logger, "stderr")
|
|
52
|
+
try:
|
|
53
|
+
project_root = Path(meta["project_root"]).resolve()
|
|
54
|
+
watch_paths = [Path(item).resolve() for item in meta["watch"]]
|
|
55
|
+
import_project(project_root, watch_paths)
|
|
56
|
+
kind = meta.get("kind", "job")
|
|
57
|
+
if kind == "dataset":
|
|
58
|
+
definition = get_dataset_registry().get(meta["job"])
|
|
59
|
+
else:
|
|
60
|
+
definition = get_registry().get(meta["job"])
|
|
61
|
+
if definition is None:
|
|
62
|
+
raise RuntimeError(f"{kind} not found during run: {meta['job']}")
|
|
63
|
+
config_data = store.read_json(run_dir / "config.json")
|
|
64
|
+
settings = load_settings(project_root)
|
|
65
|
+
validate_module_nest_depth(config_data, settings.max_module_nest_depth)
|
|
66
|
+
config = definition.config_type.model_validate(config_data)
|
|
67
|
+
validate_module_nest_depth(config.model_dump(mode="json"), settings.max_module_nest_depth)
|
|
68
|
+
instantiate_config_modules(config, max_depth=settings.max_module_nest_depth)
|
|
69
|
+
ctx = DatasetContext(run_dir, meta["job"]) if kind == "dataset" else RunContext(run_dir)
|
|
70
|
+
definition.func(config, ctx)
|
|
71
|
+
except KeyboardInterrupt as exc:
|
|
72
|
+
status = RunStatus.stopped
|
|
73
|
+
exit_code = 143
|
|
74
|
+
error = str(exc)
|
|
75
|
+
except BaseException:
|
|
76
|
+
status = RunStatus.failed
|
|
77
|
+
exit_code = 1
|
|
78
|
+
error = traceback.format_exc()
|
|
79
|
+
finally:
|
|
80
|
+
sys.stdout = original_stdout
|
|
81
|
+
sys.stderr = original_stderr
|
|
82
|
+
event_logger.flush()
|
|
83
|
+
stop_event.set()
|
|
84
|
+
heartbeat.join(timeout=1)
|
|
85
|
+
store.write_status(run_id, status, exit_code, error)
|
|
86
|
+
return exit_code
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _heartbeat_loop(run_dir: Path, stop_event: threading.Event) -> None:
|
|
90
|
+
heartbeat = run_dir / "heartbeat"
|
|
91
|
+
while not stop_event.is_set():
|
|
92
|
+
heartbeat.write_text(str(time.time()), encoding="utf-8")
|
|
93
|
+
stop_event.wait(2)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class _LogEventWriter:
|
|
97
|
+
def __init__(self, path: Path) -> None:
|
|
98
|
+
self.path = path
|
|
99
|
+
self.path.parent.mkdir(parents=True, exist_ok=True)
|
|
100
|
+
self._lock = threading.Lock()
|
|
101
|
+
self._seq = 0
|
|
102
|
+
|
|
103
|
+
def write_line(self, stream: str, line: str) -> None:
|
|
104
|
+
with self._lock:
|
|
105
|
+
record = {"seq": self._seq, "t": time.time(), "stream": stream, "line": line}
|
|
106
|
+
self._seq += 1
|
|
107
|
+
with self.path.open("a", encoding="utf-8") as fp:
|
|
108
|
+
fp.write(json.dumps(record, separators=(",", ":"), allow_nan=False) + "\n")
|
|
109
|
+
fp.flush()
|
|
110
|
+
|
|
111
|
+
def flush(self) -> None:
|
|
112
|
+
return
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class _TeeLineWriter:
|
|
116
|
+
def __init__(self, target: TextIO, event_logger: _LogEventWriter, stream: str) -> None:
|
|
117
|
+
self.target = target
|
|
118
|
+
self.event_logger = event_logger
|
|
119
|
+
self.stream = stream
|
|
120
|
+
self._buffer = ""
|
|
121
|
+
|
|
122
|
+
def write(self, text: str) -> int:
|
|
123
|
+
written = self.target.write(text)
|
|
124
|
+
self.target.flush()
|
|
125
|
+
self._buffer += text
|
|
126
|
+
while "\n" in self._buffer:
|
|
127
|
+
line, self._buffer = self._buffer.split("\n", 1)
|
|
128
|
+
self.event_logger.write_line(self.stream, line)
|
|
129
|
+
return written
|
|
130
|
+
|
|
131
|
+
def flush(self) -> None:
|
|
132
|
+
self.target.flush()
|
|
133
|
+
if self._buffer:
|
|
134
|
+
self.event_logger.write_line(self.stream, self._buffer)
|
|
135
|
+
self._buffer = ""
|
|
136
|
+
|
|
137
|
+
def isatty(self) -> bool:
|
|
138
|
+
return self.target.isatty()
|
|
139
|
+
|
|
140
|
+
@property
|
|
141
|
+
def encoding(self) -> str | None:
|
|
142
|
+
return self.target.encoding
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
if __name__ == "__main__":
|
|
146
|
+
raise SystemExit(main())
|