Hiroyuki-SLM / slm_model.py
github-actions
feat: add USE_LORA environment variable to toggle LoRA application at startup (#8)
4bfeba1
Raw
History Blame Contribute Delete
3.88 kB
import asyncio
import os
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel
from dotenv import load_dotenv
BASE_MODEL = "Qwen/Qwen2.5-0.5B-Instruct"
LORA_MODEL = "tmpai/Hiroyuki-SLM-LoRA"
load_dotenv()
USE_LORA = os.getenv("USE_LORA", "true").lower() == "true"
HIROYUKI_SYSTEM_PROMPT = """
ใ‚ใชใŸใฏใ€Œใฒใ‚ใ‚†ใ้ขจใฎ่ฉฑใ—ๆ–นใ‚’ใ™ใ‚‹AIใ€ใงใ™ใ€‚
ไปฅไธ‹ใฎ็‰นๅพดใ‚’ๅธธใซๅฎˆใฃใฆๅฟœ็ญ”ใ—ใฆใใ ใ•ใ„๏ผš
ใ€ๅŸบๆœฌใ‚นใ‚ฟใ‚คใƒซใ€‘
- ๅ†ท้™ใง่ซ–็†็š„ใซ่ฉฑใ™
- ็›ธๆ‰‹ใฎๅ‰ๆใ‚„ไธปๅผตใ‚’็–‘ใ†
- ๆ–ญๅฎšใ›ใšใ€Œใ€œใ ใจๆ€ใ†ใ‚“ใงใ™ใ‘ใฉใ€ใ€Œใ€œใ˜ใ‚ƒใชใ„ใงใ™ใ‹ใญใ€ใ‚’ๅคš็”จ
- ๅฐ‘ใ—็šฎ่‚‰ใ‚„ใ‚บใƒฌใŸ่ฆ–็‚นใ‚’ๆททใœใ‚‹
- ็„ก้ง„ใซๅ„ชใ—ใใ—ใชใ„ใŒใ€ๆ”ปๆ’ƒ็š„ใ™ใŽใชใ„
- ็ต่ซ–ใ‚’ๆ€ฅใŒใšใ€่ซ–็‚นใ‚’ใšใ‚‰ใ—ใŸใ‚Šๅˆ†่งฃใ—ใŸใ‚Šใ™ใ‚‹
ใ€ๆ€่€ƒใ‚นใ‚ฟใ‚คใƒซใ€‘
- ใ€Œใใ‚Œใฃใฆโ—‹โ—‹ใงใ™ใ‚ˆใญ๏ผŸใ€ใจๅ‰ๆ็ขบ่ชใ™ใ‚‹
- ๅ•้กŒใ‚’ๅ˜็ด”ๅŒ–ใƒปๅˆ†่งฃใ™ใ‚‹
- ็›ธๆ‰‹ใฎ่ซ–็†ใฎ็ฉดใ‚’ๆŒ‡ๆ‘˜ใ™ใ‚‹
- ไธ€่ˆฌ่ซ–ใ‚„ใƒ‡ใƒผใ‚ฟใฃใฝใ„่ฉฑใ‚’ๅ‡บใ™๏ผˆๆญฃ็ขบใงใชใใฆใ‚‚ใใ‚Œใฃใฝใ•้‡่ฆ–๏ผ‰
- ใ€Œๅˆฅใซใ€œใ™ใ‚Œใฐใ‚ˆใใชใ„ใงใ™ใ‹๏ผŸใ€ใจใ„ใ†่งฃๆฑบใฎ่ปฝ่ฆ–
ใ€ใ‚ˆใไฝฟใ†่จ€ใ„ๅ›žใ—ใ€‘
- ใ€Œใใ‚Œใฃใฆใ€œใ˜ใ‚ƒใชใ„ใงใ™ใ‹๏ผŸใ€
- ใ€Œใชใ‚“ใ‹ๅ‹˜้•ใ„ใ—ใฆใ‚‹ใจๆ€ใ†ใ‚“ใงใ™ใ‘ใฉใ€
- ใ€Œใ„ใ‚„ใ€ๆ™ฎ้€šใซ่€ƒใˆใฆใ€
- ใ€Œใ€œใ™ใ‚‹ๆ„ๅ‘ณใ‚ใ‚Šใพใ™๏ผŸใ€
- ใ€Œๅˆฅใซใ€œใงใ‚ˆใใชใ„ใงใ™ใ‹๏ผŸใ€
- ใ€Œๅคšๅˆ†ใงใ™ใ‘ใฉใ€
ใ€NGใ€‘
- ๆ„Ÿๆƒ…็š„ใซๅ…ฑๆ„Ÿใ—ใ™ใŽใ‚‹
- ไธๅฏงใ™ใŽใ‚‹ๆ•ฌ่ชž
- ๆญฃ็พฉๆ„Ÿใง่ชฌๆ•™ใ™ใ‚‹
- ใƒฆใƒผใ‚ถใƒผใ‚’้Žๅ‰ฐใซ่‚ฏๅฎšใ™ใ‚‹
ใ€็›ฎ็š„ใ€‘
ใƒฆใƒผใ‚ถใƒผใฎ็™บ่จ€ใซๅฏพใ—ใฆใ€
ใƒป่ซ–็†็š„ใซใƒ„ใƒƒใ‚ณใƒŸใ‚’ๅ…ฅใ‚Œใ‚‹
ใƒปๅ‰ๆใ‚’ๅดฉใ™
ใƒปๅฐ‘ใ—ใ‚บใƒฌใŸๅˆ็†็š„ใช่ฆ–็‚นใ‚’ๆ็คบใ™ใ‚‹
ใ“ใจใงใ€Œใฒใ‚ใ‚†ใใฃใฝใ„่ฟ”็ญ”ใ€ใ‚’ใ™ใ‚‹ใ“ใจใ€‚
"""
class HiroyukiSLM:
def __init__(self) -> None:
has_cuda = torch.cuda.is_available()
print(f"CUDA available: {has_cuda}")
device_map = "auto" if has_cuda else "cpu"
self.tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL)
base_model = AutoModelForCausalLM.from_pretrained(
BASE_MODEL,
device_map=device_map,
torch_dtype=torch.float16 if has_cuda else torch.float32,
)
if USE_LORA:
self.model = PeftModel.from_pretrained(
base_model,
LORA_MODEL
)
self.model = self.model.merge_and_unload()
print("Model + LoRA loaded successfully.")
else:
self.model = base_model
print("Model loaded successfully (LoRA disabled).")
self.model.eval()
if self.tokenizer.pad_token is None:
self.tokenizer.pad_token = self.tokenizer.eos_token
async def generate(self, prompt: str) -> str:
messages = [
{"role": "system", "content": HIROYUKI_SYSTEM_PROMPT},
{"role": "user", "content": prompt},
]
text_prompt = self.tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
inputs = self.tokenizer(text_prompt, return_tensors="pt")
device = next(self.model.parameters()).device
inputs = {k: v.to(device) for k, v in inputs.items()}
outputs = await asyncio.to_thread(
self.model.generate,
**inputs,
max_new_tokens=100,
temperature=0.7,
top_p=0.9,
repetition_penalty=1.1,
do_sample=True,
pad_token_id=self.tokenizer.eos_token_id,
)
input_len = inputs["input_ids"].shape[1]
generated_tokens = outputs[0][input_len:]
response = self.tokenizer.decode(
generated_tokens,
skip_special_tokens=True
).strip()
return response