Views
No views yet
Qwen/Qwen2.5-7B-Instruct.
It was trained as the v0.5.0 Stage-1 dense-recall adapter for Bengali and
Banglish Bangladesh Election Commission (EC) and National ID (NID) procedural
questions.services.nidw.gov.bd, ecs.gov.bd, and the 105 helpline. Static SFT weights
should not be treated as authoritative for time-sensitive facts.Qwen/Qwen2.5-7B-Instructr=64, alpha=128, dropout 0.05q_proj, k_proj, v_proj, o_proj, gate_proj,
up_proj, down_projv0.5.0-stage1dataset_manifest.json, DATASET_CARD.md, and system_prompt.txt in
this repository for the pinned data and policy metadata.Qwen/Qwen2.5-7B-Instruct, and drops you into an interactive multi-turn chat loop with token-by-token streaming. Commands: /reset clears history, /exit quits, /tokens N caps output length. Re-running the cell reuses the loaded model unless you set FORCE_RELOAD = True.1!pip -q install -U transformers peft accelerate huggingface_hub
2
3# Colab L4/A100 often ship torchvision/bitsandbytes/torchao in a broken CUDA state.
4# This adapter is bf16 LoRA inference; we do not need any of them. Removing them
5# keeps the optional accelerator probes off the from_pretrained load path.
6!pip -q uninstall -y torchvision bitsandbytes torchao
7
8import inspect, json, os, sys
9from pathlib import Path
10from threading import Thread
11
12import torch
13from huggingface_hub import snapshot_download
14
15ADAPTER_ID = os.environ.get("ADAPTER_ID", "ehzawad/ec-SFT-qwen25-7b-lora")
16ADAPTER_REV = os.environ.get("ADAPTER_REVISION") # optional pin
17ADAPTER_DIR = Path(os.environ.get("ADAPTER_DIR", "/content/adapter"))
18ADAPTER_DIR.mkdir(parents=True, exist_ok=True)
19snapshot_download(repo_id=ADAPTER_ID, revision=ADAPTER_REV, local_dir=str(ADAPTER_DIR))
20
21required = ["adapter_config.json", "adapter_model.safetensors", "system_prompt.txt",
22 "tokenizer.json", "tokenizer_config.json"]
23missing = [f for f in required if not (ADAPTER_DIR / f).is_file()]
24assert not missing, f"adapter dir {ADAPTER_DIR} missing files: {missing}"
25
26# Idempotent: skip the expensive load if model, tokenizer, SYSTEM_PROMPT already in globals.
27# Set FORCE_RELOAD=True to refresh (e.g. after changing the adapter).
28FORCE_RELOAD = False
29if (not FORCE_RELOAD) and all(n in globals() for n in ("model", "tokenizer", "SYSTEM_PROMPT")):
30 print("OK reusing already-loaded model (set FORCE_RELOAD=True to refresh)")
31else:
32 # Disable optional accelerator probes BEFORE the first transformers/peft from_pretrained call,
33 # otherwise a half-broken torchao C-extension on Colab can leave model params on the meta device.
34 import transformers.utils.import_utils as _iu
35 _iu.is_torchvision_available = _iu.is_torchvision_v2_available = (lambda: False)
36 if hasattr(_iu, "is_torchao_available"):
37 _iu.is_torchao_available = (lambda: False)
38 import peft.import_utils as _piu
39 for _n in ("is_bnb_available", "is_bnb_4bit_available", "is_torchao_available"):
40 if hasattr(_piu, _n): setattr(_piu, _n, lambda *a, **k: False)
41 for _m in list(sys.modules.values()):
42 if getattr(_m, "__name__", "").startswith("peft."):
43 for _n in ("is_bnb_available", "is_bnb_4bit_available", "is_torchao_available"):
44 if hasattr(_m, _n): setattr(_m, _n, lambda *a, **k: False)
45
46 from peft import PeftModel
47 from transformers import AutoModelForCausalLM, AutoTokenizer
48
49 assert torch.cuda.is_available(), "No GPU found. In Colab: Runtime > Change runtime type > GPU."
50 print("GPU:", torch.cuda.get_device_name(0))
51
52 BASE_MODEL = (
53 json.loads((ADAPTER_DIR / "training_args.json").read_text()).get("base_model", "Qwen/Qwen2.5-7B-Instruct")
54 if (ADAPTER_DIR / "training_args.json").is_file() else "Qwen/Qwen2.5-7B-Instruct"
55 )
56 DTYPE = torch.bfloat16 if torch.cuda.is_bf16_supported() else torch.float16
57
58 tokenizer = AutoTokenizer.from_pretrained(str(ADAPTER_DIR))
59 if tokenizer.pad_token is None: tokenizer.pad_token = tokenizer.eos_token
60 assert tokenizer.vocab_size > 100000, (
61 f"tokenizer load looks degenerate (vocab_size={tokenizer.vocab_size}); "
62 f"tokenizer.json should ship in the adapter repo")
63 assert tokenizer.chat_template, "no chat_template loaded; expected chat_template.jinja in adapter dir"
64
65 # Transformers renamed torch_dtype -> dtype in 4.49; accept either.
66 _dtype_kw = "dtype" if "dtype" in inspect.signature(AutoModelForCausalLM.from_pretrained).parameters else "torch_dtype"
67 base = AutoModelForCausalLM.from_pretrained(BASE_MODEL, **{_dtype_kw: DTYPE},
68 device_map={"": 0}, attn_implementation="sdpa")
69 model = PeftModel.from_pretrained(base, str(ADAPTER_DIR)).eval()
70 model.config.use_cache = True
71
72 SYSTEM_PROMPT = (ADAPTER_DIR / "system_prompt.txt").read_text(encoding="utf-8")
73
74from transformers import TextIteratorStreamer
75
76def answer(question: str, max_new_tokens: int = 1024) -> str:
77 messages = [{"role": "system", "content": SYSTEM_PROMPT},
78 {"role": "user", "content": question}]
79 rendered = tokenizer.apply_chat_template(messages, add_generation_prompt=True,
80 tokenize=True, return_tensors="pt")
81 input_ids = rendered.input_ids if hasattr(rendered, "input_ids") else rendered
82 input_ids = input_ids.to(next(model.parameters()).device)
83
84 streamer = TextIteratorStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True, timeout=300.0)
85 gen_kwargs = dict(
86 input_ids=input_ids, attention_mask=torch.ones_like(input_ids),
87 max_new_tokens=max_new_tokens, do_sample=False,
88 eos_token_id=tokenizer.eos_token_id,
89 pad_token_id=tokenizer.pad_token_id or tokenizer.eos_token_id,
90 use_cache=True, streamer=streamer,
91 )
92 gen_error = {}
93 def _gen():
94 try:
95 with torch.inference_mode():
96 model.generate(**gen_kwargs)
97 except BaseException as e:
98 gen_error["exc"] = e
99 th = Thread(target=_gen); th.start()
100
101 chunks = []
102 for chunk in streamer:
103 print(chunk, end="", flush=True)
104 chunks.append(chunk)
105 th.join()
106 if gen_error:
107 e = gen_error["exc"]
108 print(f"\n[generation thread raised {type(e).__name__}: {e}]")
109 reply = "".join(chunks).strip()
110 if not reply:
111 print("[WARN: 0 chars generated — check tokenizer vocab_size and chat template]")
112 return reply
113
114# Interactive multi-turn chat with token-by-token streaming.
115# Commands: /reset (clear history), /exit (quit), /tokens N (cap output at N tokens).
116MAX_POS = getattr(model.config, "max_position_embeddings", 32768)
117max_new_tokens = 1024
118history = []
119
120def _to_ids(enc):
121 if hasattr(enc, "input_ids"): enc = enc.input_ids
122 if isinstance(enc, list):
123 enc = torch.tensor([enc] if not enc or isinstance(enc[0], int) else enc, dtype=torch.long)
124 if enc.dim() == 1: enc = enc.unsqueeze(0)
125 return enc
126
127while True:
128 try:
129 q = input("USER> ").strip()
130 except (EOFError, KeyboardInterrupt):
131 print(); break
132 if not q: continue
133 if q in ("/exit", "/quit"): break
134 if q == "/reset": history.clear(); print("[cleared]"); continue
135 if q.startswith("/tokens"):
136 parts = q.split()
137 if len(parts) == 2 and parts[1].isdigit():
138 max_new_tokens = int(parts[1])
139 print(f"[max_new_tokens={max_new_tokens}]")
140 else:
141 print("[usage: /tokens 1024]")
142 continue
143
144 messages = [{"role": "system", "content": SYSTEM_PROMPT}] + history + [{"role": "user", "content": q}]
145 ids = _to_ids(tokenizer.apply_chat_template(messages, add_generation_prompt=True, tokenize=True, return_tensors="pt"))
146 ids = ids.to(next(model.parameters()).device)
147 cap = min(max_new_tokens, max(64, MAX_POS - ids.shape[1] - 32))
148
149 streamer = TextIteratorStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True, timeout=300.0)
150 gen_kwargs = dict(
151 input_ids=ids, attention_mask=torch.ones_like(ids),
152 max_new_tokens=cap, do_sample=False,
153 eos_token_id=tokenizer.eos_token_id, pad_token_id=tokenizer.pad_token_id,
154 use_cache=True, streamer=streamer,
155 )
156 gen_error = {}
157 def _gen():
158 try:
159 with torch.inference_mode():
160 model.generate(**gen_kwargs)
161 except BaseException as e:
162 gen_error["exc"] = e
163 thread = Thread(target=_gen)
164 thread.start()
165
166 print("BOT > ", end="", flush=True)
167 chunks = []
168 try:
169 for chunk in streamer:
170 print(chunk, end="", flush=True)
171 chunks.append(chunk)
172 except Exception as e:
173 print(f"\n[streamer error: {type(e).__name__}: {e}]")
174 thread.join()
175 print()
176 if gen_error:
177 e = gen_error["exc"]
178 print(f"[generation thread raised {type(e).__name__}: {e}]")
179 reply = "".join(chunks).strip()
180 if not reply:
181 print("[WARN: 0 chars generated — check tokenizer vocab_size and chat template]")
182 history += [{"role": "user", "content": q}, {"role": "assistant", "content": reply}]answer() helper above remains available for programmatic single-shot calls if you'd rather skip the input loop. The companion notebook Stage1_v5_Inference_HF_Colab.ipynb in the source repo separates the load and chat steps into their own cells.