1use std::path::Path;
19use std::sync::Arc;
20
21use crate::blocks::{
22 AttnMaskStage, BertEncoderLayerSpec, BertEncoderLayerStage, BertQkvStyle,
23 BindDecodeInputsStage, ClsTokenPoolStage, CustomStage, EmbedStage, FfnActivation,
24 GatherAddStage, GatherDecodeRopeStage, GatherFromInputStage, GatherLastTokenStage,
25 GeluFfnStage, LayerNormStage, LinearStage, LlamaDecodeLayerStage, LlamaDecoderSpec,
26 LlamaDecoderStage, LlamaKvTapStage, LmHeadStage, NomicEncoderLayerSpec, NomicEncoderLayerStage,
27 RepeatStage, ResidualAddStage, ResidualSaveStage, RmsNormStage, RopeTablesStage,
28 SelfAttnPrefillSpec, SelfAttnPrefillStage, SwiGluStage, dinov2_layer_fused,
29 dinov2_layer_fused_exact, llama_prefill_layer_composed, llama_prefill_layer_fused,
30 nomic_vision_layer_fused, transformer_encoder_layer,
31};
32use crate::escape::Emit;
33use crate::flow::ModelFlow;
34use crate::layer::LayerStack;
35use crate::profile::CompileProfile;
36use crate::side::SideOutputs;
37use crate::stage::FlowStage;
38use crate::stream::{DualStreamStage, LoadStreamStage, StoreStreamStage};
39use crate::value::FlowValue;
40
41impl ModelFlow {
42 pub fn profile_file(mut self, path: impl AsRef<Path>, default: fn() -> CompileProfile) -> Self {
44 self.profile = CompileProfile::from_toml_path(path.as_ref()).unwrap_or_else(|_| default());
45 self
46 }
47
48 pub fn profile_encoder(mut self) -> Self {
50 self.profile = CompileProfile::encoder();
51 self
52 }
53
54 pub fn gather_from_input(
56 mut self,
57 input_name: impl Into<String>,
58 weight_key: impl Into<String>,
59 ) -> Self {
60 self.stages
61 .push(FlowStage::GatherFromInput(GatherFromInputStage::new(
62 input_name, weight_key, 0,
63 )));
64 self
65 }
66
67 pub fn gather_add(
69 mut self,
70 input_name: impl Into<String>,
71 weight_key: impl Into<String>,
72 ) -> Self {
73 self.stages.push(FlowStage::GatherAdd(GatherAddStage::new(
74 input_name, weight_key, 0,
75 )));
76 self
77 }
78
79 pub fn layer_norm(
81 mut self,
82 gamma_key: impl Into<String>,
83 beta_key: impl Into<String>,
84 eps: f32,
85 ) -> Self {
86 self.stages.push(FlowStage::LayerNorm(LayerNormStage::new(
87 gamma_key, beta_key, eps,
88 )));
89 self
90 }
91
92 pub fn gelu_ffn(mut self, layer_prefix: impl Into<String>) -> Self {
94 self.stages
95 .push(FlowStage::GeluFfn(GeluFfnStage::hf_bert(layer_prefix)));
96 self
97 }
98
99 pub fn repeat_nomic_layers(
101 self,
102 count: usize,
103 hidden_size: usize,
104 num_heads: usize,
105 head_dim: usize,
106 eps: f32,
107 ) -> Self {
108 self.repeat_layers(count, move |i| FlowStage::Named {
109 name: format!("layer{i}"),
110 inner: std::sync::Arc::new(FlowStage::NomicEncoderLayer(NomicEncoderLayerStage::new(
111 NomicEncoderLayerSpec::hf(
112 format!("encoder.layers.{i}"),
113 hidden_size,
114 num_heads,
115 head_dim,
116 eps,
117 ),
118 ))),
119 })
120 }
121
122 pub fn bert_encoder_layer(mut self, spec: BertEncoderLayerSpec) -> Self {
124 self.stages
125 .push(FlowStage::BertEncoderLayer(BertEncoderLayerStage::new(
126 spec,
127 )));
128 self
129 }
130
131 pub fn repeat_bert_layers(
133 self,
134 count: usize,
135 prefix: impl Into<String>,
136 qkv_style: BertQkvStyle,
137 hidden_size: usize,
138 num_heads: usize,
139 eps: f32,
140 ) -> Self {
141 let prefix = prefix.into();
142 self.repeat_layers(count, move |i| {
143 let lp = if prefix.is_empty() {
144 format!("encoder.layer.{i}")
145 } else {
146 format!("{prefix}.encoder.layer.{i}")
147 };
148 FlowStage::Named {
149 name: format!("layer{i}"),
150 inner: std::sync::Arc::new(FlowStage::BertEncoderLayer(
151 BertEncoderLayerStage::new(BertEncoderLayerSpec::hf(
152 lp,
153 qkv_style,
154 hidden_size,
155 num_heads,
156 eps,
157 )),
158 )),
159 }
160 })
161 }
162
163 pub fn attn_mask_ones(mut self, batch: usize, seq: usize) -> Self {
165 self.stages
166 .push(FlowStage::AttnMask(AttnMaskStage::ones(batch, seq)));
167 self
168 }
169
170 pub fn repeat_dinov2_layers(
172 self,
173 count: usize,
174 hidden_size: usize,
175 num_heads: usize,
176 eps: f32,
177 ) -> Self {
178 self.repeat_layers(count, move |i| {
179 dinov2_layer_fused(i, hidden_size, num_heads, eps)
180 })
181 }
182
183 pub fn repeat_dinov2_layers_exact(
187 self,
188 count: usize,
189 hidden_size: usize,
190 num_heads: usize,
191 eps: f32,
192 ) -> Self {
193 self.repeat_layers(count, move |i| {
194 dinov2_layer_fused_exact(i, hidden_size, num_heads, eps)
195 })
196 }
197
198 pub fn repeat_transformer_encoder_layers(
203 self,
204 count: usize,
205 hidden_size: usize,
206 num_heads: usize,
207 eps: f32,
208 norm_first: bool,
209 act: FfnActivation,
210 ) -> Self {
211 self.repeat_layers(count, move |i| {
212 transformer_encoder_layer(i, hidden_size, num_heads, eps, norm_first, act)
213 })
214 }
215
216 pub fn repeat_vision_layers(
218 self,
219 count: usize,
220 hidden_size: usize,
221 num_heads: usize,
222 eps: f32,
223 ) -> Self {
224 self.repeat_layers(count, move |i| {
225 nomic_vision_layer_fused(i, hidden_size, num_heads, eps)
226 })
227 }
228
229 pub fn repeat_siglip_layers(
231 self,
232 count: usize,
233 hidden_size: usize,
234 num_heads: usize,
235 eps: f32,
236 ) -> Self {
237 self.repeat_layers(count, move |i| {
238 nomic_vision_layer_fused(i, hidden_size, num_heads, eps)
239 })
240 }
241
242 pub fn cls_token_pool(mut self, batch: usize, hidden: usize) -> Self {
244 self.stages
245 .push(FlowStage::ClsTokenPool(ClsTokenPoolStage::new(
246 batch, hidden,
247 )));
248 self
249 }
250
251 pub fn profile_prefill(mut self) -> Self {
253 self.profile = CompileProfile::llama32_prefill();
254 self
255 }
256
257 pub fn profile_decode(mut self) -> Self {
259 self.profile = CompileProfile::llama32_decode();
260 self
261 }
262
263 pub fn embed(mut self, weight_key: impl Into<String>) -> Self {
265 self.stages
266 .push(FlowStage::Embed(EmbedStage::token(weight_key)));
267 self
268 }
269
270 pub fn token_embed(self) -> Self {
272 self.embed("model.embed_tokens.weight")
273 }
274
275 pub fn rope_tables(mut self, tables: RopeTablesStage) -> Self {
277 self.stages.push(FlowStage::RopeTables(tables));
278 self
279 }
280
281 pub fn gather_decode_rope(mut self, half_dim: usize) -> Self {
283 self.stages
284 .push(FlowStage::GatherDecodeRope(GatherDecodeRopeStage::new(
285 half_dim,
286 )));
287 self
288 }
289
290 pub fn zero_beta(self, len: usize) -> Self {
292 self.zero_beta_named("zero_beta", len)
293 }
294
295 pub fn zero_beta_named(mut self, name: impl Into<String>, len: usize) -> Self {
296 self.stages.push(FlowStage::ZeroBeta {
297 name: name.into(),
298 len,
299 });
300 self
301 }
302
303 pub fn bind_decode_inputs(
305 mut self,
306 num_layers: usize,
307 custom_mask: bool,
308 need_past_kv: bool,
309 ) -> Self {
310 self.stages
311 .push(FlowStage::BindDecodeInputs(BindDecodeInputsStage {
312 num_layers,
313 use_custom_mask: custom_mask,
314 need_past_kv,
315 }));
316 self
317 }
318
319 pub fn repeat_layers(
321 mut self,
322 count: usize,
323 stage_for_layer: impl Fn(usize) -> FlowStage + Send + Sync + 'static,
324 ) -> Self {
325 self.stages
326 .push(FlowStage::Repeat(RepeatStage::new(count, stage_for_layer)));
327 self
328 }
329
330 pub fn named_layer(mut self, name: impl Into<String>, inner: FlowStage) -> Self {
332 self.stages.push(FlowStage::Named {
333 name: name.into(),
334 inner: Arc::new(inner),
335 });
336 self
337 }
338
339 pub fn layer(
341 self,
342 name: impl Into<String>,
343 build: impl FnOnce(LayerStack) -> LayerStack,
344 ) -> Self {
345 self.raw_stage(build(LayerStack::named(name)).build())
346 }
347
348 pub fn llama_prefill_layer(self, layer_idx: usize, spec: LlamaDecoderSpec) -> Self {
350 self.raw_stage(llama_prefill_layer_fused(layer_idx, spec))
351 }
352
353 pub fn llama_prefill_layer_composed(self, layer_idx: usize, spec: LlamaDecoderSpec) -> Self {
355 self.raw_stage(llama_prefill_layer_composed(layer_idx, spec))
356 }
357
358 pub fn linear(mut self, weight_key: impl Into<String>, transpose: bool) -> Self {
359 self.stages
360 .push(FlowStage::Linear(LinearStage::new(weight_key, transpose)));
361 self
362 }
363
364 pub fn residual_save(mut self) -> Self {
365 self.stages.push(FlowStage::ResidualSave(ResidualSaveStage));
366 self
367 }
368
369 pub fn residual_add(mut self) -> Self {
370 self.stages.push(FlowStage::ResidualAdd(ResidualAddStage));
371 self
372 }
373
374 pub fn swiglu(
375 mut self,
376 gate_key: impl Into<String>,
377 up_key: impl Into<String>,
378 down_key: impl Into<String>,
379 ) -> Self {
380 self.stages.push(FlowStage::SwiGlu(SwiGluStage::new(
381 gate_key, up_key, down_key,
382 )));
383 self
384 }
385
386 pub fn swiglu_hf_mlp(mut self, prefix: impl Into<String>) -> Self {
387 self.stages
388 .push(FlowStage::SwiGlu(SwiGluStage::hf_mlp(prefix)));
389 self
390 }
391
392 pub fn self_attn_prefill(mut self, spec: SelfAttnPrefillSpec) -> Self {
393 self.stages
394 .push(FlowStage::SelfAttnPrefill(SelfAttnPrefillStage::new(spec)));
395 self
396 }
397
398 pub fn gdn_scan(mut self, stage: crate::blocks::GdnScanStage) -> Self {
399 self.stages.push(FlowStage::GdnScan(stage));
400 self
401 }
402
403 pub fn store_stream(mut self, name: impl Into<String>) -> Self {
404 self.stages
405 .push(FlowStage::StoreStream(StoreStreamStage::new(name)));
406 self
407 }
408
409 pub fn load_stream(mut self, name: impl Into<String>) -> Self {
410 self.stages
411 .push(FlowStage::LoadStream(LoadStreamStage::new(name)));
412 self
413 }
414
415 pub fn bind_inputs_to_streams(
419 mut self,
420 pairs: impl IntoIterator<Item = (impl Into<String>, impl Into<String>)>,
421 ) -> Self {
422 let pairs: Vec<(String, String)> = pairs
423 .into_iter()
424 .map(|(input, stream)| (input.into(), stream.into()))
425 .collect();
426 self.stages.push(FlowStage::Custom(CustomStage::named(
427 "bind_inputs_to_streams",
428 move |emit, primary| {
429 let primary = primary.ok_or_else(|| {
430 anyhow::anyhow!("bind_inputs_to_streams requires primary input")
431 })?;
432 for (input_name, stream_name) in &pairs {
433 let value = emit.flow_input(input_name)?;
434 emit.state.streams.insert(stream_name.clone(), value);
435 }
436 Ok(Some(primary))
437 },
438 )));
439 self
440 }
441
442 pub fn dual_stream<F>(
443 mut self,
444 name: impl Into<String>,
445 stream_a: impl Into<String>,
446 stream_b: impl Into<String>,
447 f: F,
448 ) -> Self
449 where
450 F: Fn(&mut Emit<'_>, FlowValue, FlowValue) -> anyhow::Result<(FlowValue, FlowValue)>
451 + Send
452 + Sync
453 + 'static,
454 {
455 self.stages.push(FlowStage::DualStream(DualStreamStage::new(
456 name, stream_a, stream_b, f,
457 )));
458 self
459 }
460
461 pub fn plugin<F>(mut self, f: F) -> Self
462 where
463 F: Fn(&mut Emit<'_>, Option<FlowValue>) -> anyhow::Result<Option<FlowValue>>
464 + Send
465 + Sync
466 + 'static,
467 {
468 self.stages.push(crate::plugin::plugin(f));
469 self
470 }
471
472 pub fn plugin_named<F>(mut self, name: impl Into<String>, f: F) -> Self
473 where
474 F: Fn(&mut Emit<'_>, Option<FlowValue>) -> anyhow::Result<Option<FlowValue>>
475 + Send
476 + Sync
477 + 'static,
478 {
479 self.stages.push(crate::plugin::plugin_named(name, f));
480 self
481 }
482
483 pub fn hidden_states(self) -> Self {
485 self.output("hidden")
486 }
487
488 pub fn llama_decoder_layer(
490 self,
491 layer_idx: usize,
492 spec: crate::blocks::LlamaDecoderSpec,
493 ) -> Self {
494 self.named_layer(
495 format!("layer{layer_idx}"),
496 FlowStage::LlamaDecoder(LlamaDecoderStage::layer(layer_idx, spec)),
497 )
498 }
499
500 pub fn llama_decode_layer(
502 self,
503 layer_idx: usize,
504 spec: crate::blocks::LlamaDecodeLayerSpec,
505 kv_out: SideOutputs,
506 ) -> Self {
507 self.named_layer(
508 format!("layer{layer_idx}"),
509 FlowStage::LlamaDecodeLayer(LlamaDecodeLayerStage::layer(
510 layer_idx,
511 spec,
512 kv_out.inner(),
513 )),
514 )
515 }
516
517 pub fn llama_kv_tap(
519 mut self,
520 layer_idx: usize,
521 head_dim: usize,
522 eps: f32,
523 sink: &SideOutputs,
524 ) -> Self {
525 self.stages
526 .push(FlowStage::LlamaKvTap(LlamaKvTapStage::layer(
527 layer_idx,
528 head_dim,
529 eps,
530 sink.inner(),
531 rlx_ir::RopeStyle::NeoX,
534 )));
535 self
536 }
537
538 pub fn final_norm(self, eps: f32) -> Self {
540 self.rms_norm("model.norm.weight", eps)
541 }
542
543 pub fn rms_norm(mut self, weight_key: impl Into<String>, eps: f32) -> Self {
544 self.stages
545 .push(FlowStage::RmsNorm(RmsNormStage::new(weight_key, eps)));
546 self
547 }
548
549 pub fn gather_last_token_dynamic(mut self, batch: usize) -> Self {
551 self.stages
552 .push(FlowStage::GatherLastToken(GatherLastTokenStage::dynamic(
553 batch,
554 )));
555 self
556 }
557
558 pub fn gather_last_token_at(mut self, batch: usize, seq: usize) -> Self {
560 self.stages.push(FlowStage::GatherLastToken(
561 GatherLastTokenStage::static_last(batch, seq),
562 ));
563 self
564 }
565
566 pub fn lm_head(
568 mut self,
569 vocab_size: usize,
570 hidden_size: usize,
571 tie_word_embeddings: bool,
572 ) -> Self {
573 let stage = if tie_word_embeddings {
574 LmHeadStage::tied(vocab_size, hidden_size)
575 } else {
576 LmHeadStage::separate("lm_head.weight", vocab_size, hidden_size)
577 };
578 self.stages.push(FlowStage::LmHead(stage));
579 self.output("logits")
580 }
581
582 pub fn raw_stage(mut self, stage: FlowStage) -> Self {
584 self.stages.push(stage);
585 self
586 }
587
588 pub fn raw_stages(mut self, stages: impl IntoIterator<Item = FlowStage>) -> Self {
590 self.stages.extend(stages);
591 self
592 }
593
594 pub fn sequence(mut self, stages: impl IntoIterator<Item = FlowStage>) -> Self {
596 self.stages
597 .push(FlowStage::Sequence(stages.into_iter().collect()));
598 self
599 }
600
601 pub fn when(self, cond: bool, f: impl FnOnce(Self) -> Self) -> Self {
603 if cond { f(self) } else { self }
604 }
605
606 pub fn custom<F>(mut self, f: F) -> Self
608 where
609 F: Fn(&mut Emit<'_>, Option<FlowValue>) -> anyhow::Result<Option<FlowValue>>
610 + Send
611 + Sync
612 + 'static,
613 {
614 self.stages.push(FlowStage::Custom(CustomStage::new(f)));
615 self
616 }
617
618 pub fn custom_named<F>(mut self, name: impl Into<String>, f: F) -> Self
620 where
621 F: Fn(&mut Emit<'_>, Option<FlowValue>) -> anyhow::Result<Option<FlowValue>>
622 + Send
623 + Sync
624 + 'static,
625 {
626 self.stages
627 .push(FlowStage::Custom(CustomStage::named(name, f)));
628 self
629 }
630
631 pub fn patch(self, f: impl FnOnce(Self) -> Self) -> Self {
633 f(self)
634 }
635}