feat: add decoding controls
Browse files- inference.py +53 -7
inference.py
CHANGED
|
@@ -30,6 +30,33 @@ CTX_LEN = 2048
|
|
| 30 |
BOS_ID, EOS_ID, EOT_ID = 0, 1, 6
|
| 31 |
|
| 32 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
# โโ Packed Linear Modules โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 34 |
|
| 35 |
class Linear1bit(nn.Module):
|
|
@@ -254,23 +281,26 @@ class SSMoELMPacked(nn.Module):
|
|
| 254 |
|
| 255 |
@torch.inference_mode()
|
| 256 |
def generate(self, input_ids: list[int], max_new_tokens: int = 200,
|
| 257 |
-
temperature: float = 0.
|
|
|
|
| 258 |
eos_ids: tuple[int, ...] = (EOS_ID, EOT_ID)) -> list[int]:
|
| 259 |
ids = list(input_ids)
|
| 260 |
generated = []
|
| 261 |
for _ in range(max_new_tokens):
|
| 262 |
x = torch.tensor([ids[-CTX_LEN:]], dtype=torch.long)
|
| 263 |
logits = self(x)[0, -1]
|
|
|
|
|
|
|
|
|
|
| 264 |
if temperature > 0:
|
| 265 |
-
logits_np =
|
| 266 |
-
logits_np = (logits_np - logits_np.max()) / temperature
|
| 267 |
probs = np.exp(logits_np); probs /= probs.sum()
|
| 268 |
idx = np.argsort(-probs); cumsum = np.cumsum(probs[idx])
|
| 269 |
cutoff = np.searchsorted(cumsum, top_p) + 1
|
| 270 |
probs[idx[cutoff:]] = 0.0; probs /= probs.sum()
|
| 271 |
next_id = int(np.random.choice(idx, p=probs))
|
| 272 |
else:
|
| 273 |
-
next_id = int(
|
| 274 |
if next_id in eos_ids:
|
| 275 |
break
|
| 276 |
generated.append(next_id)
|
|
@@ -369,8 +399,10 @@ def main():
|
|
| 369 |
parser.add_argument("--prompt", default=None, help="Prompt for single-shot mode (--no-chat)")
|
| 370 |
parser.add_argument("--no-chat", action="store_true", help="Single-shot mode")
|
| 371 |
parser.add_argument("--max-tokens", type=int, default=200, help="Max new tokens to generate")
|
| 372 |
-
parser.add_argument("--temperature", type=float, default=0.
|
| 373 |
parser.add_argument("--top-p", type=float, default=0.9, help="Top-p nucleus sampling")
|
|
|
|
|
|
|
| 374 |
args = parser.parse_args()
|
| 375 |
|
| 376 |
print(f"Loading {args.ckpt} ...")
|
|
@@ -402,7 +434,14 @@ def main():
|
|
| 402 |
continue
|
| 403 |
ids = build_chat_prompt(tok, history, user_input)
|
| 404 |
print("Assistant: ", end="", flush=True)
|
| 405 |
-
out = model.generate(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 406 |
response = tok.decode(out).strip()
|
| 407 |
print(response)
|
| 408 |
history.append((user_input, response))
|
|
@@ -412,7 +451,14 @@ def main():
|
|
| 412 |
ids = [BOS_ID] + tok.encode(prompt).ids
|
| 413 |
print(f"\nPrompt: {prompt}")
|
| 414 |
print("Output: ", end="", flush=True)
|
| 415 |
-
out = model.generate(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 416 |
print(tok.decode(out))
|
| 417 |
|
| 418 |
|
|
|
|
| 30 |
BOS_ID, EOS_ID, EOT_ID = 0, 1, 6
|
| 31 |
|
| 32 |
|
| 33 |
+
def apply_repetition_penalty(
|
| 34 |
+
logits: np.ndarray,
|
| 35 |
+
token_ids: list[int],
|
| 36 |
+
penalty: float,
|
| 37 |
+
) -> np.ndarray:
|
| 38 |
+
"""ๆขๅบใใผใฏใณใฎ logit ใซ repetition penalty ใ้ฉ็จใใใ"""
|
| 39 |
+
if penalty <= 1.0 or not token_ids:
|
| 40 |
+
return logits
|
| 41 |
+
adjusted = logits.copy()
|
| 42 |
+
for token_id in set(token_ids):
|
| 43 |
+
if adjusted[token_id] > 0:
|
| 44 |
+
adjusted[token_id] /= penalty
|
| 45 |
+
else:
|
| 46 |
+
adjusted[token_id] *= penalty
|
| 47 |
+
return adjusted
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def filter_top_k(logits: np.ndarray, top_k: int) -> np.ndarray:
|
| 51 |
+
"""top_k ไปฅๅคใฎ logit ใ -inf ใซใใใtop_k<=0 ใชใๅคๆดใใชใใ"""
|
| 52 |
+
if top_k <= 0 or top_k >= logits.shape[-1]:
|
| 53 |
+
return logits
|
| 54 |
+
filtered = np.full_like(logits, -np.inf)
|
| 55 |
+
top_indices = np.argpartition(logits, -top_k)[-top_k:]
|
| 56 |
+
filtered[top_indices] = logits[top_indices]
|
| 57 |
+
return filtered
|
| 58 |
+
|
| 59 |
+
|
| 60 |
# โโ Packed Linear Modules โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 61 |
|
| 62 |
class Linear1bit(nn.Module):
|
|
|
|
| 281 |
|
| 282 |
@torch.inference_mode()
|
| 283 |
def generate(self, input_ids: list[int], max_new_tokens: int = 200,
|
| 284 |
+
temperature: float = 0.0, top_p: float = 0.9,
|
| 285 |
+
top_k: int = 1, repetition_penalty: float = 1.3,
|
| 286 |
eos_ids: tuple[int, ...] = (EOS_ID, EOT_ID)) -> list[int]:
|
| 287 |
ids = list(input_ids)
|
| 288 |
generated = []
|
| 289 |
for _ in range(max_new_tokens):
|
| 290 |
x = torch.tensor([ids[-CTX_LEN:]], dtype=torch.long)
|
| 291 |
logits = self(x)[0, -1]
|
| 292 |
+
logits_np = logits.numpy().astype(np.float64)
|
| 293 |
+
logits_np = apply_repetition_penalty(logits_np, ids, repetition_penalty)
|
| 294 |
+
logits_np = filter_top_k(logits_np, top_k)
|
| 295 |
if temperature > 0:
|
| 296 |
+
logits_np = (logits_np - np.nanmax(logits_np)) / temperature
|
|
|
|
| 297 |
probs = np.exp(logits_np); probs /= probs.sum()
|
| 298 |
idx = np.argsort(-probs); cumsum = np.cumsum(probs[idx])
|
| 299 |
cutoff = np.searchsorted(cumsum, top_p) + 1
|
| 300 |
probs[idx[cutoff:]] = 0.0; probs /= probs.sum()
|
| 301 |
next_id = int(np.random.choice(idx, p=probs))
|
| 302 |
else:
|
| 303 |
+
next_id = int(np.nanargmax(logits_np))
|
| 304 |
if next_id in eos_ids:
|
| 305 |
break
|
| 306 |
generated.append(next_id)
|
|
|
|
| 399 |
parser.add_argument("--prompt", default=None, help="Prompt for single-shot mode (--no-chat)")
|
| 400 |
parser.add_argument("--no-chat", action="store_true", help="Single-shot mode")
|
| 401 |
parser.add_argument("--max-tokens", type=int, default=200, help="Max new tokens to generate")
|
| 402 |
+
parser.add_argument("--temperature", type=float, default=0.0, help="Sampling temperature (0 = greedy; recommended for this model)")
|
| 403 |
parser.add_argument("--top-p", type=float, default=0.9, help="Top-p nucleus sampling")
|
| 404 |
+
parser.add_argument("--top-k", type=int, default=1, help="Keep only top-k logits before sampling (0 disables)")
|
| 405 |
+
parser.add_argument("--repetition-penalty", type=float, default=1.3, help="Penalty for tokens already present in the prompt/output")
|
| 406 |
args = parser.parse_args()
|
| 407 |
|
| 408 |
print(f"Loading {args.ckpt} ...")
|
|
|
|
| 434 |
continue
|
| 435 |
ids = build_chat_prompt(tok, history, user_input)
|
| 436 |
print("Assistant: ", end="", flush=True)
|
| 437 |
+
out = model.generate(
|
| 438 |
+
ids,
|
| 439 |
+
args.max_tokens,
|
| 440 |
+
args.temperature,
|
| 441 |
+
args.top_p,
|
| 442 |
+
args.top_k,
|
| 443 |
+
args.repetition_penalty,
|
| 444 |
+
)
|
| 445 |
response = tok.decode(out).strip()
|
| 446 |
print(response)
|
| 447 |
history.append((user_input, response))
|
|
|
|
| 451 |
ids = [BOS_ID] + tok.encode(prompt).ids
|
| 452 |
print(f"\nPrompt: {prompt}")
|
| 453 |
print("Output: ", end="", flush=True)
|
| 454 |
+
out = model.generate(
|
| 455 |
+
ids,
|
| 456 |
+
args.max_tokens,
|
| 457 |
+
args.temperature,
|
| 458 |
+
args.top_p,
|
| 459 |
+
args.top_k,
|
| 460 |
+
args.repetition_penalty,
|
| 461 |
+
)
|
| 462 |
print(tok.decode(out))
|
| 463 |
|
| 464 |
|