Spaces:
Running on Zero
Running on Zero
Decouple PMI weight from sequence sampling temperature
Browse files- README.md +22 -0
- app.py +11 -3
- src/diffusion_lm/bigram.py +22 -4
README.md
CHANGED
|
@@ -87,3 +87,25 @@ and reset each block/iteration. Gamma still subtracts gamma*C in log-score units
|
|
| 87 |
this is not a percentage-parameter remapping. Gamma=0 restores unpenalized results
|
| 88 |
for the selected maximum-path or sampling mode. Ordinary decoding ignores these
|
| 89 |
checkboxes; the original temperature weighting is unchanged.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
this is not a percentage-parameter remapping. Gamma=0 restores unpenalized results
|
| 88 |
for the selected maximum-path or sampling mode. Ordinary decoding ignores these
|
| 89 |
checkboxes; the original temperature weighting is unchanged.
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
## Independent temperature and bigram weight
|
| 93 |
+
|
| 94 |
+
The LLaDA Space now uses S(y) = sum log p_t(y_t) + w sum PMI - gamma sum C.
|
| 95 |
+
**Bigram weight** ranges from 0 to 5, default 1. A weight of 1 gives equal
|
| 96 |
+
coefficients, not necessarily equal numerical influence. Weight 0 disables PMI
|
| 97 |
+
but does not disable repetition penalties. The previous fixed 0.5*temperature
|
| 98 |
+
PMI coefficient described above is superseded for this Space.
|
| 99 |
+
|
| 100 |
+
**Sample bigram-guided sequences** samples P(y) proportional to exp(S(y)/T).
|
| 101 |
+
Temperature controls the entropy of the whole sequence score, including repetition,
|
| 102 |
+
without changing the ratios of score coefficients. T=0 selects the maximum path;
|
| 103 |
+
positive T is floored to 1e-6 for numerical stability. Maximum-path Viterbi ignores
|
| 104 |
+
temperature. Raw full-vocabulary diffusion probabilities still determine expected
|
| 105 |
+
repetition counts and retention/APD confidence. Default T is now 1, w is 1,
|
| 106 |
+
matching the former T=2 PMI coefficient and sequence distribution. Ordinary
|
| 107 |
+
diffusion retains its usual temperature behavior. No extra model forwards.
|
| 108 |
+
|
| 109 |
+
Unseen pairs have a neutral PMI correction of zero, never a forbidden transition.
|
| 110 |
+
Conditional scoring instead uses smoothed finite probabilities. Expected repetition
|
| 111 |
+
counts remain the default; the optional candidate-set count mode is unchanged.
|
app.py
CHANGED
|
@@ -33,7 +33,7 @@ PMI_MIN_COUNT = 1
|
|
| 33 |
PMI_CLIP = 2.0
|
| 34 |
BIGRAM_ENDING_DELAY_STRENGTH = 10.0
|
| 35 |
# Preserve the candidate pool and balance used in the matched Viterbi tests.
|
| 36 |
-
DEFAULT_TEMPERATURE = 2.0 if BIGRAM_ENABLED else 0.7
|
| 37 |
DEFAULT_TOP_K = 16 if BIGRAM_ENABLED else 3
|
| 38 |
|
| 39 |
MODEL_REPO_ID = os.getenv("MODEL_REPO_ID", SPACE["model_repo_id"])
|
|
@@ -125,6 +125,7 @@ def generate(
|
|
| 125 |
adaptive_parallel_decoding: bool = False,
|
| 126 |
sequence_sampling: bool = False,
|
| 127 |
count_all_candidate_bigrams: bool = False,
|
|
|
|
| 128 |
):
|
| 129 |
"""Stream iterative masked-diffusion generation from the fixed model."""
|
| 130 |
question = question.strip() or "What do you know about Amsterdam?"
|
|
@@ -136,11 +137,13 @@ def generate(
|
|
| 136 |
raise gr.Error("Bigram Viterbi is not enabled for this Space.")
|
| 137 |
try:
|
| 138 |
selector = BigramViterbiSelector(
|
| 139 |
-
_bigram_scorer(bigram_model_path).to(SESSION.device),
|
|
|
|
| 140 |
scoring_method=("pmi" if remasking_strategy == "PMI Viterbi + Repetition Penalty" else
|
| 141 |
{"Conditional bigram": "conditional", "PMI bigram": "pmi"}.get(bigram_scoring_method, "")),
|
| 142 |
min_count=int(pmi_min_count), pmi_clip=float(pmi_clip),
|
| 143 |
sequence_sampling=bool(sequence_sampling),
|
|
|
|
| 144 |
remasking_confidence={"Diffusion probability": "diffusion", "Viterbi path margin": "viterbi_margin"}.get(bigram_remasking_confidence, ""),
|
| 145 |
)
|
| 146 |
if remasking_strategy == "PMI Viterbi + Repetition Penalty":
|
|
@@ -240,7 +243,11 @@ with gr.Blocks(title=f"{DISPLAY_NAME} · masked diffusion") as demo:
|
|
| 240 |
num_steps = gr.Slider(1, 512, value=64, step=1, label="Denoising steps")
|
| 241 |
block_length = gr.Slider(1, 512, value=64, step=1, label="Block length")
|
| 242 |
temperature = gr.Slider(0.0, 2.0, value=DEFAULT_TEMPERATURE, step=0.05, label="Temperature",
|
| 243 |
-
info="
|
|
|
|
|
|
|
|
|
|
|
|
|
| 244 |
top_k = gr.Slider(1, 100, value=DEFAULT_TOP_K, step=1, label="Top-k",
|
| 245 |
info="Number of candidate tokens per position for sampling or Viterbi. At 1, only the model’s highest-scoring token is available." if BIGRAM_ENABLED else None)
|
| 246 |
pause_per_step = gr.Slider(
|
|
@@ -361,6 +368,7 @@ with gr.Blocks(title=f"{DISPLAY_NAME} · masked diffusion") as demo:
|
|
| 361 |
adaptive_parallel_decoding,
|
| 362 |
sequence_sampling,
|
| 363 |
count_all_candidate_bigrams,
|
|
|
|
| 364 |
]
|
| 365 |
def update_ar_controls(strategy, apd=False):
|
| 366 |
"""Expose AR-only controls and clear revision when another strategy is selected."""
|
|
|
|
| 33 |
PMI_CLIP = 2.0
|
| 34 |
BIGRAM_ENDING_DELAY_STRENGTH = 10.0
|
| 35 |
# Preserve the candidate pool and balance used in the matched Viterbi tests.
|
| 36 |
+
DEFAULT_TEMPERATURE = (1.0 if SPACE.get("model_backend") == "llada" else 2.0) if BIGRAM_ENABLED else 0.7
|
| 37 |
DEFAULT_TOP_K = 16 if BIGRAM_ENABLED else 3
|
| 38 |
|
| 39 |
MODEL_REPO_ID = os.getenv("MODEL_REPO_ID", SPACE["model_repo_id"])
|
|
|
|
| 125 |
adaptive_parallel_decoding: bool = False,
|
| 126 |
sequence_sampling: bool = False,
|
| 127 |
count_all_candidate_bigrams: bool = False,
|
| 128 |
+
bigram_weight: float = 1.0,
|
| 129 |
):
|
| 130 |
"""Stream iterative masked-diffusion generation from the fixed model."""
|
| 131 |
question = question.strip() or "What do you know about Amsterdam?"
|
|
|
|
| 137 |
raise gr.Error("Bigram Viterbi is not enabled for this Space.")
|
| 138 |
try:
|
| 139 |
selector = BigramViterbiSelector(
|
| 140 |
+
_bigram_scorer(bigram_model_path).to(SESSION.device),
|
| 141 |
+
float(bigram_weight) if getattr(SESSION, "llada", False) else 0.5,
|
| 142 |
scoring_method=("pmi" if remasking_strategy == "PMI Viterbi + Repetition Penalty" else
|
| 143 |
{"Conditional bigram": "conditional", "PMI bigram": "pmi"}.get(bigram_scoring_method, "")),
|
| 144 |
min_count=int(pmi_min_count), pmi_clip=float(pmi_clip),
|
| 145 |
sequence_sampling=bool(sequence_sampling),
|
| 146 |
+
independent_temperature=bool(getattr(SESSION, "llada", False)),
|
| 147 |
remasking_confidence={"Diffusion probability": "diffusion", "Viterbi path margin": "viterbi_margin"}.get(bigram_remasking_confidence, ""),
|
| 148 |
)
|
| 149 |
if remasking_strategy == "PMI Viterbi + Repetition Penalty":
|
|
|
|
| 243 |
num_steps = gr.Slider(1, 512, value=64, step=1, label="Denoising steps")
|
| 244 |
block_length = gr.Slider(1, 512, value=64, step=1, label="Block length")
|
| 245 |
temperature = gr.Slider(0.0, 2.0, value=DEFAULT_TEMPERATURE, step=0.05, label="Temperature",
|
| 246 |
+
info=("For sequence sampling: higher values increase randomness; 0 selects the best path. Bigram weight controls PMI influence. Maximum-path Viterbi ignores temperature."
|
| 247 |
+
if SESSION.llada else "In Viterbi, lower values favor diffusion predictions over bigrams; 0 ignores bigram scores. Viterbi remains deterministic.") if BIGRAM_ENABLED else None)
|
| 248 |
+
bigram_weight = gr.Slider(0.0, 5.0, value=1.0, step=0.05, label="Bigram weight",
|
| 249 |
+
visible=SESSION.llada and BIGRAM_ENABLED,
|
| 250 |
+
info="PMI coefficient: 0 disables PMI; 1 gives equal diffusion and PMI score coefficients. Independent of temperature.")
|
| 251 |
top_k = gr.Slider(1, 100, value=DEFAULT_TOP_K, step=1, label="Top-k",
|
| 252 |
info="Number of candidate tokens per position for sampling or Viterbi. At 1, only the model’s highest-scoring token is available." if BIGRAM_ENABLED else None)
|
| 253 |
pause_per_step = gr.Slider(
|
|
|
|
| 368 |
adaptive_parallel_decoding,
|
| 369 |
sequence_sampling,
|
| 370 |
count_all_candidate_bigrams,
|
| 371 |
+
bigram_weight,
|
| 372 |
]
|
| 373 |
def update_ar_controls(strategy, apd=False):
|
| 374 |
"""Expose AR-only controls and clear revision when another strategy is selected."""
|
src/diffusion_lm/bigram.py
CHANGED
|
@@ -205,7 +205,7 @@ def expected_bigram_repetition_penalties(token_ids, probabilities, vocab_size, s
|
|
| 205 |
|
| 206 |
|
| 207 |
class BigramViterbiSelector:
|
| 208 |
-
def __init__(self, scorer, weight=0.5, *, scoring_method="conditional", min_count=5, pmi_clip=5.0, remasking_confidence="diffusion", sequence_sampling=False):
|
| 209 |
if not math.isfinite(weight) or weight < 0:
|
| 210 |
raise ValueError("Bigram weight must be finite and nonnegative")
|
| 211 |
BigramScorer.validate_scoring(scoring_method, min_count, pmi_clip)
|
|
@@ -213,6 +213,7 @@ class BigramViterbiSelector:
|
|
| 213 |
raise ValueError("Remasking confidence must be 'diffusion' or 'viterbi_margin'")
|
| 214 |
self.remasking_confidence = remasking_confidence
|
| 215 |
self.sequence_sampling = bool(sequence_sampling)
|
|
|
|
| 216 |
self.last_path_margins = None
|
| 217 |
self.scorer, self.weight = scorer, float(weight)
|
| 218 |
self.scoring_method, self.min_count, self.pmi_clip = scoring_method, min_count, float(pmi_clip)
|
|
@@ -243,7 +244,7 @@ class BigramViterbiSelector:
|
|
| 243 |
return token_ids.gather(1, path[:, None]).squeeze(1)
|
| 244 |
|
| 245 |
@staticmethod
|
| 246 |
-
def sample_sequence(token_ids, emissions, transitions, weight=1.0):
|
| 247 |
"""Exact forward-filter/backward sampling from exp(total path score).
|
| 248 |
|
| 249 |
No score perturbations or model calls. Centering each forward row
|
|
@@ -255,7 +256,18 @@ class BigramViterbiSelector:
|
|
| 255 |
length, k = emissions.shape
|
| 256 |
if transitions.shape != (length - 1, k, k):
|
| 257 |
raise ValueError("Expected transitions [B-1,K,K]")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 258 |
edges = transitions.float() * weight if weight else torch.zeros_like(transitions, dtype=torch.float32)
|
|
|
|
|
|
|
|
|
|
| 259 |
forward = torch.empty_like(emissions, dtype=torch.float32)
|
| 260 |
row = emissions[0].float()
|
| 261 |
forward[0] = row - row.max()
|
|
@@ -321,6 +333,9 @@ class BigramViterbiSelector:
|
|
| 321 |
raw log probabilities + (weight * T) * transitions. The latter avoids
|
| 322 |
division by tiny T and has the exact greedy limit at T=0. Margins use
|
| 323 |
these common rescaled units, preserving their retention ranking.
|
|
|
|
|
|
|
|
|
|
| 324 |
Returned diffusion confidence always uses raw full-vocabulary p_t.
|
| 325 |
Optional repetition penalties subtract gamma*C(a,b) directly from each
|
| 326 |
edge, independently of the PMI weight and temperature. Expected counts
|
|
@@ -336,7 +351,7 @@ class BigramViterbiSelector:
|
|
| 336 |
temperature = float(temperature)
|
| 337 |
if not math.isfinite(temperature) or temperature < 0:
|
| 338 |
raise ValueError("temperature must be finite and nonnegative")
|
| 339 |
-
weight = self.weight * temperature
|
| 340 |
if not math.isfinite(weight):
|
| 341 |
raise ValueError("temperature times bigram weight must be finite")
|
| 342 |
self.last_path_margins = None
|
|
@@ -388,7 +403,10 @@ class BigramViterbiSelector:
|
|
| 388 |
if repetition_penalty_strength:
|
| 389 |
edges = edges - penalties
|
| 390 |
decoder = self.sample_sequence if self.sequence_sampling else self.decode
|
| 391 |
-
|
|
|
|
|
|
|
|
|
|
| 392 |
if self.remasking_confidence == "viterbi_margin":
|
| 393 |
self.last_path_margins = self.path_margins(candidates, emissions, edges, selected, 1.0)
|
| 394 |
elif self.remasking_confidence == "viterbi_margin":
|
|
|
|
| 205 |
|
| 206 |
|
| 207 |
class BigramViterbiSelector:
|
| 208 |
+
def __init__(self, scorer, weight=0.5, *, scoring_method="conditional", min_count=5, pmi_clip=5.0, remasking_confidence="diffusion", sequence_sampling=False, independent_temperature=False):
|
| 209 |
if not math.isfinite(weight) or weight < 0:
|
| 210 |
raise ValueError("Bigram weight must be finite and nonnegative")
|
| 211 |
BigramScorer.validate_scoring(scoring_method, min_count, pmi_clip)
|
|
|
|
| 213 |
raise ValueError("Remasking confidence must be 'diffusion' or 'viterbi_margin'")
|
| 214 |
self.remasking_confidence = remasking_confidence
|
| 215 |
self.sequence_sampling = bool(sequence_sampling)
|
| 216 |
+
self.independent_temperature = bool(independent_temperature)
|
| 217 |
self.last_path_margins = None
|
| 218 |
self.scorer, self.weight = scorer, float(weight)
|
| 219 |
self.scoring_method, self.min_count, self.pmi_clip = scoring_method, min_count, float(pmi_clip)
|
|
|
|
| 244 |
return token_ids.gather(1, path[:, None]).squeeze(1)
|
| 245 |
|
| 246 |
@staticmethod
|
| 247 |
+
def sample_sequence(token_ids, emissions, transitions, weight=1.0, temperature=1.0):
|
| 248 |
"""Exact forward-filter/backward sampling from exp(total path score).
|
| 249 |
|
| 250 |
No score perturbations or model calls. Centering each forward row
|
|
|
|
| 256 |
length, k = emissions.shape
|
| 257 |
if transitions.shape != (length - 1, k, k):
|
| 258 |
raise ValueError("Expected transitions [B-1,K,K]")
|
| 259 |
+
temperature = float(temperature)
|
| 260 |
+
if not math.isfinite(temperature) or temperature < 0:
|
| 261 |
+
raise ValueError("Sequence temperature must be finite and nonnegative")
|
| 262 |
+
if temperature == 0:
|
| 263 |
+
return BigramViterbiSelector.decode(token_ids, emissions, transitions, weight)
|
| 264 |
+
# Global path temperature changes entropy without changing the relative
|
| 265 |
+
# diffusion/PMI/repetition weights. Tiny positive T approaches argmax.
|
| 266 |
+
scale = max(temperature, 1e-6)
|
| 267 |
edges = transitions.float() * weight if weight else torch.zeros_like(transitions, dtype=torch.float32)
|
| 268 |
+
if edges.numel():
|
| 269 |
+
edges = (edges - edges.amax(dim=(1, 2), keepdim=True)) / scale
|
| 270 |
+
emissions = (emissions.float() - emissions.float().amax(-1, keepdim=True)) / scale
|
| 271 |
forward = torch.empty_like(emissions, dtype=torch.float32)
|
| 272 |
row = emissions[0].float()
|
| 273 |
forward[0] = row - row.max()
|
|
|
|
| 333 |
raw log probabilities + (weight * T) * transitions. The latter avoids
|
| 334 |
division by tiny T and has the exact greedy limit at T=0. Margins use
|
| 335 |
these common rescaled units, preserving their retention ranking.
|
| 336 |
+
With independent_temperature=True, weight directly multiplies PMI and
|
| 337 |
+
temperature only sets the sequence sampling distribution exp(S/T).
|
| 338 |
+
Maximum-path decoding is temperature-independent; T=0 samples its argmax.
|
| 339 |
Returned diffusion confidence always uses raw full-vocabulary p_t.
|
| 340 |
Optional repetition penalties subtract gamma*C(a,b) directly from each
|
| 341 |
edge, independently of the PMI weight and temperature. Expected counts
|
|
|
|
| 351 |
temperature = float(temperature)
|
| 352 |
if not math.isfinite(temperature) or temperature < 0:
|
| 353 |
raise ValueError("temperature must be finite and nonnegative")
|
| 354 |
+
weight = self.weight if self.independent_temperature else self.weight * temperature
|
| 355 |
if not math.isfinite(weight):
|
| 356 |
raise ValueError("temperature times bigram weight must be finite")
|
| 357 |
self.last_path_margins = None
|
|
|
|
| 403 |
if repetition_penalty_strength:
|
| 404 |
edges = edges - penalties
|
| 405 |
decoder = self.sample_sequence if self.sequence_sampling else self.decode
|
| 406 |
+
if self.sequence_sampling and self.independent_temperature:
|
| 407 |
+
selected = decoder(candidates, emissions, edges, 1.0, temperature=temperature)
|
| 408 |
+
else:
|
| 409 |
+
selected = decoder(candidates, emissions, edges, 1.0)
|
| 410 |
if self.remasking_confidence == "viterbi_margin":
|
| 411 |
self.last_path_margins = self.path_margins(candidates, emissions, edges, selected, 1.0)
|
| 412 |
elif self.remasking_confidence == "viterbi_margin":
|