GeneLinguaLM-v5 / inference.py
simmani91's picture
Upload GeneLinguaLM v5 model
2bb4367 verified
Raw
History Blame Contribute Delete
6.58 kB
#!/usr/bin/env python3
"""
GeneLinguaLM v5 - ๊ฐ„๋‹จํ•œ ์‚ฌ์šฉ ์˜ˆ์‹œ
Usage:
python inference_example.py
python inference_example.py --sequence "MKTAYIAKQRQISFVKSH..."
"""
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
os.environ['TRANSFORMERS_VERBOSITY'] = 'error'
import sys
import torch
from pathlib import Path
# Project path
sys.path.insert(0, str(Path(__file__).parent))
class GeneLinguaLM:
"""GeneLinguaLM v5 ๋ชจ๋ธ ๋ž˜ํผ"""
def __init__(self, checkpoint_path: str = None, device: str = "cuda"):
self.device = device
if checkpoint_path is None:
checkpoint_path = "checkpoints/instruct_lora_v5/checkpoint_step15732.pt"
print("๐Ÿงฌ GeneLinguaLM v5 ๋กœ๋”ฉ ์ค‘...")
self._load_model(checkpoint_path)
print("โœ… ๋ชจ๋ธ ๋กœ๋”ฉ ์™„๋ฃŒ!")
def _load_model(self, checkpoint_path: str):
from transformers import AutoModel, AutoTokenizer, AutoModelForCausalLM
from peft import PeftModel
from src.models.qformer import QFormer
from src.training.train_instruct import SequenceProjector
# Load checkpoint
checkpoint = torch.load(checkpoint_path, map_location=self.device, weights_only=False)
# ProtBERT (์„œ์—ด ์ธ์ฝ”๋”)
print(" - ProtBERT ๋กœ๋”ฉ...")
self.seq_tokenizer = AutoTokenizer.from_pretrained("Rostlab/prot_bert_bfd", do_lower_case=False)
self.seq_encoder = AutoModel.from_pretrained("Rostlab/prot_bert_bfd")
self.seq_encoder.to(self.device).eval()
# Q-Former
print(" - Q-Former ๋กœ๋”ฉ...")
qformer_ckpt = torch.load('checkpoints/qformer/checkpoint_step7000.pt',
map_location=self.device, weights_only=False)
ckpt_config = qformer_ckpt.get("config", {})
self.qformer = QFormer(
num_queries=ckpt_config.get("num_queries", 32),
embed_dim=ckpt_config.get("embed_dim", 768),
num_layers=ckpt_config.get("qformer_layers", 6),
num_heads=ckpt_config.get("num_heads", 12),
dna_embed_dim=1024,
)
self.qformer.to(self.device)
self.qformer.load_state_dict(checkpoint["qformer_state_dict"])
self.qformer.eval()
# Mistral LLM
print(" - Mistral-7B ๋กœ๋”ฉ...")
self.llm_tokenizer = AutoTokenizer.from_pretrained(
"mistralai/Mistral-7B-Instruct-v0.1", use_fast=False
)
if self.llm_tokenizer.pad_token is None:
self.llm_tokenizer.pad_token = self.llm_tokenizer.eos_token
import tempfile
offload_dir = tempfile.mkdtemp()
self.llm = AutoModelForCausalLM.from_pretrained(
"mistralai/Mistral-7B-Instruct-v0.1",
torch_dtype=torch.float16,
device_map="auto",
offload_folder=offload_dir,
)
lora_path = checkpoint.get("lora_path")
self.llm = PeftModel.from_pretrained(self.llm, lora_path, offload_folder=offload_dir)
self.llm.eval()
# Projector
print(" - Projector ๋กœ๋”ฉ...")
self.projector = SequenceProjector(qformer_dim=768, llm_dim=4096, num_queries=32)
self.projector.load_state_dict(checkpoint["projector_state_dict"])
self.projector.to(self.device).eval()
def describe(self, sequence: str, max_length: int = 200) -> str:
"""
๋‹จ๋ฐฑ์งˆ ์„œ์—ด์„ ์ž์—ฐ์–ด๋กœ ์„ค๋ช…
Args:
sequence: ๋‹จ๋ฐฑ์งˆ ์„œ์—ด (์˜ˆ: "MKTAYIAKQRQISFVKSH...")
max_length: ์ตœ๋Œ€ ์ƒ์„ฑ ํ† ํฐ ์ˆ˜
Returns:
๋‹จ๋ฐฑ์งˆ ๊ธฐ๋Šฅ ์„ค๋ช… (์ž์—ฐ์–ด)
"""
# ์„œ์—ด ์ „์ฒ˜๋ฆฌ (๊ณต๋ฐฑ์œผ๋กœ ๋ถ„๋ฆฌ)
seq_spaced = " ".join(list(sequence.upper().replace(" ", "")))
with torch.no_grad():
# 1. ์„œ์—ด ์ธ์ฝ”๋”ฉ
seq_inputs = self.seq_tokenizer(
seq_spaced,
return_tensors="pt",
truncation=True,
max_length=512,
padding=True,
).to(self.device)
seq_outputs = self.seq_encoder(**seq_inputs)
seq_embeds = seq_outputs.last_hidden_state
# 2. Q-Former
query_outputs = self.qformer(seq_embeds)
# 3. Projector
projected = self.projector(query_outputs)
# 4. LLM ์ƒ์„ฑ (beam search + repetition penalty)
prompt = "<s>[INST] Describe this protein sequence. [/INST]"
prompt_ids = self.llm_tokenizer(prompt, return_tensors="pt").input_ids.to(self.llm.device)
prompt_embeds = self.llm.get_input_embeddings()(prompt_ids)
projected_fp16 = projected.to(device=prompt_embeds.device, dtype=prompt_embeds.dtype)
combined_embeds = torch.cat([projected_fp16, prompt_embeds], dim=1)
# ์ตœ์  ์„ค์ •: beam_search
outputs = self.llm.generate(
inputs_embeds=combined_embeds,
max_new_tokens=max_length,
num_beams=4,
repetition_penalty=1.2,
no_repeat_ngram_size=3,
pad_token_id=self.llm_tokenizer.pad_token_id,
eos_token_id=self.llm_tokenizer.eos_token_id,
)
generated = self.llm_tokenizer.decode(outputs[0], skip_special_tokens=True)
# [/INST] ์ดํ›„ ํ…์ŠคํŠธ๋งŒ ์ถ”์ถœ
if "[/INST]" in generated:
generated = generated.split("[/INST]")[-1].strip()
return generated
def main():
import argparse
parser = argparse.ArgumentParser(description="GeneLinguaLM v5 - ๋‹จ๋ฐฑ์งˆ ์„œ์—ด ์„ค๋ช… ์ƒ์„ฑ")
parser.add_argument("--sequence", type=str, default=None, help="๋‹จ๋ฐฑ์งˆ ์„œ์—ด")
parser.add_argument("--gpu", type=int, default=0, help="GPU ๋ฒˆํ˜ธ")
args = parser.parse_args()
# GPU ์„ค์ •
os.environ['CUDA_VISIBLE_DEVICES'] = str(args.gpu)
# ๋ชจ๋ธ ๋กœ๋“œ
model = GeneLinguaLM()
# ์˜ˆ์‹œ ์„œ์—ด (์—†์œผ๋ฉด ๊ธฐ๋ณธ๊ฐ’ ์‚ฌ์šฉ)
if args.sequence:
sequence = args.sequence
else:
# ์˜ˆ์‹œ: Human Insulin
sequence = "MALWMRLLPLLALLALWGPDPAAAFVNQHLCGSHLVEALYLVCGERGFFYTPKTRREAEDLQVGQVELGGGPGAGSLQPLALEGSLQKRGIVEQCCTSICSLYQLENYCN"
print(f"\n๐Ÿ“Œ ์˜ˆ์‹œ ์„œ์—ด (Human Insulin):")
print(f" {sequence[:50]}...")
# ์„ค๋ช… ์ƒ์„ฑ
print(f"\n๐Ÿ”ฌ ๋ถ„์„ ์ค‘...")
description = model.describe(sequence)
print(f"\n๐Ÿ“ ๊ฒฐ๊ณผ:")
print("-" * 60)
print(description)
print("-" * 60)
if __name__ == "__main__":
main()