Line data Source code
1 : /**
2 : * @file Layer.h
3 : * @author Damien Balima (www.dams-labs.net)
4 : * @brief Abstract layer class
5 : * @date 2023-08-27
6 : *
7 : * @copyright Damien Balima (c) CC-BY-NC-SA-4.0 2023
8 : *
9 : */
10 : #pragma once
11 : #include "ActivationFunctions.h"
12 : #include "Neuron.h"
13 : #include "exception/NeuralNetworkException.h"
14 : #include <atomic>
15 : #include <cstddef>
16 : #include <execution>
17 : #include <functional>
18 : #include <map>
19 : #include <opencv2/opencv.hpp>
20 : #include <thread>
21 :
22 : namespace sipai {
23 : class VulkanController;
24 :
25 : using NeuronMat = std::vector<std::vector<Neuron>>;
26 :
27 : enum class LayerType { LayerInput, LayerHidden, LayerOutput };
28 :
29 : const std::map<std::string, LayerType, std::less<>> layer_map{
30 : {"LayerInput", LayerType::LayerInput},
31 : {"LayerHidden", LayerType::LayerHidden},
32 : {"LayerOutput", LayerType::LayerOutput}};
33 :
34 : /**
35 : * @brief The Layer class represents a layer in a neural network. It contains a
36 : * vector of Neurons and has methods for forward propagation, backward
37 : * propagation, and updating weights.
38 : */
39 : class Layer {
40 : public:
41 28 : explicit Layer(LayerType layerType, size_t size_x = 0, size_t size_y = 0)
42 28 : : layerType(layerType), size_x(size_x), size_y(size_y) {
43 28 : neurons = NeuronMat(size_y, std::vector<Neuron>(size_x));
44 90 : for (size_t y = 0; y < size_y; ++y) {
45 232 : for (size_t x = 0; x < size_x; ++x) {
46 170 : neurons[y][x].index_x = x;
47 170 : neurons[y][x].index_y = y;
48 : }
49 : }
50 28 : values = cv::Mat((int)size_y, (int)size_x, CV_32FC4);
51 28 : errors = cv::Mat((int)size_y, (int)size_x, CV_32FC4);
52 28 : }
53 28 : virtual ~Layer() = default;
54 :
55 : const LayerType layerType;
56 :
57 : /**
58 : * @brief 2D vector of neurons in format [rows][cols], i.e. [y][x]
59 : *
60 : */
61 : NeuronMat neurons;
62 :
63 : /**
64 : * @brief 2D matrix of values, in format (x,y)
65 : *
66 : */
67 : cv::Mat values;
68 :
69 : /**
70 : * @brief 2D matrix of errors, in format (x,y)
71 : *
72 : */
73 : cv::Mat errors;
74 :
75 : /**
76 : * @brief previous layer, or nullptr if not exists
77 : *
78 : */
79 : Layer *previousLayer = nullptr;
80 :
81 : /**
82 : * @brief next layer, or nullptr if not exists
83 : *
84 : */
85 : Layer *nextLayer = nullptr;
86 :
87 : /**
88 : * @brief width (columns)
89 : *
90 : */
91 : size_t size_x = 0;
92 :
93 : /**
94 : * @brief height (rows)
95 : *
96 : */
97 : size_t size_y = 0;
98 :
99 : /**
100 : * @brief Get the layer total size, which is (size_x * size_y)
101 : *
102 : * @return size_t
103 : */
104 232 : size_t total() const { return size_x * size_y; }
105 :
106 : /**
107 : * @brief Get the indexes (x,y) of a neuron from the layer size() index
108 : *
109 : * @param index
110 : * @return std::pair<size_t, size_t>
111 : */
112 : std::pair<size_t, size_t> getPos(const size_t &index) const {
113 : if (index >= total()) {
114 : throw std::out_of_range("Index out of range");
115 : }
116 : size_t row = index / size_x;
117 : size_t col = index % size_x;
118 : return {row, col};
119 : }
120 :
121 : /**
122 : * @brief Get a neuron from a layer size() index
123 : *
124 : * @param index
125 : * @return Neuron&
126 : */
127 : Neuron &getNeuron(const size_t &index) {
128 : const auto &[row, col] = getPos(index);
129 : return neurons[row][col];
130 : }
131 :
132 : EActivationFunction eactivationFunction = EActivationFunction::ReLU;
133 : float activationFunctionAlpha = 0.0f;
134 : std::function<cv::Vec4f(cv::Vec4f)> activationFunction;
135 : std::function<cv::Vec4f(cv::Vec4f)> activationFunctionDerivative;
136 :
137 : const std::string UndefinedLayer = "UndefinedLayer";
138 :
139 : /**
140 : * @brief Apply a function on all the layer neurons
141 : *
142 : * @tparam Function a lambda function
143 : * @param operation
144 : */
145 : template <typename Function> void apply(Function operation) {
146 : for (auto &neuronRow : neurons) {
147 : for (auto &neuron : neuronRow) {
148 : operation(neuron);
149 : }
150 : }
151 : }
152 :
153 : /**
154 : * @brief Performs forward propagation using the previous layer.
155 : */
156 : virtual void forwardPropagation();
157 :
158 : /**
159 : * @brief Performs backward propagation using the next layer.
160 : */
161 : virtual void backwardPropagation(const float &error_min,
162 : const float &error_max);
163 : /**
164 : * @brief Updates the weights of the neurons in this layer using the
165 : * previous layer and a learning rate.
166 : *
167 : * @param learningRate The learning rate to use when updating weights.
168 : */
169 : virtual void updateWeights(float learningRate);
170 :
171 12 : const std::string getLayerTypeStr() const {
172 24 : for (const auto &[key, mLayerType] : layer_map) {
173 24 : if (mLayerType == layerType) {
174 12 : return key;
175 : }
176 : }
177 0 : return UndefinedLayer;
178 : }
179 :
180 : void
181 25 : setActivationFunction(const std::function<cv::Vec4f(cv::Vec4f)> &function,
182 : const std::function<cv::Vec4f(cv::Vec4f)> &derivative) {
183 25 : activationFunction = function;
184 25 : activationFunctionDerivative = derivative;
185 25 : }
186 : };
187 : } // namespace sipai
|