| |
| """ |
| 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 |
|
|
| |
| 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 |
|
|
| |
| checkpoint = torch.load(checkpoint_path, map_location=self.device, weights_only=False) |
|
|
| |
| 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() |
|
|
| |
| 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() |
|
|
| |
| 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() |
|
|
| |
| 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(): |
| |
| 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 |
|
|
| |
| query_outputs = self.qformer(seq_embeds) |
|
|
| |
| projected = self.projector(query_outputs) |
|
|
| |
| 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) |
|
|
| |
| 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) |
|
|
| |
| 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() |
|
|
| |
| os.environ['CUDA_VISIBLE_DEVICES'] = str(args.gpu) |
|
|
| |
| model = GeneLinguaLM() |
|
|
| |
| if args.sequence: |
| sequence = args.sequence |
| else: |
| |
| 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() |
|
|