๊ธฐ๋ฅ ์์ธ ๋ณด๊ณ
์ ํ์ฑ โ in-loop ๊ฒ์ดํธ + ฮmargin(home-advantage) ๊ธฐ๋ฅ ๋ถ์
๋ถ์ ๋ฃจํธ:
AgenticAI4SCIENCE_pyrosetta_track/repos/ai4sci-kaeri๋์ ํ์ผ:pyrosetta_flow/selectivity_loop.py,pyrosetta_flow/multiobjective.py,data/somatostatin_receptor/curated/native_selectivity_baseline.json๋ชจ๋ ์์น๋ ์์ค/์ธก์ ์ง๋ ์ธ์ฉ. ๋ฏธํ์ธ ํญ๋ชฉ์ "๋ฏธ๊ฒ์ฆ"์ผ๋ก ๋ช ์.
โ ๋์ ์๋ฆฌ
1.1 selectivity_margin (์ ๋ ์ ํ์ฑ)
ํ ํ๋ณด์ SSTR2 ์ ๋ฐํ ๋ณตํฉ์ฒด๋ฅผ off-target ์์ฉ์ฒด 4์ข ์ ๋ํนํ์ฌ ๊ฒฐํฉ ๊ฐ๋๋ฅผ ๋น๊ตํ๋ค.
- off-target ์์ฉ์ฒด ์ ์:
multiobjective.py:333-338DEFAULT_OFFTARGET_RECEPTORS= SSTR1 / SSTR3 / SSTR4 / SSTR5 (curated ๋จ์ผ์ฒด์ธ PDB). - ๋์ผ ํ๋กํ ์ฝ: 2026-06-10๋ถํฐ on-target SSTR2๋ off-target๊ณผ ๋์ผํ
transplant + pre-relax ํ๋กํ ์ฝ๋ก ์ฌ์ธก์ ํ๋ค. ๊ทผ๊ฑฐ ์ฃผ์
multiobjective.py:401-403: "SSTR2 ๋ off-target ๊ณผ ๋์ผ transplant+pre-relax ๋ก ์ฌ์ margin ํธํฅ ์ ๊ฑฐ(์ด์ ์ํฐํฉํธ ์์ )." ์์ฉ์ฒด dict์ SSTR2๋ฅผ ๋ช ์์ ์ผ๋ก ์ถ๊ฐํ๋ ์ฝ๋๋multiobjective.py:405-407. - ๋ณ๋ ฌ ์คํ:
ThreadPoolExecutor(multiobjective.py:404,multiobjective.py:424-425), max_workers = min(6, ์์ฉ์ฒด ์). ์ฃผ์์ ์์ฐจ ~25๋ถ โ ๋ณ๋ ฌ ~6๋ถ/ํ๋ณด(multiobjective.py:403). โป ์ค์ธก ์๊ฐ์ ๋ณธ ๋ถ์์์ ๋ฏธ๊ฒ์ฆ(์ฃผ์ ์ธ์ฉ). - margin ์ ์:
multiobjective.py:434-435 worst = min(offtarget_ddg.values())โ ๊ฐ์ฅ ๊ฐํ(๊ฐ์ฅ ๋ฎ์ ddG) off-target.margin = worst - baselineโ ์์ = SSTR2์ ๋ ๊ฐํ๊ฒ ๊ฒฐํฉ = ์ ํ์ .- ์ฆ margin = min(offtarget ddG) โ sstr2 ddG.
- baseline ์ ํ: ๋์ผ ํ๋กํ ์ฝ SSTR2 ๊ฐ ์ฐ์ , ์คํจ ์ ๋ฃจํ ddG ํด๋ฐฑ(
multiobjective.py:432-433). - fail-closed: NaN ๋ํน ๊ฒฐ๊ณผ๋ None ์ฒ๋ฆฌ(
multiobjective.py:419), off-target์ด ํ๋๋ ์์ผ๋ฉด margin=None ๋ฐํ(multiobjective.py:428-430).
1.2 ฮmargin = home-advantage ๋ณด์
์ ๋ margin์ ํธํฅ๋์ด ์๋ค. ํ๋ณด ๋ณตํฉ์ฒด๊ฐ SSTR2 source ๊ตฌ์กฐ์์ ์ ๋ํ๋ฏ๋ก
native SST-14์กฐ์ฐจ ๋์ผ ํ๋กํ ์ฝ์์ ์(+)์ margin์ ๋ธ๋ค(multiobjective.py:436-437).
๋ฐ๋ผ์ native ๊ธฐ์ค์ ์ ๋นผ์ ๋ณด์ ํ๋ค.
delta_margin = round(margin - nat_margin, 4)(multiobjective.py:438-439).more_selective_than_native = (delta_margin is not None and delta_margin > 0)(multiobjective.py:448).- native ๊ธฐ์ค์ ๋ก๋:
_native_selectivity_baseline()(multiobjective.py:343-358),native_selectivity_baseline.json์marginํ๋๋ฅผ ์ฝ์ด ์บ์.
native baseline ์ค์ธก (native_selectivity_baseline.json:1)
{"sstr2": -61.3475,
"offtarget": {"SSTR1": -40.1563, "SSTR3": -39.0837, "SSTR4": -33.984, "SSTR5": -47.9815},
"margin": 13.37}
- min(offtarget) = SSTR5 = โ47.9815 (๊ฐ์ฅ ๊ฐํ off-target).
- ๊ฒ์ฐ: โ47.9815 โ (โ61.3475) = 13.366 โ 13.37 โ ์ ์ฅ๋ margin๊ณผ ์ผ์น(๊ฒ์ฆ ์๋ฃ).
- ์ฆ native์ home-advantage๋ +13.37์ด๋ฉฐ, ฮmargin > 0 ์ด๋ ค๋ฉด ํ๋ณด์ ์ ๋ margin์ด 13.37์ ๋์ด์ผ ํ๋ค.
1.3 ์กฐ๊ฑด๋ถ in-loop ๊ฒ์ดํธ (ddG ํ๋ก์)
off-target ๋ํน์ ๋น์ธ์(ํ๋ณดร5์์ฉ์ฒด) ๋งค iteration ์ ์ฒด ํ๋ณด์ ๋ชป ๋๋ฆฐ๋ค
(selectivity_loop.py:3-6). ํด๊ฒฐ์ฑ
์ ddG(๋ฃจํ ๋ด ์ค์ธก, ๊ฐํ ์ ํธ)๋ฅผ ์ ๋ง๋ ํ๋ก์๋ก
์ฌ์ฉํ์ฌ ๋ํน ๋์์ ์ ํํ๋ ๊ฒ.
- ๊ฒ์ดํธ ๋ก์ง
SelectivityLeaderboard.should_screen()(selectivity_loop.py:48-56): 1. ์ด๋ฏธ ๋ํนํ ์์ด์ด๋ฉด skip (selectivity_loop.py:50-51). 2. ddG๊ฐ cutoff(โ10.0)๋ณด๋ค ์ฝํ๋ฉด skip (selectivity_loop.py:52-53). 3. ๋ฆฌ๋๋ณด๋ ๋ฏธ์ถฉ์์ด๋ฉด ๋ํน (selectivity_loop.py:54-55). 4. ์ถฉ์ ์ ๊ธฐ์กด top-K ์ต์ฝ์ฒด๋ณด๋ค ddG๊ฐ ๊ฐํ๋ฉด ๋ํน (selectivity_loop.py:56,worst_ddg()=๊ฐ์ฅ ๋์ ddG,selectivity_loop.py:43-46). - ์ ๊ฒฉ ํํฐ
screen_iteration_candidates()(selectivity_loop.py:96-118): fail ์์ + clash โค clash_max + ์ดํฉํ๊ฒฐํฉ(Cys ์์น) ๋ณด์กด(_disulfide_ok,selectivity_loop.py:99-100) + PDB ์กด์ฌ. - ๋ํน ์ํ: iteration๋น
max_screen_per_iter๊ฐ(๊ธฐ๋ณธ 2,selectivity_loop.py:124), ddG ๊ฐํ ์์ผ๋ก ์ ์ฉ(selectivity_loop.py:121). - ๊ฒฐ๊ณผ ๊ธฐ๋ก:
c.extra_scores์ selectivity_margin / delta_margin / offtarget_ddg / sstr2_ddg_sameprotocol ๊ธฐ๋ก(selectivity_loop.py:134-137).
1.4 epoch ๊ฐ ํ์ต (warm-start)
๋ฌดํ ๋ฐ๊ตด ์์ง์์ run ๊ฐ ํ์ต์ ๊ธ๋ก๋ฒ ๋ฆฌ๋๋ณด๋๋ก ์ด์ด์ง๋ค.
seed_from_global()(selectivity_loop.py:23-41): ๊ธ๋ก๋ฒ ๋ฆฌ๋๋ณด๋์์ โ screened_seqs(์ญ๋ ๋ํน ์์ด) โ ์ฌ๋ํน ํํผ, โก ์ญ๋ top-K โ in-loop ๊ฒ์ดํธ ๊ธฐ์ค์ ์ ์ฌ. ๊ฒฐ๊ณผ์ ์ผ๋ก worst_ddg ์๊ณ๊ฐ ๋์ด์ฌ๋ ค์ ธ "์ญ๋ best๋ณด๋ค ์ ๋งํ ํ๋ณด๋ง" ๋ํนํ๋ค.- ํธ์ถ ์์น:
runner.py:495-501(SelectivityLeaderboard ์์ฑ + seed),runner.py:888-897(iteration๋ง๋ค screen_iteration_candidates ํธ์ถ).
โก ์ํฅ
2.1 ํ๋กํ ์ฝ ํธํฅ ์์ (์ /ํ)
- ์์ ์ (~2026-06-09): SSTR2๋ ๋ฃจํ ๋ด ddG(๋ณ๋ ํ๋กํ ์ฝ), off-target์
transplant+pre-relax. ํ๋กํ ์ฝ์ด ๋ค๋ฅด๋ฉด margin์ด ํ๋กํ ์ฝ ์ฐจ์ด๋ฅผ ์ ํ์ฑ์ผ๋ก
์ค์ธํ๋ ์ํฐํฉํธ๊ฐ ๋ฐ์(
multiobjective.py:402์ฃผ์ "์ด์ ์ํฐํฉํธ ์์ "). - ์์ ํ(2026-06-10): SSTR2๋ ๋์ผ transplant+pre-relax๋ก ์ฌ์ธก์
(
multiobjective.py:401-407, 427, 433). margin์ด ํ๋กํ ์ฝ ์ฐจ์ด๊ฐ ์๋ ์์ ์์ฉ์ฒด ์นํ๋ ์ฐจ์ด๋ฅผ ๋ฐ์ํ๊ฒ ๋จ.
2.2 home-advantage ๋ณด์ ์ ์๋ฏธ
source ๊ตฌ์กฐ ์ ๋ ํธํฅ(+13.37)์ ๋นผ๋ฏ๋ก, ฮmargin>0์ "native SST-14๋ฅผ ์ด๊ณผํ๋
์ ํ์ฑ"์ด๋ผ๋ ์๋์ ยท์ ์งํ ์ ํธ๊ฐ ๋๋ค(multiobjective.py:436-437,
selectivity_loop.py:7). ์ ๋ margin๋ง ๋ณด๋ฉด ๊ฑฐ์ ๋ชจ๋ ํ๋ณด๊ฐ ์์๋ผ ๋ณ๋ณ๋ ฅ์ด ์๋ค.
2.3 ๋น์ฉ/ํ์ ์ํฅ
ddG ํ๋ก์ ๊ฒ์ดํธ๋ก ๋ํน ํธ์ถ์ top-K ์ ๋ง ํ๋ณด๋ก ์ ํ โ in-loop์์๋ ์ ํ์ฑ์
์ธก์ ๊ฐ๋ฅํ๊ฒ ๋ง๋ ํต์ฌ ํธ๋ฆญ(selectivity_loop.py:3-6). ๊ฒ์ดํธ๊ฐ ์์ผ๋ฉด ๋งค
iteration ํ๋ณดร5์์ฉ์ฒด ๋ํน์ด ํ์ํด ๋ฌดํ ๋ฃจํ๊ฐ ์ฌ์ค์ ๋ถ๊ฐ๋ฅ.
โข ๊ด๋ จ Action Item (2026-06-10 ์ ํ์ฑ GOAL)
- ์ถ์ฒ:
_workspace/CONTINUOUS_DISCOVERY.md(์ง๋ ). ํต์ฌ ์ ์ ์ธ์ฉ: - "ฮmargin = margin โ native_margin(+13.37) โ home-advantage ๋ณด์ . >0 = native SST-14 ์ด๊ณผ ์ ํ์ฑ."
- "ํต๊ณผ(passing) = ฮmargin>0 & ฮGโคโ15 & ๋ ์ฑโคnative(hc50). ์ค๋ GOAL ์ ์๊ฒฉ ๊ธฐ์ค."
- ์ฆ ๋ณธ ๊ธฐ๋ฅ์ 2026-06-10 "SSTR2 ์ ํ์ฑ" GOAL์ ํต์ฌ ์ธก์ ์ถ์ด๋ฉฐ,
๋ฌดํ ๋ฐ๊ตด ์์ง(
continuous.py)์ ์์ ํ์ต ๋์์ด๋ค(global_selectivity_leaderboard.json). - ๋
์ฑ ๊ฒ์ดํธ(hc50, home-advantage ๋์นญ)๋
multiobjective.py:165, 172, 212์์ ฮmargin๊ณผ ๋์ผ ์ฒ ํ์ผ๋ก ๊ตฌํ๋จ(์ํธ ๋ณด์ ์ถ).
โฃ ์์ฑ๋ (%) + ๊ทผ๊ฑฐ
์ธํ๋ผ ์์ฑ๋: ์ฝ 90%
- ๊ฒ์ดํธยทฮmarginยท๋์ผํ๋กํ ์ฝยท๋ณ๋ ฌยทwarm-startยท์ดํฉํ ๋ณด์กดยทfail-closed ์ ๋ถ ๊ตฌํ๋๊ณ
runner์ ํตํฉ(runner.py:495-501, 888-897). ํ๊ท ํ
์คํธ ์กด์ฌ
(pyrosetta_flow/tests/test_continuous_discovery.py, seed/๊ฒ์ดํธ ์ผ์ด์ค).
- ์ค์ ์ด์ ๋ฐ์ดํฐ ์ถ์ : n_screened_unique=539, n_ingested_total=564
(global_selectivity_leaderboard.json:5-6) โ ํ์ดํ๋ผ์ธ์ด ์ค์ ๋ก ๋๋ ๊ฐ๋๋จ.
๊ณผํ์ ๋ชฉํ(์์๊ธ ์ ํ์ฑ ์
์ฆ) ์์ฑ๋: ๋ฎ์~์ค๊ฐ (์ ์ฑ)
- ฮmargin์ PyRosetta ๋ํน ์ ์ ์ฐจ์ด(in-silico proxy)์ผ ๋ฟ, in-vitro ์นํ๋/
๊ธฐ๋ฅ assay๋ก ๊ฒ์ฆ๋์ง ์์(multiobjective.py:13-17 ์ฃผ์: "ddGยทselectivity_margin
์ in-vitro ํ์ฒญ ์์ ์ฑ/ํฌ๊ณผ๋ assay ๋ก ๊ฒ์ฆ๋์ง ์์๋ค").
- off-target ์์ฉ์ฒด PDB๋ SSTR2 ํ๋ ์์ 0.93~0.95 ์ฌ์ ์ ๋ ฌ๋ curated ๊ตฌ์กฐ
(multiobjective.py:330-332) โ ๊ตฌ์กฐ ์ ๋ ฌ ํ์ง์ด ์ ์ ์ ๋ขฐ๋์ ์ํ.
์ธํ๋ผ/๊ณผํ ๊ตฌ๋ถ ๊ฒฐ๋ก : ์ธก์ ยท๊ฒ์ดํธยทํ์ต ํ์ดํ๋ผ์ธ์ ์ฌ์ค์ ์์ฑ. "์ ํ์ฑ ํ๋ณด ๋ฐ๊ฒฌ"์ด๋ผ๋ ๊ณผํ ๋ชฉํ๋ in-silico ์ ํธ ์์ค์์ ์งํ ์ค์ด๋ฉฐ ์คํ ๊ฒ์ฆ์ ๋ฏธ์ํ(๋ฏธ๊ฒ์ฆ).
โค ํ์ ๊ฐ์น: ์ค์
- ๊ทผ๊ฑฐ(๊ธ์ ): SSTR2 ํ์ ๋ฐฉ์ฌ์ฑ์์ฝํ(์: DOTATATE ๊ณ์ด)์์ SSTR1/3/4/5 ๋๋น ์ ํ์ฑ์ off-target ํก์/๋ฐฉ์ฌ์ ๋ ์ฑ๊ณผ ์ง๊ฒฐ๋๋ ์์์ ํต์ฌ ๋ณ์๋ค. native ๋๋น home-advantage ๋ณด์ ์ผ๋ก "์ ๋ ์ ์ ํธํฅ"์ ์ ๊ฑฐํ๊ณ ์๋ ์ ํ์ฑ๋ง ์ถ์ถํ ๋ฐฉ๋ฒ๋ก ์ in-silico ์ ํ์ฑ ์คํฌ๋ฆฌ๋์์ ์ ์ง์ฑ์ด ๋์ ์ค๊ณ๋ค.
- ๊ทผ๊ฑฐ(ํ๊ณ๋ก ์ธํ ๊ฐ์ ): ฮmargin์ ๋ํน ์ ์ proxy์ด๋ฉฐ ์คํ ๊ฒ์ฆ ๋ถ์ฌ
(
multiobjective.py:13-17). off-target ๊ตฌ์กฐ ์ ๋ ฌยท๋จ์ผ์ฒด์ธ ์ถ์ถ ๊ฐ์ ์ด ๊ฒฐ๊ณผ์ ์ํฅ. ๋ฐ๋ผ์ "์"์ด ์๋ "์ค์" โ ๋ฐฉ๋ฒ๋ก ยท์์ง๋์ด๋ง์ ๋ฐํ ๊ฐ์น ์์ผ๋, ๊ฒฐ๊ณผ์ ์๋ฌผํ์ ์ฃผ์ฅ์ wet-lab ๊ฒ์ฆ ์ ์ ํ์๋ง ์ฑ๋ฆฝ.
โฅ ์ฌ์ฉ๋ฒ
ENV=~/miniforge3/envs/bio-tools/bin/python
cd AgenticAI4SCIENCE_pyrosetta_track/repos/ai4sci-kaeri
# ๋ฌดํ ๋ฐ๊ตด(์ ํ์ฑ ๊ฒ์ดํธ ํฌํจ, STOP ํ์ผ๋ก ์ ์ง)
$ENV scripts/run_continuous_discovery.py \
--input data/somatostatin_receptor/SSTR2_SST14_complex_boltz_1.pdb \
--n-candidates 8 --max-iterations 4 --top-k 5 --selectivity-max-per-iter 2
(์ถ์ฒ: _workspace/CONTINUOUS_DISCOVERY.md ์คํ ์น์
์ง๋
)
- ์ ์ง:
touch _workspace/STOP_DISCOVERY(graceful), ์ฌ์์ ์ rm. - iteration๋น ๋ํน ๊ฐ์ ์กฐ์ :
--selectivity-max-per-iter(โmax_screen_per_iter,selectivity_loop.py:124). - ๊ฒฐ๊ณผ ํ์ธ:
runs/pyrosetta_flow/global_selectivity_leaderboard.json(best_delta_margin, entries์ delta_margin). - ํ๋ก๊ทธ๋จ ์ง์ ์ฌ์ฉ:
from pyrosetta_flow.multiobjective import screen_selectivityโ dict(selectivity_margin, delta_margin, more_selective_than_native, ...) ๋ฐํ (multiobjective.py:361, 440-450).
โฆ ํ์ ์ด์
- SSTR2 ์ ํ์ฑ์ ๋ํน ์ ์ ์ ์ ์๊ณ ์ธก์ ์ด ๋น์ธ๋ค(
selectivity_loop.py:3-6). ddG ํ๋ก์ ๊ฒ์ดํธ๊ฐ ์์ผ๋ฉด ๋ฌดํ ๋ฃจํ์์ ์ ํ์ฑ์ ์ ํ ์ธก์ ํ ์ ์๋ค. - ์ ๋ margin์ source-๊ตฌ์กฐ ํธํฅ์ผ๋ก ๋ณ๋ณ๋ ฅ์ด ์๋ค โ home-advantage ๋ณด์ (ฮmargin)์ด
์์ผ๋ฉด "native ๋๋น ์ค์ ๊ฐ์ "์ ๊ตฌ๋ถํ ์ ์๋ค(
multiobjective.py:436-437). - ๋์ผ ํ๋กํ ์ฝ ๋ณด์ ์ด ์์ผ๋ฉด ํ๋กํ ์ฝ ์ฐจ์ด๋ฅผ ์ ํ์ฑ์ผ๋ก ์ค์ธํ๋ค(์ด์ ์ํฐํฉํธ,
multiobjective.py:402).
๊ฒ์ฆ ์ธ์ฉ ๋ชฉ๋ก
| ์ฃผ์ฅ | ์ธ์ฉ |
|---|---|
| off-target 5์ข ๋์ผ ํ๋กํ ์ฝ ๋ํน | multiobjective.py:333-338, 401-410 |
| margin = min(offtarget) โ sstr2 | multiobjective.py:434-435 |
| ฮmargin = margin โ native_margin | multiobjective.py:438-439 |
| native baseline +13.37 (๊ฒ์ฐ 13.366) | native_selectivity_baseline.json:1 |
| ์กฐ๊ฑด๋ถ ddG ๊ฒ์ดํธ | selectivity_loop.py:48-56 |
| ์ดํฉํ ๋ณด์กด ํํฐ | selectivity_loop.py:99-100 |
| iteration๋น ๋ํน ์ํ(2) | selectivity_loop.py:124 |
| warm-start seed_from_global | selectivity_loop.py:23-41 |
| runner ํตํฉ | runner.py:495-501, 888-897 |
| ์คํ ๊ฒ์ฆ ๋ถ์ฌ disclaimer | multiobjective.py:13-17 |
| GOAL ํต๊ณผ ๊ธฐ์ค | _workspace/CONTINUOUS_DISCOVERY.md |
ํ์ฌ ๋ฆฌ๋๋ณด๋ ์ค์ธก ์์ฝ
์ถ์ฒ: runs/pyrosetta_flow/global_selectivity_leaderboard.json ์ง๋
(2026-06-17 ๋ถ์ ์์ ).
best_delta_margin= +9.1021 (์์ดARCGKFFWKTATSC, margin 22.4721, ddG โ32.1162; ํ์ผ line 9-17).- ๋ฆฌ๋๋ณด๋ capacity=50, entries 50๊ฑด ์ ๋ถ delta_margin > 0 (์ต์ +0.3777, ์ต๊ณ +9.1021). โ ์ฆ native(+13.37)๋ฅผ ์ด๊ณผํ๋ ์ ํ์ฑ ํ๋ณด๊ฐ top-50 ๋ฆฌ๋๋ณด๋์ 50๊ฑด ์ ์ฌ๋จ.
- ๋์ ํต๊ณ:
n_screened_unique= 539 (์ค์ off-target ๋ํนํ ๊ณ ์ ์์ด),n_ingested_total= 564 (line 5-6).
์ ์ง์ฑ ์ฃผ์ (ํ๋กฌํํธ ์์น ์ ์ )
- ํ๋กฌํํธ์ "ํ์ฌ best ฮ+0.077, native ์ด๊ณผ ์์"๋ ํ ์ธก์ ๊ณผ ๋ถ์ผ์นํ๋ค. ์ค์ธก best๋ ฮ+0.077์ด ์๋๋ผ ฮ+9.1021์ด๋ฉฐ, top-50 ๋ฆฌ๋๋ณด๋ entries๋ ์ ๋ถ ฮ>0์ด๋ค. "+0.077"์ 2026-06-10 ์ด๊ธฐ ์ค๋ ์ท(๋น์ 1๊ฑด๋ง native ์ด๊ณผ) ๊ธฐ์ค์ผ๋ก ์ถ์ ๋๋ฉฐ, ์ดํ ๋ฌดํ ๋ฐ๊ตด(539 ์์ด ๋ํน)๋ก ๋ค์ ํ๋ณด๊ฐ native๋ฅผ ์ด๊ณผํ ๊ฒ์ผ๋ก ๋ณด์ธ๋ค.
- ๋จ, ์ ฮ>0์ PyRosetta ๋ํน ์ ์ proxy ๊ธฐ์ค์ด๋ฉฐ wet-lab ๊ฒ์ฆ์ด ์๋์ ์ฌ์ฐจ ๋ช
์
(
multiobjective.py:13-17). "native ์ด๊ณผ ์ ํ์ฑ"์ in-silico ์ ํธ ํ์ ์ฃผ์ฅ์ด๋ค.