1use crate::attn::{
10 cross_attn_incremental, self_attn_full, self_attn_incremental, AttnConfig, AttnWeights, KvCache,
11};
12use crate::config::FfnActivation;
13use crate::ffn::{ffn_forward, FfnWeights};
14use crate::norm::zc_rms_norm_vec;
15use crate::ops::sigmoid;
16use crate::rope::RopeCache;
17use alloc::vec::Vec;
18
19pub struct EncoderLayer {
20 pub self_attn: AttnWeights,
21 pub self_attn_gate: f32, pub norm: Vec<f32>, pub ffn: Option<FfnWeights>,
24 pub ffn_gate: f32,
25 pub ffn_norm: Option<Vec<f32>>,
26 pub ffn_activation: Option<FfnActivation>,
27}
28
29pub struct DecoderLayer {
30 pub self_attn: AttnWeights,
31 pub self_attn_gate: f32,
32 pub self_attn_norm: Vec<f32>,
33 pub cross_attn: AttnWeights,
34 pub cross_attn_gate: f32,
35 pub cross_attn_norm: Vec<f32>,
36 pub ffn: Option<FfnWeights>,
37 pub ffn_gate: f32,
38 pub ffn_norm: Option<Vec<f32>>,
39 pub ffn_activation: Option<FfnActivation>,
40}
41
42#[allow(clippy::too_many_arguments)]
46pub fn encoder_layer_forward(
47 x: &mut [f32],
48 layer: &EncoderLayer,
49 cfg: &AttnConfig,
50 rope: &RopeCache,
51 seq_len: usize,
52 mask: Option<&[f32]>,
53 tmp: &mut Vec<f32>,
54 normed: &mut Vec<f32>,
55) {
56 let d = cfg.d_model;
57
58 normed.resize(seq_len * d, 0.0);
60 normed.copy_from_slice(&x[..seq_len * d]);
61 for t in 0..seq_len {
62 zc_rms_norm_vec(&mut normed[t * d..(t + 1) * d], &layer.norm);
63 }
64
65 tmp.resize(seq_len * d, 0.0);
67 self_attn_full(normed, tmp, &layer.self_attn, cfg, rope, seq_len, mask);
68
69 let gate = sigmoid(layer.self_attn_gate);
71 for i in 0..seq_len * d {
72 x[i] += gate * tmp[i];
73 }
74
75 if let (Some(ffn), Some(ffn_norm), Some(activation)) =
77 (&layer.ffn, &layer.ffn_norm, &layer.ffn_activation)
78 {
79 let d_ff = ffn.gate_proj.out_feat;
80 for t in 0..seq_len {
81 let row = &mut x[t * d..(t + 1) * d];
82 let mut normed_row = row.to_vec();
83 zc_rms_norm_vec(&mut normed_row, ffn_norm);
84 tmp.resize(d, 0.0);
85 ffn_forward(&normed_row, tmp, ffn, d_ff, activation);
86 let ffn_gate = sigmoid(layer.ffn_gate);
87 for (xi, &ti) in row.iter_mut().zip(tmp.iter()) {
88 *xi += ffn_gate * ti;
89 }
90 }
91 }
92}
93
94#[allow(clippy::too_many_arguments)]
100pub fn decoder_layer_forward(
101 x: &mut [f32],
102 layer: &DecoderLayer,
103 cfg: &AttnConfig,
104 rope: &RopeCache,
105 enc_kv: &KvCache,
106 dec_kv_self: &mut KvCache,
107 tmp: &mut Vec<f32>,
108 normed: &mut Vec<f32>,
109) {
110 let d = cfg.d_model;
111
112 normed.resize(d, 0.0);
114 normed.copy_from_slice(x);
115 zc_rms_norm_vec(normed, &layer.self_attn_norm);
116
117 self_attn_incremental(normed, tmp, &layer.self_attn, cfg, rope, dec_kv_self, None);
118
119 let gate = sigmoid(layer.self_attn_gate);
120 for (xi, &ti) in x.iter_mut().zip(tmp.iter()) {
121 *xi += gate * ti;
122 }
123
124 normed.copy_from_slice(x);
126 zc_rms_norm_vec(normed, &layer.cross_attn_norm);
127
128 cross_attn_incremental(normed, tmp, &layer.cross_attn, cfg, enc_kv);
129
130 let cross_gate = sigmoid(layer.cross_attn_gate);
131 for (xi, &ti) in x.iter_mut().zip(tmp.iter()) {
132 *xi += cross_gate * ti;
133 }
134
135 if let (Some(ffn), Some(ffn_norm), Some(activation)) =
137 (&layer.ffn, &layer.ffn_norm, &layer.ffn_activation)
138 {
139 let d_ff = ffn.gate_proj.out_feat;
140 normed.copy_from_slice(x);
141 zc_rms_norm_vec(normed, ffn_norm);
142 tmp.resize(d, 0.0);
143 ffn_forward(normed, tmp, ffn, d_ff, activation);
144 let ffn_gate = sigmoid(layer.ffn_gate);
145 for (xi, &ti) in x.iter_mut().zip(tmp.iter()) {
146 *xi += ffn_gate * ti;
147 }
148 }
149}