TensorTonic
Problems
Speculative Decoding Acceptance
JAX
Hard

Decide which draft tokens one speculative decoding step keeps, using the target and draft probabilities with the supplied uniform noise, and pick the correction token from the residual distribution.

The batch has B rows, and for each row a small draft model has proposed G tokens. draft_tokens[b, i] is the draft token xix_ixi​ at position iii of row bbb. The vector qiq_iqi​ = draft_probs[b, i] is the distribution the draft model sampled xix_ixi​ from, and pip_ipi​ = target_probs[b, i] is the large target model's distribution at the same position. target_probs has one extra position, pGp_GpG​, which is the target distribution after the last draft token. With uiu_iui​ = accept_uniforms[b, i], draft token iii passes its test when

ui<pi(xi)qi(xi)u_i < \frac{p_i(x_i)}{q_i(x_i)}ui​<qi​(xi​)pi​(xi​)​

The tests run in order and the first failure ends the step, so nnn = num_accepted is the number of tests passed before the first failure, or G when every test passes. One more token yyy is then drawn at position nnn from the distribution rrr.

r(v)=max⁡(pn(v)−qn(v), 0)∑wmax⁡(pn(w)−qn(w), 0)  if n<G,r(v)=pG(v)∑wpG(w)  if n=Gr(v) = \frac{\max\big(p_n(v) - q_n(v),\, 0\big)}{\sum_{w} \max\big(p_n(w) - q_n(w),\, 0\big)} \ \text{ if } n < G, \qquad r(v) = \frac{p_G(v)}{\sum_{w} p_G(w)} \ \text{ if } n = Gr(v)=∑w​max(pn​(w)−qn​(w),0)max(pn​(v)−qn​(v),0)​  if n<G,r(v)=∑w​pG​(w)pG​(v)​  if n=G

Here vvv and www run over the V vocabulary entries. With sss = sample_uniforms[b], the drawn token yyy is the smallest vvv whose cumulative probability r(0)+⋯+r(v)r(0) + \dots + r(v)r(0)+⋯+r(v) is greater than sss.

Return a dict with two keys. num_accepted is an int32 JAX array of shape (B,), and tokens is an int32 JAX array of shape (B, G + 1) whose row bbb holds the nnn accepted draft tokens, then yyy, then -1 in every remaining position.

Examples

Input: draft_tokens = [[3,2]], draft_probs = [[[0.2,0.59,0.04,0.17],[0.12,0.43,0.42,0.03]]], target_probs = [[[0.04,0.44,0.24,0.28],[0.27,0.36,0.23,0.14],[0.19,0.34,0.07,0.4]]], accept_uniforms = [[0.27,0.79]], sample_uniforms = [0.92]

Output: {"num_accepted":[1],"tokens":[[3,3,-1]]}

Explanation: Draft token 3 has target probability 0.28 and draft probability 0.17, a ratio of about 1.647, so it passes with u = 0.27. Draft token 2 has ratio 0.23 / 0.42, about 0.548, and fails with u = 0.79, so num_accepted is 1. The residual at position 1 is max(p - q, 0) = [0.15, 0, 0, 0.11], which normalizes to about [0.577, 0, 0, 0.423], and the cumulative probability first exceeds 0.92 at token 3.

Input: draft_tokens = [[1,0,2],[2,1,1]], draft_probs = [[[0.38,0.31,0.2,0.11],[0.16,0.01,0.55,0.28],[0.26,0.33,0.06,0.35]],[[0.01,0.13,0.49,0.37],[0.26,0.12,0.37,0.25],[0.05,0.25,0.67,0.03]]], target_probs = [[[0.3,0.4,0.05,0.25],[0.63,0.1,0.2,0.07],[0.16,0.05,0.46,0.33],[0.14,0.55,0.18,0.13]],[[0.11,0.71,0.08,0.1],[0.21,0.45,0.01,0.33],[0.07,0.02,0.49,0.42],[0.22,0.25,0.28,0.25]]], accept_uniforms = [[0.83,0.99,0.77],[0.6,0.08,0.03]], sample_uniforms = [0.59,0.73]

Output: {"num_accepted":[3,0],"tokens":[[1,0,2,1],[1,-1,-1,-1]]}

Input: draft_tokens = [[2]], draft_probs = [[[0.01,0.25,0.49,0.01,0.24]]], target_probs = [[[0.24,0.31,0.06,0.05,0.34],[0.04,0.17,0.1,0.14,0.55]]], accept_uniforms = [[0.66]], sample_uniforms = [0.38]

Output: {"num_accepted":[0],"tokens":[[0,-1]]}

Hint 1

jnp.take_along_axis(p, draft_tokens[..., None], axis=-1) reads each draft token's probability.

Hint 2

jnp.sum(jnp.cumprod(passed, axis=-1), axis=-1) counts tokens before the first failure.

Hint 3

x[jnp.arange(B), pos] selects a different position in each row.

Requirements

  • The function is compiled with jax.jit with every input traced, so the number of accepted tokens of a row exists only as a traced value and cannot drive a Python loop, a break or an if statement.
  • Use only the supplied uniforms for randomness and draw no random numbers of your own.

Constraints

  • B is between 1 and 4, G is between 1 and 4, and V is between 4 and 6.
  • draft_tokens is an int32 array of shape (B, G) with values from 0 to V minus 1, and the draft probability of every draft token is positive.
  • draft_probs has shape (B, G, V) and target_probs has shape (B, G + 1, V). Both are float32 with non-negative entries, and every distribution sums to 1 up to rounding.
  • accept_uniforms is a float32 array of shape (B, G) with values in [0, 1), and sample_uniforms is a float32 array of shape (B,) with values in [0, 0.99].
  • No acceptance ratio and no cumulative probability lies within 0.002 of the uniform it is compared with, and the residual at a rejected position always has positive total mass.
Try Similar Problems
Beam Search StepHardGreedy Decode Loop with ScanMediumPaged KV Cache GatherMediumGradient Accumulation with ScanHardBlockwise Attention with Online SoftmaxHardRing All-Reduce with ppermuteHardPad and Mask to Bucket LengthMediumHessian-Vector ProductMediumPer-Example Gradient ClippingMediumStraight-Through Estimator with Custom VJPMediumTraced Learning Rate ScheduleMediumExponential Moving Average with ScanMedium

Accepts: array

Accepts: array

Accepts: array

Accepts: array

Accepts: array

You must run your code first.
Speculative Decoding Acceptance

Speculative Decoding Acceptance

JAX
Hard

Decide which draft tokens one speculative decoding step keeps, using the target and draft probabilities with the supplied uniform noise, and pick the correction token from the residual distribution.

The batch has B rows, and for each row a small draft model has proposed G tokens. draft_tokens[b, i] is the draft token xix_ixi​ at position iii of row bbb. The vector qiq_iqi​ = draft_probs[b, i] is the distribution the draft model sampled xix_ixi​ from, and pip_ipi​ = target_probs[b, i] is the large target model's distribution at the same position. target_probs has one extra position, pGp_GpG​, which is the target distribution after the last draft token. With uiu_iui​ = accept_uniforms[b, i], draft token iii passes its test when

ui<pi(xi)qi(xi)u_i < \frac{p_i(x_i)}{q_i(x_i)}ui​<qi​(xi​)pi​(xi​)​

The tests run in order and the first failure ends the step, so nnn = num_accepted is the number of tests passed before the first failure, or G when every test passes. One more token yyy is then drawn at position nnn from the distribution rrr.

r(v)=max⁡(pn(v)−qn(v), 0)∑wmax⁡(pn(w)−qn(w), 0)  if n<G,r(v)=pG(v)∑wpG(w)  if n=Gr(v) = \frac{\max\big(p_n(v) - q_n(v),\, 0\big)}{\sum_{w} \max\big(p_n(w) - q_n(w),\, 0\big)} \ \text{ if } n < G, \qquad r(v) = \frac{p_G(v)}{\sum_{w} p_G(w)} \ \text{ if } n = Gr(v)=∑w​max(pn​(w)−qn​(w),0)max(pn​(v)−qn​(v),0)​  if n<G,r(v)=∑w​pG​(w)pG​(v)​  if n=G

Here vvv and www run over the V vocabulary entries. With sss = sample_uniforms[b], the drawn token yyy is the smallest vvv whose cumulative probability r(0)+⋯+r(v)r(0) + \dots + r(v)r(0)+⋯+r(v) is greater than sss.

Return a dict with two keys. num_accepted is an int32 JAX array of shape (B,), and tokens is an int32 JAX array of shape (B, G + 1) whose row bbb holds the nnn accepted draft tokens, then yyy, then -1 in every remaining position.

Examples

Input: draft_tokens = [[3,2]], draft_probs = [[[0.2,0.59,0.04,0.17],[0.12,0.43,0.42,0.03]]], target_probs = [[[0.04,0.44,0.24,0.28],[0.27,0.36,0.23,0.14],[0.19,0.34,0.07,0.4]]], accept_uniforms = [[0.27,0.79]], sample_uniforms = [0.92]

Output: {"num_accepted":[1],"tokens":[[3,3,-1]]}

Explanation: Draft token 3 has target probability 0.28 and draft probability 0.17, a ratio of about 1.647, so it passes with u = 0.27. Draft token 2 has ratio 0.23 / 0.42, about 0.548, and fails with u = 0.79, so num_accepted is 1. The residual at position 1 is max(p - q, 0) = [0.15, 0, 0, 0.11], which normalizes to about [0.577, 0, 0, 0.423], and the cumulative probability first exceeds 0.92 at token 3.

Input: draft_tokens = [[1,0,2],[2,1,1]], draft_probs = [[[0.38,0.31,0.2,0.11],[0.16,0.01,0.55,0.28],[0.26,0.33,0.06,0.35]],[[0.01,0.13,0.49,0.37],[0.26,0.12,0.37,0.25],[0.05,0.25,0.67,0.03]]], target_probs = [[[0.3,0.4,0.05,0.25],[0.63,0.1,0.2,0.07],[0.16,0.05,0.46,0.33],[0.14,0.55,0.18,0.13]],[[0.11,0.71,0.08,0.1],[0.21,0.45,0.01,0.33],[0.07,0.02,0.49,0.42],[0.22,0.25,0.28,0.25]]], accept_uniforms = [[0.83,0.99,0.77],[0.6,0.08,0.03]], sample_uniforms = [0.59,0.73]

Output: {"num_accepted":[3,0],"tokens":[[1,0,2,1],[1,-1,-1,-1]]}

Input: draft_tokens = [[2]], draft_probs = [[[0.01,0.25,0.49,0.01,0.24]]], target_probs = [[[0.24,0.31,0.06,0.05,0.34],[0.04,0.17,0.1,0.14,0.55]]], accept_uniforms = [[0.66]], sample_uniforms = [0.38]

Output: {"num_accepted":[0],"tokens":[[0,-1]]}

Hint 1

jnp.take_along_axis(p, draft_tokens[..., None], axis=-1) reads each draft token's probability.

Hint 2

jnp.sum(jnp.cumprod(passed, axis=-1), axis=-1) counts tokens before the first failure.

Hint 3

x[jnp.arange(B), pos] selects a different position in each row.

Requirements

  • The function is compiled with jax.jit with every input traced, so the number of accepted tokens of a row exists only as a traced value and cannot drive a Python loop, a break or an if statement.
  • Use only the supplied uniforms for randomness and draw no random numbers of your own.

Constraints

  • B is between 1 and 4, G is between 1 and 4, and V is between 4 and 6.
  • draft_tokens is an int32 array of shape (B, G) with values from 0 to V minus 1, and the draft probability of every draft token is positive.
  • draft_probs has shape (B, G, V) and target_probs has shape (B, G + 1, V). Both are float32 with non-negative entries, and every distribution sums to 1 up to rounding.
  • accept_uniforms is a float32 array of shape (B, G) with values in [0, 1), and sample_uniforms is a float32 array of shape (B,) with values in [0, 0.99].
  • No acceptance ratio and no cumulative probability lies within 0.002 of the uniform it is compared with, and the residual at a rejected position always has positive total mass.
Try Similar Problems
Beam Search StepHardGreedy Decode Loop with ScanMediumPaged KV Cache GatherMediumGradient Accumulation with ScanHardBlockwise Attention with Online SoftmaxHardRing All-Reduce with ppermuteHardPad and Mask to Bucket LengthMediumHessian-Vector ProductMediumPer-Example Gradient ClippingMediumStraight-Through Estimator with Custom VJPMediumTraced Learning Rate ScheduleMediumExponential Moving Average with ScanMedium

Accepts: array

Accepts: array

Accepts: array

Accepts: array

Accepts: array

You must run your code first.
Problems
Loading...
1 / 1