Create a causal attention mask. Returns a U8 tensor of shape `(seq_len, kv_len)` where 1 = masked (future position), 0 = attend. Callers use `masked_fill` or `where_cond` to apply the mask.
(
&self,
seq_len: usize,
kv_len: usize,
device: &Device,
)
| 531 | /// where 1 = masked (future position), 0 = attend. |
| 532 | /// Callers use `masked_fill` or `where_cond` to apply the mask. |
| 533 | fn causal_mask( |
| 534 | &self, |
| 535 | seq_len: usize, |
| 536 | kv_len: usize, |
| 537 | device: &Device, |
| 538 | ) -> Result<Tensor> { |
| 539 | if seq_len == 1 { |
| 540 | return Tensor::zeros((1, kv_len), DType::U8, device); |
| 541 | } |
| 542 | // Build full (seq_len, kv_len) mask in one allocation — no Tensor::cat. |
| 543 | let prefix = kv_len.saturating_sub(seq_len); |
| 544 | let mut mask = vec![0u8; seq_len * kv_len]; |
| 545 | for i in 0..seq_len { |
| 546 | let row_start = i * kv_len + prefix + i + 1; |
| 547 | let row_end = (i + 1) * kv_len; |
| 548 | if row_start < row_end { |
| 549 | mask[row_start..row_end].fill(1); |
| 550 | } |
| 551 | } |
| 552 | Tensor::from_vec(mask, (seq_len, kv_len), device) |
| 553 | } |
| 554 | |
| 555 | /// Top-K selection: returns `(values, indices)` for the largest K elements |
| 556 | /// along the last dimension. Uses partial sort O(N + K log K) for large N. |
no outgoing calls