ternion-demo / sampling.py
SolidSea
Ternion demo: fully-ternary LLM generation (ZeroGPU)
ce87f5e
Raw History Blame Contribute Delete
3.56 kB
#!/usr/bin/env python3
"""Setun-Cortex — 采样工具"""
import torch
import torch.nn.functional as F
def top_k_top_p_filtering(logits, top_k=0, top_p=0.0, filter_value=-float('Inf')):
"""Filter logits using top-k and/or top-p (nucleus) sampling."""
if top_k > 0:
top_k = min(top_k, logits.size(-1))
indices_to_remove = logits < torch.topk(logits, top_k)[0][:, -1:]
logits[indices_to_remove] = filter_value
if top_p > 0.0:
sorted_logits, sorted_indices = torch.sort(logits, descending=True)
cumulative_probs = torch.cumsum(F.softmax(sorted_logits, dim=-1), dim=-1)
sorted_indices_to_remove = cumulative_probs > top_p
sorted_indices_to_remove[..., 1:] = sorted_indices_to_remove[..., :-1].clone()
sorted_indices_to_remove[..., 0] = 0
indices_to_remove = sorted_indices[sorted_indices_to_remove]
logits[..., indices_to_remove] = filter_value
return logits
def sample_next_token(logits, temperature=0.8, top_k=40, top_p=0.9, repetition_penalty=1.0, prev_tokens=None):
"""从 logits 采样下一个 token"""
logits = logits[:, -1, :] / max(temperature, 1e-5)
# Repetition penalty
if repetition_penalty != 1.0 and prev_tokens is not None:
for token in prev_tokens[0].tolist():
if logits[0, token] < 0:
logits[0, token] *= repetition_penalty
else:
logits[0, token] /= repetition_penalty
# Top-K / Top-P filtering
logits = top_k_top_p_filtering(logits, top_k=top_k, top_p=top_p)
probs = F.softmax(logits, dim=-1)
return torch.multinomial(probs, 1)
@torch.no_grad()
def generate(model, prompt_ids, max_new_tokens=300, temperature=0.8,
top_k=40, top_p=0.9, repetition_penalty=1.0, seq_len=64, alpha_scale=0.5,
beam_width=1):
"""自回归生成文本; beam_width=1 → 采样模式, >1 → beam search (2026-08-05)"""
model.eval()
if beam_width <= 1:
gen = prompt_ids.clone()
for _ in range(max_new_tokens):
ctx = gen[:, -seq_len:]
logits = model(ctx, alpha_scale=alpha_scale)
next_id = sample_next_token(logits, temperature, top_k, top_p,
repetition_penalty, gen[:, -seq_len:] if repetition_penalty > 1 else None)
gen = torch.cat([gen, next_id], dim=1)
return gen
# ===== beam search (v17c 2026-08-05: 消除采样重复死循环) =====
import math
beams = [(prompt_ids.clone(), 0.0)]
for _ in range(max_new_tokens):
candidates = []
for seq, score in beams:
ctx = seq[:, -seq_len:]
logits = model(ctx, alpha_scale=alpha_scale)[:, -1, :] / max(temperature, 1e-5)
if repetition_penalty != 1.0:
for t in seq[0].tolist():
if logits[0, t] < 0:
logits[0, t] *= repetition_penalty
else:
logits[0, t] /= repetition_penalty
logp = F.log_softmax(logits, dim=-1)[0]
topk = torch.topk(logp, beam_width * 2)
for v, lp in zip(topk.indices.tolist(), topk.values.tolist()):
new_seq = torch.cat([seq, torch.tensor([[v]], dtype=torch.long, device=seq.device)], dim=1)
candidates.append((new_seq, score + lp))
candidates.sort(key=lambda x: x[1], reverse=True)
beams = candidates[:beam_width]
best = max(beams, key=lambda x: x[1] / ((len(x[0][0]) + 5) ** 0.8))
return best[0]