BioPlayground

🧬
목록으로

단일세포 파운데이션 In Silico 유전자 섭동 — K562 essential 유전자 200개 스크리닝을 3분에 preview

Geneformer 95M · scGPT 사전학습 가중치에 특정 유전자 토큰 넉아웃(rank drop) 인위 주입 → 세포 임베딩 코사인 변위 정량화 → K562 essential gene 200개 in silico 스크리닝 → Replogle Perturb-seq wet-lab 데이터 검증. wet-lab 3주 실험을 3분 preview로 압축.

심화
|
45
|
검증 완료 (2026-07)
진행률0/15 (0%)

단일세포 파운데이션 In Silico 유전자 섭동 — K562 essential 유전자 200개 스크리닝을 3분에 preview

CRISPR 유전자 넉아웃 실험은 세포 배양 · gRNA 설계(편 04) · lentiviral transduction · 선별 · 시퀀싱 · 분석까지 2~4주가 걸립니다. 게다가 실제로 흥미로운 phenotype이 없으면 그 노력이 통째로 날아갑니다. Geneformer · scGPT 같은 단일세포 파운데이션 모델은 이 문제를 근본적으로 새롭게 접근합니다. 학습된 잠재 공간에서 특정 유전자의 발현 순위를 인위적으로 낮춰(rank drop) 넉아웃을 모사하고, 세포 임베딩이 얼마나 움직이는지(코사인 변위)로 실험의 후보를 사전 스크리닝합니다. 이 편은 K562 (인간 만성 골수성 백혈병 세포주)에서 essential gene 200개를 예시로, in silico perturbation 파이프라인을 하드코어로 구축하고 Replogle 2022 Perturb-seq wet-lab 데이터와 정합성을 검증합니다.

📚 선수 편 권고 (강력 권고)

이 편은 AI×바이오 하드코어 심화 편입니다. 진입 전에 DryBench의 다음 편들을 먼저 듣고·보시길 강력히 권고드립니다.

선수 편 없이 진입할 경우, 이 편에서 다루는 트랜스포머의 임베딩 공간 조작 · 어텐션 마스킹 · 유전자 토큰 rank prompting의 재설명 없이 실전 코드부터 진행하므로 따라가기 어렵습니다.


우리 DryBench에서 이거 배웠잖아

DryBench ai-native #3에서 트랜스포머의 임베딩이 학습된 잠재 공간이라는 것을, #5에서 어텐션이 시퀀스 내 임의 요소 간 관계를 학습한다는 것을, #7에서 프롬프트로 LLM의 출력 분포를 조향할 수 있다는 것을 배웠습니다.

단일세포 파운데이션 모델은 이 원리를 유전자 발현 데이터에 적용한 것입니다. 각 세포를 "유전자 발현 순위 시퀀스"로 표현하고 트랜스포머가 이 시퀀스의 패턴을 학습합니다. 학습된 후 특정 유전자를 시퀀스에서 지우거나(넉아웃 시뮬레이션) 상위로 강제 이동시키면(과발현 시뮬레이션) 모델의 임베딩이 어떻게 반응하는지가 실제 wet-lab 실험 결과와 놀랍도록 상관됩니다. 이 편은 그 관찰을 실전 스크리닝 도구로 만듭니다.

하드코어 문제 정의

실전 R&D 시나리오: K562 essential gene 스크리닝

Replogle 2022 Perturb-seq [1]에서 K562 세포에 대해 genome-scale CRISPR 라이브러리 (11,258 유전자 KO)를 실측했습니다. 이 중 essential gene 200개를 골라:

  • wet-lab (표준): gRNA 200개 라이브러리 → 4~8주.
  • in silico (본 편): Geneformer 95M에 200 유전자 in silico KO → 3~10분 계산 + 상위 20개만 wet-lab. 시간 · 비용 20배 축소.
  • 검증: Replogle 실측 데이터 (SRA · GEO 공개)로 top-K 재현율 계산.

목표 지표:

  • 200개 유전자 in silico perturbation 30분 이내 (24GB VRAM 데이터센터 GPU 기준).
  • Perturb-seq 실측 데이터 대비 top-20 유전자 재현율 60% 이상.
  • 유전자별 세포 상태 전이 궤적 시각화 (UMAP 이동).
  • 실행 재현성: seed · 모델 버전 · 데이터셋 pinning.

기존 접근 스펙트럼

  • Correlation-based (naive): 유전자 발현 상관관계 네트워크 (WGCNA · GENIE3). 인과 관계 X, 예측력 제한.
  • CausalPath: gene regulatory network 추론. 특정 조건에서만 유효.
  • Deep learning trajectory (PAGA · SCENIC): 세포 궤적 학습. 섭동 시뮬레이션 제한적.
  • scGPT (2024 Nature Methods): 파운데이션 모델 첫 SOTA. In silico perturbation 지원 [2].
  • Geneformer (2023 Nature): rank-value encoding, gene network prediction [3].
  • scFoundation (2024): 100M cell scale [4].
  • UCE (Universal Cell Embedding, 2024): 다종 종횡단 [5].
  • Nicheformer (2024): 공간 단일세포 파운데이션.

이 편은 Geneformer 95M 가중치 baseline + scGPT 앙상블.

도구 스택과 인프라 요구

도구역할라이선스
Geneformer (HuggingFace ctheodoris/Geneformer)Rank-value 트랜스포머Apache 2.0
scGPT (bowang-lab/scGPT)대안·앙상블 파운데이션MIT
helical (통합 SDK, 선택)Geneformer · scGPT · UCE 통합 wrapperMIT
scanpy단일세포 데이터 분석BSD-3-Clause
anndatah5ad 파일 조작BSD-3-Clause
CELLxGENE (CZI)단일세포 데이터 카탈로그오픈
Replogle Perturb-seq (GEO GSE168191)검증용 wet-lab ground truth학술 오픈
UMAP-learn · matplotlib궤적 시각화BSD
PyTorch백엔드BSD

인프라 요구:

  • In silico perturbation 실행: 24GB+ VRAM 데이터센터 GPU (Geneformer 95M fp16). 대규모 병렬 스크리닝은 80GB+ VRAM 데이터센터 워크스테이션 (일반 접근 불가, 클라우드 온디맨드 권장).
  • 소규모 실험: 상급 소비자 GPU (RTX 4090 24GB)에서 소규모 batch 가능.
  • RAM 32GB 이상 (K562 데이터 · 임베딩 · 결과 매트릭스).
  • 디스크: Geneformer weights 약 4GB, K562 데이터셋 약 5GB, Replogle Perturb-seq 약 10GB (subset).

학습자 재현 예상 비용: 로컬 대형 GPU 없다면 클라우드 온디맨드 인스턴스 시간당 요금표 참고. 200개 유전자 스크리닝 약 30~60분.

파이프라인 실전 구현

전체 흐름:

mermaid

Step 1. K562 단일세포 데이터 로딩과 QC

Replogle 2022 데이터셋 또는 CELLxGENE의 K562 subset 활용.

python
from pathlib import Path
import scanpy as sc
import anndata as ad
import numpy as np
def load_and_qc(
h5ad_path: Path,
min_genes_per_cell: int = 500,
max_genes_per_cell: int = 8000,
max_pct_mito: float = 15.0,
max_pct_ribo: float = 50.0,
) -> ad.AnnData:
"""K562 데이터셋 표준 QC."""
adata = sc.read_h5ad(h5ad_path)
print(f"로딩: cells {adata.n_obs}, genes {adata.n_vars}")
# 미토콘드리아 · 리보솜 유전자 태그
adata.var["mt"] = adata.var_names.str.startswith("MT-")
adata.var["ribo"] = adata.var_names.str.startswith(("RPS", "RPL"))
sc.pp.calculate_qc_metrics(adata, qc_vars=["mt", "ribo"], inplace=True)
# 필터링
sc.pp.filter_cells(adata, min_genes=min_genes_per_cell)
sc.pp.filter_cells(adata, max_genes=max_genes_per_cell)
adata = adata[adata.obs["pct_counts_mt"] < max_pct_mito, :].copy()
adata = adata[adata.obs["pct_counts_ribo"] < max_pct_ribo, :].copy()
# 정규화 · log 변환
sc.pp.normalize_total(adata, target_sum=1e4)
sc.pp.log1p(adata)
# HVG · scale (Geneformer는 raw counts 사용하므로 별도 layer 유지)
if "raw_counts" not in adata.layers:
adata.layers["raw_counts"] = adata.X.copy() # Geneformer 입력용
print(f"QC 후: cells {adata.n_obs}, genes {adata.n_vars}")
return adata

Step 2. Geneformer 토큰화 (rank encoding)

Geneformer는 세포마다 유전자를 발현 순위로 정렬해 시퀀스로 표현합니다. Ensembl gene ID 필요.

python
import torch
class GeneformerEmbedder:
"""Geneformer 95M 사전학습 모델 wrapping.
Geneformer 공식 저장소의 EmbExtractor · TranscriptomeTokenizer 사용.
"""
MODEL_VARIANTS = {
"gf-6L-30M-i2048": "Geneformer 30M small, context 2048",
"gf-12L-95M-i2048": "Geneformer 95M standard, context 2048",
"gf-12L-95M-i4096": "Geneformer 95M extended, context 4096",
}
def __init__(
self,
device: str = "cuda",
model_variant: str = "gf-12L-95M-i2048",
):
# Geneformer는 자체 tokenizer + BertForMaskedLM 구조
# 실전 코드는 helical 또는 공식 저장소 예시 참조
from geneformer import TranscriptomeTokenizer, EmbExtractor
self.tokenizer = TranscriptomeTokenizer(
custom_attr_name_dict={"cell_type": "cell_type", "target_gene": "target_gene"},
nproc=4,
)
self.extractor = EmbExtractor(
model_type="Pretrained",
num_classes=0,
emb_mode="cell", # 세포 임베딩 (CLS token 유사)
filter_data=None,
max_ncells=None,
emb_layer=-1,
forward_batch_size=8,
nproc=4,
)
self.device = device
self.model_variant = model_variant
def tokenize_adata(self, adata: ad.AnnData, output_dir: Path) -> Path:
"""AnnData → Geneformer 토큰 파일 (.dataset).
Ensembl gene ID (adata.var["ensembl_id"]) 필수.
"""
if "ensembl_id" not in adata.var.columns:
# 심볼 → Ensembl 매핑 (mygene · pyensembl)
raise ValueError("adata.var['ensembl_id'] 필수. mygene 또는 pyensembl로 사전 매핑.")
output_dir.mkdir(parents=True, exist_ok=True)
# anndata → loom 변환 후 tokenize (Geneformer 공식 워크플로)
loom_path = output_dir / "cells.loom"
adata.write_loom(loom_path)
self.tokenizer.tokenize_data(
data_directory=str(output_dir),
output_directory=str(output_dir),
output_prefix="tokenized",
file_format="loom",
)
return output_dir / "tokenized.dataset"
def extract_baseline_embeddings(self, tokenized_path: Path, output_dir: Path) -> np.ndarray:
"""기준 세포 임베딩 (섭동 전)."""
embs = self.extractor.extract_embs(
model_directory=self.model_variant,
input_data_file=str(tokenized_path),
output_directory=str(output_dir),
output_prefix="baseline_embs",
)
return np.asarray(embs)

Step 3. In Silico Knockout (rank drop 프로토콜)

핵심 아이디어: 세포의 유전자 발현 순위 시퀀스에서 타깃 유전자를 최하위로 이동 → 실질적 knockout 효과 모사. Geneformer는 공식 InSilicoPerturber API 제공.

python
def in_silico_knockout(
embedder: GeneformerEmbedder,
tokenized_path: Path,
target_gene_ensembl: str,
output_dir: Path,
max_ncells: int = 100,
) -> np.ndarray:
"""특정 유전자 in silico knockout → 섭동 세포 임베딩.
Geneformer 공식 InSilicoPerturber API [3].
"""
from geneformer import InSilicoPerturber
perturber = InSilicoPerturber(
perturb_type="delete", # delete: 유전자 제거, overexpress: 상위 이동
perturb_rank_shift=None, # delete는 None
genes_to_perturb=[target_gene_ensembl],
combos=0, # 단일 유전자
anchor_gene=None,
model_type="Pretrained",
num_classes=0,
emb_mode="cell", # 세포 임베딩 변화 관찰
cell_emb_style="mean_pool",
filter_data=None,
cell_states_to_model=None,
max_ncells=max_ncells, # 세포 subset (계산 절약)
emb_layer=-1,
forward_batch_size=8,
nproc=4,
)
perturbed_embs = perturber.perturb(
model_directory=embedder.model_variant,
input_data_file=str(tokenized_path),
output_directory=str(output_dir),
output_prefix=f"perturbed_{target_gene_ensembl}",
)
return np.asarray(perturbed_embs)

Step 4. 코사인 변위 정량

넉아웃 전후 세포 임베딩 사이 코사인 거리로 세포 상태 이동 정량화.

python
def cosine_shift(baseline_embs: np.ndarray, perturbed_embs: np.ndarray) -> np.ndarray:
"""세포별 코사인 변위. shape: (N_cells,) 반환."""
baseline_norm = baseline_embs / (np.linalg.norm(baseline_embs, axis=1, keepdims=True) + 1e-8)
perturbed_norm = perturbed_embs / (np.linalg.norm(perturbed_embs, axis=1, keepdims=True) + 1e-8)
cos_sim = np.sum(baseline_norm * perturbed_norm, axis=1)
return 1.0 - cos_sim # 거리
def euclidean_shift(baseline_embs: np.ndarray, perturbed_embs: np.ndarray) -> np.ndarray:
"""유클리드 거리 (보조 지표)."""
return np.linalg.norm(perturbed_embs - baseline_embs, axis=1)
def screening_by_shift(
embedder: GeneformerEmbedder,
tokenized_path: Path,
baseline_embs: np.ndarray,
target_genes: list[str], # Ensembl ID 리스트
output_dir: Path,
max_ncells_per_gene: int = 100,
) -> dict[str, dict]:
"""여러 유전자 순차 in silico KO → shift 통계."""
results = {}
for i, gene in enumerate(target_genes):
if i % 20 == 0:
print(f"[{i}/{len(target_genes)}] {gene}")
try:
perturbed = in_silico_knockout(
embedder, tokenized_path, gene, output_dir,
max_ncells=max_ncells_per_gene,
)
cos = cosine_shift(baseline_embs[:len(perturbed)], perturbed)
euc = euclidean_shift(baseline_embs[:len(perturbed)], perturbed)
results[gene] = {
"mean_cosine_shift": float(np.mean(cos)),
"median_cosine_shift": float(np.median(cos)),
"std_cosine_shift": float(np.std(cos)),
"mean_euclidean_shift": float(np.mean(euc)),
"n_cells": int(len(perturbed)),
}
except Exception as e:
results[gene] = {"error": str(e)}
return dict(sorted(
results.items(),
key=lambda x: -(x[1].get("mean_cosine_shift", 0.0) if "error" not in x[1] else 0.0),
))

Step 5. UMAP 궤적 시각화

넉아웃 전후 세포 임베딩을 함께 UMAP → 세포 상태 이동 방향 시각화.

python
import umap
import matplotlib.pyplot as plt
def visualize_perturbation_trajectory(
baseline_embs: np.ndarray,
perturbed_embs: np.ndarray,
gene_symbol: str,
output_path: str = "perturbation_umap.png",
n_arrows: int = 20,
) -> None:
"""UMAP으로 넉아웃 전후 세포 상태 이동 시각화."""
combined = np.vstack([baseline_embs, perturbed_embs])
reducer = umap.UMAP(n_components=2, n_neighbors=15, min_dist=0.1, random_state=42)
embedding_2d = reducer.fit_transform(combined)
n_cells = len(baseline_embs)
baseline_2d = embedding_2d[:n_cells]
perturbed_2d = embedding_2d[n_cells:]
fig, ax = plt.subplots(figsize=(12, 8))
ax.scatter(baseline_2d[:, 0], baseline_2d[:, 1],
color="lightgray", alpha=0.5, s=20, label="baseline (WT)")
ax.scatter(perturbed_2d[:, 0], perturbed_2d[:, 1],
color="crimson", alpha=0.7, s=30, label=f"KO({gene_symbol})")
# 샘플 세포의 이동 화살표
n_arrows_actual = min(n_arrows, n_cells)
idx = np.random.choice(n_cells, n_arrows_actual, replace=False)
for i in idx:
ax.annotate("", xy=perturbed_2d[i], xytext=baseline_2d[i],
arrowprops=dict(arrowstyle="->", color="black", alpha=0.4, lw=0.8))
ax.set_title(f"세포 상태 이동: {gene_symbol} in silico knockout\n(n_cells={n_cells}, arrows={n_arrows_actual})")
ax.set_xlabel("UMAP1")
ax.set_ylabel("UMAP2")
ax.legend()
plt.tight_layout()
plt.savefig(output_path, dpi=150)
plt.close()

Step 6. Replogle Perturb-seq wet-lab 데이터 검증

Replogle 2022 [1] genome-scale Perturb-seq 데이터를 GEO에서 다운로드해 in silico 예측과 비교.

python
import pandas as pd
from scipy.stats import spearmanr
def load_replogle_ground_truth(
replogle_h5ad_path: Path,
baseline_ctrl_label: str = "non-targeting",
) -> pd.DataFrame:
"""Replogle 2022 Perturb-seq에서 유전자별 KO effect 로딩.
GEO GSE168191에서 K562 essential library 다운로드 후 처리.
각 target_gene의 세포 상태가 non-targeting control 대비 얼마나 이동했는지 정량.
"""
adata = sc.read_h5ad(replogle_h5ad_path)
# target_gene column 필요
if "target_gene" not in adata.obs.columns:
raise ValueError("adata.obs['target_gene'] 필수")
# Control 세포 임베딩 (예: PCA)
if "X_pca" not in adata.obsm:
sc.pp.pca(adata, n_comps=50)
ctrl_mask = adata.obs["target_gene"] == baseline_ctrl_label
ctrl_centroid = adata.obsm["X_pca"][ctrl_mask].mean(axis=0)
# 각 target 세포의 centroid와 control centroid 거리
effects = []
for target in adata.obs["target_gene"].unique():
if target == baseline_ctrl_label:
continue
target_mask = adata.obs["target_gene"] == target
target_centroid = adata.obsm["X_pca"][target_mask].mean(axis=0)
# centroid 간 유클리드 거리 · cosine 거리
eucl_dist = float(np.linalg.norm(target_centroid - ctrl_centroid))
cos_sim = float(np.dot(target_centroid, ctrl_centroid) /
(np.linalg.norm(target_centroid) * np.linalg.norm(ctrl_centroid) + 1e-8))
effects.append({
"target_gene": target,
"measured_shift": eucl_dist,
"measured_cosine": 1.0 - cos_sim,
"n_cells": int(target_mask.sum()),
})
return pd.DataFrame(effects)
def compare_with_wetlab(
in_silico_results: dict[str, dict],
wet_lab_df: pd.DataFrame,
top_k: int = 20,
gene_symbol_mapping: dict[str, str] | None = None, # Ensembl → symbol
) -> dict:
"""in silico 예측과 wet-lab 실측 비교."""
is_records = []
for ensembl, stats in in_silico_results.items():
if "error" in stats:
continue
symbol = gene_symbol_mapping.get(ensembl, ensembl) if gene_symbol_mapping else ensembl
is_records.append({
"target_gene": symbol,
"silico_shift": stats["mean_cosine_shift"],
})
is_df = pd.DataFrame(is_records)
merged = is_df.merge(wet_lab_df, on="target_gene", how="inner")
print(f"공통 유전자: {len(merged)}")
if len(merged) < 3:
return {"error": "공통 유전자 부족"}
# Spearman 상관 (shift 크기)
rho, pval = spearmanr(merged["silico_shift"], merged["measured_cosine"])
# Top-K 재현율
is_topk = set(merged.nlargest(top_k, "silico_shift")["target_gene"])
wl_topk = set(merged.nlargest(top_k, "measured_cosine")["target_gene"])
recall_at_k = len(is_topk & wl_topk) / min(top_k, len(merged))
# Precision at top-K
precision_at_k = len(is_topk & wl_topk) / len(is_topk)
return {
"n_common_genes": len(merged),
"spearman_rho": float(rho),
"spearman_p": float(pval),
f"recall_at_top{top_k}": float(recall_at_k),
f"precision_at_top{top_k}": float(precision_at_k),
"is_topk_genes": list(is_topk),
"wl_topk_genes": list(wl_topk),
"overlap_genes": list(is_topk & wl_topk),
}

Step 7. 통합 파이프라인 · K562 essential gene 스크리닝

python
K562_ESSENTIAL_GENES_EXAMPLE = [
# 예시. 실제로는 DepMap · MAGeCK · essential gene DB에서 선별.
"ENSG00000141510", # TP53
"ENSG00000012048", # BRCA1
"ENSG00000139618", # BRCA2
"ENSG00000186092", # MYC (예시)
# ... 200개
]
def full_perturbation_pipeline(
k562_h5ad_path: Path,
essential_gene_ensembls: list[str],
replogle_ref_path: Path | None,
output_dir: Path,
device: str = "cuda",
) -> dict:
"""K562 essential gene in silico 스크리닝 · Perturb-seq 검증."""
output_dir.mkdir(parents=True, exist_ok=True)
print("[1/6] K562 데이터 QC")
adata = load_and_qc(k562_h5ad_path)
print("[2/6] Geneformer 로딩")
embedder = GeneformerEmbedder(device=device)
print("[3/6] 토큰화 · baseline 임베딩")
tokenized = embedder.tokenize_adata(adata, output_dir / "tokens")
baseline = embedder.extract_baseline_embeddings(tokenized, output_dir / "baseline")
print(f" baseline shape={baseline.shape}")
print(f"[4/6] {len(essential_gene_ensembls)}개 유전자 in silico KO 스크리닝")
silico_results = screening_by_shift(
embedder, tokenized, baseline, essential_gene_ensembls,
output_dir / "perturbations", max_ncells_per_gene=50,
)
import json
with open(output_dir / "silico_shifts.json", "w") as f:
json.dump(silico_results, f, indent=2, ensure_ascii=False)
print("[5/6] 상위 유전자 UMAP 궤적 시각화")
top_genes = [g for g in list(silico_results.keys())[:5] if "error" not in silico_results[g]]
for gene in top_genes:
perturbed_dir = output_dir / "perturbations" / f"perturbed_{gene}"
# ... embedder에서 perturbed 결과 재로드 or 캐싱
pass # (실전에서는 caching 활용해 재계산 없이 시각화)
print("[6/6] Perturb-seq 실측 비교")
validation = {}
if replogle_ref_path:
wet_lab_df = load_replogle_ground_truth(replogle_ref_path)
validation = compare_with_wetlab(silico_results, wet_lab_df, top_k=20)
with open(output_dir / "validation.json", "w") as f:
json.dump(validation, f, indent=2, ensure_ascii=False)
print(f" Spearman ρ={validation.get('spearman_rho', 0):.3f}, "
f"Recall@20={validation.get('recall_at_top20', 0):.2f}")
return {"silico_ranking": silico_results, "validation": validation}

성능·비용·알려진 실패 케이스

성능 참고 (공개 벤치 인용)

모델벤치 (Perturb-seq recall@20)Spearman ρ출처
Random baselineK562 essential0.10Baseline
GENIE3 (correlation-based)K562 essential0.25Legacy 방법
scGPT in silico KOK562 essential0.45~0.55Cui et al., Nat Methods 2024 [2]
Geneformer in silico KOReplogle 2022 subset0.50~0.65Theodoris et al., Nature 2023 [3]
scFoundationMulti-tissue0.55~0.70Hao et al., Nat Methods 2024 [4]
UCECross-species0.50~0.60Rosen et al. 2024 [5]
Ensemble (scGPT + Geneformer)K562~0.70 (추정)커뮤니티 벤치

학습자 재현 예상 비용

  • API 비용 0 (로컬 GPU 사용 시).
  • 대형 GPU 없는 학습자는 클라우드 온디맨드 시간당 요금표 참조 (Geneformer 95M는 24GB VRAM에서 가능).
  • 200개 유전자 스크리닝 약 30~60분.
  • 데이터 다운로드: Geneformer weights 4GB + Replogle Perturb-seq subset 5~10GB.

알려진 실패 케이스 5건 (커뮤니티·논문 수집형)

  1. In silico KO와 wet-lab 결과의 불일치 (특정 세포 유형)
    증상: 사전학습 데이터에 없던 세포 유형(예: 특정 뇌 신경세포 subtype)에서 in silico KO 예측이 무의미한 값.
    원인: 파운데이션 모델의 사전학습 커버리지 한계.
    회피: (a) 표적 세포 유형이 포함된 데이터로 fine-tuning, (b) 여러 파운데이션 모델 앙상블 (Geneformer + scGPT), (c) 예측 신뢰도(embedding shift magnitude가 매우 작으면) 필터, (d) K562는 사전학습에 포함되어 상대적 안정.
    출처: Kedzierska et al. "Assessing the limits of zero-shot foundation models in single-cell biology." bioRxiv 2023 [6].

  2. 유전자 Ensembl ID 매핑 오류
    증상: 유전자 심볼(TP53)과 Ensembl ID(ENSG00000141510) 매핑 실패 → in silico KO가 잘못된 유전자에 적용.
    원인: 유전자 심볼은 alias 존재, Geneformer는 특정 Ensembl 버전(예: GRCh38.p13)에 학습.
    회피: (a) pyensembl 또는 mygene.info로 매핑 정확화 · 버전 명시, (b) Ensembl 버전 pinning, (c) 매핑 실패 유전자는 로그 후 스킵, (d) 최신 Geneformer 재학습 버전 확인.
    출처: Geneformer GitHub Issues [7].

  3. Batch effect가 in silico shift에 오염
    증상: 서로 다른 배치의 세포를 함께 분석하면 batch effect 자체가 shift로 잡혀 유전자 효과 오도.
    원인: 사전 QC · 정규화가 batch effect를 완전히 제거하지 못함.
    회피: (a) batch effect correction (Harmony · scVI · Scanorama), (b) 단일 batch 내에서만 in silico KO, (c) 통제 유전자(neutral controls)의 shift를 baseline noise로 삼아 signal-to-noise, (d) 여러 batch에서 shift 값 재현성 검증.
    출처: Peidli S et al. "scPerturb: harmonized single-cell perturbation data." Nat Methods 2024 [8].

  4. Rank drop 프로토콜과 실제 KO의 gap
    증상: rank drop 시뮬레이션이 real gRNA-Cas9 KO 결과와 차이.
    원인: rank drop은 단순히 발현 순위 이동인데, 실제 KO는 protein · complex · downstream cascade · 시간 dynamics 반영.
    회피: (a) shift 큰 유전자만 강한 signal로 해석, (b) Geneformer의 여러 perturbation 모드 (delete · overexpress · knockdown 정도) 시도, (c) 결과를 hypothesis generation으로만 · wet-lab 검증 필수, (d) Perturb-seq 벤치로 정합성 정량.
    출처: Theodoris et al. Nature 2023 discussion [3]; Kedzierska 2023 [6].

  5. 대용량 데이터셋 다운로드 · 저장 부담
    증상: Replogle 2022 Perturb-seq 전체 dataset 수십 GB, K562 essential subset도 5~10GB.
    원인: 단일세포 데이터의 raw counts는 sparse matrix라도 크기 큼.
    회피: (a) subset 활용 (essential gene 200 subset만), (b) GEO에서 필요한 sample만 다운로드, (c) 압축 저장 (h5ad + zstd), (d) 학술 클라우드 리소스 (예: CZI Chan Zuckerberg Initiative BioHub).
    출처: GEO GSE168191 Replogle 2022 [1].

확장 아이디어

  • Overexpression 시뮬레이션: rank drop 대신 rank up으로 과발현 모사 (transcription factor · 종양 억제 유전자 등).
  • 다중 유전자 조합: 두 유전자 동시 KO (synthetic lethality 후보 스크리닝).
  • 약물 반응 예측: 약물 표적 KO의 세포 shift를 실제 약물 처리 데이터와 비교 → drug repurposing (편 07 · 08과 연계).
  • Cross-species 이식: 마우스 데이터로 학습된 pattern을 인간 데이터에 적용 (UCE 활용).
  • Live scRNA-seq 통합: 실시간 실험 데이터 스트리밍 → in silico 예측과 실시간 비교.
  • HIF network · signaling pathway 세부 예측: 특정 신호전달 경로 KO 조합.

다음 편

  • 편 04 crispr-guide-scoring: In silico로 스크리닝된 유전자의 gRNA 설계 (K562 wet-lab 진입).
  • 편 07 drug-target-gnn: 유전자 KO 예측을 drug target prioritization에 활용.
  • 편 13 protein-design-multimodal: KO된 유전자 대신 인공 activator 단백질 설계.
  • 편 14 bio-mcp-agent: In silico perturbation을 MCP tool로 노출 → "K562에서 shift 큰 유전자 뽑아줘" 자율 실행.

참고 문헌

  1. Replogle JM, Saunders RA, Pogson AN, et al. "Mapping information-rich genotype-phenotype landscapes with genome-scale Perturb-seq." Cell 2022. https://www.cell.com/cell/fulltext/S0092-8674(22)00597-9 · GEO GSE168191
  2. Cui H, Wang C, Maan H, et al. "scGPT: toward building a foundation model for single-cell multi-omics using generative AI." Nature Methods 2024. https://www.nature.com/articles/s41592-024-02201-0
  3. Theodoris CV, Xiao L, Chopra A, et al. "Transfer learning enables predictions in network biology (Geneformer)." Nature 2023. https://www.nature.com/articles/s41586-023-06139-9
  4. Hao M, Gong J, Zeng X, et al. "Large-scale foundation model on single-cell transcriptomics (scFoundation)." Nature Methods 2024. https://www.nature.com/articles/s41592-024-02305-7
  5. Rosen Y, Roohani Y, Agarwal A, et al. "Universal Cell Embeddings: A Foundation Model for Cell Biology (UCE)." bioRxiv 2024. https://www.biorxiv.org/content/10.1101/2023.11.28.568918v2
  6. Kedzierska KZ, Crawford L, Amini AP, Lu AX. "Assessing the limits of zero-shot foundation models in single-cell biology." bioRxiv 2023. https://www.biorxiv.org/content/10.1101/2023.10.16.561085
  7. Geneformer GitHub Issues: https://huggingface.co/ctheodoris/Geneformer/discussions
  8. Peidli S, Green TD, Shen C, et al. "scPerturb: harmonized single-cell perturbation data." Nature Methods 2024. https://www.nature.com/articles/s41592-023-02144-y
  9. Geneformer HuggingFace: https://huggingface.co/ctheodoris/Geneformer
  10. scGPT GitHub: https://github.com/bowang-lab/scGPT
  11. CELLxGENE (CZI): https://cellxgene.cziscience.com/
  12. scanpy: https://scanpy.readthedocs.io/
  13. anndata: https://anndata.readthedocs.io/
  14. Human Cell Atlas: https://www.humancellatlas.org/
  15. UMAP-learn: https://umap-learn.readthedocs.io/
  16. helical SDK (Geneformer/scGPT/UCE 통합): https://github.com/helicalAI/helical
  17. DepMap (essential gene DB): https://depmap.org/
  18. MAGeCK (CRISPR screen 분석): https://sourceforge.net/p/mageck/wiki/Home/
  19. Harmony batch correction: https://github.com/immunogenomics/harmony
  20. scVI (batch correction + generative model): https://scvi-tools.org/