Spaces:
Sleeping
Sleeping
File size: 5,683 Bytes
af373e4 e7b6295 af373e4 e7b6295 af373e4 e7b6295 af373e4 e7b6295 af373e4 e7b6295 af373e4 e7b6295 af373e4 e7b6295 af373e4 e7b6295 af373e4 e7b6295 af373e4 e7b6295 af373e4 e7b6295 af373e4 e7b6295 af373e4 e7b6295 af373e4 e7b6295 | 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 | import torch
from typing import List, Dict, Any, Optional
from inspector import (
compute_probabilities,
compute_entropy,
get_top_k,
build_step_result,
)
DECODING_MODES = {
"greedy": "Greedy β selalu pilih token tertinggi (deterministik)",
"sampling": "Sampling β random sample dari distribusi (variatif)",
}
def greedy_decode_with_inspection(
model,
tokenizer,
device: str,
prompt: str,
max_new_tokens: int = 50,
top_k: int = 10,
temperature: float = 1.0,
stop_at_eos: bool = True,
decoding_mode: str = "greedy", # β BARU
top_p: float = 0.9, # β BARU
repetition_penalty: float = 1.0, # β BARU
seed: Optional[int] = None, # β BARU
progress_callback=None,
) -> List[Dict[str, Any]]:
"""
Run decoding step-by-step and extract full probability
inspection data at each step.
Args:
model : Loaded HuggingFace causal LM
tokenizer : Corresponding tokenizer
device : 'cpu' or 'cuda'
prompt : Input text string
max_new_tokens : Maximum number of tokens to generate
top_k : Number of top candidates to extract per step
temperature : Softmax temperature
stop_at_eos : Stop when EOS token is produced
decoding_mode : 'greedy' or 'sampling' β BARU
top_p : Nucleus sampling threshold β BARU
repetition_penalty: Penalize repeated tokens β BARU
seed : Random seed (sampling mode only) β BARU
progress_callback : Optional callable(step, total)
"""
if seed is not None:
torch.manual_seed(seed)
input_ids = tokenizer.encode(prompt, return_tensors="pt").to(device)
eos_token_id = tokenizer.eos_token_id
results = []
current_ids = input_ids.clone()
with torch.no_grad():
for step in range(1, max_new_tokens + 1):
outputs = model(input_ids=current_ids)
next_token_logits = outputs.logits[0, -1, :].clone()
# ββ Repetition Penalty ββββββββββββββββββββββββββββββββββ
if repetition_penalty != 1.0:
next_token_logits = _apply_repetition_penalty(
next_token_logits, current_ids[0], repetition_penalty
)
# ββ Probability Distribution ββββββββββββββββββββββββββββ
probs = compute_probabilities(next_token_logits, temperature=temperature)
# ββ Entropy & Top-K (selalu dari full distribution) βββββ
entropy = compute_entropy(probs)
top_candidates = get_top_k(probs, tokenizer, k=top_k)
# ββ Token Selection βββββββββββββββββββββββββββββββββββββ
if decoding_mode == "greedy":
chosen_token_id = torch.argmax(probs).item()
elif decoding_mode == "sampling":
filtered_probs = _top_p_filter(probs.clone(), top_p=top_p)
chosen_token_id = torch.multinomial(filtered_probs, num_samples=1).item()
else:
raise ValueError(f"Unknown decoding_mode: '{decoding_mode}'. Use 'greedy' or 'sampling'.")
chosen_token_str = tokenizer.decode([chosen_token_id])
input_so_far = tokenizer.decode(current_ids[0], skip_special_tokens=True)
step_result = build_step_result(
step=step,
input_so_far=input_so_far,
chosen_token=chosen_token_str,
top_candidates=top_candidates,
entropy=entropy,
)
step_result["decoding_mode"] = decoding_mode # β BARU
results.append(step_result)
if progress_callback:
progress_callback(step, max_new_tokens)
next_token_tensor = torch.tensor([[chosen_token_id]], device=device)
current_ids = torch.cat([current_ids, next_token_tensor], dim=1)
if stop_at_eos and chosen_token_id == eos_token_id:
break
return results
def _apply_repetition_penalty(
logits: torch.Tensor,
input_ids: torch.Tensor,
penalty: float,
) -> torch.Tensor:
"""
Turunkan probabilitas token yang sudah muncul di konteks.
Logits positif dibagi penalty, logits negatif dikali penalty.
"""
for token_id in set(input_ids.tolist()):
if logits[token_id] > 0:
logits[token_id] /= penalty
else:
logits[token_id] *= penalty
return logits
def _top_p_filter(
probs: torch.Tensor,
top_p: float = 0.9,
) -> torch.Tensor:
"""
Nucleus (top-p) filtering: zero out token di luar
top-p% cumulative probability mass.
"""
sorted_probs, sorted_indices = torch.sort(probs, descending=True)
cumulative_probs = torch.cumsum(sorted_probs, dim=-1)
sorted_indices_to_remove = cumulative_probs - sorted_probs > top_p
sorted_probs[sorted_indices_to_remove] = 0.0
filtered = torch.zeros_like(probs)
filtered.scatter_(0, sorted_indices, sorted_probs)
total = filtered.sum()
if total > 0:
filtered = filtered / total
return filtered
def get_generated_text(prompt: str, results: List[Dict]) -> str:
"""Reconstruct the full generated text from step results."""
tokens = [r["chosen_token"] for r in results]
return prompt + "".join(tokens) |