Spaces:
Paused
Paused
Merge: F2 backend — emit effective_probability for sampling-effective margins (#5)
Browse files- backend/model_service.py +46 -3
backend/model_service.py
CHANGED
|
@@ -2176,6 +2176,21 @@ async def analyze_research_attention(request: Dict[str, Any], authenticated: boo
|
|
| 2176 |
log_probs = torch.nn.functional.log_softmax(logits, dim=-1)
|
| 2177 |
top_probs = torch.exp(log_probs[top_indices])
|
| 2178 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2179 |
alternatives = []
|
| 2180 |
cumulative = 0.0
|
| 2181 |
selected_in_top = False
|
|
@@ -2184,10 +2199,13 @@ async def analyze_research_attention(request: Dict[str, Any], authenticated: boo
|
|
| 2184 |
cumulative += prob
|
| 2185 |
if idx == next_token_id:
|
| 2186 |
selected_in_top = True
|
|
|
|
| 2187 |
alternatives.append({
|
| 2188 |
"token": token_text,
|
| 2189 |
"token_id": idx,
|
| 2190 |
"probability": prob,
|
|
|
|
|
|
|
| 2191 |
"raw_probability": raw_probs[idx].item(), # T=1 probability for comparison
|
| 2192 |
"log_probability": math.log(prob) if prob > 0 else float('-inf'),
|
| 2193 |
"cumulative_probability": cumulative,
|
|
@@ -2197,6 +2215,7 @@ async def analyze_research_attention(request: Dict[str, Any], authenticated: boo
|
|
| 2197 |
# If selected token is not in top-N, add it with its actual probability
|
| 2198 |
if not selected_in_top:
|
| 2199 |
selected_prob = probs[next_token_id].item()
|
|
|
|
| 2200 |
selected_raw_prob = raw_probs[next_token_id].item()
|
| 2201 |
selected_log_prob = log_probs[next_token_id].item()
|
| 2202 |
selected_logit = raw_logits[next_token_id].item()
|
|
@@ -2207,6 +2226,8 @@ async def analyze_research_attention(request: Dict[str, Any], authenticated: boo
|
|
| 2207 |
"token": next_token_text,
|
| 2208 |
"token_id": next_token_id,
|
| 2209 |
"probability": selected_prob,
|
|
|
|
|
|
|
| 2210 |
"raw_probability": selected_raw_prob, # T=1 probability for comparison
|
| 2211 |
"log_probability": selected_log_prob,
|
| 2212 |
"cumulative_probability": None, # Not in sequence
|
|
@@ -2223,14 +2244,19 @@ async def analyze_research_attention(request: Dict[str, Any], authenticated: boo
|
|
| 2223 |
"is_selected_outlier": True
|
| 2224 |
})
|
| 2225 |
|
| 2226 |
-
# Build sampling metadata
|
|
|
|
|
|
|
|
|
|
| 2227 |
sampling_metadata = {
|
| 2228 |
"temperature": temperature,
|
| 2229 |
"top_k": top_k_param,
|
| 2230 |
"top_p": top_p_param,
|
| 2231 |
"greedy_token_id": greedy_token_id,
|
| 2232 |
"greedy_token": greedy_token,
|
| 2233 |
-
"was_greedy": next_token_id == greedy_token_id
|
|
|
|
|
|
|
| 2234 |
}
|
| 2235 |
|
| 2236 |
token_alternatives_by_step.append({
|
|
@@ -3098,6 +3124,14 @@ async def analyze_research_attention_stream(request: Dict[str, Any], authenticat
|
|
| 3098 |
log_probs = torch.nn.functional.log_softmax(logits, dim=-1)
|
| 3099 |
top_probs = torch.exp(log_probs[top_indices])
|
| 3100 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3101 |
alternatives = []
|
| 3102 |
cumulative = 0.0
|
| 3103 |
selected_in_top = False
|
|
@@ -3106,10 +3140,13 @@ async def analyze_research_attention_stream(request: Dict[str, Any], authenticat
|
|
| 3106 |
cumulative += prob
|
| 3107 |
if idx == next_token_id:
|
| 3108 |
selected_in_top = True
|
|
|
|
| 3109 |
alternatives.append({
|
| 3110 |
"token": token_text,
|
| 3111 |
"token_id": idx,
|
| 3112 |
"probability": prob,
|
|
|
|
|
|
|
| 3113 |
"raw_probability": raw_probs[idx].item(), # T=1 probability for comparison
|
| 3114 |
"log_probability": math_module.log(prob) if prob > 0 else float('-inf'),
|
| 3115 |
"cumulative_probability": cumulative,
|
|
@@ -3119,6 +3156,7 @@ async def analyze_research_attention_stream(request: Dict[str, Any], authenticat
|
|
| 3119 |
# If selected token is not in top-N, add it with its actual probability
|
| 3120 |
if not selected_in_top:
|
| 3121 |
selected_prob = probs[next_token_id].item()
|
|
|
|
| 3122 |
selected_raw_prob = raw_probs[next_token_id].item()
|
| 3123 |
selected_log_prob = log_probs[next_token_id].item()
|
| 3124 |
selected_logit = raw_logits[next_token_id].item()
|
|
@@ -3129,6 +3167,8 @@ async def analyze_research_attention_stream(request: Dict[str, Any], authenticat
|
|
| 3129 |
"token": next_token_text,
|
| 3130 |
"token_id": next_token_id,
|
| 3131 |
"probability": selected_prob,
|
|
|
|
|
|
|
| 3132 |
"raw_probability": selected_raw_prob, # T=1 probability for comparison
|
| 3133 |
"log_probability": selected_log_prob,
|
| 3134 |
"cumulative_probability": None,
|
|
@@ -3146,13 +3186,16 @@ async def analyze_research_attention_stream(request: Dict[str, Any], authenticat
|
|
| 3146 |
})
|
| 3147 |
|
| 3148 |
# Build sampling metadata
|
|
|
|
| 3149 |
sampling_metadata = {
|
| 3150 |
"temperature": temperature,
|
| 3151 |
"top_k": top_k_param,
|
| 3152 |
"top_p": top_p_param,
|
| 3153 |
"greedy_token_id": greedy_token_id,
|
| 3154 |
"greedy_token": greedy_token,
|
| 3155 |
-
"was_greedy": next_token_id == greedy_token_id
|
|
|
|
|
|
|
| 3156 |
}
|
| 3157 |
|
| 3158 |
# --- Margin computation and stability classification ---
|
|
|
|
| 2176 |
log_probs = torch.nn.functional.log_softmax(logits, dim=-1)
|
| 2177 |
top_probs = torch.exp(log_probs[top_indices])
|
| 2178 |
|
| 2179 |
+
# `probability` is the post-temperature, PRE-filter probability
|
| 2180 |
+
# (model preference). `effective_probability` is the post-filter
|
| 2181 |
+
# renormalised probability — what the sampler actually drew
|
| 2182 |
+
# from. Under top-k / top-p, alternatives outside the eligible
|
| 2183 |
+
# set get effective_probability = 0. When no filter is active,
|
| 2184 |
+
# the two values coincide. Surfacing both lets the panel
|
| 2185 |
+
# report a "model preference margin" (top-1 vs top-2 by
|
| 2186 |
+
# `probability`) and a "sampling margin" (top-1 vs top-2 by
|
| 2187 |
+
# `effective_probability` over the eligible set) — necessary
|
| 2188 |
+
# because under filtering the panel was previously showing a
|
| 2189 |
+
# margin that didn't reflect the actual decision.
|
| 2190 |
+
is_filtered = bool(
|
| 2191 |
+
(top_k_param is not None and top_k_param > 0)
|
| 2192 |
+
or (top_p_param is not None and top_p_param < 1.0)
|
| 2193 |
+
)
|
| 2194 |
alternatives = []
|
| 2195 |
cumulative = 0.0
|
| 2196 |
selected_in_top = False
|
|
|
|
| 2199 |
cumulative += prob
|
| 2200 |
if idx == next_token_id:
|
| 2201 |
selected_in_top = True
|
| 2202 |
+
eff = probs_filtered[idx].item()
|
| 2203 |
alternatives.append({
|
| 2204 |
"token": token_text,
|
| 2205 |
"token_id": idx,
|
| 2206 |
"probability": prob,
|
| 2207 |
+
"effective_probability": eff,
|
| 2208 |
+
"is_eligible": eff > 0.0,
|
| 2209 |
"raw_probability": raw_probs[idx].item(), # T=1 probability for comparison
|
| 2210 |
"log_probability": math.log(prob) if prob > 0 else float('-inf'),
|
| 2211 |
"cumulative_probability": cumulative,
|
|
|
|
| 2215 |
# If selected token is not in top-N, add it with its actual probability
|
| 2216 |
if not selected_in_top:
|
| 2217 |
selected_prob = probs[next_token_id].item()
|
| 2218 |
+
selected_eff = probs_filtered[next_token_id].item()
|
| 2219 |
selected_raw_prob = raw_probs[next_token_id].item()
|
| 2220 |
selected_log_prob = log_probs[next_token_id].item()
|
| 2221 |
selected_logit = raw_logits[next_token_id].item()
|
|
|
|
| 2226 |
"token": next_token_text,
|
| 2227 |
"token_id": next_token_id,
|
| 2228 |
"probability": selected_prob,
|
| 2229 |
+
"effective_probability": selected_eff,
|
| 2230 |
+
"is_eligible": selected_eff > 0.0,
|
| 2231 |
"raw_probability": selected_raw_prob, # T=1 probability for comparison
|
| 2232 |
"log_probability": selected_log_prob,
|
| 2233 |
"cumulative_probability": None, # Not in sequence
|
|
|
|
| 2244 |
"is_selected_outlier": True
|
| 2245 |
})
|
| 2246 |
|
| 2247 |
+
# Build sampling metadata. `is_filtered` and `eligible_count`
|
| 2248 |
+
# let the frontend decide whether to show one or two
|
| 2249 |
+
# distributions in the panel.
|
| 2250 |
+
eligible_count = int((probs_filtered > 0).sum().item())
|
| 2251 |
sampling_metadata = {
|
| 2252 |
"temperature": temperature,
|
| 2253 |
"top_k": top_k_param,
|
| 2254 |
"top_p": top_p_param,
|
| 2255 |
"greedy_token_id": greedy_token_id,
|
| 2256 |
"greedy_token": greedy_token,
|
| 2257 |
+
"was_greedy": next_token_id == greedy_token_id,
|
| 2258 |
+
"is_filtered": is_filtered,
|
| 2259 |
+
"eligible_count": eligible_count,
|
| 2260 |
}
|
| 2261 |
|
| 2262 |
token_alternatives_by_step.append({
|
|
|
|
| 3124 |
log_probs = torch.nn.functional.log_softmax(logits, dim=-1)
|
| 3125 |
top_probs = torch.exp(log_probs[top_indices])
|
| 3126 |
|
| 3127 |
+
# See non-SSE site for the rationale behind emitting both
|
| 3128 |
+
# `probability` (pre-filter model preference) and
|
| 3129 |
+
# `effective_probability` (post-filter, what the sampler
|
| 3130 |
+
# drew from). When no filter is active the two coincide.
|
| 3131 |
+
is_filtered = bool(
|
| 3132 |
+
(top_k_param is not None and top_k_param > 0)
|
| 3133 |
+
or (top_p_param is not None and top_p_param < 1.0)
|
| 3134 |
+
)
|
| 3135 |
alternatives = []
|
| 3136 |
cumulative = 0.0
|
| 3137 |
selected_in_top = False
|
|
|
|
| 3140 |
cumulative += prob
|
| 3141 |
if idx == next_token_id:
|
| 3142 |
selected_in_top = True
|
| 3143 |
+
eff = probs_filtered[idx].item()
|
| 3144 |
alternatives.append({
|
| 3145 |
"token": token_text,
|
| 3146 |
"token_id": idx,
|
| 3147 |
"probability": prob,
|
| 3148 |
+
"effective_probability": eff,
|
| 3149 |
+
"is_eligible": eff > 0.0,
|
| 3150 |
"raw_probability": raw_probs[idx].item(), # T=1 probability for comparison
|
| 3151 |
"log_probability": math_module.log(prob) if prob > 0 else float('-inf'),
|
| 3152 |
"cumulative_probability": cumulative,
|
|
|
|
| 3156 |
# If selected token is not in top-N, add it with its actual probability
|
| 3157 |
if not selected_in_top:
|
| 3158 |
selected_prob = probs[next_token_id].item()
|
| 3159 |
+
selected_eff = probs_filtered[next_token_id].item()
|
| 3160 |
selected_raw_prob = raw_probs[next_token_id].item()
|
| 3161 |
selected_log_prob = log_probs[next_token_id].item()
|
| 3162 |
selected_logit = raw_logits[next_token_id].item()
|
|
|
|
| 3167 |
"token": next_token_text,
|
| 3168 |
"token_id": next_token_id,
|
| 3169 |
"probability": selected_prob,
|
| 3170 |
+
"effective_probability": selected_eff,
|
| 3171 |
+
"is_eligible": selected_eff > 0.0,
|
| 3172 |
"raw_probability": selected_raw_prob, # T=1 probability for comparison
|
| 3173 |
"log_probability": selected_log_prob,
|
| 3174 |
"cumulative_probability": None,
|
|
|
|
| 3186 |
})
|
| 3187 |
|
| 3188 |
# Build sampling metadata
|
| 3189 |
+
eligible_count = int((probs_filtered > 0).sum().item())
|
| 3190 |
sampling_metadata = {
|
| 3191 |
"temperature": temperature,
|
| 3192 |
"top_k": top_k_param,
|
| 3193 |
"top_p": top_p_param,
|
| 3194 |
"greedy_token_id": greedy_token_id,
|
| 3195 |
"greedy_token": greedy_token,
|
| 3196 |
+
"was_greedy": next_token_id == greedy_token_id,
|
| 3197 |
+
"is_filtered": is_filtered,
|
| 3198 |
+
"eligible_count": eligible_count,
|
| 3199 |
}
|
| 3200 |
|
| 3201 |
# --- Margin computation and stability classification ---
|