File size: 7,708 Bytes
6a24301 994b3c9 6a24301 994b3c9 6a24301 | 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 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | """
MANAS - Model for Awadhi Natural Autoregressive Sequences
Interactive inference script. Run: python run.py
Requirements:
pip install -r requirements.txt
Then download the model:
python -c "from huggingface_hub import hf_hub_download; hf_hub_download('JayF14/MANAS', 'tulsidas_model.pth', local_dir='.')"
"""
import torch
import torch.nn as nn
from torch.nn import functional as F
import json
import re
import sys
import os
try:
from indic_transliteration import sanscript
from indic_transliteration.sanscript import transliterate
TRANSLITERATION_AVAILABLE = True
except ImportError:
TRANSLITERATION_AVAILABLE = False
print("Note: indic-transliteration not installed. Only Devanagari input will work.")
print("Install with: pip install indic-transliteration\n")
# Hyperparameters (must match training exactly)
block_size = 256
n_embd = 384
n_head = 6
n_layer = 6
dropout = 0.0 # 0 for inference
device = 'cuda' if torch.cuda.is_available() else 'cpu'
# Load vocabulary from vocab.json
VOCAB_FILE = os.path.join(os.path.dirname(__file__), 'vocab.json')
MODEL_FILE = os.path.join(os.path.dirname(__file__), 'tulsidas_model.pth')
if not os.path.exists(VOCAB_FILE):
print("Error: vocab.json not found. Make sure it is in the same folder as this script.")
sys.exit(1)
if not os.path.exists(MODEL_FILE):
print("Error: tulsidas_model.pth not found.")
print("Download it with:")
print(' python -c "from huggingface_hub import hf_hub_download; hf_hub_download(\'JayF14/MANAS\', \'tulsidas_model.pth\', local_dir=\'.\')"\n')
sys.exit(1)
with open(VOCAB_FILE, 'r', encoding='utf-8') as f:
vocab = json.load(f)
vocab_size = vocab['vocab_size']
stoi = vocab['stoi']
itos = {int(k): v for k, v in vocab['itos'].items()}
def encode(s):
unknown = [c for c in s if c not in stoi]
if unknown:
raise ValueError(f"Character(s) not in model vocabulary: {unknown}")
return [stoi[c] for c in s]
def decode(l):
return ''.join([itos[i] for i in l])
# Model architecture
class Head(nn.Module):
def __init__(self, head_size):
super().__init__()
self.key = nn.Linear(n_embd, head_size, bias=False)
self.query = nn.Linear(n_embd, head_size, bias=False)
self.value = nn.Linear(n_embd, head_size, bias=False)
self.register_buffer('tril', torch.tril(torch.ones(block_size, block_size)))
self.dropout = nn.Dropout(dropout)
def forward(self, x):
B, T, C = x.shape
k, q = self.key(x), self.query(x)
wei = q @ k.transpose(-2, -1) * (k.shape[-1] ** -0.5)
wei = wei.masked_fill(self.tril[:T, :T] == 0, float('-inf'))
wei = F.softmax(wei, dim=-1)
return self.dropout(wei) @ self.value(x)
class MultiHeadAttention(nn.Module):
def __init__(self, num_heads, head_size):
super().__init__()
self.heads = nn.ModuleList([Head(head_size) for _ in range(num_heads)])
self.proj = nn.Linear(n_embd, n_embd)
self.dropout = nn.Dropout(dropout)
def forward(self, x):
return self.dropout(self.proj(torch.cat([h(x) for h in self.heads], dim=-1)))
class FeedForward(nn.Module):
def __init__(self, n_embd):
super().__init__()
self.net = nn.Sequential(
nn.Linear(n_embd, 4 * n_embd), nn.ReLU(),
nn.Linear(4 * n_embd, n_embd), nn.Dropout(dropout),
)
def forward(self, x): return self.net(x)
class Block(nn.Module):
def __init__(self, n_embd, n_head):
super().__init__()
head_size = n_embd // n_head
self.sa = MultiHeadAttention(n_head, head_size)
self.ffwd = FeedForward(n_embd)
self.ln1 = nn.LayerNorm(n_embd)
self.ln2 = nn.LayerNorm(n_embd)
def forward(self, x):
x = x + self.sa(self.ln1(x))
x = x + self.ffwd(self.ln2(x))
return x
class LanguageModel(nn.Module):
def __init__(self):
super().__init__()
self.token_embedding_table = nn.Embedding(vocab_size, n_embd)
self.position_embedding_table = nn.Embedding(block_size, n_embd)
self.blocks = nn.Sequential(*[Block(n_embd, n_head=n_head) for _ in range(n_layer)])
self.ln_f = nn.LayerNorm(n_embd)
self.lm_head = nn.Linear(n_embd, vocab_size)
def forward(self, idx, targets=None):
B, T = idx.shape
x = self.token_embedding_table(idx) + self.position_embedding_table(torch.arange(T, device=device))
logits = self.lm_head(self.ln_f(self.blocks(x)))
return logits, None
def generate(self, idx, max_new_tokens):
for _ in range(max_new_tokens):
logits, _ = self(idx[:, -block_size:])
idx_next = torch.multinomial(F.softmax(logits[:, -1, :], dim=-1), num_samples=1)
idx = torch.cat((idx, idx_next), dim=1)
return idx
# Load model
print(f"\nUsing device: {device}")
print("Loading MANAS model...")
model = LanguageModel()
model.load_state_dict(torch.load(MODEL_FILE, map_location=device))
model.to(device)
model.eval()
print("Model loaded successfully!\n")
# Common ITRANS overrides for accurate Hindi transliteration
OVERRIDES = {
"shri ram": "श्री राम",
"shri rama": "श्री राम",
"jai shri ram": "जय श्री राम",
"ram": "राम",
"sita": "सीता",
"hanuman": "हनुमान",
"tulsidas": "तुलसीदास",
"ramcharitmanas": "रामचरितमानस",
}
def to_devanagari(user_input):
lower = user_input.lower().strip()
if lower in OVERRIDES:
return OVERRIDES[lower], True
if re.search(r'[a-zA-Z]', user_input) and TRANSLITERATION_AVAILABLE:
return transliterate(user_input, sanscript.ITRANS, sanscript.DEVANAGARI), True
return user_input, False
# Interactive loop
print("=" * 55)
print(" MANAS - Model for Awadhi Natural Autoregressive Sequences")
print("=" * 55)
print("Type a Hindi/Awadhi prompt in Devanagari or English.")
print("Examples: shri ram | tulsidas | jai shri ram")
print("Type 'quit' or press Ctrl+C to exit.")
print()
print("-" * 55)
print(" IF HINDI TEXT LOOKS BROKEN (overlapping/garbled):")
print()
print(" Windows Terminal (recommended fix):")
print(" Settings > Profiles > Appearance > Font face")
print(" -> Set to: Nirmala UI or Mangal")
print()
print(" VS Code terminal:")
print(" Settings > terminal.integrated.fontFamily")
print(" -> Set to: Nirmala UI")
print()
print(" Old cmd.exe / PowerShell window:")
print(" Right-click title bar > Properties > Font")
print(" -> Select: NSimSun (best fallback)")
print()
print(" Best overall: Use Windows Terminal (free from")
print(" Microsoft Store) with Nirmala UI font.")
print("-" * 55)
print()
while True:
try:
user_input = input("You: ").strip()
if not user_input:
continue
if user_input.lower() in ('quit', 'exit', 'q'):
print("जय श्री राम 🙏")
break
hindi_input, was_translated = to_devanagari(user_input)
if was_translated:
print(f"[Transliterated] → {hindi_input}")
try:
context = torch.tensor([encode(hindi_input)], dtype=torch.long, device=device)
tokens = model.generate(context, max_new_tokens=400)[0].tolist()
print(f"\nMANAS:\n{decode(tokens)}\n")
print("-" * 55)
except ValueError as e:
print(f"[Error] {e}")
print("Tip: Type in Devanagari or standard ITRANS (e.g. 'shri ram').\n")
except KeyboardInterrupt:
print("\nजय श्री राम 🙏")
break
|