总览 · ← 返回运行 20261003-004922-search-t2-heart-interp-g24
节点 n15
外部MOSTA E9.5型均值表达再锚定(T2HI-07):实现NN融合后b细胞→参考同型真实均值的γ重锚(含varfix),标签门诊断失败(严格共有型0、可靠映射仅NCC 1型/覆盖率15%),按PLAN第1步放弃网格,提交γ=0默认(输出与父节点13逐位一致)。
| 运行?一次完整的自动搜索或 Agent 会话,有自己的锁定配置和证据包。 | 20261003-004922-search-t2-heart-interp-g24 |
|---|---|
| 父节点 | n13 |
| 子节点 | n17 |
| 操作?种子:人写的起点;改进:在父节点上改;草稿:从头写;修复:修父节点的报错。 | 改进 |
| 状态 | 已打分 |
| 分数 | 搜索目标分 60.66(+0.0) · proxy 60.66(+0.0) |
| 审查 | 通过 1 越界读取:未发现问题——expr_reanchor.py 的 load_reference 仅通过 Path(view)/entry['path'] 读取 manifest['external'] 声明的挂载文件(mosta_e95_v0,E9.5,视图内允许);全部源码无绝对路径、'..'、/mnt、/home、data/raw、评分器路径读取,无网络库(requests/urllib)导入;README.md 第5行提到的 data/processed/t2/...mix.h5ad 仅为文档性对比说明,代码未读取该路径。; 2 硬编码目标统计量:未发现问题——expr_reancho… |
| 用时?从运行开始到结束(或到现在)的挂钟时间。 | 12 分 |
| 程序版本 | 4e45f90ea932e8d5d01e1819ce39995b5fd35a1d (programs.git) |
方法说明?节点程序自带的 METHOD.md:这个程序做了什么、为什么。
来自 programs.git 4e45f90ea9:solution/METHOD.md
外部MOSTA E9.5型均值表达再锚定(T2HI-07):实现NN融合后b细胞→参考同型真实均值的γ重锚(含varfix),标签门诊断失败(严格共有型0、可靠映射仅NCC 1型/覆盖率15%),按PLAN第1步放弃网格,提交γ=0默认(输出与父节点13逐位一致)。
方法(PLAN T2HI-07 的实现)
父节点 13 pipeline(mix + 空间分层 + procrustes 对齐 + 型内 NN 坐标融合 α=1.0,EXPR_BLEND_BETA=0)不动。新增 expr_reanchor.py 并接入 nn_fuse.py/run.py:
- 参考加载(
load_reference):遍历manifest["external"],读挂载的外部 h5ad(本视图为 mosta_e95_v0,5913 细胞×496 基因);表达按契约重算为 log1p(CP10k)(原存储每细胞总量仅 ~250,非 CP10k),按genes.txt对齐,按参考标签算每基因均值 M_ref。外部细胞本身绝不输出。 - 重锚(
apply_reanchor):对每个"两 bracket 共有且参考中存在"的型,被 NN 融合的 b 侧输出行做X_new=(1−γ)X_b+γ·M_ref(type,gene),仅锚定参考覆盖的基因列,逐细胞、型级锚点、不跨型;可选 VARFIX 把子集每基因 std 恢复到重锚前(clip≥0)。 - 接线:
EXPR_REANCHOR_GAMMA(提交默认 0.0=关闭)、EXPR_REANCHOR_VARFIX(默认 0)、REANCHOR_DIAG=1打印门诊断。单输入阶段(b is None)退路与父相同;external 为空/缺失时 ref_means={} 优雅跳过。
标签门诊断(PLAN 第 1 步 / 风险 1,判定:不达标)
参考标签词汇(12 个):AGM, Brain, Branchial arch, Cavity, Connective tissue, Dermomyotome, Heart, Liver, Mesenchyme, Neural crest, Notochord, Sclerotome。bracket 共有型(5 个):NCC, Peri, V-CM, aPHM, pPHM。
- 严格同名交集 = 0 型(<3,门失败)。harness 自己的官方映射表也没能把这些标签映射到官方词汇(保留原名),因为它们是解剖区域标签而非细胞类型:'Heart' 区域混含心肌/心内膜/心外膜等,'Branchial arch' 混含外胚层/内皮/间充质,用区域均值当 V-CM 或 aPHM 的型级锚点不满足机制前提("真实同型均值"),属于编造标签同一性。
- 唯一可靠的通用谱系映射是 Neural crest → NCC(NCC=neural crest cells,标准发育生物学命名)。运行时门诊断(stderr json
reanchor_gate):anchor_types=["NCC"],n_anchorable/n_fused = 341/2273 = 15.0% 覆盖率 < 30%,1 型 < 3 型,两条标准都失败。 - 若强行加 'Heart'→V-CM、'Branchial arch'→aPHM 才能凑到 61% 覆盖率,但这违反门规则的初衷(风险 1),未采用。
按 PLAN 第 1 步:"若与官方共有型 <3 或覆盖率 <30%,直接放弃本方向、提交与父逐位一致的默认"。 因此未跑 γ 网格、未花查分额度在 γ>0 配置上,提交 γ=0。
对照结果(mechanism_off_control)
- γ=0(默认,外部文件甚至不被读取除非 REANCHOR_DIAG):输出与父节点 13 提交版逐位一致——
X.data/indices/indptr与spatial_3D均 array_equal(preds/gamma0.h5ad vs 改码前用父代码生成的 preds/parent_default.h5ad)。 - vec-check ok;A 半查分 1 次(n15_reanchor_gamma0_control):60.07,四组分 64.07/66.17/53.78/56.26,与节点 13 同一输出的 A 半控制值完全一致 → 接线无副作用(+0.00)。
- 机制本身可用性验证(仅本地诊断、不查分、不提交):γ=1.0 时 reanchor_n=341(NCC 融合细胞全部被作用),表达与参考 NCC 均值的 cosine 0.359→0.993,型内 std_ratio=0.031——γ=1 几乎塌缩到型均值,印证 PLAN 风险 2(分布形状塌缩会重罚 cell_state,节点 13 教训:mmd 类惩罚靠二阶统计量修补无效)。坐标逐位不变(符合设计,只动表达)。
验证过 / 未验证
- 验证过:γ=0 逐位一致 + vec-check ok + A 半控制 60.07(1 次查分,余 19);γ=1 机制生效诊断(341 细胞、cosine、std 塌缩、坐标不动);运行 ~2s、内存与父相当;external 为空时的优雅退路(代码路径,final 视图 external 组成可能不同)。
- 未验证:任何 γ>0 的榜分(门失败,按 PLAN 停止,不花额度);varfix 变体的榜分;final 视图(final 的 external 若同为区域标签词汇,门同样失败、γ=0 逐位一致退路生效,不会崩)。
生物学知识来源
- NCC = neural crest cells 的命名同一性(通用谱系知识,标准发育生物学命名法);除此未使用任何文献/数据库/记忆中的阶段特异性信息。区域标签未做任何到细胞类型的推断映射。
对树的意义
T2HI-07 方向的瓶颈不是实现而是外部参考的标签词汇与官方 T2 心脏词汇在细胞类型粒度上不相交(区域级 vs 型级)。后续节点若再想用 external/mosta_e95_v0,可行路径是标签无关的对齐(如表达空间 OT/最近邻把参考细胞投到官方型上再算锚点),但那引入"参考细胞是否同型"的新假设,且 γ=1 诊断显示型均值锚点本身有塌缩风险;表达侧改动仍受节点 13 教训约束(cell_state/mmd 对非真实流形谱惩罚苛刻)。坐标底座(α=1.0 NN 融合)保持不动,是当前全部净增益的来源。
调研员的计划
| 名称 | 外部MOSTA E9.5型均值表达再锚定(NN坐标融合后,b细胞→真实目标流形) |
|---|---|
| 动机 | 父节点13(=父12,60.66)四组分中 shape_scale 54.49、local_spatial 56.83 最弱,但节点11(各向同性弥散)与节点13(表达β混合)已分别证明这两组的常见改法无效;节点13 ANALYSIS 明确下一步是用 external/mosta_e95_v0 引导的表达侧调整。节点13 证伪的是'在两阶段真实谱之间插值出中间表达谱'(cell_state mmd 惩罚与 DE 增益等量抵消),而把 b 侧细胞表达替换/拉向外部 E9.5 参考的同型真实均值不产生插值谱,是未被试过且与教训兼容的方向。 |
| 做法 | 步骤:1) 读 external/mosta_e95_v0(manifest/基因面板/标签与视图同格式),按型算每基因均值与 std;先只做标签诊断(若与官方共有型 <3 或覆盖率 <30%,直接放弃本方向、提交与父逐位一致的默认)。2) 在 nn_fuse.py 融合后新增 expr_reanchor:对每个两阶段共有型且参考中也存在的型,b 侧被融合细胞做 X_new=(1−γ)X_b+γM_ref(type,gene),逐细胞、型级锚点、不跨型。3) 可选 VARFIX:重锚后把该子集每基因 std 恢复到重锚前(clip≥0),防止均值拉动压缩型内方差。4) 参数网格:γ=0(对照), 0.5, 1.0,各含/不含 varfix,共 5 次 vec-score(A 半、seed0);若最佳净增益 ≤1 分(噪声内)再加 1–2 个中间 γ 或停止,总查分 ≤8。5) 硬停止规则:cell_state 较对照降 >1 分即停(节点13 验证有效)。6) 单输入阶段(b is None)退路:跳过重锚,与现有 fallback 一致。7) 提交规则:仅当某配置净榜分超对照 >1 分且 cell_state 不降时才提交该配置,否则提交 γ=0(与父逐位一致)。 |
| 风险 | 1) MOSTA 标签词汇与官方不一致或共有型太少→机制无细胞可作用;Engineer 第一步先打印标签交集与覆盖率,不达标立即停。2) 向型均值收缩仍会压缩型内分布形状,cell_state/mmd 可能再罚(节点13 varfix 只回收 1/3 损失的教训)→用 VARFIX 变体对照,若 cell_state 降 >1 即停。3) b 侧表达本身可能已比外部参考更接近目标(参考是另一数据集)→若 γ>0 使 expression_change 反降,说明参考锚点劣于原表达,放弃。4) 净增益可能 <1 分噪声→用 A 半多次查分(不同 γ)看组分单调性,不只看总分。 |
代码改动?这个节点的程序和父节点程序的逐行差别:绿色是新增,红色是删除。
对比:父节点版本 e006a839b9。改动的文件:solution/METHOD.md +22 −25、solution/expr_reanchor.py +172 −0、solution/nn_fuse.py +19 −2、solution/run.py +12 −2
diff --git a/solution/METHOD.md b/solution/METHOD.mdindex ee4f24f..2da5e4e 100644--- a/solution/METHOD.md+++ b/solution/METHOD.md@@ -1,41 +1,38 @@-# 型内NN空间融合后同步表达β混合(T2HI-01):被融合b细胞表达向其a侧同型最近邻做(1−β)X_b+βX_a线性混合;proxy全β网格净分不高于β=0对照(expr_change/local_spatial升被cell_state等量降抵消),提交默认β=0(输出与父节点12逐位一致),阴性结果完整记录。+# 外部MOSTA E9.5型均值表达再锚定(T2HI-07):实现NN融合后b细胞→参考同型真实均值的γ重锚(含varfix),标签门诊断失败(严格共有型0、可靠映射仅NCC 1型/覆盖率15%),按PLAN第1步放弃网格,提交γ=0默认(输出与父节点13逐位一致)。 -## 方法(PLAN T2HI-01 的实现)+## 方法(PLAN T2HI-07 的实现) -父节点 12 pipeline(mix + 空间分层抽样 + procrustes 对齐 + 型内 NN 坐标融合 α=1.0)不动。在 `nn_fuse.py` 的 `fuse_nn` 内,cKDTree query 返回的最近邻索引被复用于表达混合:对每个被空间融合的 b 侧输出细胞,`X_b ← (1−β)·X_b + β·X_a_nn`(同一邻居,逐细胞、位置依赖、型内),另加可选 `EXPR_BLEND_VARFIX=1`:混合后把融合子集内每基因 std 恢复到混合前(保留均值位移,clip≥0)。非共有型、a 侧细胞、坐标均不动。单输入阶段(b is None)退路与父节点相同。+父节点 13 pipeline(mix + 空间分层 + procrustes 对齐 + 型内 NN 坐标融合 α=1.0,EXPR_BLEND_BETA=0)不动。新增 `expr_reanchor.py` 并接入 `nn_fuse.py`/`run.py`: -- 开关:`EXPR_BLEND_BETA`(**提交默认 0.0 = 关闭**)、`EXPR_BLEND_VARFIX`(默认 0)。-- β=0 时融合/混合代码全被 guard 跳过,输出 X 与坐标和父节点 12 **逐位一致**(`X/data` 非零值 array_equal、`spatial_3D` array_equal,已验证);vec-check ok。+1. **参考加载**(`load_reference`):遍历 `manifest["external"]`,读挂载的外部 h5ad(本视图为 mosta_e95_v0,5913 细胞×496 基因);表达按契约重算为 log1p(CP10k)(原存储每细胞总量仅 ~250,非 CP10k),按 `genes.txt` 对齐,按参考标签算每基因均值 M_ref。外部细胞本身绝不输出。+2. **重锚**(`apply_reanchor`):对每个"两 bracket 共有且参考中存在"的型,被 NN 融合的 b 侧输出行做 `X_new=(1−γ)X_b+γ·M_ref(type,gene)`,仅锚定参考覆盖的基因列,逐细胞、型级锚点、不跨型;可选 VARFIX 把子集每基因 std 恢复到重锚前(clip≥0)。+3. **接线**:`EXPR_REANCHOR_GAMMA`(提交默认 0.0=关闭)、`EXPR_REANCHOR_VARFIX`(默认 0)、`REANCHOR_DIAG=1` 打印门诊断。单输入阶段(b is None)退路与父相同;external 为空/缺失时 ref_means={} 优雅跳过。 -## β 网格(proxy,seed0,A 半,共 7 次查分)+## 标签门诊断(PLAN 第 1 步 / 风险 1,判定:不达标) -| 配置 | 榜分 | expr_change | cell_state | local_spatial | shape_scale |-|---|---:|---:|---:|---:|---:|-| β=0(对照=父12) | **60.07** | 64.07 | **66.17** | 56.26 | 53.78 |-| β=0.1 | 60.02 | 64.47 | 65.63 | 56.21 | 53.78 |-| β=0.2 | 59.95 | 64.50 | 65.27 | 56.26 | 53.78 |-| β=0.3 | 59.93 | 64.53 | 64.99 | 56.40 | 53.78 |-| β=0.5 | 59.97 | 64.55 | 64.68 | 56.88 | 53.78 |-| β=0.3+varfix | 60.02 | 64.52 | 65.17 | 56.59 | 53.78 |-| β=0.5+varfix | 60.10 | 64.80 | 64.67 | 57.14 | 53.78 |+参考标签词汇(12 个):AGM, Brain, Branchial arch, Cavity, Connective tissue, Dermomyotome, Heart, Liver, Mesenchyme, Neural crest, Notochord, Sclerotome。bracket 共有型(5 个):NCC, Peri, V-CM, aPHM, pPHM。 -## 机制生效证据(PLAN 要求的 4 项)+- **严格同名交集 = 0 型**(<3,门失败)。harness 自己的官方映射表也没能把这些标签映射到官方词汇(保留原名),因为它们是**解剖区域标签**而非细胞类型:'Heart' 区域混含心肌/心内膜/心外膜等,'Branchial arch' 混含外胚层/内皮/间充质,用区域均值当 V-CM 或 aPHM 的型级锚点不满足机制前提("真实同型均值"),属于编造标签同一性。+- 唯一可靠的通用谱系映射是 **Neural crest → NCC**(NCC=neural crest cells,标准发育生物学命名)。运行时门诊断(stderr json `reanchor_gate`):anchor_types=["NCC"],n_anchorable/n_fused = 341/2273 = **15.0% 覆盖率 < 30%**,1 型 < 3 型,两条标准都失败。+- 若强行加 'Heart'→V-CM、'Branchial arch'→aPHM 才能凑到 61% 覆盖率,但这违反门规则的初衷(风险 1),未采用。 -1. **cosine 相似度**:被融合 b 细胞与其 a 侧邻居的表达 cos 从 0.379 升到 0.593(β=0.2,stderr 诊断 `cos_before/cos_after`)——混合确实按位置逐细胞改变了表达。-2. **型内方差**:不加 varfix 时融合子集每基因 std 按 ~(1−β)+β·ρ 收缩;varfix 变体把它恢复到混合前(mmd_u 0.0349→0.0341 @β=0.5),但 cell_state 只回收约 1/3,说明 cell_state 损失来自分布形状(mmd)而非逐基因方差。-3. **四组分**:expression_change 单调升(64.07→64.80,de_score 0.337→0.370);local_spatial 升(56.26→57.14,neighborhood_mmd 0.0746→0.0720,表达-空间对应一致化确实改善局部邻域);cell_state 近似线性降(66.17→64.67);shape_scale 恒等(坐标未动,符合设计)。-4. **响应曲线**:expression_change 对 β 单调(非 PLAN 预期的非单调),但在 β≥0.1 后饱和;净榜分对 β 平坦且全部 ≤ 对照 + 0.03(噪声 ~1 分内)。+**按 PLAN 第 1 步:"若与官方共有型 <3 或覆盖率 <30%,直接放弃本方向、提交与父逐位一致的默认"。** 因此未跑 γ 网格、未花查分额度在 γ>0 配置上,提交 γ=0。 ## 对照结果(mechanism_off_control) -β=0(默认)输出与父节点 12 逐位一致(X 非零值与坐标 array_equal,preds/default.h5ad vs preds/b0.h5ad 验证);β>0 时仅表达变化、坐标逐位不变(b0 vs b02 coords array_equal 验证)。结论:**假设被证伪**——表达向空间邻居混合的 expr_change(+0.4~0.7) 与 local_spatial(+0.6~0.9) 增益,被 cell_state(−0.5~−1.5) 等量抵消,7 个配置无一在噪声外超过 β=0。PLAN 风险 1、2 同时兑现。按 PLAN 的停止规则(cell_state 降 >1 即停、β=0.1 净降即放弃),提交保持 β=0。+- γ=0(默认,外部文件甚至不被读取除非 REANCHOR_DIAG):输出与父节点 13 提交版**逐位一致**——`X.data/indices/indptr` 与 `spatial_3D` 均 array_equal(preds/gamma0.h5ad vs 改码前用父代码生成的 preds/parent_default.h5ad)。+- vec-check ok;A 半查分 1 次(n15_reanchor_gamma0_control):60.07,四组分 64.07/66.17/53.78/56.26,与节点 13 同一输出的 A 半控制值完全一致 → 接线无副作用(+0.00)。+- 机制本身可用性验证(仅本地诊断、不查分、不提交):γ=1.0 时 reanchor_n=341(NCC 融合细胞全部被作用),表达与参考 NCC 均值的 cosine 0.359→0.993,型内 std_ratio=0.031——γ=1 几乎塌缩到型均值,印证 PLAN 风险 2(分布形状塌缩会重罚 cell_state,节点 13 教训:mmd 类惩罚靠二阶统计量修补无效)。坐标逐位不变(符合设计,只动表达)。 ## 验证过 / 未验证 -- 验证过:β=0 逐位一致 + vec-check ok;β∈{0.1,0.2,0.3,0.5}×{plain,varfix} 网格(seed0,A 半,7 次查分);运行 ~2-5s、内存不变。-- 未验证:β>0 的多种子(无配置超噪声,不值得花额度);final 视图(31 共有型、融合覆盖率更高,β 混合的作用细胞更多,cell_state 损失可能同比放大,方向结论预期不变);k>1 邻居均值混合(同属均值压缩,预期同样伤 cell_state)。-- 生物学知识来源:无新增外部知识;仅用 view 内输入数据。external/mosta 未使用。+- 验证过:γ=0 逐位一致 + vec-check ok + A 半控制 60.07(1 次查分,余 19);γ=1 机制生效诊断(341 细胞、cosine、std 塌缩、坐标不动);运行 ~2s、内存与父相当;external 为空时的优雅退路(代码路径,final 视图 external 组成可能不同)。+- 未验证:任何 γ>0 的榜分(门失败,按 PLAN 停止,不花额度);varfix 变体的榜分;final 视图(final 的 external 若同为区域标签词汇,门同样失败、γ=0 逐位一致退路生效,不会崩)。++## 生物学知识来源++- NCC = neural crest cells 的命名同一性(通用谱系知识,标准发育生物学命名法);除此未使用任何文献/数据库/记忆中的阶段特异性信息。区域标签未做任何到细胞类型的推断映射。 ## 对树的意义 -表达侧"向空间邻居混合"与坐标侧 NN 融合不同:坐标融合恢复局部连续性是纯增益(节点 10/12 各 +2.6/+2.9),表达混合在 E8.75 参考分布下是零和(评分器的 cell_state/mmd 对"不在真实流形上的中间表达谱"惩罚与 DE 方向增益等量)。下一步最值得试的是 external/mosta_e95_v0 引导的表达侧改动(节点 12 next_suggestions),或在 final 括号上直接复用当前 α=1.0 底座(31 共有型 vs proxy 5 个,融合覆盖率 12.9%→更高,local_spatial 增益可能放大)。+T2HI-07 方向的瓶颈不是实现而是**外部参考的标签词汇与官方 T2 心脏词汇在细胞类型粒度上不相交**(区域级 vs 型级)。后续节点若再想用 external/mosta_e95_v0,可行路径是标签无关的对齐(如表达空间 OT/最近邻把参考细胞投到官方型上再算锚点),但那引入"参考细胞是否同型"的新假设,且 γ=1 诊断显示型均值锚点本身有塌缩风险;表达侧改动仍受节点 13 教训约束(cell_state/mmd 对非真实流形谱惩罚苛刻)。坐标底座(α=1.0 NN 融合)保持不动,是当前全部净增益的来源。diff --git a/solution/expr_reanchor.py b/solution/expr_reanchor.pynew file mode 100644index 0000000..4c6d5f2--- /dev/null+++ b/solution/expr_reanchor.py@@ -0,0 +1,172 @@+"""External-reference type-mean expression re-anchoring (T2HI-07).++Mechanism (PLAN): NN coordinate fusion moves b-side cells next to a-side+neighbours but keeps their b-stage expression profile (expression/geometry+mismatch). For every fused b-side cell whose type is shared by both+brackets AND present in an external reference (manifest["external"],+e.g. MOSTA E9.5), pull its expression toward the reference's real+same-type per-gene mean: X_new = (1-gamma)*X_b + gamma*M_ref(type, gene).+The anchor is a real measured profile of the same cell type, so no+interpolated spectrum between the two bracket manifolds is created+(node-13 lesson). Optional VARFIX restores per-gene std of the anchored+subset to its pre-anchor value (clip >= 0).++Reference handling (contract-compliant):+- expression recomputed to log1p(CP10k) from the stored log values;+- genes aligned to the panel; genes missing from the reference are NOT+ anchored (kept as X_b);+- external cells are never emitted, only per-type means are used.++Label gate (PLAN step 1 / risk 1): the reference vocabulary must overlap+the official bracket-shared vocabulary. Only conservative cell-type+identities from general lineage knowledge are mapped+("Neural crest" -> "NCC"); anatomical REGION labels ("Heart",+"Branchial arch", "Brain", ...) mix multiple cell types and are NOT+mapped (the harness's own label mapping also left them unmapped).+If shared reference types < MIN_SHARED_TYPES or anchored coverage of the+fused b cells < MIN_COVERAGE, the mechanism must stay off (gamma=0).+"""++from __future__ import annotations++import os+from pathlib import Path++import numpy as np++MIN_SHARED_TYPES = 3+MIN_COVERAGE = 0.30++# Reference label -> official T2 heart vocabulary. Only unambiguous+# cell-type identities (general lineage knowledge: NCC = neural crest+# cells). Region labels are deliberately absent (see module docstring).+REF_LABEL_TO_OFFICIAL = {+ "Neural crest": "NCC",+}+++def _to_log1p_cp10k(X: np.ndarray) -> np.ndarray:+ counts = np.expm1(X, dtype=np.float64)+ np.clip(counts, 0.0, None, out=counts)+ tot = counts.sum(1, keepdims=True)+ tot[tot <= 0] = 1.0+ return np.log1p(counts / tot * 1e4).astype(np.float32)+++def load_reference(view: str, manifest: dict, genes: list[str]) -> tuple[dict[str, np.ndarray], dict]:+ """Per-official-type gene means (panel order) from mounted external data.++ Returns ({}, diag) when no usable external entry exists (views may+ mount empty external/). Deterministic; no cells are returned.+ """+ diag = {"ref_labels": [], "n_ref_cells": 0, "ref_types_mapped": [], "gene_cov": 0.0}+ means: dict[str, np.ndarray] = {}+ entries = manifest.get("external") or []+ gidx = {g: i for i, g in enumerate(genes)}+ for entry in entries:+ path = Path(view) / entry.get("path", "")+ if not path.exists():+ continue+ try:+ import anndata as ad++ ref = ad.read_h5ad(path)+ except Exception as exc: # pragma: no cover - defensive+ diag["error"] = f"{type(exc).__name__}: {exc}"+ continue+ if "celltype" not in ref.obs.columns:+ continue+ labels = np.asarray(ref.obs["celltype"]).astype(str)+ diag["ref_labels"] = sorted(set(labels.tolist()))+ diag["n_ref_cells"] = int(ref.n_obs)+ X = ref.X.toarray() if hasattr(ref.X, "toarray") else np.asarray(ref.X)+ X = _to_log1p_cp10k(np.asarray(X, dtype=np.float32))+ cols = np.array([gidx.get(g, -1) for g in ref.var_names], dtype=np.int64)+ have = cols >= 0+ diag["gene_cov"] = float(have.mean())+ panel = np.zeros((ref.n_obs, len(genes)), dtype=np.float32)+ panel[:, cols[have]] = X[:, have]+ for lab in sorted(set(labels.tolist())):+ off = REF_LABEL_TO_OFFICIAL.get(lab, lab)+ m = labels == lab+ means[off] = panel[m].mean(0)+ diag["ref_types_mapped"] = sorted(+ REF_LABEL_TO_OFFICIAL.get(l, l) for l in set(labels.tolist())+ )+ break+ return means, diag+++def reanchor_diag(labels_pick: np.ndarray, from_a: np.ndarray, fused_rows: np.ndarray,+ shared_types: set, ref_means: dict) -> dict:+ """Gate diagnostics: how many fused b cells a reference anchor could act on."""+ ref_types = set(ref_means)+ anchor_types = sorted(shared_types & ref_types)+ n_fused = int(fused_rows.size)+ if n_fused:+ labs = np.asarray(labels_pick).astype(str)[fused_rows]+ n_anchor = int(np.isin(labs, anchor_types).sum())+ else:+ n_anchor = 0+ return {+ "shared_types": sorted(shared_types),+ "ref_anchored_types": anchor_types,+ "n_shared_ref_types": len(anchor_types),+ "n_fused": n_fused,+ "n_anchored": n_anchor,+ "frac_anchored": float(n_anchor / n_fused) if n_fused else 0.0,+ "gate_pass": bool(len(anchor_types) >= MIN_SHARED_TYPES+ and (n_anchor / n_fused if n_fused else 0.0) >= MIN_COVERAGE),+ }+++def apply_reanchor(expr: np.ndarray, fused_rows_by_type: dict, ref_means: dict,+ gamma: float, varfix: bool) -> dict:+ """In-place X_new = (1-gamma)*X_b + gamma*M_ref(type) for fused b rows.++ Only genes covered by the reference are anchored. gamma == 0 is a+ no-op (guard, mechanism-off control).+ """+ diag = {"n_anchored": 0, "cos_before": 0.0, "cos_after": 0.0,+ "std_ratio_mean": 1.0}+ if gamma <= 0.0 or not fused_rows_by_type:+ return diag+ cos_b, cos_a, std_ratios = [], [], []+ for lab, rows in sorted(fused_rows_by_type.items()):+ m = ref_means.get(lab)+ if m is None or rows.size == 0:+ continue+ cover = m > 0+ if not cover.any():+ continue+ Xb = expr[rows]+ cos_b.append(_cos_to(Xb, m))+ Xnew = Xb.copy()+ Xnew[:, cover] = (1.0 - gamma) * Xb[:, cover] + gamma * m[cover]+ if varfix:+ sd0 = Xb.std(0)+ sd1 = Xnew.std(0)+ ok = sd1 > 1e-9+ Xnew = Xnew.copy()+ Xnew[:, ok] = Xnew[:, ok] * (sd0[ok] / sd1[ok])+ np.clip(Xnew, 0.0, None, out=Xnew)+ expr[rows] = Xnew+ cos_a.append(_cos_to(expr[rows], m))+ s1 = expr[rows].std(0)+ good = sd0_ref = Xb.std(0)+ both = (good > 1e-9) & (s1 > 1e-9)+ if both.any():+ std_ratios.append(float(np.mean(s1[both] / good[both])))+ diag["n_anchored"] += int(rows.size)+ if cos_b:+ diag["cos_before"] = float(np.mean(cos_b))+ diag["cos_after"] = float(np.mean(cos_a))+ if std_ratios:+ diag["std_ratio_mean"] = float(np.mean(std_ratios))+ return diag+++def _cos_to(X: np.ndarray, v: np.ndarray) -> float:+ num = X @ v+ den = np.linalg.norm(X, axis=1) * (np.linalg.norm(v) + 1e-12) + 1e-12+ return float(np.mean(num / den))diff --git a/solution/nn_fuse.py b/solution/nn_fuse.pyindex bbe9388..dd1fdaf 100644--- a/solution/nn_fuse.py+++ b/solution/nn_fuse.py@@ -20,6 +20,7 @@ from src.task2_spatial.frame import align_pair, log_interp, rms_radius, scale_to from src.task2_spatial.methods import _jitter, _limits, _pack_expr from src.task2_spatial.transport import as_dense +from expr_reanchor import apply_reanchor from spatial_mix import spatial_mix_indices NN_MIN_TYPE_CELLS = 5@@ -38,7 +39,7 @@ def fuse_nn(coords: np.ndarray, labels_pick: np.ndarray, from_a: np.ndarray, displacement): X_b <- (1-beta)*X_b + beta*X_a_nn. """ diag = {"types": {}, "n_fused": 0, "disp_std_mean": 0.0, "nn_dist_before_mean": 0.0,- "cos_before": 0.0, "cos_after": 0.0}+ "cos_before": 0.0, "cos_after": 0.0, "fused_rows_by_type": {}} if alpha == 0.0: return diag labels_a = np.asarray(labels_a).astype(str)@@ -66,6 +67,7 @@ def fuse_nn(coords: np.ndarray, labels_pick: np.ndarray, from_a: np.ndarray, disp[:, :fuse_ndim] = alpha * (xa[idx][:, :fuse_ndim] - pos[:, :fuse_ndim]) coords[rows_b] = pos + disp diag["n_fused"] += int(rows_b.size)+ diag["fused_rows_by_type"][lab] = rows_b diag["types"][lab] = { "n_b": int(rows_b.size), "nn_dist": float(np.mean(dist)),@@ -112,7 +114,8 @@ def _cos_mean(X: np.ndarray, Y: np.ndarray) -> float: def interpolate_fuse(stage_a, stage_b, t: float, params: dict, cells_per_bin: int = 100, ndim: int = 2, alpha: float = 1.0, fuse_ndim: int = 3,- beta: float = 0.0, varfix: bool = False):+ beta: float = 0.0, varfix: bool = False,+ ref_means: dict | None = None, gamma: float = 0.0, rvarfix: bool = False): t = float(t) damp = float(params.get("scale_damp", 1.0)) align = str(params.get("align", "procrustes"))@@ -148,6 +151,15 @@ def interpolate_fuse(stage_a, stage_b, t: float, params: dict, expr=expr if beta > 0 else None, expr_a=as_dense(stage_a.X) if beta > 0 else None, ia=ia, beta=float(beta), varfix=bool(varfix))+ fused_rows_by_type = diag.pop("fused_rows_by_type", {})+ ref_means = ref_means or {}+ gate = {"ref_types": sorted(ref_means), "fused_types": sorted(fused_rows_by_type),+ "anchor_types": sorted(set(fused_rows_by_type) & set(ref_means)),+ "n_anchorable": int(sum(fused_rows_by_type[l].size+ for l in set(fused_rows_by_type) & set(ref_means))),+ "n_fused": int(diag["n_fused"])}+ gate["frac_anchorable"] = float(gate["n_anchorable"] / gate["n_fused"]) if gate["n_fused"] else 0.0+ ra = apply_reanchor(expr, fused_rows_by_type, ref_means, float(gamma), bool(rvarfix)) coords = _jitter(coords, rng) coords = scale_to_rms(coords, target_rms) info.update(@@ -166,5 +178,10 @@ def interpolate_fuse(stage_a, stage_b, t: float, params: dict, cos_before=diag["cos_before"], cos_after=diag["cos_after"], fuse_types=diag["types"],+ reanchor_gamma=float(gamma), reanchor_varfix=bool(rvarfix),+ reanchor_n=int(ra["n_anchored"]),+ reanchor_cos_before=ra["cos_before"], reanchor_cos_after=ra["cos_after"],+ reanchor_std_ratio=ra["std_ratio_mean"],+ reanchor_gate=gate, ) return expr, coords.astype(np.float32), infodiff --git a/solution/run.py b/solution/run.pyindex 0218580..5c59c19 100644--- a/solution/run.py+++ b/solution/run.py@@ -31,6 +31,7 @@ from src.task2_spatial.methods import interpolate from src.task2_spatial.sample import take from src.task2_spatial.view_io import board_params, interp_bracket, load_manifest, panel_genes, read_stage, write_t2 +from expr_reanchor import load_reference from nn_fuse import interpolate_fuse from shape_interp import interpolate_shape from spatial_mix import interpolate_spatial@@ -47,6 +48,8 @@ NN_FUSE_ALPHA = float(os.environ.get("NN_FUSE_ALPHA", "1.0")) NN_FUSE_NDIM = int(os.environ.get("NN_FUSE_NDIM", "3")) EXPR_BLEND_BETA = float(os.environ.get("EXPR_BLEND_BETA", "0.0")) EXPR_BLEND_VARFIX = os.environ.get("EXPR_BLEND_VARFIX", "0") != "0"+EXPR_REANCHOR_GAMMA = float(os.environ.get("EXPR_REANCHOR_GAMMA", "0.0"))+EXPR_REANCHOR_VARFIX = os.environ.get("EXPR_REANCHOR_VARFIX", "0") != "0" def main() -> None:@@ -74,15 +77,22 @@ def main() -> None: cells_per_bin=CELLS_PER_BIN, ndim=BIN_NDIM, blend=SHAPE_BLEND, shift_clamp=SHAPE_SHIFT_CLAMP) elif NN_FUSE and SPATIAL_STRATIFY:+ ref_means, ref_diag = ({}, {})+ if EXPR_REANCHOR_GAMMA > 0 or os.environ.get("REANCHOR_DIAG"):+ ref_means, ref_diag = load_reference(args.data, manifest, genes) expr, coords, info = interpolate_fuse(stage_a, stage_b, t, params, cells_per_bin=CELLS_PER_BIN, ndim=BIN_NDIM, alpha=NN_FUSE_ALPHA, fuse_ndim=NN_FUSE_NDIM,- beta=EXPR_BLEND_BETA, varfix=EXPR_BLEND_VARFIX)+ beta=EXPR_BLEND_BETA, varfix=EXPR_BLEND_VARFIX,+ ref_means=ref_means, gamma=EXPR_REANCHOR_GAMMA,+ rvarfix=EXPR_REANCHOR_VARFIX)+ if ref_diag:+ info["ref_diag"] = ref_diag elif SPATIAL_STRATIFY: expr, coords, info = interpolate_spatial(stage_a, stage_b, t, params, cells_per_bin=CELLS_PER_BIN, ndim=BIN_NDIM) else: 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", "n_from_a", "n_from_b", "n_remap", "frac_remap", "n_clamped", "nn_alpha", "n_fused", "frac_fused", "disp_std_mean", "nn_dist_before_mean", "expr_blend_beta", "cos_before", "cos_after")}+ keep = {k: info.get(k) for k in ("t", "n", "rms_a", "rms_b", "out_rms", "n_shared_types", "z_dot", "z_flipped", "align", "n_from_a", "n_from_b", "n_remap", "frac_remap", "n_clamped", "nn_alpha", "n_fused", "frac_fused", "disp_std_mean", "nn_dist_before_mean", "expr_blend_beta", "cos_before", "cos_after", "reanchor_gamma", "reanchor_n", "reanchor_cos_before", "reanchor_cos_after", "reanchor_std_ratio", "reanchor_gate", "ref_diag")} print(json.dumps({"bracket": [a["stage"], b["stage"]], **keep}, default=float), file=sys.stderr) if os.environ.get("SHAPE_DIAG"): print(json.dumps(info.get("shape_types", {}), default=float), file=sys.stderr)
调研来源?调研员查到并用到的知识条目和文献检索结果(只列标题和编号)。
用到的知识库条目
| 编号 | 标题 | 出处 |
|---|---|---|
| k007 | Interval staging and held-out-window filtering of external data | notes/official/来件/virtualembryo.ai/rules.md |
| k027 | Joint expression-geometry generation with relative geometry | notes/competition/03_solution_landscape.md |
| k026 | Canonicalise predicted 3D coordinates before submission | notes/pitfalls/04_scorer_invariance.md |
分析结果?分析员写的 ANALYSIS.json:改了什么、各组分数怎么变、假设是否成立、经验和下一步建议。
| 改了什么 | 新增 expr_reanchor.py 并接入 nn_fuse.py/run.py,实现外部 MOSTA E9.5 参考型均值的表达再锚定(γ、varfix、标签门诊断);但门诊断失败(严格共有型 0、唯一可靠映射 NCC 仅覆盖 341/2273=15% 融合细胞),按 PLAN 第 1 步放弃 γ 网格,提交 γ=0,输出与父节点 13 逐位一致。 |
|---|---|
| 各组分数的变化 | cell_state:噪声内(+0.00,66.95→66.95) expression_change:噪声内(实为 +0.00,64.37→64.37,输出与父逐位一致) local_spatial:噪声内(+0.00,56.83→56.83) shape_scale:噪声内(+0.00,54.49→54.49) |
| family_id | T2HI-07 |
| 假设是否成立 | 否 |
| 经验 |
|
| mechanism_active | 否 |
| 下一步建议 |
|
对话摘要?每个角色和大模型对话的统计:轮数、工具调用、用时、token 数和最后的回答摘录;原始记录只给路径。
只给统计和最后回答的摘录;完整对话请到原始记录位置里列出的文件看。
分析员
| 角色?调研员写计划、工程师改代码、分析员解读分数、审查员检查作弊。 | 分析员 alibaba-token-plan-cn/qwen3.8-max |
|---|---|
| 调用次数 | 1 次 |
| 轮数?大模型一共回复了几轮(每轮可以调用多个工具)。 | 3 |
| 工具调用?大模型调用读文件、执行命令等工具的次数,按工具名统计。 | 共 3 次:bash 2、write 1 |
| 用时 | 不到 1 分 |
| token 数?输入 / 输出(含思考)的 token 数,来自接口返回的用量。 | 输入 14,170 · 输出 1,114 · 思考 629 |
| 任务(第一行) | 分析节点 n15 的打分结果,写 ANALYSIS.json |
| 最后的回答(摘录) | ANALYSIS.json written |
| 原始记录位置?完整对话记录在 Spark 上的文件路径;看板不复制原始内容。 | /home/spark-longxinyang/vec/runs/formal/20261003-004922-search-t2-heart-interp-g24/nodes/15/analyst.jsonl 9 KB /home/spark-longxinyang/vec/runs/formal/20261003-004922-search-t2-heart-interp-g24/nodes/15/analyst.stderr |
工程师
| 角色 | 工程师 alibaba-token-plan-cn/qwen3.8-max |
|---|---|
| 调用次数 | 1 次 |
| 轮数 | 17 |
| 工具调用 | 共 21 次:bash 19、write 2 |
| 用时 | 10 分 |
| token 数 | 输入 49,652 · 输出 8,844 · 思考 10,564 |
| 任务(第一行) | 按计划修改程序:外部MOSTA E9.5型均值表达再锚定(NN坐标融合后,b细胞→真实目标流形) |
| 最后的回答(摘录) | **做了什么**:按 PLAN T2HI-07 实现了外部 MOSTA E9.5 型均值表达再锚定(`expr_reanchor.py`,γ/varfix/门诊断全部接线,external 缺失时优雅退化)。第 1 步标签门诊断失败:参考标签是解剖区域词汇,与官方 5 个共有型严格交集为 0;唯一可靠谱系映射 Neural crest→NCC 只覆盖 341/2273=15% 融合细胞(<30%、1 型<3)。按 PLAN 硬停止规则放弃 γ 网格,提交 γ=0 默认。 **查分结果**:1 次(余 19)。γ=0 控制 A 半 60.07(64.07/66.17/53.78/56.26),与父节点 13 同一输出的控制值完全一致;输出与父逐位一致(X 与坐标 array_equal),vec-check ok,运行 ~2s。机制可用性本地验证:γ=1 锚定 341 个 NCC 细胞、cosine 0.36→0.99,但型内 std 塌缩到 3%,印证风险 2。 **下一步最值得试**:(1) 标签无关的参考对齐(表达空间最近邻/OT 把 MOSTA 细胞投到官方型上再算锚点),绕开区域级词汇问题,但需防型均值塌缩——建议 γ≤0.3 且以 cell_state 降>1 为硬停;(2) 表达侧已两次证伪(节点 13 混合、本节点门失败),剩余增益更可能在把 α=1.0 NN 融合底座拿到 final 括号验证(31 共有型,融合覆盖率远高于 12.9%);(3) shape_scale 54.5 仍是最弱组分,但节点 11 弥散、节点 9 形状插值均无效,需要新的坐标分布机制而非再调参。 |
| 原始记录位置 | /home/spark-longxinyang/vec/runs/formal/20261003-004922-search-t2-heart-interp-g24/nodes/15/engineer.jsonl 120 KB /home/spark-longxinyang/vec/runs/formal/20261003-004922-search-t2-heart-interp-g24/nodes/15/engineer.stderr |
调研员
| 角色 | 调研员 alibaba-token-plan-cn/qwen3.8-max |
|---|---|
| 调用次数 | 1 次 |
| 轮数 | 1 |
| 工具调用 | 共 0 次:— |
| 用时 | 1 分 |
| token 数 | 输入 11,487 · 输出 1,161 · 思考 1,688 |
| 任务(第一行) | 为节点 n15(改进,父节点 n13)写改进计划 PLAN.json |
| 最后的回答(摘录) | ame": "外部MOSTA E9.5型均值表达再锚定(NN坐标融合后,b细胞→真实目标流形)", "motivation": "父节点13(=父12,60.66)四组分中 shape_scale 54.49、local_spatial 56.83 最弱,但节点11(各向同性弥散)与节点13(表达β混合)已分别证明这两组的常见改法无效;节点13 ANALYSIS 明确下一步是用 external/mosta_e95_v0 引导的表达侧调整。节点13 证伪的是'在两阶段真实谱之间插值出中间表达谱'(cell_state mmd 惩罚与 DE 增益等量抵消),而把 b 侧细胞表达替换/拉向外部 E9.5 参考的同型真实均值不产生插值谱,是未被试过且与教训兼容的方向。", "approach": "步骤:1) 读 external/mosta_e95_v0(manifest/基因面板/标签与视图同格式),按型算每基因均值与 std;先只做标签诊断(若与官方共有型 <3 或覆盖率 <30%,直接放弃本方向、提交与父逐位一致的默认)。2) 在 nn_fuse.py 融合后新增 expr_reanchor:对每个两阶段共有型且参考中也存在的型,b 侧被融合细胞做 X_new=(1−γ)X_b+γM_ref(type,gene),逐细胞、型级锚点、不跨型。3) 可选 VARFIX:重锚后把该子集每基因 std 恢复到重锚前(clip≥0),防止均值拉动压缩型内方差。4) 参数网格:γ=0(对照), 0.5, 1.0,各含/不含 varfix,共 5 次 vec-score(A 半、seed0);若最佳净增益 ≤1 分(噪声内)再加 1–2 个中间 γ 或停止,总查分 ≤8。5) 硬停止规则:cell_state 较对照降 >1 分即停(节点13 验证有效)。6) 单输入阶段(b is None)退路:跳过重锚,与现有 fallback 一致。7) 提交规则:仅当某配置净榜分超对照 >1 分且 cell_state 不降时才提交该配置,否则提交 γ=0(与父逐位一致)。", "expected_groups": ["expression_change", "cell_state", "local_spatial"], "risks": "1) MOSTA 标签词汇与官方不一致或共有型太少→机制无细胞可作用;Engineer 第一步先打印标签交集与覆盖率,不达标立即停。2) 向型均值收缩仍会压缩型内分布形状,cell_state/mmd 可能再罚(节点13 varfix 只回收 1/3 损失的教训)→用 VARFIX 变体对照,若 cell_state 降 >1 即停。3) b 侧表达本身可能已比外部参考更接近目标(参考是另一数据集)→若 γ>0 使 expression_change 反降,说明参考锚点劣于原表达,放弃。4) 净增益可能 <1 分噪声→用 A 半多次查分(不同 γ)看组分单调性,不只看总分。", "family_id": "T2HI-07", "mechanism": "NN 坐标融合把 b 侧细胞移到 a 侧邻居旁但表达仍是 b 阶段谱,表达-几何对应失配;用外部 MOSTA E9.5 同型真实均值做锚点,按 γ 把这些细胞的表达拉回目标阶段的真实表达流形(含方差恢复选项),不产生两真实谱之间的插值谱。", "vs_constant_shift": "节点6 的型常数位移用括号内型均值差作为全体细胞同一位移向量,无细胞差异、无外部锚点,结果从 48.68 崩到 51.02;本方案锚点来自外部参考的型内真实均值,只作用于被空间融合、表达-几何失配的 b 侧共有型细胞,位移是逐细胞相对自身表达的收缩且钳在型内方差包络内,目标是替换到真实流形而非沿型间方向平移。", "mechanism_evidence": "诊断输出:被重锚细胞数与覆盖率(n_anchored/frac_anchored)、重锚前后表达与参考型均值的 cosine(应升)、型内每基因 std 变化(不加 varfix 应收缩、加后恢复)、四组分各自变化。关键证据是 cell_state 与 expression_change 同向改善(节点13 是此消彼长的零和),且 local_spatial 不降。", "mechanism_off_control": "γ=0(默认)时重锚代码被 guard 全跳过,输出 X 与坐标应与父节点13 提交版逐位一致(X 非零值与 spatial_3D array_equal 验证),榜分四组分 +0.00;若 γ=0 与父不一致说明接线有副作用,需修复后再网格。", "sources": []} ``` |
| 原始记录位置 | /home/spark-longxinyang/vec/runs/formal/20261003-004922-search-t2-heart-interp-g24/nodes/15/researcher.jsonl 5 KB /home/spark-longxinyang/vec/runs/formal/20261003-004922-search-t2-heart-interp-g24/nodes/15/researcher.stderr |
审查员
| 角色 | 审查员 alibaba-token-plan-cn/qwen3.8-max |
|---|---|
| 调用次数 | 1 次 |
| 轮数 | 8 |
| 工具调用 | 共 11 次:bash 10、write 1 |
| 用时 | 2 分 |
| token 数 | 输入 27,942 · 输出 1,437 · 思考 5,008 |
| 任务(第一行) | 审查节点 n15 的程序是否越界读取、写死目标、钻评分器漏洞 |
| 最后的回答(摘录) | REVIEW.json written |
| 原始记录位置 | /home/spark-longxinyang/vec/runs/formal/20261003-004922-search-t2-heart-interp-g24/nodes/15/reviewer.jsonl 138 KB /home/spark-longxinyang/vec/runs/formal/20261003-004922-search-t2-heart-interp-g24/nodes/15/reviewer.stderr |