Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: new data model #748

Merged
merged 8 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions docs/实验元数据.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# 实验元数据

> ⚠️ 自**0.3.26**版本开始,swanlab对硬件部分元数据进行调整,旧版数据依旧会在前端做向下兼容展示,但是不会再维护。
> 请试用最新的版本,以获得最佳的体验。

在每次实验开启时,也就是您执行`swanlab.init`函数时,swanlab默认将采集有关**当前工作目录**下的相关信息,以及当前计算机的硬件信息,作为实验元数据,与实验信息记录在一起。
本部分将介绍swanlab在每一次实验中记录的元数据信息,包括计算机信息、git信息等。由于历史版本原因并考虑向下兼容性,本部分元信息字段被展平而没有使用嵌套结构,可能会加重一些阅读成本。
不过大致上,我们将元数据分为三个类别:硬件信息、运行时信息、环境依赖信息。

这部分代码存储在[metadata](/swanlab/data/run/metadata)目录下。

## 硬件信息

有时候硬件信息直接决定了实验的运行、计算效率,我们将采集您的计算机的硬件信息,帮助您评估训练模型性能,他们包括:

1. CPU信息:品牌、核心数等
2. GPU信息:品牌(制造商)、型号、显存等
3. NPU信息:swanlab支持[华为昇腾AI处理器](https://e.huawei.com/cn/products/computing/ascend)的信息采集
4. SOC信息:swanlab也支持苹果m系列芯片的信息采集
5. 内存信息

于此同时,[硬件监控](/docs/硬件监控.md)的功能实现依赖于实验元数据的监测,因为我们不可能每次监控时都重新检测系统的所有硬件信息,
实际上在swanlab初始化时如何监控、监控哪些硬件信息是已经完全确定的,我们只需要在上下文中保存这些信息即可(在实际代码中,您将看到是一个个函数)。

## 运行时信息

运行时信息偏软件,他们大致包含:

1. 操作系统信息
2. git信息
3. python解释器信息

### 操作系统信息

swanlab将采集当前计算机的操作系统信息,包括操作系统型号、版本、主机名等:

```python
import platform
import socket
import os
def get_computer_info():
return {
"os": platform.platform(),
"hostname": socket.gethostname(),
"pid": os.getpid(),
"cwd": os.getcwd(),
}
```

### git信息

如果当前工作目录是一个git仓库,swanlab将通过`subprocess`采集git信息,包括当前分支、commit id等,例如:

```python
import subprocess
branch_process = subprocess.Popen(
["git", "branch", "--show-current"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
)
```

我们暂时并没有通过第三方库例如[GitPython](https://github.com/gitpython-developers/GitPython)等来获取git信息,因为我们只用到一些比较简单的信息,而且这样可以减少依赖。


### python解释器信息

python的解释器信息被保存在`sys`、`platform`标准库中,很容易获取到:

```python
import platform
import sys
def get_python_info():
return {
"python": platform.python_version(),
"python_verbose": sys.version,
"executable": sys.executable,
"command": " ".join(sys.argv),
}
```

## 环境依赖信息

环境依赖信息是指当前python环境下的依赖包信息,我们将采集当前环墶下的所有依赖包信息,包括包名、版本等:

```python
import subprocess

result = subprocess.run(["pip", "list", "--format=freeze"], stdout=subprocess.PIPE, text=True)
```
这是一个纯本文的输出,swanlab将直接保存它。

## 其他

### 第三方信息

swanlab作为一个开源项目,也会与其他第三方平台、厂商合作适配,在swanlab前端支持外显这些平台信息。这些信息也会在采集实验元数据的时候被收集。
通常,这些信息与您的训练任务没有太大关系,您可以忽略它们。

### 隐私保护

> ⚠️这是一个即将支持的功能,目前还在开发排期中。一些api可能会有所变动。

swanlab的信息收集功能是默认开启的,如果您不希望swanlab记录这些信息,在未来(因为还没来得及开发)您可以选择不记录这些信息,交互api类似:

```python
import swanlab
swanlab.set_private() # noqa
```

这样swanlab的部分功能将被禁用,包括:

1. 实验元数据收集
2. 硬件监控
3. ...
10 changes: 10 additions & 0 deletions docs/硬件信息采集.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# 硬件信息采集

本部分提供有关swanlab所记录和跟踪硬件信息、指标的相关信息以及实现的原理。

## 原理

硬件信息的采集本质上其实依赖于在实验初始化时的[实验元信息](/docs/实验元数据.md),因为这两者实际上有上下文关系:检测什么硬件、怎么检测需要通过实验元信息来确定。
在进行硬件信息的检测时,同时会附带回传一系列硬件检测函数,检测当前时刻的硬件状态,这样方便撰写监控逻辑等,也更好管理。

换句话说,硬件信息采集强依赖于实验元信息获取,
5 changes: 3 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
swankit==0.1.1b3
swanboard==0.1.6
swankit==0.1.2b2
swanboard==0.1.7b1
cos-python-sdk-v5
urllib3>=1.26.0
requests>=2.25.0
click
pyyaml
psutil
gputil==1.4.0
pynvml
rich
68 changes: 51 additions & 17 deletions swanlab/api/upload/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,45 +7,77 @@
@Description:
上传请求模型
"""
from datetime import datetime
from enum import Enum
from typing import List
from typing import List, Optional

from swankit.callback.models import ColumnClass

from swanlab.data.modules import MediaBuffer
from datetime import datetime


class ColumnModel:
"""
列信息上传模型
"""

def __init__(self, key, column_type: str, error: dict = None):
def __init__(
self,
key,
name: Optional[str],
cls: ColumnClass,
typ: str,
section_name: Optional[str],
section_type: Optional[str],
error: dict = None,
):
"""
:param key: 列名称
:param column_type: 列类型,'FLOAT', 'IMAGE', 'AUDIO', 'TEXT',必须为大写,如果传入 'DEFAULT',则会转为 'FLOAT'
:param error: 错误信息,如果错误信息不为None
Args:
key: 键
name: 键的名称
cls: 键的类别
typ: 键的类型
section_name: 键所在的section的名称
section_type: 键所在的section的类型
error: 错误信息
"""
self.key = key
self.column_type = column_type
self.name = name
self.cls = cls
self.typ = typ
self.section_name = section_name
self.section_type = section_type
self.error = error

def to_dict(self):
"""
序列化为Dict
"""
return {
"key": self.key,
"type": self.column_type,
} if self.error is None else {
d = {
"class": self.cls,
"type": self.typ,
"key": self.key,
"type": self.column_type,
"error": self.error
"name": self.name,
"error": self.error,
"sectionName": self.section_name,
"sectionType": self.section_type,
}
if self.name is None:
d.pop("name")
if self.error is None:
d.pop("error")
if self.section_name is None:
d.pop("sectionName")
if self.section_type is None:
d.pop("sectionType")
return d


class MetricType(Enum):
"""
指标类型枚举
"""

SCALAR = "scalar"
"""
标量指标
Expand All @@ -64,6 +96,7 @@ class MediaModel:
"""
媒体指标信息上传模型
"""

type = MetricType.MEDIA

def __init__(
Expand All @@ -73,7 +106,7 @@ def __init__(
key_encoded: str,
step: int,
epoch: int,
buffers: List[MediaBuffer] = None
buffers: List[MediaBuffer] = None,
):
self.metric = metric
self.step = step
Expand All @@ -99,14 +132,15 @@ def to_dict(self):
**self.metric,
"key": self.key,
"index": self.step,
"epoch": self.epoch
"epoch": self.epoch,
}


class ScalarModel:
"""
标量指标信息上传模型
"""

type = MetricType.SCALAR

def __init__(self, metric: dict, key: str, step: int, epoch: int):
Expand All @@ -123,7 +157,7 @@ def to_dict(self):
**self.metric,
"key": self.key,
"index": self.step,
"epoch": self.epoch
"epoch": self.epoch,
}


Expand All @@ -137,7 +171,7 @@ def __init__(
requirements: str = None,
metadata: dict = None,
config: dict = None,
create_time: datetime = None
create_time: datetime = None,
):
self.requirements = requirements
self.metadata = metadata
Expand Down
Loading
Loading