Virtual Cell Challenge (VCC 2026) 是一個聚焦於生物學與機器學習的年度挑戰賽。
比賽結束來進行一下復盤結案,目前暫定5篇系列文,架構如圖:

系列前言:在機器學習與生物資訊挑戰賽中,大多數的討論都圍繞在「換哪一個神經網路架構」或「怎麼做 Ensemble 刷分」。但在近期參與跨細胞背景的單細胞基因擾動預測(Single-Cell Perturbation Prediction)研究過程中,我們選擇了一條不同的路——在封關鎖定主力模型後,建立一套名為 DENG Cell Audit 的白箱審計工具鏈。本系列共 5 篇,將完整復盤我們如何透過算子追蹤、共變數去混淆、代數分解與無塵室開源工程,並進一步透過 E150 盲測與 Multi-Atlas 融合突破跨背景預測瓶頸,在複雜的高維稀疏矩陣中實踐嚴格的科學防禦。
🔗 開源專案連結:silver131-dev/deng-cell-audit (DENG Cell Audit — by ARiN)
在一般的表格數據或影像任務中,模型輸出一個浮點數向量 y ∈ R^G 就結束了。但在單細胞轉錄組(scRNA-seq)的世界裡,每一個觀測值 X_ig 代表第 i 顆細胞在第 g 個基因上的 UMI 分子計數(Unique Molecular Identifier counts)。
當我們要把從來源背景估計出的對數擾動效應向量 d ∈ R^G(經縮放因子 α 調整),作用到目標背景的控制組細胞矩陣 X ∈ ℤ_≥0^(N × G)(動輒數十萬顆細胞 × 18,533 個基因)時,預測輸出 Y 必須同時遵守三條鐵律(Invariants):
int32),且每個座標的整數化誤差必須嚴格小於 1 個 count。
如果沒有把這三條物理與工程限制寫成可逐層追蹤的「白箱算子」,一旦預測誤差(如 MSE 或 FID)不如預期,你根本無從得知: 到底是上游的效應估計不準,還是下游的整數化算子把訊號給切碎了?
operator.py)為了確保轉換過程不會破壞這三條鐵律,我們設計了四個步驟的轉換管線:
[原整數 UMI] ➔ [1. 設定邊界] ➔ [2. 浮點縮放] ➔ [3. 總預算校正] ➔ [4. 餘數取整] ➔ [最終整數 UMI]
為了讓算子的每一步變形都可被量測,我們在 deng_cell_audit/operator.py 中將轉換過程明確切分為四個可觀測的階段狀態(X ➔ W ➔ Z ➔ Y)。

以下是 deng-cell-audit 中的核心實作(純 NumPy、零黑盒依賴):
def trace_operator(matrix, effect, control_reference, allowed, alpha=1.0):
x = counts(matrix)
d, c = vector(effect, "effect"), vector(control_reference, "control reference")
m = np.asarray(allowed)
require(d.shape == c.shape == m.shape == (x.shape[1],) and m.dtype == np.dtype(bool), "operator axis or mask mismatch")
require(np.all(c >= 0) and np.isfinite(alpha) and alpha >= 0, "invalid reference or alpha")
with np.errstate(over="ignore"):
requested = alpha * d
require(np.isfinite(requested).all(), "effect overflow")
requested[~m] = 0
active = np.flatnonzero(np.abs(requested) > 1e-12)
bounded = np.clip(requested, -2.0, 2.0)
reference = np.maximum(c, .25)
scale = np.clip(1 + np.expm1(bounded) * (1 + 1 / reference), .05, np.exp(2.0))
w, z, y = x.astype(np.float64), x.astype(np.float64), x.copy()
budgets = x[:, active].sum(axis=1, dtype=np.int64)
if len(active):
w[:, active] *= scale[active]
for i, budget in enumerate(budgets):
if budget == 0:
continue
weights = w[i, active]
quota = weights * (float(budget) / float(weights.sum()))
require(np.isfinite(quota).all(), "invalid quota")
allocation = np.floor(quota).astype(np.int64)
remainder = int(budget - allocation.sum())
require(0 <= remainder <= len(active), "invalid rounding remainder")
order = np.argsort(-(quota - allocation), kind="stable")
allocation[order[:remainder]] += 1
z[i, active], y[i, active] = quota, allocation
require(np.all(y <= 2**31 - 1), "output count exceeds int32")
require(np.array_equal(y.sum(axis=1), x.sum(axis=1)), "UMI conservation failed")
require(np.array_equal(y[:, ~m], x[:, ~m]), "excluded coordinates changed")
require(np.all(y[x == 0] == 0), "zero-support invariant failed")
return {"X": x, "W": w, "Z": z, "Y": y.astype(np.int32), "requested": requested,
"bounded": bounded, "scale": scale, "active": active, "budgets": budgets}
注意函式結尾的四行 require(...):每次轉換都會在記憶體中直接斷言 不溢位、全細胞 UMI 總和相等、遮罩外座標不變、以及零支援集不擴張 。任何一項違反,程式立刻拋出 ValueError 中止,絕不讓髒資料流向下游。
當我們把這套演算法放到實際數據中測試時,看到了驚人的一幕:
在轉成整數後,有高達 82.5% ~ 99.4% 的微小浮點調整量,直接變成了 0!
第一時間大家都很恐慌:「天啊!是不是四捨五入把 AI 辛苦預測的訊號全部蒸發掉了?!」
但當我們去計算轉換前後的 總能量保留率( L2 能量) 時,卻發現它竟然高達 93% ~ 101%!
我們進一步將活躍基因按請求強度切成 Top 10% 強效應基因 與 Bottom 90% 弱效應基因,答案瞬間明朗:

如果當時我們只看「歸零率高達 90%」單一指標,就會陷入第一個錯誤直覺:「一定是整數化把模型弄壞了,趕快改寫 rounding 規則!」——但因為我們同時追蹤了 collapse_rate 與 amplitude_ratio_L2,才守住了第一道防線。
我們已將這套審計元件封裝為零外部資料依賴的 Python 套件 deng-cell-audit(支援 Python 3.12+)。你可以直接在 WSL 或 Linux 終端機執行合成示例驗證上述不變量:
git clone [https://github.com/silver131-dev/deng-cell-audit.git](https://github.com/silver131-dev/deng-cell-audit.git)
cd deng-cell-audit
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements-tested.txt
python -m pip install -e . --no-deps
# 跑 49 項自動化數值與邊界測試
python -m pytest -q
# 執行內建 8-cell x 5-gene 合成審計 Demo
python -m deng_cell_audit demo --out results/demo
打開產出的 results/demo/method_demo.json,你就能直接看到 operator_conserves_umi: true 以及 counts_stage_comparison 中對 collapse_rate 與 amplitude_ratio_L2 的同步剖析。
在第 2 篇中,我們會在特定細胞背景看到歸零率與預測誤差呈現高達 ρ = 0.853(Holm 校正 p = 0.0129)的超強相關——究竟這是演算法的漏洞,還是幕後有「隱藏的第三者」在作祟?