๊ธฐ๋ฅ ์์ธ ๋ณด๊ณ
07. ํ์ ์ต์ ํ โ Thompson Bandit + ๋ฒ ์ด์ง์ ์ต์ ํ + ์๋ ด ๊ฐ์ง
๋์ ๋ชจ๋
- pyrosetta_flow/bandit.py โ Thompson Sampling ์์น ๋ฐด๋ง (PositionBandit)
- pyrosetta_flow/bayesian_optimizer.py โ GP ๋ฒ ์ด์ง์ ์ต์ ํ (BayesianPeptideOptimizer)
- pyrosetta_flow/convergence.py โ Mann-Whitney U ์๋ ด ๊ฐ์ง (ConvergenceDetector)
- pyrosetta_flow/adapter.py โ warm-start ๋ํผ (get_bandit_guidance / initialize_from_history)
์ฑ๊ฒฉ: ๋ณธ ํด๋ฌ์คํฐ๋ ํ๋ณด๋ฅผ "๋ ๋นจ๋ฆฌยท๋ ๋๋ํ๊ฒ ๊ณ ๋ฅด๋๋ก" ๋๋ ํ์ ๊ฐ์(์ธํ๋ผ) ๊ณ์ธต์ด๋ค. ๊ฒฐ๊ณผ์ ๊ณผํ์ ์ ๋น์ฑ(ddGยท์ ํ์ฑยท๋ ์ฑ)์ ๋ณ๋ ์ค์ฝ์ด๋ง/๊ฐ๋ ๊ณ์ธต์ด ์ฑ ์์ง๋ค. ์ฆ ์ด ๋ชจ๋๋ค์ Action Item(๊ณผํ์ ๊ฒฐ๋ก )์ ์ง์ ๋ฌด๊ดํ ๊ฐ๋ฅ์ฑ์ด ๋๋ค โ ์์ธํ ๊ทผ๊ฑฐ๋ ยง3, ยง7.
โ ๋์ ์๋ฆฌ
1-A. Thompson Sampling ์์น ๋ฐด๋ง (bandit.py)
์ค์ ๊ตฌํ (stub ์๋). ๊ฐ ๋ณ์ด ๊ฐ๋ฅ ์์น๋ฅผ ํ๋์ "์(arm)"์ผ๋ก ๋ณด๊ณ Beta(ฮฑ, ฮฒ) ๋ถํฌ๋ฅผ ์ ์งํ๋ค.
- ๋ณ์ด ๊ฐ๋ฅ ์์น๋ 1-indexed๋ก
[1, 2, 4, 5, 6, 11, 12, 13]๊ณ ์ (bandit.py:24). ์ฆ Cys3ยทCys14(SS bond)์ Trp8ยทLys9ยทThr10(FWKT pharmacophore ํต์ฌ๋ถ ์ผ๋ถ)์ ์ ์งํฉ์์ ์ ์ธ โ ๋๋ฉ์ธ ์ ์ฝ์ด ์์น ํ๋ณด ์์ฒด์ ๋ฐ์๋จ. - ํ์คํ ๋ฆฌ ๋ถํธ์คํธ๋ฉ (
bandit.py:49-100):record_type=="candidate",status=="success", ddG๊ฐ[-60, 200]plausible ๋ฒ์ ๋ด(bandit.py:26-27, 60-61)์ธ ๋ ์ฝ๋๋ง ์ฌ์ฉ. WT(AGCKNFFWKTFTSC) ๊ด์ธก์ด ์์ผ๋ฉด ๊ทธ ํ๊ท ์, ์์ผ๋ฉด ์ ์ฒด ddG์ ์ค์๊ฐ์ baseline์ผ๋ก ์ผ์(bandit.py:74-78). ๊ฐ ํ๋ณด์์ WT ๋๋น ๋ฐ๋ ์์น๋ฅผ ์๋ณ(bandit.py:86-90)ํ๊ณ , ddG๊ฐ baseline๋ณด๋ค ๋ฎ์ผ๋ฉด(๊ฐ์ ) ํด๋น ์์น๋ค์ ฮฑ๋ฅผ +1, ์๋๋ฉด ฮฒ๋ฅผ +1 (bandit.py:95-100). - ์์น ์ ํ (
sample_focus_positions,bandit.py:102-115): ๊ฐ ์์ Beta ๋ถํฌ์์random.betavariate(ฮฑ, ฮฒ)๋ก ํ๋ณธ์ ๋ฝ๊ณ (bandit.py:110) ํ๋ณธ๊ฐ ์์ n๊ฐ ์์น๋ฅผ ๋ฐํ. โ ์ ํต Thompson Sampling (posterior sampling ๊ธฐ๋ฐ ํ์-ํ์ฉ ๊ท ํ).rng์ฃผ์ ๊ฐ๋ฅํด ์ฌํ์ฑ ํ๋ณด. - ์จ๋ผ์ธ ๊ฐฑ์
update(bandit.py:117-124)์ ์ง๋จ์ฉget_arm_stats(๊ธฐ๋๊ฐ ฮฑ/(ฮฑ+ฮฒ), ๊ด์ธก์)(bandit.py:126-137) ์ ๊ณต.
์ฃผ์: ๊ฐ์ /์ ํ๋ฅผ ์ด์ง(Bernoulli) ์ผ๋ก๋ง ๋ณธ๋ค. ddG๊ฐ 1์ ์ข์์ง ๊ฒ๊ณผ 50์ ์ข์์ง ๊ฒ์ ๋์ผํ๊ฒ ฮฑ+1 ์ฒ๋ฆฌ โ ๊ฐ์ ํญ(magnitude)์ ๋ฌด์. ๋ํ ๋ค์ค ์์น๊ฐ ๋์์ ๋ฐ๋ ํ๋ณด๋ credit assignment๊ฐ ๋ชจ๋ ๋ณ์ด ์์น์ ๊ท ๋ฑ ๋ถ๋ฐฐ๋์ด, ์ด๋ ์์น๊ฐ ์ค์ ๊ธฐ์ฌํ๋์ง ๊ตฌ๋ถ ๋ถ๊ฐ(
bandit.py:96-100). ์๊ณ ๋ฆฌ์ฆ ์์ฒด๋ ์ ์์ด๋ ์ ํธ ํด์๋๋ ๊ฑฐ์น ํธ.
1-B. GP ๋ฒ ์ด์ง์ ์ต์ ํ (bayesian_optimizer.py)
์ค์ ๊ตฌํ (stub ์๋). ๋จ, BoTorch ์ ๋ฌด์ ๋ฐ๋ผ 2๋จ ํด๋ฐฑ.
- ์๋ฒ ๋ฉ ๊ณ์ธต (pluggable):
PeptideEmbedderABC(bayesian_optimizer.py:61-90) ์๋ OneHotEmbedderโ ์๊ธฐ๋น 20-dim one-hot ์ฐ๊ฒฐ,max_lenํจ๋ฉ(:96-130). ์ธ๋ถ ์์กด ์์. ์ค์ ๋ก runner๊ฐ ์ฌ์ฉํ๋ ์๋ฒ ๋(runner.py:479).ESM2Embedderโ transformers/torch ํ์, mean-pool last hidden state(:136-183). ์ค์ ๊ตฌํ์ด๋ runner์์ ๋ฏธ์ฌ์ฉ(์ค์น ์์กด).- GP ๋๋ฆฌ๋ชจ๋ธ:
- BoTorch ๊ฐ์ฉ ์
SingleTaskGPร ๋ชฉ์ ํจ์ ๊ฐ์ โModelListGP,fit_gpytorch_mll๋ก marginal likelihood ์ต์ ํ(:362-372). - ๋ฏธ๊ฐ์ฉ ์
_FallbackGPโ numpy๋ง์ผ๋ก RBF ์ปค๋ GP๋ฅผ ์ง์ ๊ตฌํ(์ปค๋ ํ๋ ฌ ์ญํ๋ ฌnp.linalg.inv, ์์ธก ํ๊ท /๋ถ์ฐ)(:189-246). ์ ์ GP ํ๊ท์ ๊ทธ๋๋ก โ stub์ด ์๋๋ผ ์ถ์ํ ์ ์ ๊ตฌํ. - ํ๋ํจ์(acquisition):
- BoTorch ๊ฒฝ๋ก: qNEHVI๋ฅผ import๋ ํ๋(
:33-35), ์ค์ _acquisition_botorch๋ posterior ํ๊ท ์ ref point ๋๋น ๊ฐ์ ๋ ๊ณฑ(product-of-improvements) ์ ์ฐ๋ ๊ฒฝ๋ ํ๋ก์๋ค(:516-531). ์ฃผ์์๋ "full qNEHVI is expensive for large sets"๋ผ๊ณ ๋ช ์(:516-517). โ ์ฆ ์ง์ง qNEHVI hypervolume ๊ณ์ฐ์ ์ํํ์ง ์์. - ํด๋ฐฑ ๊ฒฝ๋ก: ๋ชฉ์ ๋ณ UCB(
mean + 2.0ยทโvar) ํฉ์ฐ(:533-550). - ์ ์ ์์ฑ
suggest(:386-428): reference_seq์ ๋ํด ํ์ฉ ์์น๋ง๋ค 19๊ฐ ๋จ์ผ์ ๋ณ์ด๋ฅผ ์ ๋ถ enumerate(_enumerate_mutations,:430-464)ํ๊ณ ํ๋๊ฐ ์์ n๊ฐ ๋ฐํ. - ๋ชฉ์ ํจ์: runner์์
["ddg"(์ต์ํ), "ecr_score"(์ต๋ํ)]๋ก ์ค์ (runner.py:480-482); ์ต์ํ ๋ชฉ์ ์ ๋ถํธ ๋ฐ์ ์ผ๋ก ํญ์ ์ต๋ํ ๋ฌธ์ ๋ก ๋ณํ(:316-320).
ํตํฉ ๊น์ด ์ฃผ์: scoring_pipeline์์ BO๋
fitโsuggest๋ง ํธ์ถํ๊ณ ๊ทธ ์ ์์ ๋ค์ ํ๋ณด ์์ฑ์ ํผ๋๋ฐฑํ์ง ์๋๋ค. ์ฝ๋ ์ฃผ์์ด ๋ช ์: "Step 4: Bayesian Optimization suggest (๋ถ์ํจ๊ณผ ์์ โ ๋ก๊ทธ๋ง)"(scoring_pipeline.py:246), ๊ฒฐ๊ณผ๋BO suggest top-3 positions: ...์ถ๋ ฅ์ ๊ทธ์นจ(scoring_pipeline.py:270-274). ์ฆ BO๋ ํ์ฌ ๊ด์ฐฐ์/๋ก๊น ๋ชจ๋๋ก๋ง ์๋ํ๋ฉฐ ํ์ ๋ฃจํ๋ฅผ ์ค์ ๋ก ์กฐํฅํ์ง ์๋๋ค.
1-C. Mann-Whitney U ์๋ ด ๊ฐ์ง (convergence.py)
์ค์ ๊ตฌํ (stub ์๋), scipy ๋ฌด์์กด.
_rank_data(convergence.py:14-27): ๋์ ํ๊ท ์์ ์ฒ๋ฆฌ ํฌํจํ ์์ ๋ถ์ฌ โ ์ ์._mann_whitney_u(:30-59): U ํต๊ณ๋ = R1 โ n1(n1+1)/2, n_total โฅ 8์ผ ๋ ์ฐ์์ฑ ๋ณด์ ์๋ ์ ๊ท๊ทผ์ฌ(ฮผ=n1ยทn2/2, ฯ=โ(n1ยทn2ยท(N+1)/12)), ์์ธก p๊ฐ = 2ยท(1โฮฆ(z))(:50-58). n_total<8์ด๋ฉด ๋ณด์์ ์ผ๋ก 1.0 ๋ฐํ(๋ฐ์ดํฐ ๋ถ์กฑ)(:47-48). ฮฆ๋math.erf๊ธฐ๋ฐ ์ ๊ท CDF(:62-64). โ ๊ต๊ณผ์ ์ ๊ท๊ทผ์ฌ ์ ํ. (๋์ ๋ถ์ฐ ๋ณด์ ํญ์ ์๋ต โ ๋์ ๋ง์ ๋ ์ฝ๊ฐ ๋ณด์์ .)ConvergenceDetector.is_converged(:79-143): ์ต๊ทผ window์ ์ง์ window์ top-k ddG๋ฅผ ๋น๊ต. ์๋ ด ํ์ = (p > ์ ์์์ค, ์ฆ ๋์ด์ ์ ์ํ ๊ฐ์ ์์) AND (๋ณ๋๊ณ์ CV < 0.15) ๋์ ์ถฉ์กฑ(:126-129). ์ต์2ยทwindow_sizeiteration ํ์(:94-99). ์ฌ๋์ด ์ฝ์ ๊ถ๊ณ ๋ฌธ์์ด ์์ฑ.
์ค์(ํตํฉ): runner๋ ๋งค iteration
add_iterationโis_converged๋ก ํ๋๊ทธ๋ฅผ ๊ณ์ฐํ๊ณ emitter๋ก ๋ณด๊ณ (runner.py:906-924,1287-1293)ํ์ง๋ง, ๋ฉ์ธ iteration ๋ฃจํ(runner.py:508)์๋conv_flag๊ธฐ๋ฐbreak๊ฐ ์๋ค. ์ฆ ์๋ ด ๊ฐ์ง๋ ์๋ฌธ(advisory)ยทUI ํ์์ฉ์ผ ๋ฟ ๋ฃจํ๋ฅผ ์กฐ๊ธฐ ์ข ๋ฃ์ํค์ง ์๋๋ค. (๋ณ๋์ validation ๋จ๊ณ early-stop์ CV ๊ธฐ๋ฐ์ผ๋ก ์กด์ฌํ๋ โrunner.py:1368-1376โ ์ด๋ ์ต์ข ํ๋ณด ๋ค์ค์ํ ๊ฒ์ฆ์ฉ์ด์ง ๋ณธ ์๋ ด๊ฐ์ง๊ธฐ์ ๋ฌด๊ด.)
โก ์ํฅ (ํ์ ํจ์จ / warm-start)
- warm-start:
get_bandit_guidance(adapter.py:113-128)๊ฐ prior_records๋ก ๋ฐด๋ง์ ๋ถํธ์คํธ๋ฉํดfocus_positions๋ฅผ ์ฐ์ถ. runner๋ Planner๊ฐ focus_positions๋ฅผ ๋น์๋ ๊ฒฝ์ฐ์๋ง ๋ฐด๋ง ์ถ์ฒ์ผ๋ก ์ฑ์ด๋ค(runner.py:592-593,if bandit_guidance and not guidance.get("focus_positions")). โ LLM Planner ์ฐ์ , ๋ฐด๋ง์ ๋ฐ์ดํฐ ๊ธฐ๋ฐ ํด๋ฐฑ. ๋ฌดํ ๋ฐ๊ตด ์์ง์ ๊ธ๋ก๋ฒ ๋ฆฌ๋๋ณด๋ warm-start(runner.py:498)์ ํจ๊ป "์ด์ ์คํ ์ง์ ์ฌ์ฌ์ฉ" ์ถ์ ํ์ฑ. - ํ์ ํจ์จ: ๋ฐด๋ง์ ๊ณผ๊ฑฐ์ ๊ฐ์ ์ ๋ง์ด ๋ธ ์์น๋ก ๋ณ์ด ์์ฐ์ ํธํฅ โ ๋ฌด์์ ์์น ๋๋น ์๋ ด ๊ฐ์ ๊ธฐ๋. ๋ค๋ง ยง1-A์ ๊ฑฐ์น credit assignmentยท์ด์งํ๋ก ์ ํธ๊ฐ ์ฝํด์ง ์ ์์.
- BO ์ํฅ์ ํ์ฌ ๋ฏธ๋ฏธ: ยง1-B๋๋ก ์ ์์ด ๋ฃจํ์ ํผ๋๋ฐฑ๋์ง ์์(๋ก๊น
๋ง), ์ค์ธก ํ์ ํจ์จ ๊ธฐ์ฌ๋ ์ฌ์ค์ 0์ ๊ฐ๊น๋ค. ํฅํ
suggest๊ฒฐ๊ณผ๋ฅผ ํ๋ณด ํ์ ์ฃผ์ ํ๋ฉด ์ํฅ์ด ์๊น. - ์๋ ด ๊ฐ์ง ์ํฅ: ์กฐ๊ธฐ ์ข ๋ฃ๊ฐ ์๋๋ผ "๊ทธ๋ง๋ ๋งํ๋ค"๋ ์ ํธ ์ ๊ณต โ ์ฌ๋/์์ ์ค์ผ์คํธ๋ ์ดํฐ์ ์์ฌ๊ฒฐ์ ๋ณด์กฐ. ๊ณ์ฐ ์์ฐ ์ ๊ฐ ํจ๊ณผ๋ ํ์ฌ ์๋ํ๋์ด ์์ง ์์.
โข ๊ด๋ จ Action Item
์ง์ ๋ฌด๊ด (ํ์ ๊ฐ์์ ์ธํ๋ผ ๊ณ์ธต) โ ๊ทผ๊ฑฐ:
- ์ด ๋ชจ๋๋ค์ ์ด๋ค ํ๋ณด๊ฐ SSTR2 ์ ํ์ ยท์ ๋
์ฑ์ธ์ง๋ฅผ ๊ฒฐ์ ํ์ง ์๋๋ค. ๊ทธ ํ์ ์ ddG ๊ณ์ฐ(PyRosetta)ยท์ ํ์ฑ ๋ฃจํ(
selectivity_loop)ยท์ฝ๋ฆฌํ ๊ฐ๋(pharmacology_guards.py)๊ฐ ํ๋ค. ๋ฐด๋ง/BO/์๋ ด์ "๊ทธ ํ์ ๋์์ ์ด๋ค ์์๋ก ์ผ๋ง๋ ๋นจ๋ฆฌ ๊ณ ๋ฅผ์ง"๋ง ๋ค๋ฃฌ๋ค. - ์ฝ๋ ์์ฒด๊ฐ ์์ ์ ๋ณด์กฐ ์ญํ ๋ก ์ ์ธ: ๋ฐด๋ง์ Planner ๋ฏธ์ง์ ์ ํด๋ฐฑ(
runner.py:592), BO๋ "๋ถ์ํจ๊ณผ ์์ โ ๋ก๊ทธ๋ง"(scoring_pipeline.py:246), ์๋ ด์ break ์๋ advisory(runner.py:508๋ฃจํ์ ๋ฏธ๋ฐ์). - ๋ฐ๋ผ์ ๊ณผํ์ ๊ฒฐ๋ก (Action Item)์ ๋ฐ๊พธ์ง ์์ผ๋ฉฐ, ์ ๊ฑฐํด๋ ๊ฒฐ๊ณผ์ ์ ํ์ฑ์ ๋ณํ์ง ์๊ณ ์๋/์์ฐ๋ง ์ํฅ ๋ฐ๋๋ค.
โ Action Item๊ณผ์ ์ฐ๊ฒฐ๊ณ ๋ฆฌ๋ ๊ฐ์ ์ : "๋์ผ ์์ฐ์ผ๋ก ๋ ์ข์ ํ๋ณด์ ๋๋ฌํ ํ๋ฅ ์ ๋์ธ๋ค"๋ ํจ์จ ์ถ์์๋ง ๊ธฐ์ฌ.
โฃ ์์ฑ๋ % + ๊ทผ๊ฑฐ
| ๋ชจ๋ | ์์ฑ๋ | ๊ทผ๊ฑฐ |
|---|---|---|
bandit.py (Thompson) |
90% | ๋ถํธ์คํธ๋ฉยทํ๋ณธยท๊ฐฑ์ ยท์ง๋จ ๋ชจ๋ ์ค๊ตฌํ, rng ์ฃผ์
์ฌํ์ฑ, ๋๋ฉ์ธ ์์น ์ ์ฝ ๋ฐ์. ํตํฉ๋ ํ์ฑ(runner.py:592). ๊ฐ์ : ์ด์งํ๋ก ๊ฐ์ ํญ ๋ฌด์, ๋ค์ค๋ณ์ด credit assignment ๋ฏธ๋ถ๋ฆฌ(bandit.py:96-100). ์ ์ฉ ํ
์คํธ ๋ค์ ์กด์ฌ(tests/test_bandit.py). |
bayesian_optimizer.py (GP/BO) |
65% | GP(BoTorch+numpy ํด๋ฐฑ)ยท์๋ฒ ๋ยทenumerateยทsuggest ์ค๊ตฌํ. ๋จ (a) qNEHVI๋ import๋ง, ์ค์ ๋ product-of-improvements ํ๋ก์(:516-531); (b) suggest ๊ฒฐ๊ณผ๊ฐ ๋ฃจํ์ ๋ฏธํผ๋๋ฐฑ(scoring_pipeline.py:246, ๋ก๊น
๋ง). ์ฆ "๊ตฌํ๋์ผ๋ ๋ฏธ๋ฐฐ์ ". |
convergence.py (Mann-Whitney) |
85% | ์์ยทUยท์ ๊ท๊ทผ์ฌยทCV ๊ฒ์ดํธ ์ ์ ๊ตฌํ, scipy ๋ฌด์์กด. ๊ฐ์ : ๋์ ๋ถ์ฐ๋ณด์ ํญ ์๋ต, ๊ทธ๋ฆฌ๊ณ ์กฐ๊ธฐ์ข
๋ฃ ๋ฏธ๋ฐฐ์ (advisory only, runner.py:508 ๋ฃจํ์ break ์์). ์ ์ฉ ํ
์คํธ ์กด์ฌ(tests/test_convergence.py). |
adapter.get_bandit_guidance |
95% | ์์ ๋ํผ, ์์ธ ๋น์น๋ช
์ฒ๋ฆฌ(runner.py:467-468), Planner ํฌ๋งท ํธํ. |
ํด๋ฌ์คํฐ ์ข ํฉ โ 80% (์๊ณ ๋ฆฌ์ฆ ๊ตฌํ ํ์ง์ ๋์, ์ผ๋ถ๋ "๊ตฌํ ํ ๋ฏธ๋ฐฐ์ "์ด๋ผ ์ด์ ๊ธฐ์ฌ๊ฐ ์ ์ฌ ์ํ).
โค ํ์ ๊ฐ์น (BO/bandit์ ๋จ๋ฐฑ์ง ์ค๊ณ ์ ์ฉ ์์)
- Thompson Sampling์ ์๊ธฐ ์์น ์ ํ์ ์ ์ฉ: ์์ด ๊ณต๊ฐ์ ์กฐํฉํญ๋ฐ(14aa ร 20AA)์ด๋ผ ์ ์ ํ์ ๋ถ๊ฐ. ์์น๋ณ Beta-Bernoulli ๋ฐด๋ง์ "์ด๋ ์์น๋ฅผ ๊ฑด๋๋ฆด ๋ ๊ฐ์ ํ๋ฅ ์ด ๋์๊ฐ"๋ฅผ posterior๋ก ํ์ต โ ์์น ์์ค ํ์-ํ์ฉ ๊ท ํ์ ๊ฒฝ๋์ผ๋ก ์ ๊ณตํ๋ ํฉ๋ฆฌ์ ๋ชจ๋ธ๋ง. ๋จ๋ฐฑ์ง ๋ณ์ด ์ค๊ณ์์ ๋ฐด๋ง ๊ธฐ๋ฐ ์์น ์ฐ์ ์์ํ๋ ๋ฌธํ์ ์ผ๋ก ํ๋นํ ์ ๊ทผ.
- GP ๊ธฐ๋ฐ ๋ค๋ชฉ์ BO (qNEHVI ์งํฅ): ddG-์ ํ์ฑ ๋ฑ ์์ถฉ ๋ชฉ์ ์ Pareto ์ ์ ์ surrogate๋ก ํ์ํ๋ ๊ฒ์ wet-lab/๋ํน ๋น์ฉ์ด ํฐ ํฉํ์ด๋ ์ค๊ณ์์ sample-efficiency๋ฅผ ๋์ด๋ ํ์ค ํจ๋ฌ๋ค์. ESM-2 ์๋ฒ ๋ฉ ์ต์ ์ ์์ด ์ ์ฌ๋๋ฅผ ์ ์ฌ๊ณต๊ฐ ๊ฑฐ๋ฆฌ๋ก ํ์ํด GP ์ปค๋์ ์๋ฏธ ๋ถ์ฌ โ ์ต์ PLM+BO ๊ฒฐํฉ ํ๋ฆ๊ณผ ์ ํฉ.
- scipy ๋ฌด์์กด Mann-Whitney U + CV ์ด์ค ๊ฒ์ดํธ: ๋จ์ best๊ฐ ์ถ์ ์ด ์๋๋ผ ๋ถํฌ ์์ค(์ค์ ๊ฒฝํฅ ๋ณํ ์์ + ์ ๋ณ๋)์์ plateau๋ฅผ ํต๊ณ์ ์ผ๋ก ํ์ โ ๋ ธ์ด์ฆ ํฐ ddG ์๊ณ์ด์ ๋ํด ๊ณผ์ ํฉ ์๋ ์ ์ง ๊ท์น. ์ฌํ์ฑยท์ด์์ฑ(์ธ๋ถ ์์กด 0) ์ธก๋ฉด์์ ์ค์ฉ์ .
- ์ข ํฉ ์์: "ํฐ LLM Planner + ๋ฐ์ดํฐ ๊ธฐ๋ฐ ๋ฐด๋ง/BO ํด๋ฐฑ + ํต๊ณ์ ์๋ ด"์ ํ์ด๋ธ๋ฆฌ๋๋, ๋น์ผ ๋ฌผ๋ฆฌ ์๋ฎฌ๋ ์ด์ (PyRosetta) ํธ์ถ ์์ฐ์ ํต๊ณ์ ์ผ๋ก ์ ์ฝํ๋ ค๋ active-learningํ ์ค๊ณ๋ก์ ๋ฐฉ๋ฒ๋ก ์ ๊ฐ์น๊ฐ ์๋ค. ๋ค๋ง ๊ฐ์น ์คํ์ BO ํผ๋๋ฐฑยท์๋ ด ์กฐ๊ธฐ์ข ๋ฃ์ ๋ฐฐ์ ์์ฑ์ ๋ฌ๋ ค ์์.
โฅ ์ฌ์ฉ๋ฒ
๋ฐด๋ง (์ง์ )
from pyrosetta_flow.bandit import PositionBandit
bandit = PositionBandit() # ๊ธฐ๋ณธ ์์น [1,2,4,5,6,11,12,13]
bandit.initialize_from_history(records) # experiment_log ๋ ์ฝ๋ ๋ฆฌ์คํธ
focus = bandit.sample_focus_positions(n=3)
๋ฐด๋ง (runner ํตํฉ ๋ํผ) โ adapter.get_bandit_guidance(records, n_focus=3) โ {"focus_positions": [...], "source": "bandit_thompson", "arm_stats": {...}}. runner๋ Planner๊ฐ focus๋ฅผ ๋น์ ์ ๋๋ง ์ฌ์ฉ(runner.py:592-593).
๋ฒ ์ด์ง์ ์ต์ ํ
from pyrosetta_flow.bayesian_optimizer import BayesianPeptideOptimizer, OneHotEmbedder
bo = BayesianPeptideOptimizer(
embedder=OneHotEmbedder(max_len=14),
objectives=["ddg", "ecr_score"],
maximize=[False, True],
)
bo.fit(obs_dicts) # [{"sequence","ddg","ecr_score"}, ...] (>=2๊ฑด)
sugg = bo.suggest(n=3, reference_seq="AGCKNFFWKTFTSC")
runner๋ _HAS_BO ์ ์๋ ์์ฑ(runner.py:476-486)ํ๊ณ scoring_pipeline๊ฐ fitโsuggest(ํ์ฌ ๋ก๊น
์ ์ฉ).
์๋ ด ๊ฐ์ง
from pyrosetta_flow.convergence import ConvergenceDetector
det = ConvergenceDetector(window_size=3, significance_level=0.05)
det.add_iteration(it, top_k_ddgs)
converged, details = det.is_converged() # details: p_value, cv, recommendation
runner๋ ๋งค iteration ํธ์ถยทemitter ๋ณด๊ณ (runner.py:906-924). config ํค: convergence_window_size, convergence_significance, bandit_n_focus(schema.py:37-39).
โฆ ์ ํ์ํ๊ฐ (Action Item ๋ฌด๊ด์์๋)
์ด ํด๋ฌ์คํฐ๋ ๊ฒฐ๋ก ์ ๋ฐ๊พธ์ง ์์ผ๋ฏ๋ก "์์ด๋ ๋๋ ๊ฒ ์๋๋"๋ ์ง๋ฌธ์ด ์์ฐ์ค๋ฝ๋ค. ๊ทธ๋ผ์๋ ํ์ํ ์ด์ ๋ ๋น์ฉ ๊ตฌ์กฐ ๋๋ฌธ์ด๋ค.
- ๋ฌผ๋ฆฌ ์๋ฎฌ๋ ์ด์ ์์ฐ์ด ๋ณ๋ชฉ. PyRosetta ddGยท๋ํน์ ํ๋ณด๋น ์์ด~์๋ถ. ์์ด ๊ณต๊ฐ์ ์กฐํฉํญ๋ฐ์ด๋ผ ๋ฌด์์/์ ์ ํ์์ ๊ฐ์ ์์ฐ์ผ๋ก ํจ์ฌ ์ ์ ์ข์ ํ๋ณด์ ๋๋ฌํ๋ค. ๋ฐด๋ง์ ๋ณ์ด ์์ฐ์ "์ญ์ฌ์ ์ผ๋ก ์ ๋๋ ์์น"๋ก ํธํฅํด ๋์ผ ์์ฐ๋น ๊ธฐ๋ ์ํ์ ๋์ธ๋ค. ๊ฒฐ๋ก ์ ์ ํ์ฑ์ด ์๋๋ผ ๊ฒฐ๋ก ์ ๋๋ฌํ๋ ์๋ยทํ๋ฅ ์ ๋ค๋ฃจ๋ฏ๋ก ์ธํ๋ผ์ด๋ฉฐ, ๋ฌดํ ๋ฐ๊ตด ์์ง์ฒ๋ผ ์ฅ๊ธฐ ๊ฐ๋ ์ ๊ทธ ๋์ ํจ๊ณผ๊ฐ ํต์ฌ ์์ฐ์ด ๋๋ค.
- warm-start = ์ง์์ ๋ง๊ฐ ๋ฐฉ์ง.
initialize_from_history/๊ธ๋ก๋ฒ ๋ฆฌ๋๋ณด๋๋ ์ด์ ์คํ์์ ๋ฐฐ์ด ์์น ์ ํธ๋ฅผ ๋ค์ ์คํ์ด ์์ํ๊ฒ ํ๋ค. ์ด๊ฒ์ด ์์ผ๋ฉด ๋งค ์คํ์ด cold-start๋ก ๋์ผ ํ์ต์ ๋ฐ๋ณต โ ๋ฌดํ ์์ง ์ค๊ณ์ ์ ์ (์ญ๋ ์ง์ ์ฌ์ฌ์ฉ)์ ์ง๊ฒฐ. - ์ ์ง ๊ท์น = ์์ฐ ๋ญ๋น ์ฐจ๋จ. ์๋ ด ๊ฐ์ง๋ plateau๋ฅผ ํต๊ณ์ ์ผ๋ก ์๋ ค, ๊ฐ์ ์๋ iteration์ ์๋ฎฌ๋ ์ด์ ์์ฐ์ ๋ ์ฐ๋ ๊ฒ์ ๋ง๋ ์ ํธ๋ฅผ ์ค๋ค(ํ์ฌ๋ advisory์ง๋ง ์๋ ์ข ๋ฃ๋ก ์น๊ฒฉ ์ ์ฆ์ ์์ฐ ์ ๊ฐ).
- Planner ํ๊ฐ/๊ณต๋ฐฑ์ ์์ ๋ง. ๋ฐด๋ง์ LLM Planner๊ฐ focus_positions๋ฅผ ๋ชป ์ค ๋์ ๋ฐ์ดํฐ ๊ธฐ๋ฐ ํด๋ฐฑ(
runner.py:592)์ผ๋ก, ํ์์ด ๋ฌด๋ฐฉํฅ์ผ๋ก ๋น ์ง๋ ๊ฒ์ ๋ฐฉ์งํ๋ค.
์์ฝ: ๊ณผํ์ ํ์ ์ ์ค์ฝ์ด๋ง/๊ฐ๋๊ฐ, ๊ทธ ํ์ ์ ์ธ์ ยท๋ฌด์์ ๋ํด ํจ์จ์ ์ผ๋ก ๋ด๋ฆด์ง๋ ๋ณธ ํด๋ฌ์คํฐ๊ฐ ์ฑ ์์ง๋ค. Action Item์ ์ง์ ๊ธฐ์ฌํ์ง ์์ง๋ง, ํ์ ๋ ์๋ฎฌ๋ ์ด์ ์์ฐ์ ๊ฐ์ง ๋ฐ๊ตด ํ์ดํ๋ผ์ธ์ ์ฒ๋ฆฌ๋ยท์ง์๊ฐ๋ฅ์ฑ์ ๊ฒฐ์ ํ๋ ๋ณด์กฐ ์ธํ๋ผ๋ก์ ํ์ํ๋ค. ๋ค๋ง BO ํผ๋๋ฐฑ ๋ฐฐ์ ๊ณผ ์๋ ด ๊ธฐ๋ฐ ์๋ ์ข ๋ฃ๊ฐ ๋ฏธ์์ด๋ฏ๋ก, ํ์ฌ ์คํจ ๊ธฐ์ฌ๋ "๋ฐด๋ง warm-start" ์ถ์ ์ง์ค๋์ด ์๊ณ BO/์๋ ด์ ์ ์ฌ๋ ฅ ์ํ์์ ๋ฐํ๋๋ค.
๊ฒ์ฆ ์ธ์ฉ ๋ชฉ๋ก (file_path:line)
bandit.py:24โ ๋ณ์ด ๊ฐ๋ฅ ์์น ๊ณ ์ [1,2,4,5,6,11,12,13](SS bond/pharmacophore ์ผ๋ถ ์ ์ธ)bandit.py:26-27, 60-61โ ddG plausible ๋ฒ์ ํํฐ[-60, 200]bandit.py:49-100โinitialize_from_history๋ถํธ์คํธ๋ฉ (baselineยทcreditยทฮฑ/ฮฒ ๊ฐฑ์ )bandit.py:74-78โ WT ํ๊ท ๋๋ ์ค์๊ฐ baselinebandit.py:95-100โ ๊ฐ์ /์ ํ ์ด์ง โ ฮฑ/ฮฒ +1 (magnitude ๋ฌด์, ๋ค์ค๋ณ์ด ๊ท ๋ฑ credit)bandit.py:102-115โsample_focus_positions(random.betavariateThompson ํ๋ณธ)bandit.py:117-137โupdate/get_arm_statsbayesian_optimizer.py:25-45โ BoTorch ์ ํ์ import ๊ฐ๋bayesian_optimizer.py:96-130โOneHotEmbedder์ค๊ตฌํbayesian_optimizer.py:136-183โESM2Embedder์ค๊ตฌํ(๋ฏธ๋ฐฐ์ )bayesian_optimizer.py:189-246โ_FallbackGPnumpy RBF GP ์ ์ ๊ตฌํbayesian_optimizer.py:362-372โ BoTorchSingleTaskGP/ModelListGPfitbayesian_optimizer.py:430-464โ ๋จ์ผ์ ๋ณ์ด enumeratebayesian_optimizer.py:516-531โ qNEHVI ๋์ product-of-improvements ํ๋ก์bayesian_optimizer.py:533-550โ ํด๋ฐฑ UCB ํ๋ํจ์convergence.py:14-27โ_rank_data๋์ ํ๊ท ์์convergence.py:30-59โ_mann_whitney_u์ ๊ท๊ทผ์ฌ p๊ฐconvergence.py:62-64โmath.erf์ ๊ท CDF (scipy ๋ฌด์์กด)convergence.py:94-99โ ์ต์2ยทwindow_sizeiteration ์๊ตฌconvergence.py:126-129โ ์๋ ด = (p>์ ์์์ค) AND (CV<0.15)adapter.py:113-128โget_bandit_guidancewarm-start ๋ํผrunner.py:462-472โ ๋ฐด๋ง/์๋ ด detector ์ด๊ธฐํrunner.py:476-486โBayesianPeptideOptimizer์๋ ์์ฑ(OneHotEmbedder, ddg/ecr_score)runner.py:508โ ๋ฉ์ธ iteration ๋ฃจํ (conv_flag ๊ธฐ๋ฐ break ๋ถ์ฌ)runner.py:592-593โ Planner ๋ฏธ์ง์ ์์๋ง ๋ฐด๋ง focus ์ ์ฉ (ํด๋ฐฑ)runner.py:906-924, 1287-1293โ ์๋ ด ๊ณ์ฐยทemitter ๋ณด๊ณ (advisory)scoring_pipeline.py:246โ "Step 4: BO suggest (๋ถ์ํจ๊ณผ ์์ โ ๋ก๊ทธ๋ง)"scoring_pipeline.py:249-279โ BOfitโsuggest, ๊ฒฐ๊ณผ ๋ก๊น ๋งschema.py:37-39โ config ํคconvergence_window_size/convergence_significance/bandit_n_focustests/test_bandit.py,tests/test_convergence.pyโ ์ ์ฉ ๋จ์ ํ ์คํธ ์กด์ฌ