批量生成语法
Pyruns 支持在 YAML 配置值中使用管道语法声明多值参数,自动生成所有参数组合的任务。
语法总览
| 语法 | 名称 | 效果 | 示例 |
|---|---|---|---|
a | b | c | Product(笛卡尔积) | 与其他 Product 参数全排列组合 | 3 值 × 2 值 = 6 组合 |
(a | b | c) | Zip(配对组合) | 按位置一一对应,所有 Zip 长度须一致 | 3 值 → 3 组合 |
两种语法可混合使用,总任务数 = Product 各参数值数量之积 × Zip 长度。
Product — 笛卡尔积
使用 | 分隔多个值:
lr: 0.001 | 0.01 | 0.1
batch_size: 32 | 64效果:生成所有可能的组合(笛卡尔积)。
lr=0.001, batch_size=32
lr=0.001, batch_size=64
lr=0.01, batch_size=32
lr=0.01, batch_size=64
lr=0.1, batch_size=32
lr=0.1, batch_size=64总数:3 × 2 = 6 个任务
Zip — 配对组合
使用括号 (|) 包裹管道符及其元素:
seed: (1 | 2 | 3)
name: (alpha | beta | gamma)效果:按位置配对组合(行为类似 Python 内置的 zip() 函数)。
seed=1, name=alpha
seed=2, name=beta
seed=3, name=gamma总数:3 个任务
约束:所有应用 Zip 语法声明的参数所包含的元素数量必须绝对一致。
混合使用
Product 和 Zip 原则可以共同混用组合:
# Product 参数
lr: 0.001 | 0.01 | 0.1
batch_size: 32 | 64
# Zip 参数
seed: (1 | 2 | 3)
name: (alpha | beta | gamma)
# 固定参数
epochs: 100
model: resnet50总数:Product 组合数 × Zip 组合数 = (3 × 2) × 3 = 18 个任务
公式:$\text{Total} = \prod(\text{product counts}) \times \text{zip length}$
完整示例
输入配置
# 超参搜索实验
training:
lr: 0.001 | 0.01
optimizer: adam | sgd
model:
hidden_size: 128 | 256
# 控制变量 — 每组实验固定种子
seed: (42 | 123 | 777)
run_name: (trial_a | trial_b | trial_c)
# 其余参数固定
epochs: 50
dataset: cifar10生成的任务列表
| # | lr | optimizer | hidden_size | seed | run_name |
|---|---|---|---|---|---|
| 1 | 0.001 | adam | 128 | 42 | trial_a |
| 2 | 0.001 | adam | 128 | 123 | trial_b |
| 3 | 0.001 | adam | 128 | 777 | trial_c |
| 4 | 0.001 | adam | 256 | 42 | trial_a |
| ... | ... | ... | ... | ... | ... |
| 24 | 0.01 | sgd | 256 | 777 | trial_c |
总数:(2 × 2 × 2) × 3 = 24 个任务
生成后的持久化目录
_pyruns_/
├── my-exp-[1-of-24]/
│ ├── task_info.json
│ ├── config.yaml ← lr=0.001, optimizer=adam, hidden_size=128, seed=42
│ └── run_logs/
│ └── run1.log
├── my-exp-[2-of-24]/
│ ├── config.yaml ← lr=0.001, optimizer=adam, hidden_size=128, seed=123
│ └── ...
└── my-exp-[24-of-24]/
└── ...类型推断规则
管道语法中的各类数据节点会自动依据 Python SafeLoader 协议尝试推断类型:
| 输入示例 | 目标推断类型 |
|---|---|
0.001 | float |
42 | int |
true | bool |
adam | str |
[1, 2] | list |
None | NoneType |
嵌套参数支持
管道语法同样实用于多维且深层嵌套字典叶子节点:
model:
architecture: resnet | vgg | densenet
layers:
hidden: 128 | 256
output: 10生成阶段后台函数 flatten_dict() 展开其为一维空间以便交叉:
model.architecture: resnet | vgg | densenet → product, 3 values
model.layers.hidden: 128 | 256 → product, 2 values
model.layers.output: 10 → fixed总任务数:3 × 2 = 6
确认对话框
当检测到管道语法时(任务数 > 1),点击 GENERATE 会弹出确认对话框:
┌─────────────────────────────────────────┐
│ 🔮 批量生成确认 [24] │
├─────────────────────────────────────────┤
│ 任务前缀: my-exp │
│ my-exp-[1-of-24] ~ my-exp-[24-of-24] │
│ │
│ 🔀 Product 参数 (笛卡尔积) 2×2×2 = 8 │
│ ├─ lr: 0.001 | 0.01 │
│ ├─ optimizer: adam | sgd │
│ └─ hidden_size: 128 | 256 │
│ │
│ 🔗 Zip 参数 (配对组合) ×3 │
│ ├─ seed: 42 | 123 | 777 │
│ └─ run_name: trial_a | trial_b | ... │
│ │
│ 📊 Total = 2 × 2 × 2 × 3 = 24 │
├─────────────────────────────────────────┤
│ [取消] [确认生成 24] │
└─────────────────────────────────────────┘_meta_desc 字段
每个生成的配置会自动附加一个 _meta_desc 字段,记录该任务与其他任务不同的参数值:
# config.yaml
lr: 0.001
optimizer: adam
hidden_size: 128
seed: 42
run_name: trial_a
_meta_desc: "lr=0.001, optimizer=adam, hidden_size=128, seed=42, run_name=trial_a"此字段以 _meta 开头,在保存到 config.yaml 时会被自动过滤。
错误处理
Zip 长度不匹配
seed: (1 | 2 | 3)
name: (alpha | beta) # ← 只有 2 个值!错误:ValueError: All (zip) parameters must have equal length. Got: seed=3, name=2
无管道语法
如果配置中没有任何 | 语法,点击 GENERATE 将直接生成 1 个任务,无需确认。
相关 API
| 函数 | 模块 | 用途 |
|---|---|---|
generate_batch_configs() | utils.config_utils | 生成所有参数组合 |
count_batch_configs() | utils.config_utils | 预览任务数量 |
strip_batch_pipes() | utils.config_utils | 去除管道语法(取首个值) |
_parse_pipe_value() | utils.config_utils | 解析单个值的管道语法 |
flatten_dict() | utils.config_utils | 展平嵌套字典 |
unflatten_dict() | utils.config_utils | 还原嵌套字典 |