Spaces:
Running on Zero
Running on Zero
File size: 5,633 Bytes
927a79a 14a68cc 927a79a 14a68cc 927a79a 14a68cc 927a79a 14a68cc 927a79a 14a68cc 927a79a 14a68cc 927a79a 14a68cc 927a79a 14a68cc 927a79a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | # 1. ต้อง import spaces เป็นบรรทัดแรกสุดสำหรับ Hugging Face ZeroGPU
try:
import spaces
except ImportError:
spaces = None
import os
import re
import torch
import torch.nn as nn
import torch.nn.functional as F
from pythainlp.tokenize import word_tokenize
import gradio as gr
# Setup Device
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# 2. โหลด Vocab และ Weights
vocab_file = "vocab_v6.pt"
model_file = "my_llm_v6_big_brain.pth"
if not os.path.exists(vocab_file) or not os.path.exists(model_file):
raise FileNotFoundError("❌ ไม่พบไฟล์ vocab_v6.pt หรือ my_llm_v6_big_brain.pth ในโฟลเดอร์!")
vocab_data = torch.load(vocab_file, map_location="cpu")
word2idx = vocab_data['word2idx']
idx2word = vocab_data['idx2word']
vocab_size = len(word2idx)
SPECIAL_TOKENS = ["<|user|>", "<|bot|>", "<|end|>"]
# 3. Helper Functions
def preprocess_text(text):
text = re.sub(r'([\+\-\*/=])', r' \1 ', text)
text = re.sub(r'\s+', ' ', text)
return text.strip()
def tokenize_input(text):
text = preprocess_text(text)
sub_tokens = word_tokenize(text, engine="newmm")
return [w for w in sub_tokens if w.strip()]
def encode(tokens):
return [word2idx.get(w, 1) for w in tokens]
def decode(token_ids):
words = []
for i in token_ids:
w = idx2word.get(i, '')
if w not in SPECIAL_TOKENS and i not in [0, 1]:
words.append(w)
return "".join(words)
# 4. Model Architecture (V6 Big Brain)
MAX_LEN = 64
class BigBrainMiniLLM(nn.Module):
def __init__(self, vocab_size, d_model=512, nhead=8, num_layers=6, dropout=0.15):
super().__init__()
self.embedding = nn.Embedding(vocab_size, d_model)
self.pos_embedding = nn.Embedding(MAX_LEN, d_model)
self.drop = nn.Dropout(dropout)
encoder_layer = nn.TransformerEncoderLayer(
d_model=d_model, nhead=nhead, dim_feedforward=2048, dropout=dropout, batch_first=True
)
self.transformer = nn.TransformerEncoder(encoder_layer, num_layers=num_layers)
self.fc_out = nn.Linear(d_model, vocab_size)
def forward(self, x):
seq_len = x.size(1)
positions = torch.arange(0, seq_len, device=x.device).unsqueeze(0)
out = self.drop(self.embedding(x) + self.pos_embedding(positions))
mask = torch.triu(torch.full((seq_len, seq_len), float('-inf'), device=x.device), diagonal=1)
out = self.transformer(out, mask=mask)
return self.fc_out(out)
model = BigBrainMiniLLM(vocab_size=vocab_size, d_model=512, nhead=8, num_layers=6, dropout=0.15).to(device)
model.load_state_dict(torch.load(model_file, map_location=device))
model.eval()
# 5. ZeroGPU Decorator Wrapper
def gpu_decorator(func):
if spaces is not None and hasattr(spaces, "GPU"):
return spaces.GPU(func)
return func
@gpu_decorator
def bot_response(message, history, temp, top_k, rep_penalty):
if not message.strip():
return ""
tokens = ["<|user|>"] + tokenize_input(message) + ["<|bot|>"]
encoded = encode(tokens)
input_tensor = torch.tensor(encoded, dtype=torch.long).unsqueeze(0).to(device)
generated = list(encoded)
bot_start_len = len(encoded)
with torch.no_grad():
for _ in range(40):
if input_tensor.size(1) >= MAX_LEN - 1:
break
outputs = model(input_tensor)
logits = outputs[0, -1, :] / temp
# Repetition Penalty
generated_bot = generated[bot_start_len:]
for t in set(generated_bot):
if logits[t] < 0:
logits[t] *= rep_penalty
else:
logits[t] /= rep_penalty
if top_k > 0:
v, _ = torch.topk(logits, min(top_k, logits.size(-1)))
logits[logits < v[-1]] = -float('Inf')
probs = F.softmax(logits, dim=-1)
next_token = torch.multinomial(probs, num_samples=1).item()
if next_token == 0 or idx2word.get(next_token) == "<|end|>":
break
generated.append(next_token)
input_tensor = torch.tensor(generated, dtype=torch.long).unsqueeze(0).to(device)
return decode(generated[bot_start_len:])
# 6. Build Gradio Interface (ย้าย theme ไปไว้ที่ launch() ตาม Gradio 6.0)
with gr.Blocks() as demo:
gr.Markdown(
"""
# 🧠 Thai Mini-LLM V6 (Big Brain 23.7M)
### โมเดลภาษาไทยขนาดจิ๋ว เทรนจาก 0 ด้วยสถาปัตยกรรม Transformer (Word-Level)
"""
)
with gr.Row():
with gr.Column(scale=3):
gr.ChatInterface(
fn=bot_response,
additional_inputs=[
gr.Slider(0.1, 1.5, value=0.5, step=0.1, label="Temperature (ความมั่ว/ความคิดสร้างสรรค์)"),
gr.Slider(1, 50, value=10, step=1, label="Top-K (การจำกัดขอบเขตคลังคำ)"),
gr.Slider(1.0, 2.5, value=1.3, step=0.1, label="Repetition Penalty (บทลงโทษคำซ้ำ)"),
],
)
gr.Markdown("--- \n *Created with ❤️ | Custom PyTorch Model trained from Scratch*")
if __name__ == "__main__":
demo.launch(theme=gr.themes.Soft())
|