Skip to content

fused CPU/f32 neox RoPE - #48

Open
DrJesseGlass wants to merge 5 commits into
downstreamfrom
cpu-optimized/quantized-qwen3-rope
Open

fused CPU/f32 neox RoPE#48
DrJesseGlass wants to merge 5 commits into
downstreamfrom
cpu-optimized/quantized-qwen3-rope

Conversation

@DrJesseGlass

Copy link
Copy Markdown
Owner

No description provided.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 70445d9078

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

for bh in 0..b * h {
let chunk = bh * t * d;
for it in 0..t {
let (cos, sin) = self.cos_sin_at(offset + it);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Return an error when RoPE positions exceed the table

When the CPU/f32 fast path is enabled, offset + it is passed to cos_sin_at, which slices self.cos_f32[start..end] without bounds checks returning a Result. For inputs whose prompt/decode position exceeds max_position_embeddings, the previous path failed through self.cos.narrow(...)?, but this default path will panic and crash the caller instead of propagating an error; add the same range validation before entering the fused loop or make cos_sin_at fallible.

Useful? React with 👍 / 👎.

@DrJesseGlass

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1bcdbc82ea

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

/// Apply RoPE (q, k shape: B x H x L x D)
pub fn apply(&self, q: &Tensor, k: &Tensor, offset: usize) -> Result<(Tensor, Tensor)> {
// CPU f32 fast path: fused neox on raw slices, bit-identical to the op path.
if *FUSED_ROPE && q.device().is_cpu() && q.dtype() == DType::F32 {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep the fused RoPE path out of prefill

This condition also catches prompt/prefill calls (seq_len > 1) on CPU f32 tensors, not just single-token decode. The new rope_neox_f32 implementation below iterates b*h*t*d in a single thread, whereas the existing candle_nn::rotary_emb::rope CPU path uses par_chunks for t > 1, so long CPU prefills now bypass the parallel implementation and can become much slower. Please either gate this branch on seq_len == 1 or parallelize it before replacing the op path.

Useful? React with 👍 / 👎.

@DrJesseGlass

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e94b8827e0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

fn rope_neox_f32(&self, x: &Tensor, offset: usize) -> Result<Tensor> {
let (b, h, t, d) = x.dims4()?;
let half = d / 2;
debug_assert_eq!(half, self.half_d);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Guard mismatched RoPE head dims in release

When this fast path is used with a CPU/F32 decode input whose last dimension does not match the RotaryEmbedding head dim (for example an inconsistent GGUF key_length/projection shape, or a direct caller of the public apply), this debug_assert is compiled out in release. The old candle_nn::rotary_emb::rope path returned a shape error, but the fused path can either index past cos[j]/sin[j] and panic or return a tensor using only part of the RoPE table, so make this a runtime bail! before slicing.

Useful? React with 👍 / 👎.

@DrJesseGlass

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4c6d4d4fec

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// candle_nn::rotary_emb::rope (same op order) but on raw slices, no apply_op3.
fn rope_neox_f32(&self, x: &Tensor, offset: usize) -> Result<Tensor> {
let (b, h, t, d) = x.dims4()?;
let half = d / 2;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 Badge Reject odd RoPE head dimensions in the fast path

When the CPU/f32 decode fast path runs with an odd head dimension, half is floor(d / 2), so the new check still passes for a matching RotaryEmbedding and the loop only writes the paired coordinates, leaving the final coordinate as zero; with d == 1 it reaches the max_pos division with half_d == 0 and panics. The previous rotary_emb::rope path rejected these shapes via its cos_n_embd * 2 != n_embd validation, so this changes an edge/invalid config from a clean error into corrupted q/k values or a panic; bail when d is odd before continuing.

Useful? React with 👍 / 👎.

@DrJesseGlass

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

Reviewed commit: ebfa511c86

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant