1use crate::layers::{Activation, Bias1d, Dense};
2use crate::matmul::MatMulImpl;
3use crate::{Dtype, Float};
4
5#[derive(Clone, Debug, Default)]
7pub struct GLU<
8 E: Dtype + Float + MatMulImpl,
9 const I: usize,
10 const O: usize,
11 A: crate::Module<[E; O], Output = [E; O]> + Default = Activation<E>,
12> {
13 gate_connections: Dense<E, I, O>,
14 gate_bias: Bias1d<E, O>,
15
16 sig_connections: Dense<E, I, O>,
17 sig_bias: Bias1d<E, O>,
18
19 activation: A,
20}
21
22impl<E: Dtype + Float + MatMulImpl, const I: usize, const O: usize> GLU<E, I, O, Activation<E>> {
23 pub fn sigmoid() -> Self {
24 Self {
25 activation: Activation::<E>::Sigmoid,
26 ..Self::default()
27 }
28 }
29 pub fn relu() -> Self {
30 Self {
31 activation: Activation::<E>::Relu,
32 ..Self::default()
33 }
34 }
35 pub fn leaky_relu(a: f32) -> Self {
36 Self {
37 activation: Activation::<E>::LeakyRelu(E::from_f32(a).unwrap()),
38 ..Self::default()
39 }
40 }
41 pub fn tanh() -> Self {
42 Self {
43 activation: Activation::<E>::Tanh,
44 ..Self::default()
45 }
46 }
47}
48
49impl<
50 E: Dtype + Float + MatMulImpl,
51 const I: usize,
52 const O: usize,
53 A: crate::Module<[E; O], Output = [E; O]> + Default,
54 > GLU<E, I, O, A>
55{
56 #[doc(hidden)]
57 pub fn connection_params(&self) -> (&[[E; I]; O], &[E; O], &[[E; I]; O], &[E; O]) {
58 (
59 &self.gate_connections.weights,
60 self.gate_bias.bias.raw_grads_ref(),
61 &self.sig_connections.weights,
62 self.sig_bias.bias.raw_grads_ref(),
63 )
64 }
65}
66
67impl<E: Dtype + Float + MatMulImpl, const I: usize, const O: usize>
68 GLU<E, I, O, super::Swish<E, O>>
69{
70 pub fn swish() -> Self {
71 Self::default()
72 }
73}
74
75impl<
76 E: Dtype + Float + MatMulImpl,
77 const I: usize,
78 const O: usize,
79 A: crate::Module<[E; O], Output = [E; O]> + TracedModule<[E; O]> + Default,
80 > crate::Module<[E; I]> for GLU<E, I, O, A>
81{
82 type Output = [E; O];
83
84 fn forward(&self, x: &[E; I]) -> Result<Self::Output, crate::Error> {
85 let gates = self.gate_bias.forward(&self.gate_connections.forward(x)?)?;
86 let mut gates = self.activation.forward(&gates)?;
87 let sigs = self.sig_bias.forward(&self.sig_connections.forward(x)?)?;
88
89 gates
90 .iter_mut()
91 .zip(sigs.into_iter())
92 .for_each(|(o, s)| *o *= s);
93
94 Ok(gates)
95 }
96}
97
98use crate::TracedModule;
99
100impl<
101 E: Dtype + Float + MatMulImpl,
102 const I: usize,
103 const O: usize,
104 A: crate::Module<[E; O], Output = [E; O]> + TracedModule<[E; O]> + Default,
105 > TracedModule<[E; I]> for GLU<E, I, O, A>
106{
107 type Trace = (
108 (
110 <Dense<E, I, O> as TracedModule<[E; I]>>::Trace,
111 <Bias1d<E, O> as TracedModule<[E; O]>>::Trace,
112 <A as TracedModule<[E; O]>>::Trace,
113 ),
114 (
116 <Dense<E, I, O> as TracedModule<[E; I]>>::Trace,
117 <Bias1d<E, O> as TracedModule<[E; O]>>::Trace,
118 ),
119 ([E; O], [E; O]),
121 );
122
123 fn traced_forward(
124 &self,
125 x: [E; I],
126 ) -> Result<(<Self as crate::Module<[E; I]>>::Output, Self::Trace), crate::Error> {
127 let (gc_out, gc_trace) = self.gate_connections.traced_forward(x.clone())?;
128 let (gb_out, gb_trace) = self.gate_bias.traced_forward(gc_out)?;
129 let (ga_out, ga_trace) = self.activation.traced_forward(gb_out)?;
130
131 let (sc_out, sc_trace) = self.sig_connections.traced_forward(x)?;
132 let (sb_out, sb_trace) = self.sig_bias.traced_forward(sc_out)?;
133
134 let mut out = ga_out.clone();
135 out.iter_mut()
136 .zip(sb_out.iter())
137 .for_each(|(o, s)| *o *= *s);
138
139 Ok((
140 out,
141 (
142 (gc_trace, gb_trace, ga_trace),
143 (sc_trace, sb_trace),
144 (ga_out, sb_out),
145 ),
146 ))
147 }
148}
149
150use crate::BackpropModule;
151
152impl<
153 E: Dtype + Float + MatMulImpl,
154 const I: usize,
155 const O: usize,
156 A: crate::Module<[E; O], Output = [E; O]>
157 + TracedModule<[E; O]>
158 + BackpropModule<[E; O]>
159 + Default,
160 > crate::BackpropModule<[E; I]> for GLU<E, I, O, A>
161{
162 type SelfGrads = (
163 (
165 <Dense<E, I, O> as BackpropModule<[E; I]>>::SelfGrads,
166 <Bias1d<E, O> as BackpropModule<[E; O]>>::SelfGrads,
167 <A as BackpropModule<[E; O]>>::SelfGrads,
168 ),
169 (
171 <Dense<E, I, O> as BackpropModule<[E; I]>>::SelfGrads,
172 <Bias1d<E, O> as BackpropModule<[E; O]>>::SelfGrads,
173 ),
174 );
175
176 fn backprop(
177 &self,
178 trace: &<Self as crate::TracedModule<[E; I]>>::Trace,
179 grads_wrt_output: <Self as crate::Module<[E; I]>>::Output,
180 ) -> ([E; I], Self::SelfGrads) {
181 let mut sig_grads_wrt_output = grads_wrt_output.clone();
183 sig_grads_wrt_output
184 .iter_mut()
185 .zip(trace.2 .0)
186 .for_each(|(g, o)| *g *= o);
187 let (sig_grads, sb_grads) = self.sig_bias.backprop(&trace.1 .1, sig_grads_wrt_output);
189 let (sig_grads, sc_grads) = self.sig_connections.backprop(&trace.1 .0, sig_grads);
190
191 let mut gate_grads_wrt_output = grads_wrt_output;
193 gate_grads_wrt_output
194 .iter_mut()
195 .zip(trace.2 .1)
196 .for_each(|(g, o)| *g *= o);
197
198 let (gate_grads, ga_grads) = self.activation.backprop(&trace.0 .2, gate_grads_wrt_output);
200 let (gate_grads, gb_grads) = self.gate_bias.backprop(&trace.0 .1, gate_grads);
201 let (gate_grads, gc_grads) = self.gate_connections.backprop(&trace.0 .0, gate_grads);
202
203 let mut out = sig_grads;
206 out.iter_mut()
207 .zip(gate_grads.into_iter())
208 .for_each(|(o, x)| *o += x);
209
210 (out, ((gc_grads, gb_grads, ga_grads), (sc_grads, sb_grads)))
211 }
212
213 fn update(
214 &mut self,
215 applyer: &mut impl crate::optimizers::GradApplyer,
216 updates: Self::SelfGrads,
217 ) -> Result<(), crate::Error> {
218 self.gate_connections.update(applyer, updates.0 .0)?;
219 self.gate_bias.update(applyer, updates.0 .1)?;
220 self.activation.update(applyer, updates.0 .2)?;
221
222 self.sig_connections.update(applyer, updates.1 .0)?;
223 self.sig_bias.update(applyer, updates.1 .1)?;
224
225 Ok(())
226 }
227}
228
229impl<
230 E: Dtype + Float + MatMulImpl,
231 const I: usize,
232 const O: usize,
233 A: crate::Module<[E; O], Output = [E; O]> + Default + crate::LoadableModule,
234 > crate::LoadableModule for GLU<E, I, O, A>
235{
236 fn save(
237 &self,
238 path: String,
239 dict: &mut std::collections::HashMap<String, Vec<f64>>,
240 ) -> Result<(), crate::LoadSaveError> {
241 self.gate_connections
242 .save(path.clone() + ".gate_connections", dict)?;
243 self.gate_bias.save(path.clone() + ".gate_bias", dict)?;
244 self.activation.save(path.clone() + ".activation", dict)?;
245
246 self.sig_connections
247 .save(path.clone() + ".sig_connections", dict)?;
248 self.sig_bias.save(path + ".sig_bias", dict)?;
249
250 Ok(())
251 }
252
253 fn load(
254 &mut self,
255 path: String,
256 dict: &std::collections::HashMap<String, Vec<f64>>,
257 ) -> Result<(), crate::LoadSaveError> {
258 self.gate_connections
259 .load(path.clone() + ".gate_connections", dict)?;
260 self.gate_bias.load(path.clone() + ".gate_bias", dict)?;
261 self.activation.load(path.clone() + ".activation", dict)?;
262
263 self.sig_connections
264 .load(path.clone() + ".sig_connections", dict)?;
265 self.sig_bias.load(path + ".sig_bias", dict)?;
266
267 Ok(())
268 }
269}
270
271impl<
272 E: Dtype + Float + MatMulImpl,
273 const I: usize,
274 const O: usize,
275 A: crate::Module<[E; O], Output = [E; O]> + Default + crate::ResetParams,
276 > crate::ResetParams for GLU<E, I, O, A>
277{
278 fn rand_params<RNG: rand::Rng>(
279 &mut self,
280 rng: &mut RNG,
281 scale: f32,
282 ) -> Result<(), crate::Error> {
283 self.gate_connections.rand_params(rng, scale)?;
284 self.gate_bias.rand_params(rng, scale)?;
285 self.sig_connections.rand_params(rng, scale)?;
286 self.sig_bias.rand_params(rng, scale)?;
287 self.activation.rand_params(rng, scale)?;
288 Ok(())
289 }
290}
291
292#[cfg(test)]
293mod tests {
294 use super::*;
295 use crate::Module;
296
297 #[test]
298 fn test_forward() {
299 let mut g = GLU::<f32, 1, 1>::default();
300 g.gate_connections.weights[0] = [1.0];
301 g.sig_connections.weights[0] = [1.0];
302
303 assert_eq!(g.forward(&[1.0]), Ok([1.0]));
304
305 g.activation = Activation::Sigmoid;
306 let o = g.forward(&[0.5]).unwrap()[0];
308 assert!(o > 0.3);
309 assert!(o < 0.35);
310
311 let mut g = GLU::<f32, 2, 1>::default();
312 g.gate_connections.weights[0] = [1.0, 0.0];
313 g.sig_connections.weights[0] = [0.0, 1.0];
314
315 assert_eq!(g.forward(&[1.0, 1.0]), Ok([1.0]));
316 assert_eq!(g.forward(&[1.0, 0.5]), Ok([0.5]));
317 assert_eq!(g.forward(&[0.2, 1.0]), Ok([0.2]));
318 assert_eq!(g.forward(&[-1.0, 1.0]), Ok([0.0])); assert_eq!(g.traced_forward([1.0, 0.5]).unwrap().0, [0.5]);
321 assert_eq!(g.traced_forward([-1.0, 1.0]).unwrap().0, [0.0]); }
323
324 #[test]
325 fn test_backward_simple() {
326 let mut g = GLU::<f32, 2, 1>::default();
327 g.gate_connections.weights = [[2.0, 1.0]];
328 g.gate_bias.bias.raw_grads_mut()[0] = -2.0;
329 g.sig_connections.weights = [[1.0, -1.0]];
330 g.sig_bias.bias.raw_grads_mut()[0] = 1.0;
331
332 let (out, trace) = g.traced_forward([1.0, 2.0]).unwrap();
333 assert_eq!(out, [0.0]);
334
335 assert_eq!(trace.2, ([2.0], [0.0]));
337
338 let (_out_grads, grads) = g.backprop(&trace, [-1.0]);
340 assert_eq!(out, [0.0]); assert_eq!(
343 (grads.0 .0, grads.0 .1.raw_grads(), grads.0 .2),
344 ([[0.0, 0.0]], [0.0], ())
345 ); assert_eq!(
347 (grads.1 .0, grads.1 .1.raw_grads()),
348 ([[-2.0, -4.0]], [-2.0])
349 ); }
351}