xpriment


Namexpriment JSON
Version 0.0.2 PyPI version JSON
download
home_pageNone
Summary实验管理框架
upload_time2025-10-07 20:28:07
maintainerNone
docs_urlNone
authorpotatoQi
requires_python>=3.9
licenseApache-2.0
keywords experiment scheduler machine-learning lark monitoring
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # 实验管理框架

一个轻量级的Python实验管理框架,提供:

🚀 **批量调度** - TOML 配置文件一键启动多组实验,支持优先级和并发控制  
📊 **指标记录** - 动态 CSV 管理,`upd_row()` + `save_row()` 数据库风格操作  
🌐 **可视化监控** - 配备 Web UI,实时查看实验状态和日志  
📱 **飞书同步** - 训练指标实时同步到多维表格,团队协作更便捷

<div align="center">
  <img src="https://raw.githubusercontent.com/potatoQi/EXP/main/docs/images/1.png" alt="实验管理界面" width="80%">
  <p><em>实验管理界面 - 批量调度与实时监控</em></p>
</div>

<div align="center">
  <img src="https://raw.githubusercontent.com/potatoQi/EXP/main/docs/images/2.png" alt="实验详情页面" width="80%">
  <p><em>实验查询页面 - 实验查询与内容预览</em></p>
</div>


## 如何嵌入到你的工程

只需完成两件事:

1. **写包装脚本**——用 `Experiment` 包装你的训练命令,EXP 会负责目录、日志和状态。
2. **写指标**——在训练脚本中调用 `load_experiment()`,然后即可使用 EXP 提供的 api。

搞定这两步,就可以单点运行,也能批量调度。

### 使用前准备

```bash
pip install -e . 或者 pip install xpriment
```

### 🎯 快速体验

### 方式一:单点运行

**1. 创建一个 toy example**

```python
# 创建一个 toy 训练脚本 train.py
import time
from experiment_manager.core import load_experiment

exp = load_experiment()

for i in range(3):
    exp.upd_row(step=i, loss=1.0/(i+1))
    exp.save_row()
    print(f"Step {i}, Loss: {1.0/(i+1):.3f}")
    time.sleep(1)

# 创建包装脚本 run_exp.py
from pathlib import Path
from experiment_manager.core import Experiment

exp = Experiment(
  name="test",
  command="python train.py",
  base_dir=Path("./results"),
  cwd=Path(".")
)
exp.run(background=False) # True 时后台运行
```

**2. 运行并查看结果**

  ```bash
  python run_exp.py
  ```

  输出会在 `<base_dir>/<name>_<timestamp>/`

### 方式二:配置驱动批量调度

1. **写一个最小配置**

  ```toml
  # config.toml
  [scheduler]
  base_experiment_dir = "./results"
  max_concurrent_experiments = 2

  [[experiments]]
  name = "exp1"
  command = "python train.py"

  [[experiments]]
  name = "exp2"
  command = "python train.py"
  ```

2. **启动调度器并打开 UI**

  ```bash
  EXP run config.toml               # 执行配置中所有实验
  EXP see ./results                 # 可视化监控界面
  ```

## 🧰 Experiment API 速览

| API | 说明 |
| --- | --- |
| `Experiment(...)` | 核心入口。常用参数:`name`(实验名)、`command`(实际训练命令)、`base_dir`(输出根目录)、`cwd`、`tags`、`gpu_ids`、`description`。若需要飞书同步,使用 `lark_config` 传入凭据或 URL,实例会在创建时生成工作目录并写入 `metadata.json`。 |
| `load_experiment()` | 训练脚本内获取当前运行的 `Experiment` 实例。该函数依赖调度器或包装脚本注入的目录信息;如果直接裸跑脚本,会抛出说明性异常,提示未在 EXP 环境下启动。 |
| `exp.run(background=False, extra_env=None)` | 启动训练命令并记录日志。`background=True` 时异步执行且自动创建输出线程;`extra_env` 可传字典为子进程增删环境变量。方法会维护运行状态并把 PID、日志路径等写入 `metadata.json`。 |
| `exp.upd_row(**metrics)` | 累积一行指标数据到缓冲区(字典),常用于每个 step/epoch 结束后调用。支持任意键值对,默认将值转为字符串或数值,下一次 `save_row()` 会将本次更新写入 CSV。 |
| `exp.save_row(lark=False, lark_config=None)` | 将缓冲区写入 `<work_dir>/metrics/*.csv`,必要时扩展字段并回填旧数据。`lark=True` 时会尝试同步飞书:默认使用实例创建时的 `lark_config`,也可以通过参数传入临时覆盖并在成功后持久化。 |

### 参数详解

#### `Experiment(...)`

| 参数 | 类型 | 说明 | 示例 |
| --- | --- | --- | --- |
| `name` | `str` | 实验名称,最终目录名为 `name_timestamp`。 | `"cnn_small"` |
| `command` | `str` | 实际执行的训练指令,会在 `run()` 时通过 shell 启动。 | `"python train.py --epochs 20"` |
| `base_dir` | `PathLike` | 实验输出根目录,必须存在或可创建。 | `Path("./experiments")` |
| `tags` | `List[str]` | 可选标签,写入 `metadata.json` 方便筛选。默认 `[]`。 | `["cnn", "baseline"]` |
| `gpu_ids` | `List[int]` | 指定 GPU 序号,会自动设置 `CUDA_VISIBLE_DEVICES`。 | `[0, 1]` |
| `cwd` | `PathLike` | 运行子进程时的工作目录,未提供则使用新建的实验目录。 | `Path("./training")` |
| `resume` | `str` | 继续已有实验,值为原目录时间戳(如 `2025-09-30__11-02-13`)。 | `"2025-09-30__11-02-13"` |
| `description` | `str` | 备注信息,会写入 `metadata.json` 并在 UI 中展示。 | `"Sweep with cosine LR"` |
| `lark_config` | `Dict[str,str] \| str` | 飞书配置,支持直接传 URL (`str`) 或包含 `app_id`、`app_secret`、`app_token`、`table_id` 等键的字典。解析后会持久化,用于后续同步。 | `{"app_id": "cli_xxx", "app_secret": "xxx", "url": "https://example.feishu.cn/base/app123?table=tbl123"}` |

#### `load_experiment()`

无入参。从训练脚本中返回当前 `Experiment` 实例,若脚本未通过 EXP 启动则抛出异常。

#### `exp.run(background=False, extra_env=None)`

| 参数 | 类型 | 说明 | 示例 |
| --- | --- | --- | --- |
| `background` | `bool` | `True` 为后台执行并开启日志收集线程;`False` 时阻塞等待命令结束。默认 `True`。 | `background=False` |
| `extra_env` | `Dict[str, str]` | 额外注入/覆盖的环境变量;值为 `None` 的键会被删除。 | `{"WANDB_MODE": "offline"}` |

#### `exp.upd_row(**metrics)`

可变关键字参数:任意指标键值对,合并到内部缓冲区,直到下一次 save_row 时才写回。常见示例:

```python
exp.upd_row(epoch=i, train_loss=loss, lr=scheduler.get_last_lr()[0])
```

#### `exp.save_row(lark=False, lark_config=None)`

| 参数 | 类型 | 说明 | 示例 |
| --- | --- | --- | --- |
| `lark` | `bool` | 是否触发飞书同步。默认 `False`。 | `lark=True` |
| `lark_config` | `Dict[str,str] \| str` | 本次写入的飞书覆盖配置。若提供,将与实例已有配置合并(覆盖优先),并在成功后写入 `metadata.json`。 | `{"view_id": "vewABCDEFG"}` |

## 📈 进阶:飞书配置最佳实践

### 单点实验
- 在创建 `Experiment(...)` 时直接通过 `lark_config` 提供飞书凭据,可传字典或 URL 字符串。
- 建议在字典中显式包含 `app_id`、`app_secret`、`app_token`、`table_id`(视图可选 `view_id`)。若传入 URL,框架会自动解析 `app_token`/`table_id`/`view_id`。
- 实例在首次同步成功后会将最终配置写入 `metadata.json`,`resume` 或后续 `save_row(lark=True)` 会复用这份配置。

### 调度器
- 在 `[scheduler]` 段落设置共享凭据,例如 `lark_config = { app_id = "cli_xxx", app_secret = "xxx" }`,避免每个实验重复填写。
- 每个 `[[experiments]]` 可通过 `lark_url` 或 `lark_config` 覆盖/补充表格信息,字段会覆盖调度器级别的同名项。
- 若某实验需要独立账号,只需在该实验的 `lark_config` 中补齐完整凭据即可。

### 合并逻辑速览
- 调度模式下:`[scheduler].lark_config` < `[[experiments]].lark_config`/`lark_url`。
- 单点实验:构造函数的 `lark_config` 与实例已有配置(如 `resume` 读取的 `metadata.json`)合并,新传入值优先。
- `exp.save_row(lark=True, lark_config=...)` 会在实例默认配置之上再次叠加本次调用的覆盖值。

## License

This repository is licensed under the [Apache-2.0 License](https://github.com/potatoQi/EXP/blob/main/LICENSE).

## Star History

![Star History Chart](https://api.star-history.com/svg?repos=potatoQi/EXP&type=Date)

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "xpriment",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": "experiment, scheduler, machine-learning, lark, monitoring",
    "author": "potatoQi",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/40/bb/f47e5ec2e5873d867b0828765b9cd000d4caf676054d9f04cf0d0f28c5db/xpriment-0.0.2.tar.gz",
    "platform": null,
    "description": "# \u5b9e\u9a8c\u7ba1\u7406\u6846\u67b6\n\n\u4e00\u4e2a\u8f7b\u91cf\u7ea7\u7684Python\u5b9e\u9a8c\u7ba1\u7406\u6846\u67b6\uff0c\u63d0\u4f9b\uff1a\n\n\ud83d\ude80 **\u6279\u91cf\u8c03\u5ea6** - TOML \u914d\u7f6e\u6587\u4ef6\u4e00\u952e\u542f\u52a8\u591a\u7ec4\u5b9e\u9a8c\uff0c\u652f\u6301\u4f18\u5148\u7ea7\u548c\u5e76\u53d1\u63a7\u5236  \n\ud83d\udcca **\u6307\u6807\u8bb0\u5f55** - \u52a8\u6001 CSV \u7ba1\u7406\uff0c`upd_row()` + `save_row()` \u6570\u636e\u5e93\u98ce\u683c\u64cd\u4f5c  \n\ud83c\udf10 **\u53ef\u89c6\u5316\u76d1\u63a7** - \u914d\u5907 Web UI\uff0c\u5b9e\u65f6\u67e5\u770b\u5b9e\u9a8c\u72b6\u6001\u548c\u65e5\u5fd7  \n\ud83d\udcf1 **\u98de\u4e66\u540c\u6b65** - \u8bad\u7ec3\u6307\u6807\u5b9e\u65f6\u540c\u6b65\u5230\u591a\u7ef4\u8868\u683c\uff0c\u56e2\u961f\u534f\u4f5c\u66f4\u4fbf\u6377\n\n<div align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/potatoQi/EXP/main/docs/images/1.png\" alt=\"\u5b9e\u9a8c\u7ba1\u7406\u754c\u9762\" width=\"80%\">\n  <p><em>\u5b9e\u9a8c\u7ba1\u7406\u754c\u9762 - \u6279\u91cf\u8c03\u5ea6\u4e0e\u5b9e\u65f6\u76d1\u63a7</em></p>\n</div>\n\n<div align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/potatoQi/EXP/main/docs/images/2.png\" alt=\"\u5b9e\u9a8c\u8be6\u60c5\u9875\u9762\" width=\"80%\">\n  <p><em>\u5b9e\u9a8c\u67e5\u8be2\u9875\u9762 - \u5b9e\u9a8c\u67e5\u8be2\u4e0e\u5185\u5bb9\u9884\u89c8</em></p>\n</div>\n\n\n## \u5982\u4f55\u5d4c\u5165\u5230\u4f60\u7684\u5de5\u7a0b\n\n\u53ea\u9700\u5b8c\u6210\u4e24\u4ef6\u4e8b\uff1a\n\n1. **\u5199\u5305\u88c5\u811a\u672c**\u2014\u2014\u7528 `Experiment` \u5305\u88c5\u4f60\u7684\u8bad\u7ec3\u547d\u4ee4\uff0cEXP \u4f1a\u8d1f\u8d23\u76ee\u5f55\u3001\u65e5\u5fd7\u548c\u72b6\u6001\u3002\n2. **\u5199\u6307\u6807**\u2014\u2014\u5728\u8bad\u7ec3\u811a\u672c\u4e2d\u8c03\u7528 `load_experiment()`\uff0c\u7136\u540e\u5373\u53ef\u4f7f\u7528 EXP \u63d0\u4f9b\u7684 api\u3002\n\n\u641e\u5b9a\u8fd9\u4e24\u6b65\uff0c\u5c31\u53ef\u4ee5\u5355\u70b9\u8fd0\u884c\uff0c\u4e5f\u80fd\u6279\u91cf\u8c03\u5ea6\u3002\n\n### \u4f7f\u7528\u524d\u51c6\u5907\n\n```bash\npip install -e . \u6216\u8005 pip install xpriment\n```\n\n### \ud83c\udfaf \u5feb\u901f\u4f53\u9a8c\n\n### \u65b9\u5f0f\u4e00\uff1a\u5355\u70b9\u8fd0\u884c\n\n**1. \u521b\u5efa\u4e00\u4e2a toy example**\n\n```python\n# \u521b\u5efa\u4e00\u4e2a toy \u8bad\u7ec3\u811a\u672c train.py\nimport time\nfrom experiment_manager.core import load_experiment\n\nexp = load_experiment()\n\nfor i in range(3):\n    exp.upd_row(step=i, loss=1.0/(i+1))\n    exp.save_row()\n    print(f\"Step {i}, Loss: {1.0/(i+1):.3f}\")\n    time.sleep(1)\n\n# \u521b\u5efa\u5305\u88c5\u811a\u672c run_exp.py\nfrom pathlib import Path\nfrom experiment_manager.core import Experiment\n\nexp = Experiment(\n  name=\"test\",\n  command=\"python train.py\",\n  base_dir=Path(\"./results\"),\n  cwd=Path(\".\")\n)\nexp.run(background=False) # True \u65f6\u540e\u53f0\u8fd0\u884c\n```\n\n**2. \u8fd0\u884c\u5e76\u67e5\u770b\u7ed3\u679c**\n\n  ```bash\n  python run_exp.py\n  ```\n\n  \u8f93\u51fa\u4f1a\u5728 `<base_dir>/<name>_<timestamp>/`\n\n### \u65b9\u5f0f\u4e8c\uff1a\u914d\u7f6e\u9a71\u52a8\u6279\u91cf\u8c03\u5ea6\n\n1. **\u5199\u4e00\u4e2a\u6700\u5c0f\u914d\u7f6e**\n\n  ```toml\n  # config.toml\n  [scheduler]\n  base_experiment_dir = \"./results\"\n  max_concurrent_experiments = 2\n\n  [[experiments]]\n  name = \"exp1\"\n  command = \"python train.py\"\n\n  [[experiments]]\n  name = \"exp2\"\n  command = \"python train.py\"\n  ```\n\n2. **\u542f\u52a8\u8c03\u5ea6\u5668\u5e76\u6253\u5f00 UI**\n\n  ```bash\n  EXP run config.toml               # \u6267\u884c\u914d\u7f6e\u4e2d\u6240\u6709\u5b9e\u9a8c\n  EXP see ./results                 # \u53ef\u89c6\u5316\u76d1\u63a7\u754c\u9762\n  ```\n\n## \ud83e\uddf0 Experiment API \u901f\u89c8\n\n| API | \u8bf4\u660e |\n| --- | --- |\n| `Experiment(...)` | \u6838\u5fc3\u5165\u53e3\u3002\u5e38\u7528\u53c2\u6570\uff1a`name`\uff08\u5b9e\u9a8c\u540d\uff09\u3001`command`\uff08\u5b9e\u9645\u8bad\u7ec3\u547d\u4ee4\uff09\u3001`base_dir`\uff08\u8f93\u51fa\u6839\u76ee\u5f55\uff09\u3001`cwd`\u3001`tags`\u3001`gpu_ids`\u3001`description`\u3002\u82e5\u9700\u8981\u98de\u4e66\u540c\u6b65\uff0c\u4f7f\u7528 `lark_config` \u4f20\u5165\u51ed\u636e\u6216 URL\uff0c\u5b9e\u4f8b\u4f1a\u5728\u521b\u5efa\u65f6\u751f\u6210\u5de5\u4f5c\u76ee\u5f55\u5e76\u5199\u5165 `metadata.json`\u3002 |\n| `load_experiment()` | \u8bad\u7ec3\u811a\u672c\u5185\u83b7\u53d6\u5f53\u524d\u8fd0\u884c\u7684 `Experiment` \u5b9e\u4f8b\u3002\u8be5\u51fd\u6570\u4f9d\u8d56\u8c03\u5ea6\u5668\u6216\u5305\u88c5\u811a\u672c\u6ce8\u5165\u7684\u76ee\u5f55\u4fe1\u606f\uff1b\u5982\u679c\u76f4\u63a5\u88f8\u8dd1\u811a\u672c\uff0c\u4f1a\u629b\u51fa\u8bf4\u660e\u6027\u5f02\u5e38\uff0c\u63d0\u793a\u672a\u5728 EXP \u73af\u5883\u4e0b\u542f\u52a8\u3002 |\n| `exp.run(background=False, extra_env=None)` | \u542f\u52a8\u8bad\u7ec3\u547d\u4ee4\u5e76\u8bb0\u5f55\u65e5\u5fd7\u3002`background=True` \u65f6\u5f02\u6b65\u6267\u884c\u4e14\u81ea\u52a8\u521b\u5efa\u8f93\u51fa\u7ebf\u7a0b\uff1b`extra_env` \u53ef\u4f20\u5b57\u5178\u4e3a\u5b50\u8fdb\u7a0b\u589e\u5220\u73af\u5883\u53d8\u91cf\u3002\u65b9\u6cd5\u4f1a\u7ef4\u62a4\u8fd0\u884c\u72b6\u6001\u5e76\u628a PID\u3001\u65e5\u5fd7\u8def\u5f84\u7b49\u5199\u5165 `metadata.json`\u3002 |\n| `exp.upd_row(**metrics)` | \u7d2f\u79ef\u4e00\u884c\u6307\u6807\u6570\u636e\u5230\u7f13\u51b2\u533a\uff08\u5b57\u5178\uff09\uff0c\u5e38\u7528\u4e8e\u6bcf\u4e2a step/epoch \u7ed3\u675f\u540e\u8c03\u7528\u3002\u652f\u6301\u4efb\u610f\u952e\u503c\u5bf9\uff0c\u9ed8\u8ba4\u5c06\u503c\u8f6c\u4e3a\u5b57\u7b26\u4e32\u6216\u6570\u503c\uff0c\u4e0b\u4e00\u6b21 `save_row()` \u4f1a\u5c06\u672c\u6b21\u66f4\u65b0\u5199\u5165 CSV\u3002 |\n| `exp.save_row(lark=False, lark_config=None)` | \u5c06\u7f13\u51b2\u533a\u5199\u5165 `<work_dir>/metrics/*.csv`\uff0c\u5fc5\u8981\u65f6\u6269\u5c55\u5b57\u6bb5\u5e76\u56de\u586b\u65e7\u6570\u636e\u3002`lark=True` \u65f6\u4f1a\u5c1d\u8bd5\u540c\u6b65\u98de\u4e66\uff1a\u9ed8\u8ba4\u4f7f\u7528\u5b9e\u4f8b\u521b\u5efa\u65f6\u7684 `lark_config`\uff0c\u4e5f\u53ef\u4ee5\u901a\u8fc7\u53c2\u6570\u4f20\u5165\u4e34\u65f6\u8986\u76d6\u5e76\u5728\u6210\u529f\u540e\u6301\u4e45\u5316\u3002 |\n\n### \u53c2\u6570\u8be6\u89e3\n\n#### `Experiment(...)`\n\n| \u53c2\u6570 | \u7c7b\u578b | \u8bf4\u660e | \u793a\u4f8b |\n| --- | --- | --- | --- |\n| `name` | `str` | \u5b9e\u9a8c\u540d\u79f0\uff0c\u6700\u7ec8\u76ee\u5f55\u540d\u4e3a `name_timestamp`\u3002 | `\"cnn_small\"` |\n| `command` | `str` | \u5b9e\u9645\u6267\u884c\u7684\u8bad\u7ec3\u6307\u4ee4\uff0c\u4f1a\u5728 `run()` \u65f6\u901a\u8fc7 shell \u542f\u52a8\u3002 | `\"python train.py --epochs 20\"` |\n| `base_dir` | `PathLike` | \u5b9e\u9a8c\u8f93\u51fa\u6839\u76ee\u5f55\uff0c\u5fc5\u987b\u5b58\u5728\u6216\u53ef\u521b\u5efa\u3002 | `Path(\"./experiments\")` |\n| `tags` | `List[str]` | \u53ef\u9009\u6807\u7b7e\uff0c\u5199\u5165 `metadata.json` \u65b9\u4fbf\u7b5b\u9009\u3002\u9ed8\u8ba4 `[]`\u3002 | `[\"cnn\", \"baseline\"]` |\n| `gpu_ids` | `List[int]` | \u6307\u5b9a GPU \u5e8f\u53f7\uff0c\u4f1a\u81ea\u52a8\u8bbe\u7f6e `CUDA_VISIBLE_DEVICES`\u3002 | `[0, 1]` |\n| `cwd` | `PathLike` | \u8fd0\u884c\u5b50\u8fdb\u7a0b\u65f6\u7684\u5de5\u4f5c\u76ee\u5f55\uff0c\u672a\u63d0\u4f9b\u5219\u4f7f\u7528\u65b0\u5efa\u7684\u5b9e\u9a8c\u76ee\u5f55\u3002 | `Path(\"./training\")` |\n| `resume` | `str` | \u7ee7\u7eed\u5df2\u6709\u5b9e\u9a8c\uff0c\u503c\u4e3a\u539f\u76ee\u5f55\u65f6\u95f4\u6233\uff08\u5982 `2025-09-30__11-02-13`\uff09\u3002 | `\"2025-09-30__11-02-13\"` |\n| `description` | `str` | \u5907\u6ce8\u4fe1\u606f\uff0c\u4f1a\u5199\u5165 `metadata.json` \u5e76\u5728 UI \u4e2d\u5c55\u793a\u3002 | `\"Sweep with cosine LR\"` |\n| `lark_config` | `Dict[str,str] \\| str` | \u98de\u4e66\u914d\u7f6e\uff0c\u652f\u6301\u76f4\u63a5\u4f20 URL (`str`) \u6216\u5305\u542b `app_id`\u3001`app_secret`\u3001`app_token`\u3001`table_id` \u7b49\u952e\u7684\u5b57\u5178\u3002\u89e3\u6790\u540e\u4f1a\u6301\u4e45\u5316\uff0c\u7528\u4e8e\u540e\u7eed\u540c\u6b65\u3002 | `{\"app_id\": \"cli_xxx\", \"app_secret\": \"xxx\", \"url\": \"https://example.feishu.cn/base/app123?table=tbl123\"}` |\n\n#### `load_experiment()`\n\n\u65e0\u5165\u53c2\u3002\u4ece\u8bad\u7ec3\u811a\u672c\u4e2d\u8fd4\u56de\u5f53\u524d `Experiment` \u5b9e\u4f8b\uff0c\u82e5\u811a\u672c\u672a\u901a\u8fc7 EXP \u542f\u52a8\u5219\u629b\u51fa\u5f02\u5e38\u3002\n\n#### `exp.run(background=False, extra_env=None)`\n\n| \u53c2\u6570 | \u7c7b\u578b | \u8bf4\u660e | \u793a\u4f8b |\n| --- | --- | --- | --- |\n| `background` | `bool` | `True` \u4e3a\u540e\u53f0\u6267\u884c\u5e76\u5f00\u542f\u65e5\u5fd7\u6536\u96c6\u7ebf\u7a0b\uff1b`False` \u65f6\u963b\u585e\u7b49\u5f85\u547d\u4ee4\u7ed3\u675f\u3002\u9ed8\u8ba4 `True`\u3002 | `background=False` |\n| `extra_env` | `Dict[str, str]` | \u989d\u5916\u6ce8\u5165/\u8986\u76d6\u7684\u73af\u5883\u53d8\u91cf\uff1b\u503c\u4e3a `None` \u7684\u952e\u4f1a\u88ab\u5220\u9664\u3002 | `{\"WANDB_MODE\": \"offline\"}` |\n\n#### `exp.upd_row(**metrics)`\n\n\u53ef\u53d8\u5173\u952e\u5b57\u53c2\u6570\uff1a\u4efb\u610f\u6307\u6807\u952e\u503c\u5bf9\uff0c\u5408\u5e76\u5230\u5185\u90e8\u7f13\u51b2\u533a\uff0c\u76f4\u5230\u4e0b\u4e00\u6b21 save_row \u65f6\u624d\u5199\u56de\u3002\u5e38\u89c1\u793a\u4f8b\uff1a\n\n```python\nexp.upd_row(epoch=i, train_loss=loss, lr=scheduler.get_last_lr()[0])\n```\n\n#### `exp.save_row(lark=False, lark_config=None)`\n\n| \u53c2\u6570 | \u7c7b\u578b | \u8bf4\u660e | \u793a\u4f8b |\n| --- | --- | --- | --- |\n| `lark` | `bool` | \u662f\u5426\u89e6\u53d1\u98de\u4e66\u540c\u6b65\u3002\u9ed8\u8ba4 `False`\u3002 | `lark=True` |\n| `lark_config` | `Dict[str,str] \\| str` | \u672c\u6b21\u5199\u5165\u7684\u98de\u4e66\u8986\u76d6\u914d\u7f6e\u3002\u82e5\u63d0\u4f9b\uff0c\u5c06\u4e0e\u5b9e\u4f8b\u5df2\u6709\u914d\u7f6e\u5408\u5e76\uff08\u8986\u76d6\u4f18\u5148\uff09\uff0c\u5e76\u5728\u6210\u529f\u540e\u5199\u5165 `metadata.json`\u3002 | `{\"view_id\": \"vewABCDEFG\"}` |\n\n## \ud83d\udcc8 \u8fdb\u9636\uff1a\u98de\u4e66\u914d\u7f6e\u6700\u4f73\u5b9e\u8df5\n\n### \u5355\u70b9\u5b9e\u9a8c\n- \u5728\u521b\u5efa `Experiment(...)` \u65f6\u76f4\u63a5\u901a\u8fc7 `lark_config` \u63d0\u4f9b\u98de\u4e66\u51ed\u636e\uff0c\u53ef\u4f20\u5b57\u5178\u6216 URL \u5b57\u7b26\u4e32\u3002\n- \u5efa\u8bae\u5728\u5b57\u5178\u4e2d\u663e\u5f0f\u5305\u542b `app_id`\u3001`app_secret`\u3001`app_token`\u3001`table_id`\uff08\u89c6\u56fe\u53ef\u9009 `view_id`\uff09\u3002\u82e5\u4f20\u5165 URL\uff0c\u6846\u67b6\u4f1a\u81ea\u52a8\u89e3\u6790 `app_token`/`table_id`/`view_id`\u3002\n- \u5b9e\u4f8b\u5728\u9996\u6b21\u540c\u6b65\u6210\u529f\u540e\u4f1a\u5c06\u6700\u7ec8\u914d\u7f6e\u5199\u5165 `metadata.json`\uff0c`resume` \u6216\u540e\u7eed `save_row(lark=True)` \u4f1a\u590d\u7528\u8fd9\u4efd\u914d\u7f6e\u3002\n\n### \u8c03\u5ea6\u5668\n- \u5728 `[scheduler]` \u6bb5\u843d\u8bbe\u7f6e\u5171\u4eab\u51ed\u636e\uff0c\u4f8b\u5982 `lark_config = { app_id = \"cli_xxx\", app_secret = \"xxx\" }`\uff0c\u907f\u514d\u6bcf\u4e2a\u5b9e\u9a8c\u91cd\u590d\u586b\u5199\u3002\n- \u6bcf\u4e2a `[[experiments]]` \u53ef\u901a\u8fc7 `lark_url` \u6216 `lark_config` \u8986\u76d6/\u8865\u5145\u8868\u683c\u4fe1\u606f\uff0c\u5b57\u6bb5\u4f1a\u8986\u76d6\u8c03\u5ea6\u5668\u7ea7\u522b\u7684\u540c\u540d\u9879\u3002\n- \u82e5\u67d0\u5b9e\u9a8c\u9700\u8981\u72ec\u7acb\u8d26\u53f7\uff0c\u53ea\u9700\u5728\u8be5\u5b9e\u9a8c\u7684 `lark_config` \u4e2d\u8865\u9f50\u5b8c\u6574\u51ed\u636e\u5373\u53ef\u3002\n\n### \u5408\u5e76\u903b\u8f91\u901f\u89c8\n- \u8c03\u5ea6\u6a21\u5f0f\u4e0b\uff1a`[scheduler].lark_config` < `[[experiments]].lark_config`/`lark_url`\u3002\n- \u5355\u70b9\u5b9e\u9a8c\uff1a\u6784\u9020\u51fd\u6570\u7684 `lark_config` \u4e0e\u5b9e\u4f8b\u5df2\u6709\u914d\u7f6e\uff08\u5982 `resume` \u8bfb\u53d6\u7684 `metadata.json`\uff09\u5408\u5e76\uff0c\u65b0\u4f20\u5165\u503c\u4f18\u5148\u3002\n- `exp.save_row(lark=True, lark_config=...)` \u4f1a\u5728\u5b9e\u4f8b\u9ed8\u8ba4\u914d\u7f6e\u4e4b\u4e0a\u518d\u6b21\u53e0\u52a0\u672c\u6b21\u8c03\u7528\u7684\u8986\u76d6\u503c\u3002\n\n## License\n\nThis repository is licensed under the [Apache-2.0 License](https://github.com/potatoQi/EXP/blob/main/LICENSE).\n\n## Star History\n\n![Star History Chart](https://api.star-history.com/svg?repos=potatoQi/EXP&type=Date)\n",
    "bugtrack_url": null,
    "license": "Apache-2.0",
    "summary": "\u5b9e\u9a8c\u7ba1\u7406\u6846\u67b6",
    "version": "0.0.2",
    "project_urls": {
        "Homepage": "https://github.com/potatoQi/EXP",
        "Issues": "https://github.com/potatoQi/EXP/issues",
        "Repository": "https://github.com/potatoQi/EXP"
    },
    "split_keywords": [
        "experiment",
        " scheduler",
        " machine-learning",
        " lark",
        " monitoring"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "9ebe86f1377d819a92a6b3057a5f8f17a0a4958164d7d9cc918e7a4eb76375a9",
                "md5": "635fd9d4c35a738b8627136de90e69bd",
                "sha256": "689fdb71eccaffc5dd93970f60cb12d3fa5a30db4cde0351a4a2ac522decb7e9"
            },
            "downloads": -1,
            "filename": "xpriment-0.0.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "635fd9d4c35a738b8627136de90e69bd",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 67279,
            "upload_time": "2025-10-07T20:28:06",
            "upload_time_iso_8601": "2025-10-07T20:28:06.997975Z",
            "url": "https://files.pythonhosted.org/packages/9e/be/86f1377d819a92a6b3057a5f8f17a0a4958164d7d9cc918e7a4eb76375a9/xpriment-0.0.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "40bbf47e5ec2e5873d867b0828765b9cd000d4caf676054d9f04cf0d0f28c5db",
                "md5": "91fae9d68d2692bec3e780649bb40f9d",
                "sha256": "d8fdddbaa29ecd763f3146208cd79bf12b55af25abad1fd28218b21b65ac5829"
            },
            "downloads": -1,
            "filename": "xpriment-0.0.2.tar.gz",
            "has_sig": false,
            "md5_digest": "91fae9d68d2692bec3e780649bb40f9d",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 71121,
            "upload_time": "2025-10-07T20:28:07",
            "upload_time_iso_8601": "2025-10-07T20:28:07.973585Z",
            "url": "https://files.pythonhosted.org/packages/40/bb/f47e5ec2e5873d867b0828765b9cd000d4caf676054d9f04cf0d0f28c5db/xpriment-0.0.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-07 20:28:07",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "potatoQi",
    "github_project": "EXP",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "xpriment"
}
        
Elapsed time: 1.44780s