Skip to main content

teeny_core/nn/
instancenorm.rs

1/*
2 * Copyright (c) 2026 Teenygrad.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *   http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17use core::marker::PhantomData;
18
19use crate::{
20    dtype::{Dtype, EagerTensor, Tensor},
21    nn::Layer,
22};
23
24// ─── InstanceNorm1d ──────────────────────────────────────────────────────────
25
26/// Instance normalisation over a 3-D `[N, C, L]` input.
27///
28/// Normalises each (N, C) pair independently over the L spatial dimension.
29/// Output shape equals input shape.
30///
31/// Parameters:
32/// - `num_features`        — number of channels C
33/// - `eps`                 — numerical stability constant (default 1e-5)
34/// - `momentum`            — EMA weight for running stats (default 0.1)
35/// - `affine`              — if true, learns per-channel γ and β (default false)
36/// - `track_running_stats` — maintain running mean/var (default false)
37pub struct InstanceNorm1d<D: Dtype, IT, OT, const RANK: usize> {
38    /// Number of channels/features.
39    pub num_features: usize,
40    /// Numerical stability constant added to the variance.
41    pub eps: f64,
42    /// Weight of the current batch in the running-stats exponential moving average.
43    pub momentum: f64,
44    /// Whether to learn per-channel scale (gamma) and shift (beta) parameters.
45    pub affine: bool,
46    /// Whether to maintain running mean/variance across batches.
47    pub track_running_stats: bool,
48    _pd: PhantomData<(D, IT, OT)>,
49}
50
51impl<D: Dtype, IT, OT, const RANK: usize> InstanceNorm1d<D, IT, OT, RANK> {
52    /// Creates a new layer with default `eps`/`momentum`, affine/running-stats off.
53    pub fn new(num_features: usize) -> Self {
54        Self {
55            num_features,
56            eps: 1e-5,
57            momentum: 0.1,
58            affine: false,
59            track_running_stats: false,
60            _pd: PhantomData,
61        }
62    }
63
64    /// Sets the numerical stability constant.
65    pub fn with_eps(mut self, eps: f64) -> Self {
66        self.eps = eps;
67        self
68    }
69    /// Sets the running-stats EMA momentum.
70    pub fn with_momentum(mut self, m: f64) -> Self {
71        self.momentum = m;
72        self
73    }
74    /// Sets whether to learn per-channel scale/shift parameters.
75    pub fn with_affine(mut self, a: bool) -> Self {
76        self.affine = a;
77        self
78    }
79    /// Sets whether to maintain running mean/variance across batches.
80    pub fn with_track_running_stats(mut self, t: bool) -> Self {
81        self.track_running_stats = t;
82        self
83    }
84}
85
86impl<D: Dtype, IT: Tensor<D, RANK> + EagerTensor, OT: Tensor<D, RANK>, const RANK: usize> Layer<IT>
87    for InstanceNorm1d<D, IT, OT, RANK>
88{
89    type Output = OT;
90    fn call(&self, _input: IT) -> Self::Output {
91        todo!()
92    }
93}
94
95// ─── InstanceNorm2d ──────────────────────────────────────────────────────────
96
97/// Instance normalisation over a 4-D `[N, C, H, W]` input.
98pub struct InstanceNorm2d<D: Dtype, IT, OT, const RANK: usize> {
99    /// Number of channels/features.
100    pub num_features: usize,
101    /// Numerical stability constant added to the variance.
102    pub eps: f64,
103    /// Weight of the current batch in the running-stats exponential moving average.
104    pub momentum: f64,
105    /// Whether to learn per-channel scale (gamma) and shift (beta) parameters.
106    pub affine: bool,
107    /// Whether to maintain running mean/variance across batches.
108    pub track_running_stats: bool,
109    _pd: PhantomData<(D, IT, OT)>,
110}
111
112impl<D: Dtype, IT, OT, const RANK: usize> InstanceNorm2d<D, IT, OT, RANK> {
113    /// Creates a new layer with default `eps`/`momentum`, affine/running-stats off.
114    pub fn new(num_features: usize) -> Self {
115        Self {
116            num_features,
117            eps: 1e-5,
118            momentum: 0.1,
119            affine: false,
120            track_running_stats: false,
121            _pd: PhantomData,
122        }
123    }
124
125    /// Sets the numerical stability constant.
126    pub fn with_eps(mut self, eps: f64) -> Self {
127        self.eps = eps;
128        self
129    }
130    /// Sets the running-stats EMA momentum.
131    pub fn with_momentum(mut self, m: f64) -> Self {
132        self.momentum = m;
133        self
134    }
135    /// Sets whether to learn per-channel scale/shift parameters.
136    pub fn with_affine(mut self, a: bool) -> Self {
137        self.affine = a;
138        self
139    }
140    /// Sets whether to maintain running mean/variance across batches.
141    pub fn with_track_running_stats(mut self, t: bool) -> Self {
142        self.track_running_stats = t;
143        self
144    }
145}
146
147impl<D: Dtype, IT: Tensor<D, RANK> + EagerTensor, OT: Tensor<D, RANK>, const RANK: usize> Layer<IT>
148    for InstanceNorm2d<D, IT, OT, RANK>
149{
150    type Output = OT;
151    fn call(&self, _input: IT) -> Self::Output {
152        todo!()
153    }
154}
155
156// ─── InstanceNorm3d ──────────────────────────────────────────────────────────
157
158/// Instance normalisation over a 5-D `[N, C, D, H, W]` input.
159pub struct InstanceNorm3d<D: Dtype, IT, OT, const RANK: usize> {
160    /// Number of channels/features.
161    pub num_features: usize,
162    /// Numerical stability constant added to the variance.
163    pub eps: f64,
164    /// Weight of the current batch in the running-stats exponential moving average.
165    pub momentum: f64,
166    /// Whether to learn per-channel scale (gamma) and shift (beta) parameters.
167    pub affine: bool,
168    /// Whether to maintain running mean/variance across batches.
169    pub track_running_stats: bool,
170    _pd: PhantomData<(D, IT, OT)>,
171}
172
173impl<D: Dtype, IT, OT, const RANK: usize> InstanceNorm3d<D, IT, OT, RANK> {
174    /// Creates a new layer with default `eps`/`momentum`, affine/running-stats off.
175    pub fn new(num_features: usize) -> Self {
176        Self {
177            num_features,
178            eps: 1e-5,
179            momentum: 0.1,
180            affine: false,
181            track_running_stats: false,
182            _pd: PhantomData,
183        }
184    }
185
186    /// Sets the numerical stability constant.
187    pub fn with_eps(mut self, eps: f64) -> Self {
188        self.eps = eps;
189        self
190    }
191    /// Sets the running-stats EMA momentum.
192    pub fn with_momentum(mut self, m: f64) -> Self {
193        self.momentum = m;
194        self
195    }
196    /// Sets whether to learn per-channel scale/shift parameters.
197    pub fn with_affine(mut self, a: bool) -> Self {
198        self.affine = a;
199        self
200    }
201    /// Sets whether to maintain running mean/variance across batches.
202    pub fn with_track_running_stats(mut self, t: bool) -> Self {
203        self.track_running_stats = t;
204        self
205    }
206}
207
208impl<D: Dtype, IT: Tensor<D, RANK> + EagerTensor, OT: Tensor<D, RANK>, const RANK: usize> Layer<IT>
209    for InstanceNorm3d<D, IT, OT, RANK>
210{
211    type Output = OT;
212    fn call(&self, _input: IT) -> Self::Output {
213        todo!()
214    }
215}