Skip to content

Commit 4358f13

Browse files
SAKURA-CATZeyi-Lin
andauthored
feat: cloud only and subcontracting (#843)
* feat: cloud only and subcontracting * fix: some comments and test * delete some tips for #777 * fix: watch tip * fix: comment * fix: mkdir * callback -> callbacks * fix: swanlog --------- Co-authored-by: ZeYi Lin <[email protected]>
1 parent 886c4e6 commit 4358f13

File tree

14 files changed

+311
-153
lines changed

14 files changed

+311
-153
lines changed

.github/workflows/test-when-pr.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ jobs:
2828
pip install -r requirements.txt
2929
pip install -r requirements-media.txt
3030
pip install -r requirements-dev.txt
31+
pip install -r requirements-dashboard.txt
3132
3233
- name: Run Tests (First Attempt)
3334
id: test_first_try

docs/插件化设计.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# 插件化设计
2+
3+
考虑到训练性能影响、包大小等因素,自[#780](https://github.com/SwanHubX/SwanLab/issues/780)起,swanlab将云端和本地版分开,在
4+
`mode="cloud"`
5+
时,不再运行本地版服务。本地版服务的主要将交由[SwanLab-Dashboard](https://github.com/SwanHubX/SwanLab-Dashboard)分包处理。
6+
7+
> NOTE: 由于维护精力问题,本地版服务进入维护模式,不再更新新功能,仅维护bug和适配新版本swanlab的接口变化。
8+
>
9+
> 好消息是,当[#780](https://github.com/SwanHubX/SwanLab/issues/780)
10+
> 完成的同时,我们将提供私有化部署版,代替[SwanLab-Dashboard](https://github.com/SwanHubX/SwanLab-Dashboard)的绝大多数使用场景。
11+
12+
---
13+
14+
SwanLab-SDK可以被抽象为一个解码器,使用者通过传入不同的数据以及配置,完成不同可视化场景的预处理。
15+
以此为基础,swanlab在处理的时候提供了不同的事件,通过事件回调(同步)的方式完成各种需求——因此,所谓的插件本质上是一个事件回调处理器。有关事件的详细信息,可参阅[回调函数](https://github.com/SwanHubX/SwanLab-Toolkit/wiki/第3部分:回调函数)
16+
17+
在swanlab源码当中,有一个继承自[SwanKitCallback](https://github.com/SwanHubX/SwanLab-Toolkit/blob/b914037d471628e2d3194d2d4bb4d9f3f3a7fb9c/swankit/callback/__init__.py#L17C7-L17C22)
18+
的helper,用于聚合所有的插件回调函数。当某一个事件回调被触发时,helper会按照插件的传入次序依次**同步**调用插件的回调函数。
19+
20+
> 从上述设计可以看出我们不会再关心回调处理函数的返回值是什么,因为我们认为插件的回调函数是无状态的,不应该有返回值。
21+
22+
## 🙋 如何自定义一个插件(回调处理器)
23+
24+
swanlab一切的起点都是`swanlab.init`,此函数允许传入`callbacks`参数,用于向helper注册插件回调函数。我们约定所有的回调处理器都应该继承自
25+
`SwanKitCallback`,类似下面这样:
26+
27+
```python
28+
from swankit.callback import SwanKitCallback
29+
30+
31+
class CustomCallback(SwanKitCallback):
32+
def __str__(self):
33+
# 用于在swanlab.init的时候打印插件的名称,并作为插件的唯一标识
34+
return "CustomCallback"
35+
36+
def on_stop(self, error: str = None):
37+
print("Experiment stopped.")
38+
```
39+
40+
然后在`swanlab.init`的时候传入`callbacks`参数:
41+
42+
```python
43+
import swanlab
44+
from swankit.callback import SwanKitCallback
45+
46+
47+
class CustomCallback(SwanKitCallback):
48+
def __str__(self):
49+
# 用于在swanlab.init的时候打印插件的名称,并作为插件的唯一标识
50+
return "CustomCallback"
51+
52+
def on_stop(self, error: str = None):
53+
print("Experiment stopped.")
54+
55+
56+
swanlab.init(callback=CustomCallback())
57+
```
58+
59+
这样,在实验结束后,swanlab会调用`CustomCallback``on_stop`方法,在终端打印`Experiment stopped`
60+
61+
## ⚠️ 分包后的单元测试
62+
63+
尽管`swanboard`函数变成一个可选依赖,但是单元测试时依旧需要`swanboard`的支持。即运行单元测试之前,需确保
64+
`pip install swanboard`

docs/登录认证.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
> [#792](https://github.com/SwanHubX/SwanLab/issues/792) [#797](https://github.com/SwanHubX/SwanLab/issues/797)
55
66
对于云端版而言,swanlab需要用户提供api key以完成登录认证,完成云端的鉴权。用户可以在swanlab的 [官网](https://swanlab.cn)
7-
上注册账号,然后在[个人中心](https://swanlab.cn/space/~/settings)获取api key。本部分主要讲解sdk中登录认证的代码逻辑。
7+
上注册账号,然后在[个人中心](https://swanlab.cn/space/~/settings)获取api key。

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ filename = "requirements.txt"
5858

5959
[tool.hatch.metadata.hooks.requirements_txt.optional-dependencies]
6060
media = ["requirements-media.txt"] # pip install "swanlab[meida]"
61+
dashboard = ["requirements-dashboard.txt"] # pip install "swanlab[dashboard]"
6162

6263
[tool.hatch.metadata.hooks.fancy-pypi-readme] # 动态设置readme
6364
content-type = "text/markdown"
@@ -91,6 +92,7 @@ include = [
9192
"/README.md", # 包含readme
9293
"/requirements.txt", # 包含依赖
9394
"/requirements-media.txt", # 包含可选依赖
95+
"/requirements-dashboard.txt", # 包含可选依赖
9496
]
9597

9698
[tool.hatch.build.targets.wheel]

requirements-dashboard.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
swanboard==0.1.7b1

requirements.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
swankit==0.1.3
2-
swanboard==0.1.7b1
32
cos-python-sdk-v5
43
urllib3>=1.26.0
54
requests>=2.25.0

swanlab/api/upload/__init__.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
@Description:
88
上传相关接口
99
"""
10-
from ..http import get_http, sync_error_handler
11-
from .model import ColumnModel, MediaModel, ScalarModel, FileModel
1210
from typing import List
11+
1312
from swanlab.error import ApiError
1413
from swanlab.log import swanlog
14+
from .model import ColumnModel, MediaModel, ScalarModel, FileModel
15+
from ..http import get_http, sync_error_handler
1516

1617
house_url = '/house/metrics'
1718

@@ -21,12 +22,7 @@ def create_data(metrics: List[dict], metrics_type: str) -> dict:
2122
携带上传日志的指标信息
2223
"""
2324
http = get_http()
24-
return {
25-
"projectId": http.proj_id,
26-
"experimentId": http.exp_id,
27-
"type": metrics_type,
28-
"metrics": metrics
29-
}
25+
return {"projectId": http.proj_id, "experimentId": http.exp_id, "type": metrics_type, "metrics": metrics}
3026

3127

3228
@sync_error_handler
@@ -71,7 +67,7 @@ def upload_scalar_metrics(scalar_metrics: List[ScalarModel]):
7167
_valid_files = {
7268
'config.yaml': ['config', 'yaml'],
7369
'requirements.txt': ['requirements', 'txt'],
74-
'swanlab-metadata.json': ['metadata', 'json']
70+
'swanlab-metadata.json': ['metadata', 'json'],
7571
}
7672
"""
7773
支持上传的文件列表,filename: key
@@ -117,5 +113,6 @@ def upload_column(columns: List[ColumnModel]):
117113
"upload_column",
118114
"ScalarModel",
119115
"MediaModel",
120-
"ColumnModel"
116+
"ColumnModel",
117+
"FileModel",
121118
]

swanlab/cli/commands/dashboard/watch.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77
@Description:
88
watch命令
99
"""
10-
from swanlab.env import get_swanlog_dir, SwanLabEnv
11-
from swanlab.log import swanlog
12-
from swanboard import SwanBoardRun
13-
import click
1410
import os
15-
import sys
1611
import socket
12+
import sys
13+
14+
import click
15+
16+
from swanlab.env import get_swanlog_dir, SwanLabEnv
17+
from swanlab.log import swanlog
1718

1819

1920
def get_free_port(address='0.0.0.0', default_port=5092) -> int:
@@ -88,7 +89,7 @@ def get_free_port(address='0.0.0.0', default_port=5092) -> int:
8889
readable=True,
8990
),
9091
help="Specify the folder to store Swanlog, which is by default the folder where Swanlab Watch is run."
91-
"The option will be deprecated in the future, you can just use `swanlab watch <LOG PATH>` to specify the path."
92+
"The option will be deprecated in the future, you can just use `swanlab watch <LOG PATH>` to specify the path.",
9293
)
9394
@click.option(
9495
"--log-level",
@@ -101,6 +102,12 @@ def watch(path: str, host: str, port: int, logdir: str, log_level: str):
101102
"""
102103
Run this commands to turn on the swanlab service.
103104
"""
105+
try:
106+
# noinspection PyPackageRequirements
107+
from swanboard import SwanBoardRun
108+
except ModuleNotFoundError:
109+
click.echo("Please install the swanboard package: `pip install swanlab[dashboard]`")
110+
return sys.exit(1)
104111
swanlog.level = log_level
105112
# ----- 校验path,path如果被输入,已经由上层校验已存在,可读,是一个文件夹 -----
106113
if logdir is not None:

0 commit comments

Comments
 (0)