metrale_model_arch/deepseek_v4_mtp/
proposer.rs1use super::*;
9
10impl DraftProposer for DeepseekV4MtpHead {
11 fn alloc_state(&self, gpu: &dyn GpuBackend) -> Result<Box<dyn ProposerState>> {
12 Ok(Box::new(self.alloc_state_inner(gpu)?))
13 }
14
15 fn propose(
16 &self,
17 last_token: u32,
18 target_hidden: DevicePtr,
19 position: usize,
20 num_drafts: usize,
21 state: &mut dyn ProposerState,
22 ctx: &ForwardContext,
23 stream: u64,
24 _draft_embed_target: Option<DevicePtr>,
25 grammar_bitmask: Option<&[i32]>,
26 _target_hidden_stack: Option<DevicePtr>,
27 ) -> Result<Vec<u32>> {
28 let v4_state = state
29 .as_any_mut()
30 .downcast_mut::<DeepseekV4MtpProposerState>()
31 .ok_or_else(|| anyhow::anyhow!("Invalid V4 MTP proposer state"))?;
32
33 let mut drafts = Vec::with_capacity(num_drafts);
34 let mut current_token = last_token;
35 let mut current_hidden = target_hidden;
36 for i in 0..num_drafts {
37 if grammar_bitmask.is_some() && i > 0 {
38 tracing::warn!(
39 "V4 MTP grammar-masked drafting with num_drafts>1 (i={i}); \
40 mask held fixed across draft positions — acceptance may drop."
41 );
42 }
43 let draft = self.forward_one(
44 current_token,
45 current_hidden,
46 position + i,
47 v4_state,
48 ctx,
49 stream,
50 grammar_bitmask,
51 )?;
52 tracing::debug!(
53 "V4 MTP propose[{i}]: token={current_token} pos={} mtp_seq_len={} → draft={draft}",
54 position + i,
55 v4_state.seq_len,
56 );
57 drafts.push(draft);
58 current_token = draft;
59 current_hidden = ctx.buffers.hidden_states();
62 }
63 v4_state.last_num_drafted = drafts.len();
64 Ok(drafts)
65 }
66
67 fn after_verify(
68 &self,
69 num_accepted: usize,
70 state: &mut dyn ProposerState,
71 _stream: u64,
72 ) -> Result<()> {
73 let v4_state = state
74 .as_any_mut()
75 .downcast_mut::<DeepseekV4MtpProposerState>()
76 .ok_or_else(|| anyhow::anyhow!("Invalid V4 MTP proposer state"))?;
77 let num_drafted = v4_state.last_num_drafted.max(1);
81 let num_to_trim = num_drafted.saturating_sub(num_accepted);
82 let old_sl = v4_state.seq_len;
83 if num_to_trim > 0 {
84 v4_state.seq_len = v4_state.seq_len.saturating_sub(num_to_trim);
85 }
86 tracing::debug!(
87 "V4 MTP after_verify: accepted={num_accepted} drafted={num_drafted} \
88 trim={num_to_trim} mtp_seq_len: {old_sl} → {}",
89 v4_state.seq_len,
90 );
91 Ok(())
92 }
93
94 fn free_state(&self, _gpu: &dyn GpuBackend, state: &mut dyn ProposerState) -> Result<()> {
95 let v4_state = state
96 .as_any_mut()
97 .downcast_mut::<DeepseekV4MtpProposerState>()
98 .ok_or_else(|| anyhow::anyhow!("Invalid V4 MTP proposer state"))?;
99 if !v4_state.block_table.is_empty() {
100 self.kv_cache.lock().free_blocks(&v4_state.block_table);
101 v4_state.block_table.clear();
102 }
103 v4_state.seq_len = 0;
104 Ok(())
105 }
106}