From a380821e33d140448d400b7076fb46d995340dfa Mon Sep 17 00:00:00 2001 From: KAAANG <79990647+SAKURA-CAT@users.noreply.github.com> Date: Fri, 20 Sep 2024 14:39:00 +0800 Subject: [PATCH 01/12] Create namer.py --- swanlab/data/run/namer.py | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 swanlab/data/run/namer.py diff --git a/swanlab/data/run/namer.py b/swanlab/data/run/namer.py new file mode 100644 index 00000000..24534d4b --- /dev/null +++ b/swanlab/data/run/namer.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +r""" +@DATE: 2024/9/20 14:35 +@File: namer.py +@IDE: pycharm +@Description: + 命名器、取色器 +""" From 79be53929fe91f0d42b3300057962b9d8a8ef1bc Mon Sep 17 00:00:00 2001 From: KAAANG <79990647+SAKURA-CAT@users.noreply.github.com> Date: Fri, 20 Sep 2024 14:42:51 +0800 Subject: [PATCH 02/12] update:namer --- swanlab/data/run/namer.py | 19 +++++++++++++++++++ test/unit/data/run/test_namer.py | 9 +++++++++ 2 files changed, 28 insertions(+) create mode 100644 test/unit/data/run/test_namer.py diff --git a/swanlab/data/run/namer.py b/swanlab/data/run/namer.py index 24534d4b..71a80610 100644 --- a/swanlab/data/run/namer.py +++ b/swanlab/data/run/namer.py @@ -7,3 +7,22 @@ @Description: 命名器、取色器 """ +from typing import Tuple, Optional + + +def generate_name(index: Optional[int] = None) -> str: + """ + 生成名称 + :param index: 生成名称的索引,约定为历史实验数,可以为None + :return: 生成的名称 + """ + pass + + +def generate_color(index: Optional[int] = None) -> Tuple[str, str]: + """ + 生成颜色 + :param index: 生成颜色的索引,约定为历史实验数,可以为None + :return: 生成的颜色,(白天颜色,夜晚颜色) + """ + pass diff --git a/test/unit/data/run/test_namer.py b/test/unit/data/run/test_namer.py new file mode 100644 index 00000000..c03488c4 --- /dev/null +++ b/test/unit/data/run/test_namer.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +r""" +@DATE: 2024/9/20 14:42 +@File: test_namer.py +@IDE: pycharm +@Description: + 测试命名器、取色器 +""" From b4917ce78477796bc17c13cdcf7cf79dbf7a9f2c Mon Sep 17 00:00:00 2001 From: KAAANG <79990647+SAKURA-CAT@users.noreply.github.com> Date: Fri, 20 Sep 2024 14:46:03 +0800 Subject: [PATCH 03/12] update:test --- test/unit/data/run/test_namer.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/unit/data/run/test_namer.py b/test/unit/data/run/test_namer.py index c03488c4..f6b3ed3b 100644 --- a/test/unit/data/run/test_namer.py +++ b/test/unit/data/run/test_namer.py @@ -7,3 +7,20 @@ @Description: 测试命名器、取色器 """ +from swanlab.data.run import namer + + +def test_name_no_index(): + pass + + +def test_name_with_index(): + pass + + +def test_color_no_index(): + pass + + +def test_color_with_index(): + pass From a371fd59634f96a84e78d577f5226b435d9a507e Mon Sep 17 00:00:00 2001 From: KAAANG <79990647+SAKURA-CAT@users.noreply.github.com> Date: Fri, 20 Sep 2024 14:47:09 +0800 Subject: [PATCH 04/12] Update namer.py --- swanlab/data/run/namer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swanlab/data/run/namer.py b/swanlab/data/run/namer.py index 71a80610..5007f49e 100644 --- a/swanlab/data/run/namer.py +++ b/swanlab/data/run/namer.py @@ -19,7 +19,7 @@ def generate_name(index: Optional[int] = None) -> str: pass -def generate_color(index: Optional[int] = None) -> Tuple[str, str]: +def generate_colors(index: Optional[int] = None) -> Tuple[str, str]: """ 生成颜色 :param index: 生成颜色的索引,约定为历史实验数,可以为None From 26ff65f15343ab5a3817c28301b871e5b49aa222 Mon Sep 17 00:00:00 2001 From: KAAANG <79990647+SAKURA-CAT@users.noreply.github.com> Date: Fri, 20 Sep 2024 14:49:54 +0800 Subject: [PATCH 05/12] update:test-color --- test/unit/data/run/test_namer.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/unit/data/run/test_namer.py b/test/unit/data/run/test_namer.py index f6b3ed3b..88b92816 100644 --- a/test/unit/data/run/test_namer.py +++ b/test/unit/data/run/test_namer.py @@ -19,8 +19,16 @@ def test_name_with_index(): def test_color_no_index(): - pass + colors = namer.generate_colors() + assert len(colors) == 2 + assert isinstance(colors, tuple) def test_color_with_index(): - pass + colors = namer.generate_colors(4) + assert len(colors) == 2 + assert isinstance(colors, tuple) + # 极大数 + colors = namer.generate_colors(999999999) + assert len(colors) == 2 + assert isinstance(colors, tuple) From f6f2bc699898f390882049ff1ec7827d073444cd Mon Sep 17 00:00:00 2001 From: KAAANG <79990647+SAKURA-CAT@users.noreply.github.com> Date: Fri, 20 Sep 2024 14:54:19 +0800 Subject: [PATCH 06/12] Update test-when-pr.yml --- .github/workflows/test-when-pr.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/test-when-pr.yml b/.github/workflows/test-when-pr.yml index 4702fd81..0ccf2f06 100644 --- a/.github/workflows/test-when-pr.yml +++ b/.github/workflows/test-when-pr.yml @@ -5,8 +5,6 @@ on: paths: - swanlab/** - test/** - branches: - - main jobs: test: From 755126e09730014eeca936ba275734d12ddbaf8a Mon Sep 17 00:00:00 2001 From: KAAANG <79990647+SAKURA-CAT@users.noreply.github.com> Date: Fri, 20 Sep 2024 15:06:29 +0800 Subject: [PATCH 07/12] update:test-name --- test/unit/data/run/test_namer.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/unit/data/run/test_namer.py b/test/unit/data/run/test_namer.py index 88b92816..9818ccc9 100644 --- a/test/unit/data/run/test_namer.py +++ b/test/unit/data/run/test_namer.py @@ -11,11 +11,16 @@ def test_name_no_index(): - pass + name = namer.generate_name() + assert isinstance(name, str) def test_name_with_index(): - pass + name = namer.generate_name(4) + assert isinstance(name, str) + # 极大数 + name = namer.generate_name(999999999) + assert isinstance(name, str) def test_color_no_index(): From 8ade4e3bc84384ae2b256eb9657233cda165d9d0 Mon Sep 17 00:00:00 2001 From: ZeYi Lin <944270057@qq.com> Date: Fri, 20 Sep 2024 15:12:01 +0800 Subject: [PATCH 08/12] add generate name and colors --- swanlab/data/run/namer.py | 78 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/swanlab/data/run/namer.py b/swanlab/data/run/namer.py index 5007f49e..fa533aaf 100644 --- a/swanlab/data/run/namer.py +++ b/swanlab/data/run/namer.py @@ -8,7 +8,7 @@ 命名器、取色器 """ from typing import Tuple, Optional - +import random def generate_name(index: Optional[int] = None) -> str: """ @@ -16,7 +16,34 @@ def generate_name(index: Optional[int] = None) -> str: :param index: 生成名称的索引,约定为历史实验数,可以为None :return: 生成的名称 """ - pass + prefix_list = [ + "swan-", # 天鹅 + "rat-", # 鼠 + "ox-", # 牛 + "tiger-", # 虎 + "rabbit-", # 兔 + "dragon-", # 龙 + "snake-", # 蛇 + "horse-", # 马 + "goat-", # 羊 + "monkey-", # 猴 + "rooster-", # 鸡 + "dog-", # 狗 + "pig-" # 猪 + "cat-", # 猫 + "elephant-",# 象 + "penguin-", # 企鹅 + "kangaroo-",# 袋鼠 + "monkey-", # 猴 + "panda-", # 熊猫 + "tiger-", # 虎 + "lion-", # 狮 + "zebra-", # 斑马 + ] + + index = int(index) + prefix = prefix_list[index % len(prefix_list)] + return prefix + str(index+1) def generate_colors(index: Optional[int] = None) -> Tuple[str, str]: @@ -25,4 +52,49 @@ def generate_colors(index: Optional[int] = None) -> Tuple[str, str]: :param index: 生成颜色的索引,约定为历史实验数,可以为None :return: 生成的颜色,(白天颜色,夜晚颜色) """ - pass + light_colors = [ + "#528d59", # 绿色 + "#587ad2", # 蓝色 + "#c24d46", # 红色 + "#9cbe5d", # 青绿色 + "#6ebad3", # 天蓝色 + "#dfb142", # 橙色 + "#6d4ba4", # 紫色 + "#8cc5b7", # 淡青绿色 + "#892d58", # 紫红色 + "#40877c", # 深青绿色 + "#d0703c", # 深橙色 + "#d47694", # 粉红色 + "#e3b292", # 淡橙色 + "#b15fbb", # 浅紫红色 + "#905f4a", # 棕色 + "#989fa3", # 灰色 + ] + + # 黑夜模式的颜色暂时和light_colors保持一致 + dark_colors = [ + "#528d59", # 绿色 + "#587ad2", # 蓝色 + "#c24d46", # 红色 + "#9cbe5d", # 青绿色 + "#6ebad3", # 天蓝色 + "#dfb142", # 橙色 + "#6d4ba4", # 紫色 + "#8cc5b7", # 淡青绿色 + "#892d58", # 紫红色 + "#40877c", # 深青绿色 + "#d0703c", # 深橙色 + "#d47694", # 粉红色 + "#e3b292", # 淡橙色 + "#b15fbb", # 浅紫红色 + "#905f4a", # 棕色 + "#989fa3", # 灰色 + ] + + if index is None: + choice_color = random.choice(light_colors) + return choice_color, choice_color # 随机返回一个颜色,夜晚颜色暂时固定为黑色 + else: + choice_color_light = light_colors[index % len(light_colors)] + choice_color_dark = dark_colors[index % len(dark_colors)] + return choice_color_light, choice_color_dark # 返回对应索引的颜色,如果超出范围则取模 From b90f3c4ad39fbe373f2d4ddca92968779353c15c Mon Sep 17 00:00:00 2001 From: ZeYi Lin <944270057@qq.com> Date: Fri, 20 Sep 2024 15:21:21 +0800 Subject: [PATCH 09/12] fix: index is None --- swanlab/data/run/namer.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/swanlab/data/run/namer.py b/swanlab/data/run/namer.py index fa533aaf..9972f38f 100644 --- a/swanlab/data/run/namer.py +++ b/swanlab/data/run/namer.py @@ -41,9 +41,12 @@ def generate_name(index: Optional[int] = None) -> str: "zebra-", # 斑马 ] - index = int(index) - prefix = prefix_list[index % len(prefix_list)] - return prefix + str(index+1) + if index is None: + prefix = random.choice(prefix_list) + return prefix + else: + prefix = prefix_list[index % len(prefix_list)] + return prefix + str(index+1) def generate_colors(index: Optional[int] = None) -> Tuple[str, str]: From 371adad0169ad70d080a7e71eab49226652aa1e0 Mon Sep 17 00:00:00 2001 From: KAAANG <79990647+SAKURA-CAT@users.noreply.github.com> Date: Fri, 20 Sep 2024 15:26:56 +0800 Subject: [PATCH 10/12] update:namer --- swanlab/data/run/namer.py | 136 ++++++++++++++++++++------------------ 1 file changed, 70 insertions(+), 66 deletions(-) diff --git a/swanlab/data/run/namer.py b/swanlab/data/run/namer.py index 9972f38f..f1e4f7e5 100644 --- a/swanlab/data/run/namer.py +++ b/swanlab/data/run/namer.py @@ -10,43 +10,85 @@ from typing import Tuple, Optional import random +prefix_list = [ + "swan-", # 天鹅 + "rat-", # 鼠 + "ox-", # 牛 + "tiger-", # 虎 + "rabbit-", # 兔 + "dragon-", # 龙 + "snake-", # 蛇 + "horse-", # 马 + "goat-", # 羊 + "monkey-", # 猴 + "rooster-", # 鸡 + "dog-", # 狗 + "pig-" # 猪 + "cat-", # 猫 + "elephant-", # 象 + "penguin-", # 企鹅 + "kangaroo-", # 袋鼠 + "monkey-", # 猴 + "panda-", # 熊猫 + "tiger-", # 虎 + "lion-", # 狮 + "zebra-", # 斑马 +] + + def generate_name(index: Optional[int] = None) -> str: """ 生成名称 :param index: 生成名称的索引,约定为历史实验数,可以为None :return: 生成的名称 """ - prefix_list = [ - "swan-", # 天鹅 - "rat-", # 鼠 - "ox-", # 牛 - "tiger-", # 虎 - "rabbit-", # 兔 - "dragon-", # 龙 - "snake-", # 蛇 - "horse-", # 马 - "goat-", # 羊 - "monkey-", # 猴 - "rooster-", # 鸡 - "dog-", # 狗 - "pig-" # 猪 - "cat-", # 猫 - "elephant-",# 象 - "penguin-", # 企鹅 - "kangaroo-",# 袋鼠 - "monkey-", # 猴 - "panda-", # 熊猫 - "tiger-", # 虎 - "lion-", # 狮 - "zebra-", # 斑马 - ] - + if index is None: prefix = random.choice(prefix_list) return prefix else: prefix = prefix_list[index % len(prefix_list)] - return prefix + str(index+1) + return prefix + str(index + 1) + + +light_colors = [ + "#528d59", # 绿色 + "#587ad2", # 蓝色 + "#c24d46", # 红色 + "#9cbe5d", # 青绿色 + "#6ebad3", # 天蓝色 + "#dfb142", # 橙色 + "#6d4ba4", # 紫色 + "#8cc5b7", # 淡青绿色 + "#892d58", # 紫红色 + "#40877c", # 深青绿色 + "#d0703c", # 深橙色 + "#d47694", # 粉红色 + "#e3b292", # 淡橙色 + "#b15fbb", # 浅紫红色 + "#905f4a", # 棕色 + "#989fa3", # 灰色 +] + +# 黑夜模式的颜色暂时和light_colors保持一致 +dark_colors = [ + "#528d59", # 绿色 + "#587ad2", # 蓝色 + "#c24d46", # 红色 + "#9cbe5d", # 青绿色 + "#6ebad3", # 天蓝色 + "#dfb142", # 橙色 + "#6d4ba4", # 紫色 + "#8cc5b7", # 淡青绿色 + "#892d58", # 紫红色 + "#40877c", # 深青绿色 + "#d0703c", # 深橙色 + "#d47694", # 粉红色 + "#e3b292", # 淡橙色 + "#b15fbb", # 浅紫红色 + "#905f4a", # 棕色 + "#989fa3", # 灰色 +] def generate_colors(index: Optional[int] = None) -> Tuple[str, str]: @@ -55,48 +97,10 @@ def generate_colors(index: Optional[int] = None) -> Tuple[str, str]: :param index: 生成颜色的索引,约定为历史实验数,可以为None :return: 生成的颜色,(白天颜色,夜晚颜色) """ - light_colors = [ - "#528d59", # 绿色 - "#587ad2", # 蓝色 - "#c24d46", # 红色 - "#9cbe5d", # 青绿色 - "#6ebad3", # 天蓝色 - "#dfb142", # 橙色 - "#6d4ba4", # 紫色 - "#8cc5b7", # 淡青绿色 - "#892d58", # 紫红色 - "#40877c", # 深青绿色 - "#d0703c", # 深橙色 - "#d47694", # 粉红色 - "#e3b292", # 淡橙色 - "#b15fbb", # 浅紫红色 - "#905f4a", # 棕色 - "#989fa3", # 灰色 - ] - - # 黑夜模式的颜色暂时和light_colors保持一致 - dark_colors = [ - "#528d59", # 绿色 - "#587ad2", # 蓝色 - "#c24d46", # 红色 - "#9cbe5d", # 青绿色 - "#6ebad3", # 天蓝色 - "#dfb142", # 橙色 - "#6d4ba4", # 紫色 - "#8cc5b7", # 淡青绿色 - "#892d58", # 紫红色 - "#40877c", # 深青绿色 - "#d0703c", # 深橙色 - "#d47694", # 粉红色 - "#e3b292", # 淡橙色 - "#b15fbb", # 浅紫红色 - "#905f4a", # 棕色 - "#989fa3", # 灰色 - ] - + if index is None: choice_color = random.choice(light_colors) - return choice_color, choice_color # 随机返回一个颜色,夜晚颜色暂时固定为黑色 + return choice_color, choice_color # 随机返回一个颜色 else: choice_color_light = light_colors[index % len(light_colors)] choice_color_dark = dark_colors[index % len(dark_colors)] From 8359915e6307ee9680f37e088870f723d579fb94 Mon Sep 17 00:00:00 2001 From: KAAANG <79990647+SAKURA-CAT@users.noreply.github.com> Date: Fri, 20 Sep 2024 15:29:22 +0800 Subject: [PATCH 11/12] Update namer.py --- swanlab/data/run/namer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/swanlab/data/run/namer.py b/swanlab/data/run/namer.py index f1e4f7e5..c4cde6ec 100644 --- a/swanlab/data/run/namer.py +++ b/swanlab/data/run/namer.py @@ -42,7 +42,6 @@ def generate_name(index: Optional[int] = None) -> str: :param index: 生成名称的索引,约定为历史实验数,可以为None :return: 生成的名称 """ - if index is None: prefix = random.choice(prefix_list) return prefix From 076db81a6c3518f5af2f9af08f98d6c29fd4f04a Mon Sep 17 00:00:00 2001 From: KAAANG <79990647+SAKURA-CAT@users.noreply.github.com> Date: Fri, 20 Sep 2024 16:52:37 +0800 Subject: [PATCH 12/12] update:exp-name --- requirements.txt | 4 +- swanlab/data/formater.py | 30 +++++++++++++- swanlab/data/run/helper.py | 9 ++--- swanlab/data/run/main.py | 52 ++++++++++++------------- swanlab/data/sdk.py | 14 +------ test/unit/data/test_fomater.py | 71 ++++++++++++++++++++++++++++------ 6 files changed, 120 insertions(+), 60 deletions(-) diff --git a/requirements.txt b/requirements.txt index 0dfbb453..f2741c7e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ -swankit==0.1.1b1 -swanboard==0.1.3b5 +swankit==0.1.1b3 +swanboard==0.1.4b1 cos-python-sdk-v5 urllib3>=1.26.0 requests>=2.25.0 diff --git a/swanlab/data/formater.py b/swanlab/data/formater.py index a9304a14..7dca5aa6 100644 --- a/swanlab/data/formater.py +++ b/swanlab/data/formater.py @@ -89,8 +89,8 @@ def _auto_cut(name: str, value: str, max_len: int, cut: bool) -> str: def check_proj_name_format(name: str, auto_cut: bool = True) -> str: """ - 检查项目名格式,必须是0-9a-zA-Z以及连字符(_-.+) - 最大长度为100个字符 + 检查实验名称格式,最大长度为95个字符,一个中文字符算一个字符 + 其他不做限制,实验名称可以包含任何字符 Parameters ---------- @@ -121,6 +121,32 @@ def check_proj_name_format(name: str, auto_cut: bool = True) -> str: return _auto_cut("project", name, max_len, auto_cut) +def check_exp_name_format(name: str, auto_cut: bool = True) -> str: + """ + 检查实验名称格式,最大长度为95个字符,一个中文字符算一个字符 + 其他不做限制,实验名称可以包含任何字符 + :param name: 实验名称 + :param auto_cut: 是否自动截断,默认为True + :return: str 检查后的字符串 + """ + max_len = 95 + if not check_string(name): + raise ValueError("Experiment name is an empty string") + name = name.strip() + return _auto_cut("experiment", name, max_len, auto_cut) + + +def check_desc_format(desc: str, auto_cut: bool = True) -> str: + """ + 检查描述格式,最大长度为255个字符,一个中文字符算一个字符 + :param desc: 描述信息 + :param auto_cut: 是否自动截断,默认为True + :return: str 检查后的字符串 + """ + max_len = 255 + return _auto_cut("description", desc, max_len, auto_cut) + + def check_key_format(key: str, auto_cut=True) -> str: """检查key字符串格式 不能超过255个字符,可以包含任何字符,不允许.和/以及空格开头 diff --git a/swanlab/data/run/helper.py b/swanlab/data/run/helper.py index 0f3273119..b6872f57 100644 --- a/swanlab/data/run/helper.py +++ b/swanlab/data/run/helper.py @@ -7,7 +7,7 @@ @Description: 回调函数操作员,批量处理回调函数的调用 """ -from typing import List, Union, Dict, Any, Callable +from typing import List, Union, Dict, Any, Tuple from swankit.callback import SwanKitCallback, MetricInfo, ColumnInfo, OperateErrorInfo, RuntimeInfo from swankit.core import SwanLabSharedSettings import swanlab.error as E @@ -56,7 +56,7 @@ def __run_all(self, method: str, *args, **kwargs): @classmethod def parse_return(cls, ret: OperatorReturnType, key: str = None): """ - 解析返回值,选择不为None的返回值 + 解析返回值,选择不为None的返回值,如果都为None,则返回None 如果key不为None,则返回对应key的返回值 :param ret: 返回值 :param key: 返回值的key @@ -78,10 +78,9 @@ def before_init_experiment( exp_name: str, description: str, num: int, - suffix: str, - setter: Callable[[str, str, str, str], None], + colors: Tuple[str, str], ): - return self.__run_all("before_init_experiment", run_id, exp_name, description, num, suffix, setter) + return self.__run_all("before_init_experiment", run_id, exp_name, description, num, colors) def on_run(self): try: diff --git a/swanlab/data/run/main.py b/swanlab/data/run/main.py index 5f579229..a14a1bba 100644 --- a/swanlab/data/run/main.py +++ b/swanlab/data/run/main.py @@ -18,8 +18,9 @@ from datetime import datetime from typing import Callable, Optional, Dict from .helper import SwanLabRunOperator, RuntimeInfo -from ..formater import check_key_format +from ..formater import check_key_format, check_exp_name_format, check_desc_format from swanlab.env import get_mode, get_swanlog_dir +from . import namer as N import random @@ -50,7 +51,6 @@ def __init__( description: str = None, run_config=None, log_level: str = None, - suffix: str = None, exp_num: int = None, operator: SwanLabRunOperator = SwanLabRunOperator(), ): @@ -74,9 +74,6 @@ def __init__( 当前实验的日志等级,默认为 'info',可以从 'debug' 、'info'、'warning'、'error'、'critical' 中选择 不区分大小写,如果不提供此参数(为None),则默认为 'info' 如果提供的日志等级不在上述范围内,默认改为info - suffix : str, optional - 实验名称后缀,用于区分同名实验,格式为yyyy-mm-dd_HH-MM-SS - 如果不提供此参数(为None),不会添加后缀 exp_num : int, optional 历史实验总数,用于云端颜色与本地颜色的对应 operator : SwanLabRunOperator, optional @@ -106,14 +103,15 @@ def __init__( # 如果config是以下几个类别之一,则抛出异常 if isinstance(run_config, (int, float, str, bool, list, tuple, set)): raise TypeError( - f"config: {run_config} (type: {type(run_config)}) is not a json serialized dict (Surpport type is dict, MutableMapping, omegaconf.DictConfig, Argparse.Namespace), please check it" + f"config: {run_config} (type: {type(run_config)}) is not a json serialized dict " + f"(Support type is dict, MutableMapping, omegaconf.DictConfig, Argparse.Namespace), please check it" ) global config config.update(run_config) setattr(config, "_SwanLabConfig__on_setter", self.__operator.on_runtime_info_update) self.__config = config # ---------------------------------- 注册实验 ---------------------------------- - self.__exp: SwanLabExp = self.__register_exp(experiment_name, description, suffix, num=exp_num) + self.__exp: SwanLabExp = self.__register_exp(experiment_name, description, num=exp_num) # 实验状态标记,如果status不为0,则无法再次调用log方法 self.__state = SwanLabRunState.RUNNING @@ -132,7 +130,8 @@ def _(state: SwanLabRunState): # 系统信息采集 self.__operator.on_runtime_info_update( RuntimeInfo( - requirements=get_requirements(), metadata=get_system_info(get_package_version(), self.settings.log_dir) + requirements=get_requirements(), + metadata=get_system_info(get_package_version(), self.settings.log_dir), ) ) @@ -335,31 +334,30 @@ def __str__(self) -> str: def __register_exp( self, - experiment_name: str, + experiment_name: str = None, description: str = None, - suffix: str = None, num: int = None, ) -> SwanLabExp: """ 注册实验,将实验配置写入数据库中,完成实验配置的初始化 """ - - def setter(exp_name: str, light_color: str, dark_color: str, desc: str): - """ - 设置实验相关信息的函数 - :param exp_name: 实验名称 - :param light_color: 亮色 - :param dark_color: 暗色 - :param desc: 实验描述 - :return: - """ - # 实验创建成功,设置实验相关信息 - self.settings.exp_name = exp_name - self.settings.exp_colors = (light_color, dark_color) - self.settings.description = desc - - self.__operator.before_init_experiment(self.__run_id, experiment_name, description, num, suffix, setter) - + if experiment_name: + e = check_exp_name_format(experiment_name) + if experiment_name != e: + swanlog.warning("The experiment name has been truncated automatically.") + experiment_name = e + if description: + d = check_desc_format(description) + if description != d: + swanlog.warning("The description has been truncated automatically.") + description = d + experiment_name = N.generate_name(num) if experiment_name is None else experiment_name + description = "" if description is None else description + colors = N.generate_colors(num) + self.__operator.before_init_experiment(self.__run_id, experiment_name, description, num, colors) + self.settings.exp_name = experiment_name + self.settings.exp_colors = colors + self.settings.description = description return SwanLabExp(self.settings, operator=self.__operator) @staticmethod diff --git a/swanlab/data/sdk.py b/swanlab/data/sdk.py index f2d893fd..a993264f 100644 --- a/swanlab/data/sdk.py +++ b/swanlab/data/sdk.py @@ -76,7 +76,6 @@ def init( description: str = None, config: Union[dict, str] = None, logdir: str = None, - suffix: Union[str, None, bool] = "default", mode: Literal["disabled", "cloud", "local"] = None, load: str = None, public: bool = None, @@ -119,14 +118,6 @@ def init( anything other than data generated by Swanlab. In this case, if you want to view the logs, you must use something like `swanlab watch -l ./your_specified_folder` to specify the folder path. - suffix : str, optional - The suffix of the experiment name, the default is 'default'. - If this parameter is 'default', suffix will be '%b%d-%h-%m-%s'(example:'Feb03_14-45-37'), - which represents the current time. - example: experiment_name = 'example', suffix = 'default' -> 'example_Feb03_14-45-37'; - If this parameter is None or False, no suffix will be added. - If this parameter is a string, the suffix will be the string you provided. - Attention: experiment_name + suffix must be unique, otherwise the experiment will not be created. mode : str, optional Allowed values are 'cloud', 'cloud-only', 'local', 'disabled'. If the value is 'cloud', the data will be uploaded to the cloud and the local log will be saved. @@ -155,7 +146,6 @@ def init( description = _load_data(load_data, "description", description) config = _load_data(load_data, "config", config) logdir = _load_data(load_data, "logdir", logdir) - suffix = _load_data(load_data, "suffix", suffix) mode = _load_data(load_data, "mode", mode) project = _load_data(load_data, "project", project) workspace = _load_data(load_data, "workspace", workspace) @@ -163,7 +153,8 @@ def init( operator, c = _create_operator(mode, public) project = _check_proj_name(project if project else os.path.basename(os.getcwd())) # 默认实验名称为当前目录名 exp_num = SwanLabRunOperator.parse_return( - operator.on_init(project, workspace, logdir=logdir), key=c.__str__() if c else None + operator.on_init(project, workspace, logdir=logdir), + key=c.__str__() if c else None, ) # 初始化confi参数 config = _init_config(config) @@ -175,7 +166,6 @@ def init( description=description, run_config=config, log_level=kwargs.get("log_level", "info"), - suffix=suffix, exp_num=exp_num, operator=operator, ) diff --git a/test/unit/data/test_fomater.py b/test/unit/data/test_fomater.py index e8b1e436..6e6c716d 100644 --- a/test/unit/data/test_fomater.py +++ b/test/unit/data/test_fomater.py @@ -15,6 +15,7 @@ check_proj_name_format, _auto_cut, check_key_format, + check_exp_name_format, ) @@ -53,18 +54,7 @@ def test_no_cut(self, name: str, value: str): class TestProjName: @pytest.mark.parametrize( "value", - [ - generate(size=100), - generate(size=1), - "-", - "_", - ".12", - "1", - "1.b", - "a.b", - "+", - "1+1" - ], + [generate(size=100), generate(size=1), "-", "_", ".12", "1", "1.b", "a.b", "+", "1+1"], ) def test_proj_name_common(self, value): """ @@ -118,6 +108,63 @@ def test_proj_name_no_cut(self, value: str): check_proj_name_format(value, auto_cut=False) +class TestExpName: + @pytest.mark.parametrize( + "value", + [generate(size=95), generate(size=1), "-", "_", ".12", "1", "1.b", "a.b", "+", "1+1", "你好"], + ) + def test_exp_name_common(self, value): + """ + 测试正常情况 + """ + assert check_exp_name_format(value) == value + + @pytest.mark.parametrize("value", [None, 1, [], {}]) + def test_exp_name_type_error(self, value: str): + """ + 测试类型错误 + """ + with pytest.raises(TypeError): + check_exp_name_format(value) + + @pytest.mark.parametrize("value", ["", " "]) + def test_exp_name_value_error(self, value: str): + """ + 测试空值 + """ + with pytest.raises(ValueError): + check_exp_name_format(value) + + @pytest.mark.parametrize( + "value", + [ + generate(size=101), + generate(size=1000), + generate(size=10000), + ], + ) + def test_exp_name_auto_cut(self, value: str): + """ + 测试自动截断 + """ + assert len(check_exp_name_format(value)) == 95 + + @pytest.mark.parametrize( + "value", + [ + generate(size=96), + generate(size=1000), + generate(size=10000), + ], + ) + def test_exp_name_no_cut(self, value: str): + """ + 测试不自动截断 + """ + with pytest.raises(IndexError): + check_exp_name_format(value, auto_cut=False) + + class TestTag: @pytest.mark.parametrize(