FlexNN 1
Fully connected neural network built from scratch with flexible n-layer design and multiple activations.
Loading...
Searching...
No Matches
Layer.hpp
Go to the documentation of this file.
1
20#pragma once
21
22#include <type_traits>
23#include <variant>
24
25#include "Dense.hpp"
26#include "Conv1D.hpp"
27#include "BatchNorm1D.hpp"
28#include "Pool1D.hpp"
30
31namespace FlexNN::Layers {
32
49class Layer {
50 public:
51 // Construction from each concrete type — implicit so
52 // `NeuralNetwork net({Dense(...), Dense(...)})` works.
53 Layer(Dense d) : var_(std::move(d)) {}
54 Layer(Conv1D c) : var_(std::move(c)) {}
55 Layer(BatchNorm1D b) : var_(std::move(b)) {}
56 Layer(MaxPool1D m) : var_(std::move(m)) {}
57 Layer(AvgPool1D a) : var_(std::move(a)) {}
58
62 LayerType type() const noexcept {
63 return std::visit([](auto&& v) { return v.type(); }, var_);
64 }
65
70 return std::visit([](auto&& v) { return v.activation(); }, var_);
71 }
72
81 return std::visit(
82 [](auto&& v) -> Activations::ActivationParameters {
83 using T = std::decay_t<decltype(v)>;
84 if constexpr (std::is_same_v<T, Dense> || std::is_same_v<T, Conv1D>) {
85 return v.activationParams();
86 } else {
88 }
89 },
90 var_);
91 }
92
98 std::pair<Eigen::MatrixXd, Eigen::MatrixXd> forward(
99 const Eigen::MatrixXd& input) const {
100 return std::visit([&](auto&& v) { return v.forward(input); }, var_);
101 }
102
112 Eigen::MatrixXd backward(const Eigen::MatrixXd& nextW,
113 const Eigen::MatrixXd& nextdZ,
114 const Eigen::MatrixXd& currZ) const {
115 return std::visit(
116 [&](auto&& v) { return v.backward(nextW, nextdZ, currZ); }, var_);
117 }
118
125 Eigen::MatrixXd backward(const Eigen::MatrixXd& upstream,
126 const Eigen::MatrixXd& currZ) const {
127 return std::visit(
128 [&](auto&& v) { return v.backward(upstream, currZ); }, var_);
129 }
130
137 void updateWeights(const Eigen::MatrixXd& dW, const Eigen::VectorXd& db,
138 double lr) noexcept {
139 std::visit([&](auto&& v) { v.update(dW, db, lr); }, var_);
140 }
141 void update(const Eigen::MatrixXd& dW, const Eigen::VectorXd& db,
142 double lr) noexcept {
143 updateWeights(dW, db, lr);
144 }
145
153 Eigen::MatrixXd weightsMatrix() const {
154 return std::visit(
155 [](auto&& v) -> Eigen::MatrixXd {
156 using T = std::decay_t<decltype(v)>;
157 if constexpr (std::is_same_v<T, Dense>) {
158 return v.weights();
159 } else if constexpr (std::is_same_v<T, Conv1D>) {
160 return v.weights();
161 } else if constexpr (std::is_same_v<T, BatchNorm1D>) {
162 return Eigen::MatrixXd();
163 } else if constexpr (std::is_same_v<T, MaxPool1D> ||
164 std::is_same_v<T, AvgPool1D>) {
165 return Eigen::MatrixXd();
166 } else {
167 return Eigen::MatrixXd();
168 }
169 },
170 var_);
171 }
172
182 Eigen::MatrixXd propagate(const Eigen::MatrixXd& dZ) const {
183 return std::visit(
184 [&](auto&& v) -> Eigen::MatrixXd {
185 using T = std::decay_t<decltype(v)>;
186 if constexpr (std::is_same_v<T, Dense>) {
187 return v.weights().transpose() * dZ;
188 } else if constexpr (std::is_same_v<T, Conv1D>) {
189 return v.propagate(dZ);
190 } else if constexpr (std::is_same_v<T, BatchNorm1D>) {
191 return v.propagate(dZ);
192 } else if constexpr (std::is_same_v<T, MaxPool1D>) {
193 return v.propagate(dZ);
194 } else if constexpr (std::is_same_v<T, AvgPool1D>) {
195 return v.propagate(dZ);
196 } else {
197 return dZ;
198 }
199 },
200 var_);
201 }
202
210 std::pair<Eigen::MatrixXd, Eigen::VectorXd> grad(
211 const Eigen::MatrixXd& dZ, const Eigen::MatrixXd& input) const {
212 return std::visit(
213 [&](auto&& v) -> std::pair<Eigen::MatrixXd, Eigen::VectorXd> {
214 using T = std::decay_t<decltype(v)>;
215 if constexpr (std::is_same_v<T, Dense>) {
216 double m = static_cast<double>(dZ.cols());
217 Eigen::MatrixXd dW = dZ * input.transpose() / m;
218 Eigen::VectorXd db = dZ.rowwise().mean();
219 return {dW, db};
220 } else if constexpr (std::is_same_v<T, Conv1D>) {
221 return v.grad(dZ, input);
222 } else if constexpr (std::is_same_v<T, BatchNorm1D>) {
223 return v.grad(dZ, input);
224 } else if constexpr (std::is_same_v<T, MaxPool1D> ||
225 std::is_same_v<T, AvgPool1D>) {
226 return v.grad(dZ, input);
227 } else {
228 return {Eigen::MatrixXd(), Eigen::VectorXd()};
229 }
230 },
231 var_);
232 }
233
240 const auto& variant() const noexcept { return var_; }
241 auto& variant() noexcept { return var_; }
242
243 // Helpers for ModelIO/tests to query concrete type without visit boilerplate.
244 const Dense* asDense() const noexcept { return std::get_if<Dense>(&var_); }
245 Dense* asDense() noexcept { return std::get_if<Dense>(&var_); }
246 const Conv1D* asConv1D() const noexcept { return std::get_if<Conv1D>(&var_); }
247 Conv1D* asConv1D() noexcept { return std::get_if<Conv1D>(&var_); }
248 const BatchNorm1D* asBatchNorm1D() const noexcept {
249 return std::get_if<BatchNorm1D>(&var_);
250 }
252 return std::get_if<BatchNorm1D>(&var_);
253 }
254 const MaxPool1D* asMaxPool1D() const noexcept {
255 return std::get_if<MaxPool1D>(&var_);
256 }
257 MaxPool1D* asMaxPool1D() noexcept { return std::get_if<MaxPool1D>(&var_); }
258 const AvgPool1D* asAvgPool1D() const noexcept {
259 return std::get_if<AvgPool1D>(&var_);
260 }
261 AvgPool1D* asAvgPool1D() noexcept { return std::get_if<AvgPool1D>(&var_); }
262
263 private:
264 std::variant<Dense, Conv1D, BatchNorm1D, MaxPool1D, AvgPool1D> var_;
265};
266
267} // namespace FlexNN::Layers
Per-activation hyperparameters for FlexNN::Activations.
BatchNorm1D layer for FlexNN::Layers (training stats, aux export).
1D temporal convolution for FlexNN::Layers.
Dense (fully-connected) layer for FlexNN::Layers.
Pool1D layers — MaxPool1D and AvgPool1D (weightless).
Definition Pool1D.hpp:58
Definition BatchNorm1D.hpp:26
Definition Conv1D.hpp:28
Fully-connected layer: Z = W*X + b, A = act(Z).
Definition Dense.hpp:31
Type-erased layer — holds one concrete layer type.
Definition Layer.hpp:49
Layer(AvgPool1D a)
Definition Layer.hpp:57
Activations::Activation activation() const noexcept
Activation for this layer.
Definition Layer.hpp:69
BatchNorm1D * asBatchNorm1D() noexcept
Definition Layer.hpp:251
Dense * asDense() noexcept
Definition Layer.hpp:245
const MaxPool1D * asMaxPool1D() const noexcept
Definition Layer.hpp:254
const auto & variant() const noexcept
Direct access to the underlying variant (for ModelIO).
Definition Layer.hpp:240
MaxPool1D * asMaxPool1D() noexcept
Definition Layer.hpp:257
const Conv1D * asConv1D() const noexcept
Definition Layer.hpp:246
void update(const Eigen::MatrixXd &dW, const Eigen::VectorXd &db, double lr) noexcept
Definition Layer.hpp:141
auto & variant() noexcept
Definition Layer.hpp:241
Eigen::MatrixXd backward(const Eigen::MatrixXd &upstream, const Eigen::MatrixXd &currZ) const
Backward with already-propagated upstream (W_next^T*dZ_next).
Definition Layer.hpp:125
Layer(BatchNorm1D b)
Definition Layer.hpp:55
const AvgPool1D * asAvgPool1D() const noexcept
Definition Layer.hpp:258
Eigen::MatrixXd backward(const Eigen::MatrixXd &nextW, const Eigen::MatrixXd &nextdZ, const Eigen::MatrixXd &currZ) const
Backward pass for this layer (dispatch via visit).
Definition Layer.hpp:112
void updateWeights(const Eigen::MatrixXd &dW, const Eigen::VectorXd &db, double lr) noexcept
SGD update — dispatches to concrete update.
Definition Layer.hpp:137
std::pair< Eigen::MatrixXd, Eigen::VectorXd > grad(const Eigen::MatrixXd &dZ, const Eigen::MatrixXd &input) const
Compute dW/db for this layer given dZ and input.
Definition Layer.hpp:210
const Dense * asDense() const noexcept
Definition Layer.hpp:244
std::pair< Eigen::MatrixXd, Eigen::MatrixXd > forward(const Eigen::MatrixXd &input) const
Forward pass for this layer (dispatch via visit).
Definition Layer.hpp:98
Layer(Dense d)
Definition Layer.hpp:53
Eigen::MatrixXd weightsMatrix() const
Weight matrix for backward — Dense/Conv1D.
Definition Layer.hpp:153
const BatchNorm1D * asBatchNorm1D() const noexcept
Definition Layer.hpp:248
Conv1D * asConv1D() noexcept
Definition Layer.hpp:247
Layer(MaxPool1D m)
Definition Layer.hpp:56
Activations::ActivationParameters activationParams() const noexcept
Activation hyperparameters (e.g., LeakyReLU alpha).
Definition Layer.hpp:80
Layer(Conv1D c)
Definition Layer.hpp:54
Eigen::MatrixXd propagate(const Eigen::MatrixXd &dZ) const
Propagate gradient to previous layer (W^T * dZ or col2im).
Definition Layer.hpp:182
LayerType type() const noexcept
Layer kind (Dense, Conv1D, ...).
Definition Layer.hpp:62
AvgPool1D * asAvgPool1D() noexcept
Definition Layer.hpp:261
Definition Pool1D.hpp:22
Activation
Activation function identifier.
Definition Activation.hpp:41
Definition BatchNorm1D.hpp:24
LayerType
Layer kind, stable on-wire (uint8_t).
Definition LayerTypes.hpp:22
Hyperparameters for activations.
Definition ActivationParameters.hpp:30