Blowfish
Introduction
**Blowfish๋ ๋ถ์ ๋ ์ฑ ์์ธก์ ์ํํ๊ธฐ ์ํด ๊ฐ๋ฐ๋ ๋ํ ์ธ์ด ๋ชจ๋ธ(LLM)์ ๋๋ค.
Qwen3-14B๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ์ธํ๋(Fine-tuning)๋์์ผ๋ฉฐ, ๋จ์ํ ์ด์ง ๋ถ๋ฅ๋ฅผ ๋์ด Chain-of-Thought (CoT) ๋ฐฉ์์ ํตํด ๋ ์ฑ ํ์ ์ ํํ์ /์๋ฌผํ์ ๊ทผ๊ฑฐ๋ฅผ ๋ ผ๋ฆฌ์ ์ผ๋ก ์ค๋ช ํฉ๋๋ค.
์ฌ์ฉ์๊ฐ ์
๋ ฅํ SMILES, Cell Line, Bio Assay, ๊ทธ๋ฆฌ๊ณ ์ฃผ์ RDKit Features์ ์ข
ํฉ์ ์ผ๋ก ๋ถ์ํ์ฌ ์ต์ข
์ ์ผ๋ก ๋
์ฑ ์ฌ๋ถ(๋
์ฑ / ๋น๋
์ฑ)๋ฅผ ํ๋จํฉ๋๋ค.
์ฃผ์ ํน์ง
- Base Model: Qwen3-14B
- Task: ์ด์ง ๋ ์ฑ ์์ธก (Binary Toxicity Prediction) ๋ฐ ๋ถ์ ๊ตฌ์กฐ ๋ถ์
- Language: ํ๊ตญ์ด (์์คํ ์ง์๋ฌธ), ์์ด (ํํ์ ์ถ๋ก ๋ฐ ๋ต๋ณ)
- Input Data:
- SMILES Code
- Cell Line / Cell Type
- Bio Assay Name
- RDKit Features (SHAP Value ๊ธฐ์ค ์/ํ์ Feature ๊ฐ 3๊ฐ)
ํ๋กฌํํธ ํ์
๋ชจ๋ธ์ ์ฑ๋ฅ์ ์ต์ ํํ๊ธฐ ์ํด ํ์ต ์ ์ฌ์ฉ๋ ํ๋กฌํํธ ํ์์ ์ค์ํด์ผ ํฉ๋๋ค.
์์คํ ํ๋กฌํํธ (System Prompt)
"๋น์ ์ ๋ถ์ ๋ ์ฑ ์์ธก์ ํนํ๋ ํํ์ ๋ณดํ/๋ ์ฑํ ์ ๋ฌธ๊ฐ์ ๋๋ค. ์ฌ์ฉ์๋ ๋ ์ฑ/๋น๋ ์ฑ์ ์ํฅ์ ๋ง์ด ๋ผ์น๋ Feature 3๊ฐ์ฉ์ ์ ๊ณตํฉ๋๋ค... (์ค๋ต) ... tool call์ ์ฌ์ฉํ์ง ๋ง์ธ์."
์ฌ์ฉ์ ์ ๋ ฅ ํ ํ๋ฆฟ (User Input Template)
SMILES: {smiles_code}
Cell Line: {cell_line}
Bio Assay Name: {endpoint_category}
Feature NL: {feature_NL_description}
Feature Descript: {feature_detailed_description}
{cot_instruction}
Inference
requirements
pip install transformers torch accelerate
Usage with transformers
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
# 1. ๋ชจ๋ธ ๋ฐ ํ ํฌ๋์ด์ ๋ก๋
model_id = "TeamUNIVA/Blowfish"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
model_id,
torch_dtype=torch.bfloat16,
device_map="auto"
)
# 2. ์์คํ
ํ๋กฌํํธ ์ ์
system_prompt = (
"๋น์ ์ ๋ถ์ ๋
์ฑ ์์ธก์ ํนํ๋ ํํ์ ๋ณดํ/๋
์ฑํ ์ ๋ฌธ๊ฐ์
๋๋ค.\n"
"์ฌ์ฉ์๋ ๋
์ฑ/๋น๋
์ฑ์ ์ํฅ์ ๋ง์ด ๋ผ์น๋ Feature 3๊ฐ์ฉ์ ์ ๊ณตํฉ๋๋ค.\n\n"
"์
๋ ฅ(์ฌ์ฉ์๊ฐ ์ ๊ณต):\n"
"- SMILES\n- Cell Type\n- Cell Line\n- Bio Assay Name\n"
"- ๋
์ฑ์ ๋ผ์น๋ ์ํฅ์ด ํฐ ์์ 3๊ฐ RDKit Feature\n"
"- ๋น๋
์ฑ์ ๋ผ์น๋ ์ํฅ์ด ํฐ ์์ 3๊ฐ RDKit Feature\n\n"
"์ํ ๊ณผ์
(Tasks):\n"
"SMILES ๊ตฌ์กฐ ๋ถ์\n"
"- ๊ณ ๋ฆฌ(๋ฐฉํฅ์กฑ/์ง๋ฐฉ์กฑ), ํคํ
๋ก์์, ์ ํ ์ค์ฌ, ๋ฐ์์ฑ ๋ชจํฐํ, H-๊ฒฐํฉ ๊ณต์ฌ/์์ฉ๊ธฐ ๋ฑ์\n"
" SMILES์์ ์ง์ ๊ด์ฐฐ ๊ฐ๋ฅํ ๋ฒ์๋ก๋ง ๊ธฐ์ .\n\n"
"Cell Type, Cell Line, Assay Name ํน์ง ๋ถ์ ๋ฐ SMILES์ ์ฐ๊ฒฐ\n\n"
"RDKit feature ๋ถ์\n"
"- ๊ฐ feature๊ฐ ์๋ฏธํ๋ ๋ฐ์ ์ผ๋ฐ์ ๋
์ฑ ๋ฆฌ์คํฌ์ ์ฃผ๋ ์ํฅ ์์ฝ.\n"
"- ๊ฐ๋ฅํ ๊ฒฝ์ฐ Assay ๋งฅ๋ฝ(์: ARE ์ฐํ์คํธ๋ ์ค)๊ณผ ์ฐ๊ฒฐ.\n\n"
"์ข
ํฉ ํ๋จ(์ต์ข
๊ฒฐ๋ก )\n"
"- (1) SMILES ๋ชจํฐํ, (2) Cell line/Cell type + Assay ๋งฅ๋ฝ, (3) RDKit feature๋ฅผ ํตํฉํด\n"
" ๋
์ฑ ์ฌ๋ถ๋ฅผ ์ด์ง์ผ๋ก ํ๋จ.\n\n"
"์ถ๋ ฅ ๊ท์น:\n"
"- ๋ณธ๋ฌธ์ ์์ด๋ก ์์ฑ.\n"
"- ๋ง์ง๋ง ์ค์ ์๋ ์ค ํ๋๋ง ๋จ๋
ํ๊ธฐ:\n"
"<answer>toxic</answer>\n"
"<answer>nontoxic</answer>\n\n"
)
# 3. ์
๋ ฅ ๋ฐ์ดํฐ ์์
smiles_code = "O=C(O)/C=C/C(=O)O.O=C(O)/C=C/C(=O)O.O=C(O)/C=C/C(=O)O.CN(C)CCN(Cc1cccs1)c2ccccn2.CN(C)CCN(Cc1cccs1)c2ccccn2"
cell_line = "HepG2 (Liver)"
feature_NL = "Top toxic features: ... / Top non-toxic features: ...",
feature_descript = "Detailed feature descriptions"
bio_assay = "AhR"
instruction = "ํํฉ๋ฌผ O=C(O)/C=C/C(=O)O.O=C(O)/C=C/C(=O)O.O=C(O)/C=C/C(=O)O.CN(C)CCN(Cc1cccs1)c2ccccn2.CN(C)CCN(Cc1cccs1)c2ccccn2์ ๋
์ฑ/๋น๋
์ฑ ์ฌ๋ถ๋ฅผ ํ๋จํ์์ค."
# 4. ํ๋กฌํํธ ๊ตฌ์ฑ
user_content = (
f"SMILES: {smiles_code}\n"
f"Cell Line: {cell_line}\n"
f"Bio Assay Name: {bio_assay}\n"
f"Feature NL: {feature_NL}\n"
f"Feature Descript: {feature_descript}\n\n"
f"{instruction}"
)
# 5. ์ฑํ
ํ
ํ๋ฆฟ ์ ์ฉ ๋ฐ ์์ฑ
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_content}
]
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
inputs = tokenizer([text], return_tensors="pt").to(model.device)
outputs = model.generate(
**inputs,
max_new_tokens=8192,
temperature=0.7,
top_p=0.8,
do_sample=True
)
# 6. ๊ฒฐ๊ณผ ๋์ฝ๋ฉ
response = tokenizer.decode(outputs[0][inputs.input_ids.shape[1]:], skip_special_tokens=True)
print(response)
Acknowledgements
๋ณธ ๊ฒฐ๊ณผ๋ฌผ์ ๊ณผํ๊ธฐ์ ์ ๋ณดํต์ ๋ถ์ ํ๊ตญ์ง๋ฅ์ ๋ณด์ฌํ์งํฅ์์ ์ง์์ ๋ฐ์ ์ํ๋ ใ2025๋ ์ด๊ฑฐ๋AI ํ์ฐ ์ํ๊ณ ์กฐ์ฑ์ฌ์ ใ์ ์ฐ๊ตฌ ์ฑ๊ณผ์ ์ผ๋ถ์ ๋๋ค.
- Downloads last month
- 7