Views
No views yet
HindiCausalLM class with Hindi-specific optimizations:HindiCausalLM, HindiCausalLMConfig, SentencePieceTokenizerWrapper) which are not part of the standard Hugging Face transformers library. The custom Python files are included in this repository.1import os
2from huggingface_hub import hf_hub_download
3
4# Configuration
5repo_id = "convaiinnovations/hindi-foundational-model-base"
6model_dir = "." # Use current directory for downloaded files
7
8# Download model files
9print(f"Downloading files for {repo_id}...")
10config_path = hf_hub_download(repo_id=repo_id, filename="config.json", local_dir=model_dir)
11tokenizer_path = hf_hub_download(repo_id=repo_id, filename="tokenizer.model", local_dir=model_dir)
12
13# Download custom module files (these are crucial!)
14hindi_model_path = hf_hub_download(repo_id=repo_id, filename="hindi_language_model.py", local_dir=model_dir)
15hindi_embeddings_path = hf_hub_download(repo_id=repo_id, filename="hindi_embeddings.py", local_dir=model_dir)
16
17# Try safetensors first, then bin
18try:
19 weights_path = hf_hub_download(repo_id=repo_id, filename="model.safetensors", local_dir=model_dir)
20 using_safetensors = True
21except:
22 weights_path = hf_hub_download(repo_id=repo_id, filename="pytorch_model.bin", local_dir=model_dir)
23 using_safetensors = False
24
25print("All necessary files downloaded.")1import os
2import json
3import torch
4import argparse # Keep argparse for potential future use
5import numpy as np
6import time
7import traceback # For detailed exception info
8
9# Try importing safetensors
10try:
11 import safetensors.torch
12 SAFE_TENSORS_AVAILABLE = True
13except ImportError:
14 SAFE_TENSORS_AVAILABLE = False
15
16print("[INFO] --- Debug Inference Script Started ---")
17if SAFE_TENSORS_AVAILABLE: print("[INFO] safetensors library found.")
18else: print("[WARNING] safetensors library not found.")
19
20# --- Attempt to import custom modules ---
21print("[DEBUG] Attempting to import custom modules...")
22try:
23 from hindi_language_model import HindiCausalLM, HindiCausalLMConfig
24 from hindi_embeddings import SentencePieceTokenizerWrapper
25 print("[INFO] Successfully imported custom modules.")
26except ImportError as e:
27 print(f"[ERROR] Failed to import custom modules: {e}"); traceback.print_exc()
28
29# --- End Custom Module Import ---
30
31
32# --- Main Generation Function Definition ---
33def run_generation(
34 model_path: str,
35 prompt: str,
36 max_len: int,
37 temp: float,
38 top_k: int,
39 seed: int,
40 device_str: str
41):
42 """Loads model and generates text, printing debug info."""
43 print(f"\nINFO: --- Starting Generation ---")
44 print(f"[DEBUG] Args: path='{model_path}', max_len={max_len}, temp={temp}, top_k={top_k}, seed={seed}, device='{device_str}'")
45
46 # --- Setup ---
47 t_start_setup = time.time()
48 try:
49 torch.manual_seed(seed); np.random.seed(seed); device = torch.device(device_str)
50 if device.type == 'cuda': torch.cuda.manual_seed_all(seed)
51 print(f"[INFO] Using device: {device}")
52 print(f"[DEBUG] Setup took {time.time()-t_start_setup:.4f}s")
53 except Exception as e: print(f"[ERROR] Device/Seed setup failed: {e}"); traceback.print_exc(); return None
54
55 # --- Load Tokenizer ---
56 print("\n[INFO] --- Loading Tokenizer ---")
57 t_start_load = time.time(); tokenizer = None
58 try:
59 tokenizer_model_file = os.path.join(model_path, "tokenizer.model")
60 print(f"[DEBUG] Looking for tokenizer at: {tokenizer_model_file}")
61 assert os.path.exists(tokenizer_model_file), "tokenizer.model not found!"
62 tokenizer = SentencePieceTokenizerWrapper(tokenizer_model_file) # Use imported class
63 print(f"[INFO] Tokenizer loaded. Vocab: {getattr(tokenizer, 'vocab_size', 'N/A')}")
64 # Get BOS/EOS (handle if missing)
65 bos_id = getattr(tokenizer, 'bos_token_id', 1) # Default 1
66 eos_id = getattr(tokenizer, 'eos_token_id', 2) # Default 2
67 print(f"[INFO] BOS ID: {bos_id}, EOS ID: {eos_id}")
68 except Exception as e: print(f"[ERROR] Tokenizer loading failed: {e}"); traceback.print_exc(); return None
69
70 # --- Load Config ---
71 print("\n[INFO] --- Loading Config ---")
72 lm_config = None
73 try:
74 config_file = os.path.join(model_path, "config.json")
75 print(f"[DEBUG] Looking for config at: {config_file}")
76 assert os.path.exists(config_file), "config.json not found!"
77 with open(config_file, 'r', encoding='utf-8') as f: config_dict = json.load(f)
78 print(f"[DEBUG] Config JSON loaded.")
79 # Check/fix vocab size
80 tok_vocab = getattr(tokenizer, 'vocab_size', None)
81 if tok_vocab and 'vocab_size' in config_dict and config_dict['vocab_size'] != tok_vocab: print(f"[WARN] Config/Tokenizer vocab mismatch. Using tokenizer size: {tok_vocab}"); config_dict['vocab_size'] = tok_vocab
82 # Instantiate config
83 if hasattr(HindiCausalLMConfig, 'from_dict'): lm_config = HindiCausalLMConfig.from_dict(config_dict)
84 else: lm_config = HindiCausalLMConfig(**config_dict)
85 print("[INFO] Model config loaded.")
86 except Exception as e: print(f"[ERROR] Config loading failed: {e}"); traceback.print_exc(); return None
87
88 # --- Load Model ---
89 print("\n[INFO] --- Loading Model ---")
90 model = None
91 try:
92 print(f"[DEBUG] Instantiating {HindiCausalLM.__name__}...")
93 model = HindiCausalLM(lm_config); print(f"[INFO] Model structure created.")
94 weights_file = None; s_path = os.path.join(model_path, "model.safetensors"); b_path = os.path.join(model_path, "pytorch_model.bin")
95 print(f"[DEBUG] Checking weights: {s_path} (exists: {os.path.exists(s_path)}), {b_path} (exists: {os.path.exists(b_path)})")
96 if SAFE_TENSORS_AVAILABLE and os.path.exists(s_path): weights_file = s_path
97 elif os.path.exists(b_path): weights_file = b_path
98 else: raise FileNotFoundError("Model weights (.safetensors or .bin) not found!")
99 print(f"[INFO] Loading weights from: {weights_file}")
100 if weights_file.endswith(".safetensors"): state_dict = safetensors.torch.load_file(weights_file, device="cpu")
101 else: state_dict = torch.load(weights_file, map_location="cpu")
102 print(f"[DEBUG] State dict loaded to CPU. Keys: {len(state_dict)}")
103 try: load_res = model.load_state_dict(state_dict, strict=True)
104 except RuntimeError as e_load: print(f"[WARN] Strict load failed: {e_load}. Trying non-strict."); load_res = model.load_state_dict(state_dict, strict=False)
105 missing = getattr(load_res, "missing_keys", []); unexpected = getattr(load_res, "unexpected_keys", [])
106 print(f"[INFO] State dict loaded. Missing: {len(missing)}. Unexpected: {len(unexpected)}")
107 if missing: print(f"[WARN] Missing keys: {missing[:5]}...")
108 if unexpected: print(f"[WARN] Unexpected keys: {unexpected[:5]}...")
109 del state_dict; model.to(device); model.eval()
110 print("[INFO] Model loaded to device and set to eval mode.")
111 print(f"[DEBUG] Tokenizer+Config+Model loading took {time.time()-t_start_load:.2f}s")
112 except Exception as e: print(f"[ERROR] Model loading failed: {e}"); traceback.print_exc(); return None
113
114 # --- Generation ---
115 print("\n[INFO] --- Starting Text Generation ---")
116 t_start_gen = time.time()
117 print(f"[INFO] Prompt: \"{prompt}\"")
118 try:
119 print("[DEBUG] Encoding prompt...")
120 # Use __call__ or sp_model.EncodeAsIds
121 if hasattr(tokenizer, '__call__'):
122 print("DEBUG: Trying tokenizer(prompt)...")
123 encoded_result = tokenizer(prompt, return_tensors=None)
124 if isinstance(encoded_result, dict) and 'input_ids' in encoded_result: input_ids = encoded_result['input_ids']
125 else: print(f"DEBUG: __call__ result type {type(encoded_result)} unexpected. Trying sp_model.EncodeAsIds...");
126 if hasattr(tokenizer, 'sp_model') and hasattr(tokenizer.sp_model, 'EncodeAsIds'): input_ids = tokenizer.sp_model.EncodeAsIds(prompt)
127 else: raise AttributeError("Cannot find suitable encoding method (__call__ or sp_model.EncodeAsIds)")
128 elif hasattr(tokenizer, 'sp_model') and hasattr(tokenizer.sp_model, 'EncodeAsIds'):
129 print("DEBUG: Trying tokenizer.sp_model.EncodeAsIds...")
130 input_ids = tokenizer.sp_model.EncodeAsIds(prompt)
131 else: raise AttributeError("Cannot find suitable encoding method")
132 print(f"[DEBUG] Prompt token IDs: {input_ids}")
133
134 if bos_id is not None: print(f"[DEBUG] Prepending BOS {bos_id}"); input_ids = [bos_id] + input_ids
135 input_tensor = torch.tensor([input_ids], dtype=torch.long, device=device); print(f"[DEBUG] Initial input tensor shape: {input_tensor.shape}")
136 generated_ids = input_tensor
137
138 print("[DEBUG] Starting generation loop...")
139 with torch.no_grad():
140 for i in range(max_len - len(input_ids)):
141 step = i + 1; print(f"\nDEBUG: --- Step {step}/{max_len - len(input_ids)} | Current len: {generated_ids.shape[1]} ---")
142 t_fwd = time.time();
143
144 # --- FORWARD CALL AND LOGIT EXTRACTION ---
145 outputs = model(input_ids=generated_ids) # model call
146
147 # *** CORRECTED LOGIT ACCESS ***
148 if isinstance(outputs, dict) and 'logits' in outputs:
149 logits = outputs['logits'] # Access via key if output is dict
150 print(f"DEBUG: Fwd pass {time.time()-t_fwd:.4f}s. Accessed dict['logits'].")
151 elif hasattr(outputs, 'logits'):
152 logits = outputs.logits # Access via attribute if output is object
153 print(f"DEBUG: Fwd pass {time.time()-t_fwd:.4f}s. Accessed outputs.logits.")
154 else:
155 print(f"[ERROR] Model output type is {type(outputs)}, and does not contain 'logits'.")
156 raise TypeError("Model output format error.")
157 # *** END CORRECTION ***
158
159 next_token_logits = logits[:, -1, :]; print(f"DEBUG: Next logits shape: {next_token_logits.shape}")
160
161 # --- Sampling ---
162 if temp > 0: scaled_logits = next_token_logits / temp
163 else: scaled_logits = next_token_logits # Greedy
164 if top_k > 0: kth_vals, _ = torch.topk(scaled_logits, k=top_k, dim=-1); scaled_logits[scaled_logits < kth_vals[:, -1].unsqueeze(-1)] = -float("Inf")
165 probs = torch.softmax(scaled_logits, dim=-1); next_token_id = torch.multinomial(probs, num_samples=1); print(f"DEBUG: Sampled ID: {next_token_id.item()}")
166 generated_ids = torch.cat([generated_ids, next_token_id], dim=1)
167 if next_token_id.item() == eos_id: print(f"INFO: EOS token {eos_id} generated."); break
168 else: print(f"INFO: Reached max length {max_len}.")
169
170 # --- Decode ---
171 print("\nDEBUG: --- Post-processing ---")
172 output_ids = generated_ids[0].cpu().tolist(); print(f"[DEBUG] Raw output IDs: {output_ids}")
173 processed_ids = output_ids
174 if bos_id and processed_ids and processed_ids[0] == bos_id: print("[DEBUG] Removing BOS"); processed_ids = processed_ids[1:]
175 if eos_id and processed_ids and processed_ids[-1] == eos_id: print("[DEBUG] Removing EOS"); processed_ids = processed_ids[:-1]
176 print(f"[DEBUG] Processed IDs: {processed_ids}")
177 print("[INFO] Decoding...")
178 # Use sp_model.DecodeIds or decode
179 if hasattr(tokenizer, 'sp_model') and hasattr(tokenizer.sp_model, 'DecodeIds'): print("DEBUG: Decoding using tokenizer.sp_model.DecodeIds..."); generated_text = tokenizer.sp_model.DecodeIds(processed_ids)
180 elif hasattr(tokenizer, 'decode'): print("DEBUG: Decoding using tokenizer.decode..."); generated_text = tokenizer.decode(processed_ids)
181 else: raise AttributeError("Cannot find suitable decoding method")
182 print(f"[DEBUG] Decoded text: '{generated_text}'")
183 print(f"[INFO] Generation successful ({time.time() - t_start_gen:.2f}s).")
184 return generated_text
185
186 except Exception as e: print(f"ERROR: Generation loop error: {e}"); traceback.print_exc(); return None
187# --- End Generation Function Definition ---
188
189
190# --- Main Execution Block ---
191if __name__ == "__main__":
192 # --- Parameters ---
193 model_dir = "." # Use current directory if files are downloaded here
194 prompt = "गंगा नदी"
195 max_len = 80
196 temp = 2
197 top_k = 45
198 seed = 42
199 device = "cuda" if torch.cuda.is_available() else "cpu"
200
201 print("\n[INFO] --- Simple Hindi Text Generation Script ---")
202 print(f"[INFO] Model Dir: {model_dir}")
203 print(f"[INFO] Prompt: \"{prompt}\"")
204 print(f"[INFO] Max Length: {max_len}")
205 print(f"[INFO] Temperature: {temp}")
206 print(f"[INFO] Top-K: {top_k}")
207 print(f"[INFO] Seed: {seed}")
208 print(f"[INFO] Device: {device}")
209 print("-" * 30)
210
211 # --- Validate Path ---
212 if not os.path.isdir(model_dir): print(f"[ERROR] Model directory not found: {model_dir}"); exit(1)
213
214 # --- Run Generation ---
215 if 'run_generation' in locals():
216 generated_output = run_generation(
217 model_path=model_dir, prompt=prompt, max_len=max_len,
218 temp=temp, top_k=top_k, seed=seed, device_str=device
219 )
220 else: print("[ERROR] run_generation function is not defined!"); generated_output = None
221
222 # --- Print Result ---
223 print("\n" + "="*20 + " Final Generation Result " + "="*20)
224 if generated_output is not None:
225 print(f"Prompt: {prompt}")
226 print("-" * (40 + len(" Final Generation Result ")))
227 print("Generated Text:")
228 print(generated_output)
229 else:
230 print("\n[FAILURE] Text generation failed. Check print statements above.")
231 print("=" * (40 + len(" Final Generation Result ")))1prompt = "हिंदी भाषा"
2# Output: "हिंदी भाषा भारत की सबसे महत्वपूर्ण भाषाओं में से एक है। यह भारत के उत्तर भारत के राज्यों में मुख्य भाषा के रूप में बोली जाती है..."1prompt = "एक बार की बात है"
2# Output: "एक बार की बात है, जब मैं छोटा था, तब मेरे दादाजी मुझे एक कहानी सुनाया करते थे। वह कहानी एक ऐसे राजा की थी जो अपने राज्य में..."