ViuAI commited on
Commit
4df20ff
·
verified ·
1 Parent(s): 064e7e4

Update quickstart.py for official release

Browse files
Files changed (1) hide show
  1. quickstart.py +129 -0
quickstart.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sys
3
+ import torch
4
+ from huggingface_hub import hf_hub_download
5
+ from tokenizers import Tokenizer
6
+ from safetensors.torch import load_file
7
+
8
+ # Ensure UTF-8 console output on Windows
9
+ if sys.platform == "win32":
10
+ try:
11
+ sys.stdout.reconfigure(encoding="utf-8")
12
+ sys.stdin.reconfigure(encoding="utf-8")
13
+ except Exception:
14
+ pass
15
+
16
+ REPO_ID = "ViuAI/Sarus-500M"
17
+ EOT_ID = 64002
18
+
19
+ def main():
20
+ print("=" * 70)
21
+ print("🚀 ViuAI Sarus-500M -- 1-Click Interactive Terminal Chat")
22
+ print("=" * 70)
23
+
24
+ device = "cuda" if torch.cuda.is_available() else "cpu"
25
+ print(f"[*] Compute Device: {device.upper()}")
26
+
27
+ # 1. Download or locate local architecture & tokenizer
28
+ base_dir = os.path.dirname(os.path.abspath(__file__))
29
+
30
+ if os.path.exists(os.path.join(base_dir, "model.py")):
31
+ sys.path.insert(0, base_dir)
32
+ else:
33
+ print("[*] Downloading model architecture from Hugging Face...")
34
+ p_model = hf_hub_download(repo_id=REPO_ID, filename="model.py")
35
+ hf_hub_download(repo_id=REPO_ID, filename="config.py")
36
+ sys.path.insert(0, os.path.dirname(p_model))
37
+
38
+ from model import ViuAI
39
+ from config import ViuAIConfig
40
+
41
+ tok_local = os.path.join(base_dir, "tokenizer.json")
42
+ if not os.path.exists(tok_local):
43
+ print("[*] Downloading tokenizer...")
44
+ tok_local = hf_hub_download(repo_id=REPO_ID, filename="tokenizer.json")
45
+
46
+ tokenizer = Tokenizer.from_file(tok_local)
47
+ cfg = ViuAIConfig(vocab_size=tokenizer.get_vocab_size(), context_length=2048)
48
+ model = ViuAI(cfg).to(device)
49
+
50
+ # 2. Download or locate Safetensors weights
51
+ weights_local = os.path.join(base_dir, "model.safetensors")
52
+ if not os.path.exists(weights_local):
53
+ print("[*] Downloading model.safetensors (~1.1 GB)...")
54
+ weights_local = hf_hub_download(repo_id=REPO_ID, filename="model.safetensors")
55
+
56
+ print(f"[*] Loading weights from {os.path.basename(weights_local)}...")
57
+ state_dict = load_file(weights_local)
58
+ model.load_state_dict(state_dict, strict=False)
59
+ model.eval()
60
+
61
+ print("\n[OK] Sarus-500M Ready! Type 'exit' to quit.\n" + "-" * 70)
62
+
63
+ while True:
64
+ try:
65
+ prompt = input("\n👤 USER >> ").strip()
66
+ if not prompt:
67
+ continue
68
+ if prompt.lower() in ["exit", "quit", "q"]:
69
+ print("\nSession ended.")
70
+ break
71
+
72
+ formatted = f"<|user|>\n{prompt}<|endofturn|>\n<|assistant|>\n"
73
+ ids = tokenizer.encode(formatted).ids
74
+ idx = torch.tensor([ids], dtype=torch.long, device=device)
75
+
76
+ print("🤖 SARUS >> ", end="", flush=True)
77
+
78
+ generated = []
79
+ prev_text = ""
80
+
81
+ with torch.no_grad():
82
+ for _ in range(300):
83
+ idx_cond = idx if idx.size(1) <= cfg.context_length else idx[:, -cfg.context_length:]
84
+ logits, _ = model(idx_cond)
85
+ logits = logits[:, -1, :]
86
+
87
+ # Repetition penalty
88
+ if generated:
89
+ gen_t = torch.tensor(list(set(generated)), dtype=torch.long, device=device)
90
+ score = logits[:, gen_t]
91
+ logits[:, gen_t] = torch.where(score < 0, score * 1.15, score / 1.15)
92
+
93
+ # Top-K & Top-P Sampling
94
+ sampling_logits = logits / 0.15
95
+ top_k_val = min(50, sampling_logits.size(-1))
96
+ kth_vals, _ = torch.topk(sampling_logits, top_k_val)
97
+ sampling_logits[sampling_logits < kth_vals[:, [-1]]] = float("-inf")
98
+
99
+ sorted_logits, sorted_indices = torch.sort(sampling_logits, descending=True)
100
+ cum_probs = torch.cumsum(torch.softmax(sorted_logits, dim=-1), dim=-1)
101
+ remove_mask = cum_probs > 0.90
102
+ remove_mask[..., 1:] = remove_mask[..., :-1].clone()
103
+ remove_mask[..., 0] = False
104
+ indices_to_remove = torch.zeros_like(sampling_logits, dtype=torch.bool).scatter_(1, sorted_indices, remove_mask)
105
+ sampling_logits[indices_to_remove] = float("-inf")
106
+
107
+ probs = torch.softmax(sampling_logits, dim=-1)
108
+ idx_next = torch.multinomial(probs, num_samples=1)
109
+ token_id = idx_next.item()
110
+
111
+ if token_id == EOT_ID:
112
+ break
113
+
114
+ generated.append(token_id)
115
+ idx = torch.cat([idx, idx_next], dim=1)
116
+
117
+ curr_text = tokenizer.decode(generated)
118
+ chunk = curr_text[len(prev_text):]
119
+ print(chunk, end="", flush=True)
120
+ prev_text = curr_text
121
+
122
+ print()
123
+
124
+ except KeyboardInterrupt:
125
+ print("\nSession interrupted.")
126
+ break
127
+
128
+ if __name__ == "__main__":
129
+ main()