总览 · ← 返回运行 20261003-171955-search-t2-embryo-interp-chain-12h
节点 n5 在终选来历上
mix 混抽 + 共有类型时间差向量强收敛:a 侧细胞 +α·t·Δ_type、b 侧 −α·(1−t)·Δ_type(α=5,只移已表达项、只留 |Δ|≥0.25 基因),坐标不动。
| 运行?一次完整的自动搜索或 Agent 会话,有自己的锁定配置和证据包。 | 20261003-171955-search-t2-embryo-interp-chain-12h |
|---|---|
| 父节点 | n2 |
| 子节点 | n8、n9 |
| 操作?种子:人写的起点;改进:在父节点上改;草稿:从头写;修复:修父节点的报错。 | 改进 |
| 状态 | 已打分 |
| 分数 | 搜索目标分 61.51(+4.3) · proxy 61.51(+4.3) · 3 次复测均分 61.66 |
| 审查 | 通过 1 越界读取:未发现——run.py 仅通过 view_io 的 load_manifest/read_stage/panel_genes 读取 --data 视图内文件(run.py:157-168),无绝对路径、'..'、/mnt、/home、下载或目标阶段文件访问,import 的 src.task2_spatial 为环境提供的任务脚手架而非评分器代码。; 2 硬编码目标统计量:未发现——位移向量 Δ=μ_b−μ_a 由两个输入阶段现场计算(run.py:82-94),常量仅为通用超参(α=5、|Δ|≥0.25 阈值、共有类型 ≥10 细胞),无写死的类型比例表、基因列表或表达数值。… |
| 用时?从运行开始到结束(或到现在)的挂钟时间。 | 17 分 |
| 程序版本 | ce70a2f10a25a699dab4e3caddb7335bf4f793a8 (programs.git) |
| 导入自 | 20261003-094242-search-t2-embryo-interp-g24-D-s2#5 |
| 备注 | re-scored at launch (origin 20261003-094242-search-t2-embryo-interp-g24-D-s2 node 5, score there 61.51) |
方法说明?节点程序自带的 METHOD.md:这个程序做了什么、为什么。
来自 programs.git ce70a2f10a:solution/METHOD.md
mix 混抽 + 共有类型时间差向量强收敛:a 侧细胞 +α·t·Δ_type、b 侧 −α·(1−t)·Δ_type(α=5,只移已表达项、只留 |Δ|≥0.25 基因),坐标不动。
方法(family T2EI-01,PLAN 指定的类型级表达时间收敛)
在父节点 2 的 mix 管线(procrustes3d 对齐、scale_damp=0.5、按类型分层混抽 (1−t, t)、n=5000)之上,新增一步:
- 对两个括号阶段都出现(各 ≥10 细胞)的类型,Δ_type = μ_b − μ_a(该类型两阶段伪批量均值差),只保留 |Δ| ≥ 0.25 的基因(与 DE 阈值一致,小变化视为噪声)。
- 来自 stage_a 的该类型细胞:x ← clip(x + α·t·Δ, 0);来自 stage_b 的:x ← clip(x − α·(1−t)·Δ, 0)。
- 稀疏保持(关键结构修复):只对细胞中已表达(x>0)的项做位移,零项保持零。位移是逐类型常数向量,若不限制到已表达项,零元比例会从 93% 掉到 54%,细胞不再像真实细胞,variogram/mmd_u 崩溃(见下)。
- 坐标完全不动 → 表达-位置配对(neighborhood_mmd)不因机制本身被破坏。
- 单输入阶段退路:与父节点一致,分层复制最后观测阶段,不做位移。
- 参数:α 默认 5.0,环境变量
T2_CONVERGE_ALPHA覆盖(提交时保持打开);α=0 为机制关闭对照。
机制生效证据(seed 0,proxy E6.75+E8.0→E7.25,t=0.4)
- α=0 输出与父节点 run.py 输出逐位相同(X 与坐标 array_equal=True),管线正确。
- α=5:10 个共有类型全部位移;型内表达标准差比 0.91(变化 <10%,型内结构未坍缩);型间均值距离比 0.79(收缩);零元比例 0.929→0.941(b 侧下移经 clip 略增,结构保持)。
- 加权伪批量几乎不动:抽样比例 (1−t, t) 使两侧位移在全局均值中精确抵消(α 大不改变整体均值,只消解型内端点双峰);de_score 的变化来自 clip 的不对称。
对照与查分结果(A 半,seed 0,除注明外)
| 配置 | 总分 | cell_state | variogram skill | mmd_u skill | neighborhood skill |
|---|---|---|---|---|---|
| α=0(对照=父节点) | 56.36 | 36.23 | 0.216 | 0.509 | 0.545 |
| α=0.5 稠密位移(无稀疏保持) | 56.02 | 27.33 | 0.097 | 0.450 | 0.496 |
| α=0.2 稠密 | ~55.4 | 30.64 | 0.126 | 0.487 | 0.527 |
| α=0.5 稀疏 | 56.63 | 37.10 | 0.228 | 0.514 | 0.544 |
| α=1.0 稀疏 | 56.95 | 38.33 | 0.243 | 0.524 | 0.544 |
| α=1.5 稀疏 | 57.41 | 40.03 | 0.262 | 0.539 | 0.545 |
| α=2.5 稀疏 | 58.81 | 44.33 | 0.315 | 0.572 | 0.557 |
| α=4 稀疏 | 60.27 | 47.42 | 0.357 | 0.592 | 0.576 |
| α=5 稀疏(提交) | 60.55 | 47.82 | 0.371 | 0.585 | 0.583 |
| α=6 稀疏 | 60.43 | 47.26 | 0.381 | 0.565 | 0.584 |
| α=10 稀疏 | 57.93 | 40.82 | 0.392 | 0.424 | 0.543 |
| α=5,seed 1 | 60.34 | 47.82 | - | - | - |
稠密位移(PLAN 原式,不加稀疏保持)在所有 α 上都比对照差:它同时打坏稀疏结构。机制的收益全部来自"稀疏保持 + 大 α"这一修正版。
验证过 / 没验证
- 验证:α=0 逐位复现父节点;α 网格 0.2–10(A 半,13 次查分);平台在 4–6,取中值 5(对平台边缘最稳);seed 0/1 分数一致(60.55 / 60.34);输出确定(同 seed 逐位相同);vec-check 通过;运行 ~30s、峰值内存远低于限值。
- 没验证:final 视图真实括号(E7.25+E8.0→E7.5,t=1/3)无法本地查分。α=5 远超 PLAN 的 {0.2..1.0} 建议区间,是在代理的大跨度括号(E6.75→E8.0,Δ 很大)上调出的;真实括号更窄、Δ 更小,同样的 α 产生的绝对位移也更小(Δ 正比于括号跨度),预期方向可迁移,但平台位置可能偏移。α=10 时 mmd_u 崩溃说明过冲有真实代价,故不取平台右缘。
- B 半噪声 ~1 分:+4.2(56.36→60.55)远超噪声,但正式分是 B 半,幅度可能不同。
知识来源
未使用任何文献/数据库先验;Δ_type 完全由视图内两个输入阶段现场计算(无保留阶段信息、无硬编码类型名/比例/表达值)。|Δ|≥0.25 阈值沿用评分简报中 DE 指标的显著性阈值,属通用约定而非禁窗知识。
风险与下一步
- variogram skill 仍只有 0.371(<0.5 地板):型内端点双峰未完全消除。下一步可试:按分位数把 a 侧型内分布映射到插值分布,或对 Δ 位移加型内随机权重(保持共变结构)。
- occupancy_dice skill 0.369 一直很低且对表达机制不敏感(坐标项),是形状组剩余失分主因,需坐标侧改进。
调研员的计划
| 名称 | mix+类型级表达时间收敛(改善 cell_state/variogram) |
|---|---|
| 动机 | 父节点 2 的 cell_state 组仅 37.49,是四组中最弱的。拆到指标:variogram skill 0.228(得分 2.85/12.5,远低于地板 6.25),mmd_u skill 0.521(得分 6.52/12.5,刚过地板)。METHOD.md 已注明原因:两端真实细胞按比例混抽形成双峰分布,不像中间阶段。mix 只做了组成插值(抽哪边的细胞),没有做类型内表达插值(细胞表达值仍停在端点),导致混合后基因共变结构(variogram)和状态分布(mmd_u)都偏离中间目标。 |
| 做法 | 在 mix 框架上增加类型级表达收敛步骤: 1. 对共有类型(两阶段都出现的类型),计算该类型在 stage_a 和 stage_b 的均值表达向量 μ_a, μ_b,得到时间变化向量 Δ = μ_b − μ_a。 2. 来自 stage_a 的该类型细胞:x ← x + α·t·Δ;来自 stage_b 的:x ← x − α·(1−t)·Δ。α 为收敛阻尼,初值 0.5,搜索 {0.2, 0.3, 0.5, 0.7, 1.0}。t 为插值比例(proxy 上约 0.4)。 3. 仅出现在单侧的类型不做位移。 4. 坐标不动,保持表达-位置配对。 5. 单输入阶段退路:无括号时直接复制最后阶段细胞,不做位移(与现有 fallback 一致)。 6. vec-score 筛选:先跑 α=0(对照)和 α=0.5,比较 cell_state 组(重点看 variogram 和 mmd_u 的 skill);若 variogram skill 升到 0.4 以上再细化 α;同时监控 neighborhood_mmd skill 不低于 0.5(结构门)、de_direction 不降。 7. 表达值截断到 [0, +∞),不引入负值。 |
| 风险 | 1) α 过大导致型内方差坍缩,mmd_u 反而变差——Engineer 应在 α=1.0 时检查型内标准差是否降到真值的一半以下;2) 类型标签在两个阶段间不完全对应(n_shared_types 少),大部分细胞得不到位移——检查 info 里 n_shared_types,若 <5 则退化为全局均值收敛;3) 邻域组对表达微扰敏感——监控 neighborhood_mmd skill,若降到 0.5 以下立即降 α;4) 预期提升 ~3-5 分(cell_state 从 37→42+),大于 1 分噪声但需 2 次查分确认。 |
代码改动?这个节点的程序和父节点程序的逐行差别:绿色是新增,红色是删除。
对比:父节点版本 9b12f3efec。改动的文件:solution/METHOD.md +52 −0、solution/README.md +5 −5、solution/run.py +135 −11
diff --git a/solution/METHOD.md b/solution/METHOD.mdnew file mode 100644index 0000000..f16e960--- /dev/null+++ b/solution/METHOD.md@@ -0,0 +1,52 @@+mix 混抽 + 共有类型时间差向量强收敛:a 侧细胞 +α·t·Δ_type、b 侧 −α·(1−t)·Δ_type(α=5,只移已表达项、只留 |Δ|≥0.25 基因),坐标不动。++## 方法(family T2EI-01,PLAN 指定的类型级表达时间收敛)++在父节点 2 的 mix 管线(procrustes3d 对齐、scale_damp=0.5、按类型分层混抽 (1−t, t)、n=5000)之上,新增一步:++1. 对两个括号阶段都出现(各 ≥10 细胞)的类型,Δ_type = μ_b − μ_a(该类型两阶段伪批量均值差),只保留 |Δ| ≥ 0.25 的基因(与 DE 阈值一致,小变化视为噪声)。+2. 来自 stage_a 的该类型细胞:x ← clip(x + α·t·Δ, 0);来自 stage_b 的:x ← clip(x − α·(1−t)·Δ, 0)。+3. **稀疏保持(关键结构修复)**:只对细胞中已表达(x>0)的项做位移,零项保持零。位移是逐类型常数向量,若不限制到已表达项,零元比例会从 93% 掉到 54%,细胞不再像真实细胞,variogram/mmd_u 崩溃(见下)。+4. 坐标完全不动 → 表达-位置配对(neighborhood_mmd)不因机制本身被破坏。+5. 单输入阶段退路:与父节点一致,分层复制最后观测阶段,不做位移。+6. 参数:α 默认 5.0,环境变量 `T2_CONVERGE_ALPHA` 覆盖(提交时保持打开);α=0 为机制关闭对照。++## 机制生效证据(seed 0,proxy E6.75+E8.0→E7.25,t=0.4)++- α=0 输出与父节点 run.py 输出逐位相同(X 与坐标 array_equal=True),管线正确。+- α=5:10 个共有类型全部位移;型内表达标准差比 0.91(变化 <10%,型内结构未坍缩);型间均值距离比 0.79(收缩);零元比例 0.929→0.941(b 侧下移经 clip 略增,结构保持)。+- 加权伪批量几乎不动:抽样比例 (1−t, t) 使两侧位移在全局均值中精确抵消(α 大不改变整体均值,只消解型内端点双峰);de_score 的变化来自 clip 的不对称。++## 对照与查分结果(A 半,seed 0,除注明外)++| 配置 | 总分 | cell_state | variogram skill | mmd_u skill | neighborhood skill |+|---|---:|---:|---:|---:|---:|+| α=0(对照=父节点) | 56.36 | 36.23 | 0.216 | 0.509 | 0.545 |+| α=0.5 稠密位移(无稀疏保持) | 56.02 | 27.33 | 0.097 | 0.450 | 0.496 |+| α=0.2 稠密 | ~55.4 | 30.64 | 0.126 | 0.487 | 0.527 |+| α=0.5 稀疏 | 56.63 | 37.10 | 0.228 | 0.514 | 0.544 |+| α=1.0 稀疏 | 56.95 | 38.33 | 0.243 | 0.524 | 0.544 |+| α=1.5 稀疏 | 57.41 | 40.03 | 0.262 | 0.539 | 0.545 |+| α=2.5 稀疏 | 58.81 | 44.33 | 0.315 | 0.572 | 0.557 |+| α=4 稀疏 | 60.27 | 47.42 | 0.357 | 0.592 | 0.576 |+| **α=5 稀疏(提交)** | **60.55** | **47.82** | **0.371** | **0.585** | **0.583** |+| α=6 稀疏 | 60.43 | 47.26 | 0.381 | 0.565 | 0.584 |+| α=10 稀疏 | 57.93 | 40.82 | 0.392 | 0.424 | 0.543 |+| α=5,seed 1 | 60.34 | 47.82 | - | - | - |++稠密位移(PLAN 原式,不加稀疏保持)在所有 α 上都比对照差:它同时打坏稀疏结构。机制的收益全部来自"稀疏保持 + 大 α"这一修正版。++## 验证过 / 没验证++- 验证:α=0 逐位复现父节点;α 网格 0.2–10(A 半,13 次查分);平台在 4–6,取中值 5(对平台边缘最稳);seed 0/1 分数一致(60.55 / 60.34);输出确定(同 seed 逐位相同);vec-check 通过;运行 ~30s、峰值内存远低于限值。+- 没验证:final 视图真实括号(E7.25+E8.0→E7.5,t=1/3)无法本地查分。α=5 远超 PLAN 的 {0.2..1.0} 建议区间,是在代理的大跨度括号(E6.75→E8.0,Δ 很大)上调出的;真实括号更窄、Δ 更小,同样的 α 产生的绝对位移也更小(Δ 正比于括号跨度),预期方向可迁移,但平台位置可能偏移。α=10 时 mmd_u 崩溃说明过冲有真实代价,故不取平台右缘。+- B 半噪声 ~1 分:+4.2(56.36→60.55)远超噪声,但正式分是 B 半,幅度可能不同。++## 知识来源++未使用任何文献/数据库先验;Δ_type 完全由视图内两个输入阶段现场计算(无保留阶段信息、无硬编码类型名/比例/表达值)。|Δ|≥0.25 阈值沿用评分简报中 DE 指标的显著性阈值,属通用约定而非禁窗知识。++## 风险与下一步++- variogram skill 仍只有 0.371(<0.5 地板):型内端点双峰未完全消除。下一步可试:按分位数把 a 侧型内分布映射到插值分布,或对 Δ 位移加型内随机权重(保持共变结构)。+- occupancy_dice skill 0.369 一直很低且对表达机制不敏感(坐标项),是形状组剩余失分主因,需坐标侧改进。diff --git a/solution/README.md b/solution/README.mdindex d3647c3..aa33d1e 100644--- a/solution/README.md+++ b/solution/README.md@@ -1,6 +1,6 @@-# mix(T2:embryo:val_interp)+# mix + 类型级表达时间收敛(T2:embryo:val_interp) -T2 方法卡的全胚插值选择:`mix`,align=procrustes3d(共有类型质心三维 Kabsch),scale_damp=0.5(目标 RMS 只走 log 线性的一半,防止代理上冲过真值)。其余同心脏 mix:括号两端按 (1−t, t) 分层抽真实细胞,表达和坐标一起走,细胞数夹到 [583, 5000]。-proxy(E6.75 + E8.0 → E7.25,t=0.4)预期 55.96(seed 0 实测 55.957,与方法卡一致;表达 59.1 / 状态 36.3 / 形状 73.6 / 邻域 54.9)。-final(E7.25 + E8.0 → E7.5,t=1/3):n=5000,RMS 168.2,z_dot 0.93,共有类型 11,与 `data/processed/t2/T2__embryo__val_interp__mix.h5ad` 逐位相同。-已知弱点:细胞状态组只有 36(两端细胞混抽不像中间阶段);scale_damp=0.5 是按代理慢增长段调的,真实括号 E7.25→E8.0 是快增长段,RMS 168 可能偏小。+父节点 mix(procrustes3d、scale_damp=0.5、分层混抽)之上新增:共有类型按 Δ=μ_b−μ_a+对 a 侧 +α·t·Δ、b 侧 −α·(1−t)·Δ 位移,只动已表达项、只留 |Δ|≥0.25 基因,clip≥0,坐标不动。+α 默认 5(`T2_CONVERGE_ALPHA` 可覆盖;α=0 逐位复现父节点)。proxy A 半:对照 56.36 → 60.55(seed 1:60.34)。+详见 METHOD.md。diff --git a/solution/run.py b/solution/run.pyindex 7ba73af..28df8a5 100644--- a/solution/run.py+++ b/solution/run.py@@ -1,28 +1,150 @@ #!/usr/bin/env python3-"""mix (T2 interpolation): real cells from both bracketing inputs, drawn (1−t, t).+"""mix + per-type temporal expression convergence (T2 interpolation). -Brackets the target with the nearest inputs before and after it, puts both in-one frame (``ALIGN``), rescales both clouds to the log-linear RMS+Parent (node 2) mix: brackets the target with the nearest inputs before and+after it, aligns both clouds in one frame (procrustes3d on shared-type+centroids), rescales both to the damped log-linear RMS exp(log r_a + SCALE_DAMP·t·Δlog r), and draws cells stratified by type:-round(t·n) from the later stage, the rest from the earlier one. Expression and-coordinates travel together. n is log-linear in t, clipped to the board range.-Parameters are the T2 card's choice for this board (selected_params.json).-If the target is not bracketed, falls back to the latest input before it.+round(t·n) from the later stage, the rest from the earlier one. Coordinates+travel with the cells. n is log-linear in t, clipped to the board range.++New mechanism (CONVERGE_ALPHA, family T2EI-01): for every cell type present in+both bracketing stages (≥10 cells per side), compute its temporal change+vector Δ = μ_b − μ_a from the stage pseudobulk means, keeping only genes with+|Δ| ≥ 0.25 (the DE threshold; smaller changes are noise). Cells drawn from the+earlier stage get x ← x + α·t·Δ; cells from the later stage get+x ← x − α·(1−t)·Δ, applied only to entries already expressed in the cell and+clipped at 0. This moves the two endpoint sub-populations of each type toward+their intermediate state (opposite directions, type-specific magnitude).+Preserving the sparse on/off structure is essential: a dense per-gene shift+drops the zero fraction from 93% to 54% and collapses variogram/mmd_u.+Coordinates are untouched, so the expression–position pairing is preserved by+construction. α = 0 disables the mechanism and reproduces the parent mix+bit-for-bit under the same seed.++α = 5 (plateau 4–6 on the proxy bracket; α = 10 collapses mmd_u) is far above+the naive interpolation value α = 1: because the stratified draw weights+(1−t, t) exactly cancel the shifts in the overall pseudobulk, larger α does+not move the population mean but keeps collapsing the within-type endpoint+bimodality until clipping and over-shooting take over.++If the target is not bracketed, falls back to a stratified copy of the latest+input before it (no displacement possible without two stages). """ from __future__ import annotations import argparse import json+import os import sys import numpy as np -from src.task2_spatial.methods import interpolate-from src.task2_spatial.sample import take+from src.task2_spatial.frame import align_pair, log_interp, rms_radius, scale_to_rms+from src.task2_spatial.methods import _jitter+from src.task2_spatial.sample import interp_count, mix_indices, take+from src.task2_spatial.shift import type_means+from src.task2_spatial.transport import as_dense from src.task2_spatial.view_io import board_params, interp_bracket, load_manifest, panel_genes, read_stage, write_t2 PARAMS = {"align": "procrustes3d", "scale_damp": 0.5}+CONVERGE_ALPHA = float(os.environ.get("T2_CONVERGE_ALPHA", "5.0"))+# Only shift genes whose temporal change is real (|Δ| >= DE threshold) and only+# entries already expressed in the cell, so the sparse on/off structure of real+# cells is preserved (a dense per-gene shift destroys it and tanks variogram/mmd).+CONVERGE_MIN_DELTA = float(os.environ.get("T2_CONVERGE_MIN_DELTA", "0.25"))+CONVERGE_NNZ_ONLY = os.environ.get("T2_CONVERGE_NNZ_ONLY", "1") == "1"+++def mix_converge(stage_a, stage_b, t: float, params: dict, alpha: float):+ t = float(t)+ damp = float(params.get("scale_damp", 1.0))+ align = str(params.get("align", "procrustes"))+ rng = np.random.default_rng(int(params.get("seed", 0)))++ aligned_a, aligned_b, info = align_pair(stage_a.coords, stage_b.coords, stage_a.labels, stage_b.labels, align)+ rms_a = rms_radius(stage_a.coords)+ rms_b = rms_radius(stage_b.coords)+ target_rms = log_interp(rms_a, rms_b, t, damp)+ ca = scale_to_rms(aligned_a, target_rms)+ cb = scale_to_rms(aligned_b, target_rms)+ n = interp_count(stage_a.n, stage_b.n, t, int(params["min_cells"]), int(params["max_cells"]),+ float(params.get("count_damp", 1.0)))+ ia, ib = mix_indices(stage_a.labels, stage_b.labels, t, n, rng)++ xa = as_dense(stage_a.X, ia) if ia.size else np.zeros((0, len(stage_a.genes)), np.float32)+ xb = as_dense(stage_b.X, ib) if ib.size else np.zeros((0, len(stage_b.genes)), np.float32)++ conv = {"alpha": alpha, "n_shared_types_converged": 0, "within_type_std_rel": None,+ "between_type_mean_dist_rel": None}+ if alpha != 0.0 and ia.size and ib.size:+ means_a = type_means(stage_a.X, stage_a.labels)+ means_b = type_means(stage_b.X, stage_b.labels)+ la = np.asarray(stage_a.labels).astype(str)+ lb = np.asarray(stage_b.labels).astype(str)+ cnt_a = {k: int((la == k).sum()) for k in means_a}+ cnt_b = {k: int((lb == k).sum()) for k in means_b}+ shared = sorted(k for k in set(means_a) & set(means_b) if cnt_a[k] >= 10 and cnt_b[k] >= 10)+ delta = {}+ for lab in shared:+ d = (means_b[lab] - means_a[lab]).astype(np.float32)+ if CONVERGE_MIN_DELTA > 0:+ d = np.where(np.abs(d) >= CONVERGE_MIN_DELTA, d, np.float32(0.0)).astype(np.float32)+ delta[lab] = d+ if shared:+ before = np.vstack([xa, xb]).astype(np.float64)+ labs_a = np.asarray(stage_a.labels).astype(str)[ia]+ labs_b = np.asarray(stage_b.labels).astype(str)[ib]+ def _shift(block, w, d):+ out = np.clip(block + np.float32(w) * d, 0.0, None)+ if CONVERGE_NNZ_ONLY:+ return np.where(block > 0, out, block)+ return out++ for lab in shared:+ d = delta[lab]+ ma = labs_a == lab+ if ma.any():+ xa[ma] = _shift(xa[ma], alpha * t, d)+ mb = labs_b == lab+ if mb.any():+ xb[mb] = _shift(xb[mb], -alpha * (1.0 - t), d)+ after = np.vstack([xa, xb]).astype(np.float64)+ # mechanism evidence: within-type std and between-type mean distance+ labs = np.concatenate([labs_a, labs_b])+ stds, dists_b, dists_a = [], [], []+ centroids = {}+ for lab in shared:+ m = labs == lab+ if m.sum() >= 5:+ stds.append((after[m].std(axis=0).mean(), before[m].std(axis=0).mean()))+ centroids[lab] = (after[m].mean(axis=0), before[m].mean(axis=0))+ keys = list(centroids)+ for i in range(len(keys)):+ for j in range(i + 1, len(keys)):+ dists_a.append(np.linalg.norm(centroids[keys[i]][0] - centroids[keys[j]][0]))+ dists_b.append(np.linalg.norm(centroids[keys[i]][1] - centroids[keys[j]][1]))+ if stds:+ arr = np.array(stds)+ conv["within_type_std_rel"] = float(arr[:, 0].mean() / max(arr[:, 1].mean(), 1e-12))+ if dists_a:+ conv["between_type_mean_dist_rel"] = float(np.mean(dists_a) / max(np.mean(dists_b), 1e-12))+ conv["n_shared_types_converged"] = len(shared)++ expr = np.clip(np.vstack([xa, xb]), 0.0, None).astype(np.float32) if (ia.size or ib.size) else np.zeros((0, len(stage_a.genes)), np.float32)+ coord_parts = []+ if ia.size:+ coord_parts.append(np.asarray(ca[ia], dtype=np.float64))+ if ib.size:+ coord_parts.append(np.asarray(cb[ib], dtype=np.float64))+ coords = _jitter(np.vstack(coord_parts), rng)+ coords = scale_to_rms(coords, target_rms)+ info.update(+ t=t, n=int(expr.shape[0]), rms_a=rms_a, rms_b=rms_b, target_rms=target_rms,+ out_rms=rms_radius(coords), n_from_a=int(ia.size), n_from_b=int(ib.size), **conv,+ )+ return expr, coords.astype(np.float32), info def main() -> None:@@ -44,8 +166,10 @@ def main() -> None: stage_a = read_stage(args.data, a, genes) stage_b = read_stage(args.data, b, genes) params = board_params(manifest, "mix", PARAMS, args.seed)- expr, coords, info = interpolate(stage_a, stage_b, t, params)- keep = {k: info.get(k) for k in ("t", "n", "rms_a", "rms_b", "out_rms", "n_shared_types", "z_dot", "z_flipped", "align")}+ expr, coords, info = mix_converge(stage_a, stage_b, t, params, CONVERGE_ALPHA)+ keep = {k: info.get(k) for k in ("t", "n", "rms_a", "rms_b", "out_rms", "n_shared_types", "z_dot", "z_flipped",+ "align", "alpha", "n_shared_types_converged", "within_type_std_rel",+ "between_type_mean_dist_rel", "n_from_a", "n_from_b")} print(json.dumps({"bracket": [a["stage"], b["stage"]], **keep}, default=float), file=sys.stderr) write_t2(args.out, expr, coords, genes, seed=args.seed)
调研来源?调研员查到并用到的知识条目和文献检索结果(只列标题和编号)。
用到的知识库条目
| 编号 | 标题 | 出处 |
|---|---|---|
| k007 | Interval staging and held-out-window filtering of external data | notes/official/来件/virtualembryo.ai/rules.md |
| k028 | LLM-driven code evolution for analysis algorithms | 10.64898/2026.02.26.707870 |
| k027 | Joint expression-geometry generation with relative geometry | notes/competition/03_solution_landscape.md |
分析结果?分析员写的 ANALYSIS.json:改了什么、各组分数怎么变、假设是否成立、经验和下一步建议。
| 改了什么 | 在父节点 2 的 mix 管线(procrustes3d 对齐、scale_damp=0.5、按类型分层混抽 (1-t,t)、n=5000)之上新增类型级表达时间收敛:共有类型 Δ=μ_b-μ_a(只保留 |Δ|>=0.25 的基因),a 侧细胞 +α·t·Δ、b 侧 -α·(1-t)·Δ,且位移只作用于该细胞已表达(x>0)的项、clip>=0,坐标完全不动;α 默认 5(T2_CONVERGE_ALPHA 可覆盖,α=0 关闭机制)。 |
|---|---|
| 各组分数的变化 | cell_state:明显变好,是本节点的主要收益:variogram 0.02952→0.01395(skill 0.228→0.389,得分 2.85→4.86,+2.00),mmd_u 0.01657→0.0122(skill 0.521→0.597,+0.94);组 37.49→49.28(+11.79 个百分点 ≈ +2.94 榜分)。 expression_change:略变好、幅度接近噪声:de_score 0.2069→0.2759(skill 0.562→0.587,+0.31 分),de_direction 0.3757→0.3919(+0.09 分,在 T2 约 1 分噪声内)。Engineer 归因于 clip 的不对称,方向与 PLAN 的'de_direction 不降'一致。 local_spatial:变好且高于噪声:neighborhood_mmd 0.05791→0.04971(skill 0.573→0.610,得分 14.32→15.26,+0.94),组 57.27→61.02(+3.75 个百分点);结构门未受影响(邻域 skill 已在 0.5 地板之上)。 shape_scale:完全不变(+0.00):d2_shape 0.00841、occupancy_dice 0.7735(skill 0.367)、scale_log_ratio 0.0099 三项与父节点逐位相同——坐标不动,符合设计;occupancy_dice 仍是形状组主要失分项。 |
| family_id | T2EI-01 |
| 假设是否成立 | 是 |
| 经验 |
|
| mechanism_active | 是 |
| 下一步建议 |
|
对话摘要?每个角色和大模型对话的统计:轮数、工具调用、用时、token 数和最后的回答摘录;原始记录只给路径。
只给统计和最后回答的摘录;完整对话请到原始记录位置里列出的文件看。
分析员
| 角色?调研员写计划、工程师改代码、分析员解读分数、审查员检查作弊。 | 分析员 alibaba-token-plan-cn/qwen3.8-max |
|---|---|
| 调用次数 | 1 次 |
| 轮数?大模型一共回复了几轮(每轮可以调用多个工具)。 | 4 |
| 工具调用?大模型调用读文件、执行命令等工具的次数,按工具名统计。 | 共 4 次:— |
| 用时 | 不到 1 分 |
| token 数?输入 / 输出(含思考)的 token 数,来自接口返回的用量。 | 输入 17,121 · 输出 1,790 · 思考 1,503 |
| 任务(第一行) | 分析节点 n5 的打分结果,写 ANALYSIS.json |
| 最后的回答(摘录) | ANALYSIS.json written |
| 原始记录位置?完整对话记录在 Spark 上的文件路径;看板不复制原始内容。 | /home/spark-longxinyang/vec/runs/formal/20261003-171955-search-t2-embryo-interp-chain-12h/nodes/5/analyst.jsonl (文件不在) |
工程师
| 角色 | 工程师 alibaba-token-plan-cn/qwen3.8-max |
|---|---|
| 调用次数 | 1 次 |
| 轮数 | 38 |
| 工具调用 | 共 39 次:— |
| 用时 | 14 分 |
| token 数 | 输入 77,158 · 输出 13,339 · 思考 15,640 |
| 任务(第一行) | 按计划修改程序:mix+类型级表达时间收敛(改善 cell_state/variogram) |
| 最后的回答(摘录) | **做了什么**:在父节点 mix 上实现 PLAN 的类型级时间收敛(T2EI-01),并做了一个关键结构修复——位移只作用于已表达项且只保留 |Δ|≥0.25 基因(稠密位移会把零元率从 93% 打到 54%,反而降分)。α 网格 0.2→10 扫描后取平台(4–6)中值 α=5,坐标不动。 **查分**(proxy A 半,14 次):对照 α=0(与父节点逐位相同)56.36 → α=5 得 **60.55**(seed 1:60.34);cell_state 36.2→47.8(variogram skill 0.216→0.371,mmd_u 0.509→0.585),neighborhood 0.545→0.583,DE 组略升。α=10 时 mmd_u 崩溃(0.424),故不取更高。vec-check 通过、同 seed 逐位确定、~30s CPU。 **下一步最值得试**:① variogram 仍低于地板——型内端点双峰未消尽,可试分位数映射或型内随机权重位移;② occupancy_dice skill 0.369 是形状组主要失分,需坐标侧改进(与表达机制正交);③ 真实括号更窄(E7.25→E8.0,t=1/3),α 平台位置可能偏移,后续节点可在 final 视图验证 α∈[3,6] 的敏感性。 |
| 原始记录位置 | /home/spark-longxinyang/vec/runs/formal/20261003-171955-search-t2-embryo-interp-chain-12h/nodes/5/engineer.jsonl (文件不在) |
调研员
| 角色 | 调研员 alibaba-token-plan-cn/qwen3.8-max |
|---|---|
| 调用次数 | 1 次 |
| 轮数 | 1 |
| 工具调用 | 共 0 次:— |
| 用时 | 1 分 |
| token 数 | 输入 9,269 · 输出 1,051 · 思考 2,837 |
| 任务(第一行) | 为节点 n5(改进,父节点 n2)写改进计划 PLAN.json |
| 最后的回答(摘录) | ```json
{
"name": "mix+类型级表达时间收敛(改善 cell_state/variogram)",
"motivation": "父节点 2 的 cell_state 组仅 37.49,是四组中最弱的。拆到指标:variogram skill 0.228(得分 2.85/12.5,远低于地板 6.25),mmd_u skill 0.521(得分 6.52/12.5,刚过地板)。METHOD.md 已注明原因:两端真实细胞按比例混抽形成双峰分布,不像中间阶段。mix 只做了组成插值(抽哪边的细胞),没有做类型内表达插值(细胞表达值仍停在端点),导致混合后基因共变结构(variogram)和状态分布(mmd_u)都偏离中间目标。",
"approach": "在 mix 框架上增加类型级表达收敛步骤:\n1. 对共有类型(两阶段都出现的类型),计算该类型在 stage_a 和 stage_b 的均值表达向量 μ_a, μ_b,得到时间变化向量 Δ = μ_b − μ_a。\n2. 来自 stage_a 的该类型细胞:x ← x + α·t·Δ;来自 stage_b 的:x ← x − α·(1−t)·Δ。α 为收敛阻尼,初值 0.5,搜索 {0.2, 0.3, 0.5, 0.7, 1.0}。t 为插值比例(proxy 上约 0.4)。\n3. 仅出现在单侧的类型不做位移。\n4. 坐标不动,保持表达-位置配对。\n5. 单输入阶段退路:无括号时直接复制最后阶段细胞,不做位移(与现有 fallback 一致)。\n6. vec-score 筛选:先跑 α=0(对照)和 α=0.5,比较 cell_state 组(重点看 variogram 和 mmd_u 的 skill);若 variogram skill 升到 0.4 以上再细化 α;同时监控 neighborhood_mmd skill 不低于 0.5(结构门)、de_direction 不降。\n7. 表达值截断到 [0, +∞),不引入负值。",
"expected_groups": ["cell_state"],
"risks": "1) α 过大导致型内方差坍缩,mmd_u 反而变差——Engineer 应在 α=1.0 时检查型内标准差是否降到真值的一半以下;2) 类型标签在两个阶段间不完全对应(n_shared_types 少),大部分细胞得不到位移——检查 info 里 n_shared_types,若 <5 则退化为全局均值收敛;3) 邻域组对表达微扰敏感——监控 neighborhood_mmd skill,若降到 0.5 以下立即降 α;4) 预期提升 ~3-5 分(cell_state 从 37→42+),大于 1 分噪声但需 2 次查分确认。",
"family_id": "T2EI-01",
"mechanism": "对共有类型,按该类型的实际时间变化向量 Δ 将端点细胞表达向中间收敛,收敛幅度由 α·t(或 α·(1−t))控制,方向取决于细胞来源阶段。",
"vs_constant_shift": "不是给所有细胞加同一个向量:(1) 位移向量 Δ 逐类型不同,正比于该类型真实时间变化;(2) 来自 stage_a 和 stage_b 的细胞位移方向相反(相向收敛,而非同向平移);(3) 幅度由插值比例 t 和阻尼 α 共同决定。全局常数位移对所有细胞加同一 Δ,不区分类型和来源阶段,无法消除双峰。",
"mechanism_evidence": "Engineer 应输出:(1) 位移前后每个共有类型的型内表达标准差(应基本不变,<10% 变化);(2) 型间均值距离(应收缩 α·t 比例);(3) variogram skill 和 mmd_u skill 的绝对值变化;(4) 若 α=0 时指标与父节点一致,说明管线正确。",
"mechanism_off_control": "设 α=0(或命令行 --converge-alpha 0),所有细胞表达不做位移,输出应与父节点 mix 完全一致(相同 seed 下逐位相同)。若 α=0 与 α=0.5 的 variogram/mmd_u 无差别,说明机制未生效。",
"sources": []
}
``` |
| 原始记录位置 | /home/spark-longxinyang/vec/runs/formal/20261003-171955-search-t2-embryo-interp-chain-12h/nodes/5/researcher.jsonl (文件不在) |
审查员
| 角色 | 审查员 alibaba-token-plan-cn/qwen3.8-max |
|---|---|
| 调用次数 | 1 次 |
| 轮数 | 8 |
| 工具调用 | 共 12 次:— |
| 用时 | 1 分 |
| token 数 | 输入 20,683 · 输出 1,368 · 思考 3,038 |
| 任务(第一行) | 审查节点 n5 的程序是否越界读取、写死目标、钻评分器漏洞 |
| 最后的回答(摘录) | REVIEW.json written |
| 原始记录位置 | /home/spark-longxinyang/vec/runs/formal/20261003-171955-search-t2-embryo-interp-chain-12h/nodes/5/reviewer.jsonl (文件不在) |