gary-boon commited on
Commit
e11c277
·
unverified ·
2 Parent(s): 778d7c86f43bd6

Merge: F2 backend — emit effective_probability for sampling-effective margins (#5)

Browse files
Files changed (1) hide show
  1. 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 ---