mcpField
E
exploratory-autoresearch

exploratory-autoresearch

github.com/gaasher数据与数据库17841 次安装17 周前更新
代码仓库

关于 exploratory-autoresearch

exploratory-autoresearch 是用于开放式 ML 实验的技能,先安排广泛探索,再进行针对性优化。它结合逐轮诊断分析、方法登记表和防止连续微调停滞的机制。

主要功能

  1. 01按温度调度实验方向
  2. 02支持突变、合并与优化
  3. 03停滞保护机制强制转向
  4. 04逐轮执行诊断分析
  5. 05维护方法登记表与实验记录

适用场景

  1. 01先探索不同 ML 模型系列再优化
  2. 02组合登记表中的互补方法
  3. 03小幅改进停滞时转向新方向

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/gaasher/agent-loop-skills --skill exploratory-autoresearch

安装后在 Claude Code 中输入/exploratory-autoresearch确认已加载。

附带文件examples/run.example.yaml

详细介绍

探索式自动研究循环

这个循环运行强度很高。和标准的 ml-autoresearch 一样,每次实验后都会进行诊断分析。不同之处在于,每次迭代的变更类型由温度调度器决定,而非 Agent 凭直觉选择:它会在早期强制进行大幅、多样的尝试(全面重写、根本不同的架构和训练方案),随后进入自适应阶段,从尝试(全新、大胆的方法)、合并(组合两种已登记的方法)或利用(对当前最佳方案进行有针对性的微调)中做出选择。停滞保护机制会在连续运行 <stagnation_limit> 次后禁止利用,强制转回尝试或合并,避免循环陷入爬坡式优化。反馈信号是从运行日志中读取的 <metric>;approaches.md 登记表和每次迭代的 move_type 是调度器得以运行的关键。

你是研究人员。循环开始后,不要暂停并请求许可。

适用场景

适用于开放式 ML 研究任务:你希望在细化之前强制拓宽探索范围——调度器会保证先采样多个不同类别,再逐渐收敛;停滞保护机制则能防止无休止的小幅改动。默认将 <swing_budget> = 3、<stagnation_limit> = 3;若要扩大初始探索范围,可调高 <swing_budget>。不适用于优先分析的标准 ml-autoresearch(如果你希望完全由分析驱动每次变更,而不使用强制尝试调度器,请使用该方案);也不适用于单次训练、固定参数扫描,或没有可测量标量指标的任务。

设置

以交互方式确定绑定值。 如果工作目录中存在 loop.run.yaml,则加载该文件,用一行确认各项值,然后直接进入循环。否则:在 Claude Code 中(可使用 AskUserQuestion 工具——记录 <host> = claude-code),根据项目推断每项绑定值的可能取值,并将其作为推荐选项展示;在其他主机上(<host> = other),则逐项以带引号的纯文本提示提问。然后编写 loop.run.yaml(格式:examples/run.example.yaml),并且在创建任何其他文件之前,先向用户确认每一项值。 对于 branches 策略,执行 git checkout -b autoresearch/<run_tag>(标签取自今天的日期;分支必须不存在)。对于 time 门控,在 <sandbox_root>/run_with_timeout.sh 中写入 timeout $(( <budget> * 60 )) <entrypoint> "$@" 并将其用作运行命令;在 2 × <budget> 分钟时强制终止。对于 epochs,则在某个 <editable_files> 文件中调整 epoch 上限。

绑定含义默认值推断方式
<metric> / <metric_direction>要优化的标量 + minimize/maximize—扫描可编辑文件和 README,查找指标名称
<run_cmd> / <entrypoint>端到端运行一次实验的命令—pyproject.toml / .venv / README
<editable_files>可编辑的文件(绝不可编辑评估工具链)—模型 / 配置 / 训练脚本;排除数据、日志、环境、工具链
<sandbox_root>存放快照和记录表的位置./sandbox位于可编辑文件所在目录旁
<iter_strategy>snapshots 或 branchessnapshots当前工作目录是否为干净的 git 仓库?
<gate> / <budget>time(分钟)或 epochs,以及限制值—配置中现有的时间 / epoch 设置
<swing_budget>进入自适应模式前强制进行大胆尝试的次数3(3–5)值越大,初始探索范围越广
<stagnation_limit>强制转向前允许连续利用的最大次数3—

文件编辑防护:在任何时候(设置或循环期间)触碰任何文件之前,都要确认该文件属于 <editable_files>,因为其他所有内容都是只读的基准事实(评估工具链定义了 <metric>)。无一例外。

初始化沙盒

创建目录结构并写入账本表头:

<sandbox_root>/
├── loop.run.yaml      ← resolved bindings (written now)
├── results.tsv        ← experiment ledger, header only (written now)
├── approaches.md      ← registry of every distinct approach (header only, written now)
└── iter1/             ← created at loop start

results.tsv 表头(制表符分隔;move_type ∈ {swing, merge, exploit}):

iter	<metric>	status	move_type	analysis_summary	description

approaches.md 表头:# Approach Registry,再加一行说明,指出合并步骤会查阅该文件以寻找可组合的互补方法。

循环(无限循环——直到中断)

第 1 次迭代始终是未修改的基线(不计为一次 swing):跳过动作选择和变更规划,但仍须执行强制分析——它是第 2 次迭代所依据的首个实证锚点。<editable_files> 中的所有内容都可以修改(架构、优化器、超参数、数据管道、损失函数、初始化、评估);尤其在 swing 中,鼓励彻底重写。唯一限制是代码能够运行并在 <budget> 内完成。训练轮次效率也是目标的一部分——用更少的有效步数达到相同分数,也是真正的胜利。简单性标准:其他条件相同,越简单越好——增加 20 行杂乱代码只提升 0.001,不值得;通过删除代码获得 0.001 的提升(或指标持平),则应 keep。

调度器会在迭代期间将两个计数器保存在内存中:swings_taken(swing 迭代总数,不包括基线)和 consecutive_exploit(自上次 swing/merge 以来的 exploit 次数;任何 swing 或 merge 都会将其重置为 0)。

每次迭代复制此检查清单,并逐项勾选:

  • 1. 查看状态。 branches:git log --oneline -5。snapshots:确认 iter<N>/ 不存在。阅读第 N-1 次迭代的分析摘要和这两个计数器。
  • 2. 选择 move_type(第 1 次迭代:跳过——基线)。按下方调度器规则执行,然后在修改任何文件前记录动作。
  • 3. 提出假设(第 1 次迭代:跳过)。说明动作及其理由(引用规则或分析)、计划做什么,以及会涉及哪些 <editable_files>。参见三种动作。
  • 4. 创建快照/提交,然后应用变更。 snapshots:创建 iter<N>/{code_snapshot,analysis,results}/,将每个 <editable_files> 复制到 code_snapshot/,将 loop.run.yaml 复制到 iter<N>/,然后应用变更。branches:应用变更,然后执行 git commit -am "<move_type>: <desc>"。
  • 5. 运行实验,将所有内容重定向到文件(绝不使用 tee):<entrypoint> > <sandbox_root>/iter<N>/<run_log> 2>&1(受时间限制时使用 run_with_timeout.sh)。如果超时,终止进程并按崩溃处理。
  • 6. 读取指标:grep '^<metric>:' <sandbox_root>/iter<N>/<run_log>。如果结果为空,执行 tail -n 50 <run_log>,阅读回溯信息,并尝试一次简单修复(拼写错误/导入错误);如果问题根本无法修复,则记录为 crash 并继续。
  • 7. 分析结果——必做,且须生成实际的产物文件。参见分析。
  • 8. 更新 approaches.md(仅 swing 和 merge 动作)。参见登记表。
  • 9. 记录到 results.tsv(不跟踪——绝不提交)。参见账本。
  • 10. 保留或回退(变更已在本次迭代中运行)。若按 <metric_direction> 判断有所改善 → keep,并更新当前最佳结果。相同/更差/崩溃 → discard/crash;branches 执行 git reset --hard HEAD~1,snapshots 从 iter<N>/code_snapshot/ 恢复 <editable_files>。记录 discard 前先应用简单性标准。若发生崩溃/OOM,用最小变更修复,同时保留原意(OOM → 减小 batch 并使用 grad-accum,以保持有效 batch 大小)——绝不改变实验。
  • 11. 更新计数器(见下文),然后返回第 1 步。
调度器(步骤 2 — 这是循环的核心规则)

请严格按顺序遵循这些规则——它们是硬性约束,不是建议:

IF   iter == 1                                  → baseline   (run unmodified; no move)
ELIF swings_taken < <swing_budget>              → swing      (forced exploration)
ELIF consecutive_exploit >= <stagnation_limit>  → swing OR merge  (forced pivot — exploit BANNED)
ELSE                                            → agent chooses: swing / merge / exploit

在空闲的 ELSE 分支中,让第 N-1 次迭代的分析结果决定:

  • swing:如果当前方案族存在根本性上限——例如,所有排名靠前的结果都有相同的失败模式。
  • merge:如果 approaches.md 中有两个或更多条目具备各自独特且互不重叠的优势(优先选择改变了不同维度的父方案——它们可以叠加,而非相互干扰)。
  • exploit:如果当前最佳方案有明显的、由分析指出的提升空间,且无需采用新架构。
计数器更新(步骤 11)
if move_type in {swing, merge}:  swings_taken += 1 (swing only); consecutive_exploit = 0
elif move_type == exploit:       consecutive_exploit += 1
三种改进方式(步骤 3)
  • Swing — 与之前每次 swing 的方案都要有根本性差异(不能只是微调;差异应当明显到一眼就能看出与当前最佳方案不同)。多数人会本能地在架构上进行 swing——要克制这种冲动。以下维度同样有效,但尚未得到充分探索:架构族(信息流动方式、深度与宽度、跳跃连接、局部与全局);初始化(基于幅值、保留结构、由输入统计数据驱动、稀疏——带来不同的早期动态);数据管线(排序、采样、确定性、视图空间覆盖范围——不只是增强方式);按组件解耦学习率(早期/后期层、归一化层、偏置、头各自有其最佳步长);评估(单次前向传播、多视图、检查点平均、校准);目标函数(损失形状、目标锐度、辅助/一致性信号)。真正的 swing 应以尚未尝试的方式探索其中一个维度。
  • Merge — 从 approaches.md 中选择两个或更多条目,并指出分别取用了哪些部分;结果应是一个新方案,而不是任一父方案的微小变体。优先选择来自不同维度的组件。
  • Exploit — 基于具体的分析结果,对当前最佳方案进行有针对性且聚焦的改动。每次只改一两项;将各个维度解耦(分别测试新优化器和新学习率,以确定结果由哪项改动导致)。绝不能改用不同架构。
分析(步骤 7 — 必须执行;须生成实际产物)

这是推动下一步决策的核心。运行最能加深你对结果成因理解的分析。每个分析脚本都放在 iter<N>/analysis/ 中;每个输出(图表、CSV、文本)都放在 iter<N>/results/ 中,并将标准输出重定向到该目录。在结果文件生成之前不要继续——没有写入文件的分析就不算完成。可选分析维度(按需选择):梯度范数/流动、激活统计/饱和度、嵌入(PCA/CKA/坍塌)、错误与混淆分析、损失动态与提升空间(截止时是否仍在改善?)、权重/参数统计、数据分析(通常收益最高)、计算分析。

撰写一份简洁的分析摘要(3–8 条):说明检查了什么、最重要的一项发现,以及这对下一步决策的启示(倾向于 swing / merge / exploit 中的哪一种)。

消融纪律(对涉及多个维度的任何 keep 之后):你还不知道是哪部分带来了提升——请标记这一点,并考虑在下一轮进行消融式 exploit,每次回退一个组件。基于未经消融的多维改动继续构建,就等于在未知基础上构建。

面向未来的监测。 分析后,问问自己:“我希望当时记录了哪些数据?”——如果生成结果的脚本位于 <editable_files> 中,请立即添加这些记录(最佳周期检查点、逐层梯度范数、逐类别准确率)。更丰富的日志能提升今后每一次分析的质量;添加监测本身也是有效的一轮迭代(将其记录为 move_type=exploit)。

登记表(步骤 8 — 仅用于 swing 和 merge 的 approaches.md)

追加一条记录;axes changed 字段用于 merge 步骤寻找互补的父方案(改变了不同维度的两个方案,优于两个都改变架构的方案):

## Approach <N>: <short name>
- **move_type**: swing | merge
- **iter**: <N>
- **<metric>**: <value>  (status: keep | discard | crash)
- **axes changed**: architecture | initialization | data pipeline | optimizer | lr schedule | evaluation | objective | other
- **key ideas**: <what makes this approach distinct>
- **strengths** / **weaknesses** (from analysis): <what worked / what the analysis says is missing>
- **ablated?**: yes (which components isolated, what was found) / no
- **parents** (merge only): Approach X + Approach Y — axes taken from each

台账

<sandbox_root>/results.tsv,使用制表符分隔,自由文本中不得出现逗号。状态 ∈ {keep,discard, crash};发生崩溃时,指标使用 0.000000。对于 branches,第一列使用 7 位字符的提交标识, 而非迭代次数。

iter	<metric>	status	move_type	analysis_summary	description
1	0.6320	keep	swing	baseline; grad norms clean, no pathologies	baseline
2	0.5910	discard	swing	ResNet blocks; gradient flow good but overfit on 5 epochs	ResNet-style residual blocks
3	0.6890	keep	swing	MLP-Mixer; feature mixing effective, less overfit	MLP-Mixer token+channel mix
4	0.7120	keep	merge	Mixer channel-mix + ResNet skips; best of both	merge: Mixer + ResNet skips
5	0.7250	keep	exploit	train/val gap small; warmup helped stability	add 2-epoch LR warmup
6	0.7240	discard	exploit	no gain from dropout; val acc unchanged	add dropout 0.1
7	0.6800	discard	swing	forced pivot after stagnation guard; ViT too data-hungry	ViT patch-16 from scratch

approaches.md 登记表——每次 swing/merge 记录一条,格式如上。示例:

# Approach Registry
The merge step consults this file to find complementary approaches to combine.

## Approach 3: MLP-Mixer
- **move_type**: swing
- **iter**: 3
- **val_acc**: 0.6890  (status: keep)
- **axes changed**: architecture
- **key ideas**: token mixing + channel mixing, no convolutions
- **strengths**: less overfit than ResNet, fast per-epoch
- **weaknesses**: spatial locality not exploited; edges/textures underused
- **ablated?**: no

总结时报告最佳迭代(不一定是最后一次)。不要提交 results.tsv 或 approaches.md——将它们保留为未跟踪文件。

约束

  • 只能编辑 <editable_files> 中的文件——每次编辑前都要确认,因为其他所有内容都是 只读的事实依据,且评估框架定义了 <metric>。
  • 每次迭代只做一项更改,以便将每次指标变化归因于一项操作。
  • 调度规则是硬性约束,不是建议。 当 consecutive_exploit >= <stagnation_limit> 时,你必须选择 swing 或 merge——无论分析结果如何, 都不能选择 exploit;这一限制用于防止无休止的爬坡优化。
  • 每次迭代都必须进行分析,并在 iter<N>/results/ 中生成实际文件;没有分析支撑的操作会使循环 退化为盲目迭代,并导致后续决策缺乏依据。
  • swing 必须与此前每次 swing 有根本区别;merge 必须注明从各个父项中分别采纳了哪些内容—— 否则登记表和广度保证都毫无意义。
  • 不要安装项目中没有的包或添加依赖;辅助脚本只能使用标准库。
  • 始终将训练输出重定向到 <run_log>;绝不要使用 tee。沙盒是自包含的——不得通过 ../ 越界。

停止

此循环会一直运行,直到人工中断——不要停下来询问“要继续吗?”或“现在停下来合适吗?”。人工可能不在, 并期待任务无限期自主运行。得到可用结果,意味着开始下一次迭代,而不是结束。如果想法枯竭:重新阅读 范围内的文件,寻找遗漏的角度;深入分析(梯度/激活值/嵌入/错误总能揭示一些问题);将 approaches.md 中此前接近成功的方案结合起来;或者尝试更激进的 swing。

评论

支持 Markdown