60double sigmoid(
const double &x) {
return 1.0 / (1.0 + std::exp(-x)); }
67double dsigmoid(
const double &x) {
return x * (1 - x); }
74double relu(
const double &x) {
return std::max(0.0, x); }
81double drelu(
const double &x) {
return x >= 0.0 ? 1.0 : 0.0; }
88double tanh(
const double &x) {
return 2 / (1 + std::exp(-2 * x)) - 1; }
95double dtanh(
const double &x) {
return 1 - x * x; }
106double square(
const double &x) {
return x * x; }
128 double (*activation_function)(
const double &);
129 double (*dactivation_function)(
const double &);
131 std::string activation;
132 std::vector<std::valarray<double>> kernel;
141 DenseLayer(
const int &neurons,
const std::string &activation,
142 const std::pair<size_t, size_t> &kernel_shape,
143 const bool &random_kernel) {
145 if (activation ==
"sigmoid") {
146 activation_function = neural_network::activations::sigmoid;
147 dactivation_function = neural_network::activations::sigmoid;
148 }
else if (activation ==
"relu") {
149 activation_function = neural_network::activations::relu;
150 dactivation_function = neural_network::activations::drelu;
151 }
else if (activation ==
"tanh") {
152 activation_function = neural_network::activations::tanh;
153 dactivation_function = neural_network::activations::dtanh;
154 }
else if (activation ==
"none") {
156 activation_function =
157 neural_network::util_functions::identity_function;
158 dactivation_function =
159 neural_network::util_functions::identity_function;
162 std::cerr <<
"ERROR (" << __func__ <<
") : ";
163 std::cerr <<
"Invalid argument. Expected {none, sigmoid, relu, "
165 std::cerr << activation << std::endl;
166 std::exit(EXIT_FAILURE);
168 this->activation = activation;
169 this->neurons = neurons;
183 DenseLayer(
const int &neurons,
const std::string &activation,
184 const std::vector<std::valarray<double>> &kernel) {
186 if (activation ==
"sigmoid") {
187 activation_function = neural_network::activations::sigmoid;
188 dactivation_function = neural_network::activations::sigmoid;
189 }
else if (activation ==
"relu") {
190 activation_function = neural_network::activations::relu;
191 dactivation_function = neural_network::activations::drelu;
192 }
else if (activation ==
"tanh") {
193 activation_function = neural_network::activations::tanh;
194 dactivation_function = neural_network::activations::dtanh;
195 }
else if (activation ==
"none") {
197 activation_function =
198 neural_network::util_functions::identity_function;
199 dactivation_function =
200 neural_network::util_functions::identity_function;
203 std::cerr <<
"ERROR (" << __func__ <<
") : ";
204 std::cerr <<
"Invalid argument. Expected {none, sigmoid, relu, "
206 std::cerr << activation << std::endl;
207 std::exit(EXIT_FAILURE);
209 this->activation = activation;
210 this->neurons = neurons;
211 this->kernel = kernel;
249 std::vector<neural_network::layers::DenseLayer>
layers;
257 const std::vector<std::pair<int, std::string>> &config,
258 const std::vector<std::vector<std::valarray<double>>> &kernels) {
260 if (config.begin()->second !=
"none") {
261 std::cerr <<
"ERROR (" << __func__ <<
") : ";
263 <<
"First layer can't have activation other than none got "
264 << config.begin()->second;
265 std::cerr << std::endl;
266 std::exit(EXIT_FAILURE);
269 if (config.size() <= 1) {
270 std::cerr <<
"ERROR (" << __func__ <<
") : ";
271 std::cerr <<
"Invalid size of network, ";
272 std::cerr <<
"Atleast two layers are required";
273 std::exit(EXIT_FAILURE);
276 for (
size_t i = 0; i < config.size(); i++) {
278 config[i].first, config[i].second, kernels[i]));
280 std::cout <<
"INFO: Network constructed successfully" << std::endl;
288 std::vector<std::vector<std::valarray<double>>>
290 std::vector<std::vector<std::valarray<double>>> details;
291 std::vector<std::valarray<double>> current_pass = X;
292 details.emplace_back(X);
293 for (
const auto &l :
layers) {
294 current_pass =
multiply(current_pass, l.kernel);
295 current_pass =
apply_function(current_pass, l.activation_function);
296 details.emplace_back(current_pass);
314 const std::vector<std::pair<int, std::string>> &config) {
316 if (config.begin()->second !=
"none") {
317 std::cerr <<
"ERROR (" << __func__ <<
") : ";
319 <<
"First layer can't have activation other than none got "
320 << config.begin()->second;
321 std::cerr << std::endl;
322 std::exit(EXIT_FAILURE);
325 if (config.size() <= 1) {
326 std::cerr <<
"ERROR (" << __func__ <<
") : ";
327 std::cerr <<
"Invalid size of network, ";
328 std::cerr <<
"Atleast two layers are required";
329 std::exit(EXIT_FAILURE);
334 config[0].first, config[0].second,
335 {config[0].first, config[0].first},
false));
337 for (
size_t i = 1; i < config.size(); i++) {
339 config[i].first, config[i].second,
340 {config[i - 1].first, config[i].first},
true));
342 std::cout <<
"INFO: Network constructed successfully" << std::endl;
380 std::pair<std::vector<std::vector<std::valarray<double>>>,
381 std::vector<std::vector<std::valarray<double>>>>
383 const bool &normalize,
const int &slip_lines = 1) {
384 std::ifstream in_file;
385 in_file.open(file_name.c_str(), std::ios::in);
387 if (!in_file.is_open()) {
388 std::cerr <<
"ERROR (" << __func__ <<
") : ";
389 std::cerr <<
"Unable to open file: " << file_name << std::endl;
390 std::exit(EXIT_FAILURE);
392 std::vector<std::vector<std::valarray<double>>> X,
396 for (
int i = 0; i < slip_lines; i++) {
397 std::getline(in_file, line,
'\n');
400 while (!in_file.eof() && std::getline(in_file, line,
'\n')) {
401 std::valarray<double> x_data,
403 std::stringstream ss(line);
405 while (std::getline(ss, token,
',')) {
411 y_data.resize(this->layers.back().neurons);
413 if (y_data.size() > 1) {
414 y_data[x_data[x_data.size() - 1]] = 1;
418 y_data[0] = x_data[x_data.size() - 1];
422 y_data.resize(this->layers.back().neurons);
424 if (y_data.size() > 1) {
425 y_data[x_data[x_data.size() - 1]] = 1;
429 y_data[0] = x_data[x_data.size() - 1];
434 X.push_back({x_data});
435 Y.push_back({y_data});
443 return make_pair(X, Y);
452 const std::vector<std::valarray<double>> &X) {
465 const std::vector<std::vector<std::valarray<double>>> &X) {
467 std::vector<std::vector<std::valarray<double>>> predicted_batch(
469 for (
size_t i = 0; i < X.size(); i++) {
473 return predicted_batch;
485 void fit(
const std::vector<std::vector<std::valarray<double>>> &X_,
486 const std::vector<std::vector<std::valarray<double>>> &Y_,
487 const int &epochs = 100,
const double &learning_rate = 0.01,
488 const size_t &batch_size = 32,
const bool &shuffle =
true) {
489 std::vector<std::vector<std::valarray<double>>> X = X_, Y = Y_;
491 if (X.size() != Y.size()) {
492 std::cerr <<
"ERROR (" << __func__ <<
") : ";
493 std::cerr <<
"X and Y in fit have different sizes" << std::endl;
494 std::exit(EXIT_FAILURE);
496 std::cout <<
"INFO: Training Started" << std::endl;
497 for (
int epoch = 1; epoch <= epochs; epoch++) {
503 std::chrono::high_resolution_clock::now();
507 for (
size_t batch_start = 0; batch_start < X.size();
508 batch_start += batch_size) {
509 for (
size_t i = batch_start;
510 i < std::min(X.size(), batch_start + batch_size); i++) {
511 std::vector<std::valarray<double>> grad, cur_error,
516 std::vector<std::vector<std::valarray<double>>> gradients;
517 gradients.resize(this->layers.size());
519 for (
size_t i = 0; i < gradients.size(); i++) {
521 gradients[i],
get_shape(this->layers[i].kernel));
524 cur_error = predicted - Y[i];
527 cur_error, neural_network::util_functions::square));
533 for (
size_t j = this->layers.size() - 1; j >= 1; j--) {
539 this->layers[j].dactivation_function));
546 gradients[j] = gradients[j] + grad / double(batch_size);
549 for (
size_t j = this->layers.size() - 1; j >= 1; j--) {
551 this->layers[j].kernel = this->layers[j].kernel -
552 gradients[j] * learning_rate;
557 std::chrono::high_resolution_clock::now();
560 std::chrono::duration_cast<std::chrono::microseconds>(stop -
564 std::cout.precision(4);
566 std::cout <<
"Training: Epoch " << epoch <<
'/' << epochs;
567 std::cout <<
", Loss: " << loss;
568 std::cout <<
", Accuracy: " << acc;
569 std::cout <<
", Taken time: " << duration.count() / 1e6
571 std::cout << std::endl;
587 void fit_from_csv(
const std::string &file_name,
const bool &last_label,
588 const int &epochs,
const double &learning_rate,
589 const bool &normalize,
const int &slip_lines = 1,
590 const size_t &batch_size = 32,
591 const bool &shuffle =
true) {
596 this->
fit(
data.first,
data.second, epochs, learning_rate, batch_size,
606 void evaluate(
const std::vector<std::vector<std::valarray<double>>> &X,
607 const std::vector<std::vector<std::valarray<double>>> &Y) {
608 std::cout <<
"INFO: Evaluation Started" << std::endl;
609 double acc = 0, loss = 0;
610 for (
size_t i = 0; i < X.size(); i++) {
612 std::vector<std::valarray<double>> pred =
620 neural_network::util_functions::square) *
626 std::cout <<
"Evaluation: Loss: " << loss;
627 std::cout <<
", Accuracy: " << acc << std::endl;
639 const bool &normalize,
const int &slip_lines = 1) {
653 std::string file_name = _file_name;
655 if (file_name.find(
".model") == file_name.npos) {
656 file_name +=
".model";
658 std::ofstream out_file;
660 out_file.open(file_name.c_str(),
661 std::ofstream::out | std::ofstream::trunc);
663 if (!out_file.is_open()) {
664 std::cerr <<
"ERROR (" << __func__ <<
") : ";
665 std::cerr <<
"Unable to open file: " << file_name << std::endl;
666 std::exit(EXIT_FAILURE);
708 out_file <<
layers.size();
709 out_file << std::endl;
710 for (
const auto &layer : this->layers) {
711 out_file << layer.neurons <<
' ' << layer.activation << std::endl;
712 const auto shape =
get_shape(layer.kernel);
713 out_file << shape.first <<
' ' << shape.second << std::endl;
714 for (
const auto &row : layer.kernel) {
715 for (
const auto &val : row) {
716 out_file << val <<
' ';
718 out_file << std::endl;
721 std::cout <<
"INFO: Model saved successfully with name : ";
722 std::cout << file_name << std::endl;
733 std::ifstream in_file;
734 in_file.open(file_name.c_str());
736 if (!in_file.is_open()) {
737 std::cerr <<
"ERROR (" << __func__ <<
") : ";
738 std::cerr <<
"Unable to open file: " << file_name << std::endl;
739 std::exit(EXIT_FAILURE);
741 std::vector<std::pair<int, std::string>> config;
742 std::vector<std::vector<std::valarray<double>>>
745 size_t total_layers = 0;
746 in_file >> total_layers;
747 for (
size_t i = 0; i < total_layers; i++) {
749 std::string activation;
750 size_t shape_a = 0, shape_b = 0;
751 std::vector<std::valarray<double>> kernel;
752 in_file >> neurons >> activation >> shape_a >> shape_b;
753 for (
size_t r = 0; r < shape_a; r++) {
754 std::valarray<double> row(shape_b);
755 for (
size_t c = 0; c < shape_b; c++) {
758 kernel.push_back(row);
760 config.emplace_back(make_pair(neurons, activation));
762 kernels.emplace_back(kernel);
764 std::cout <<
"INFO: Model loaded successfully" << std::endl;
776 <<
"==============================================================="
778 std::cout <<
"\t\t+ MODEL SUMMARY +\t\t\n";
780 <<
"==============================================================="
782 for (
size_t i = 1; i <=
layers.size(); i++) {
783 std::cout << i <<
")";
784 std::cout <<
" Neurons : "
786 std::cout <<
", Activation : "
787 <<
layers[i - 1].activation;
788 std::cout <<
", kernel Shape : "
790 std::cout << std::endl;
793 <<
"==============================================================="
818 myNN.
fit_from_csv(
"iris.csv",
true, 100, 0.3,
false, 2, 32,
true);
823 myNN.single_predict({{6.4, 2.9, 4.3, 1.3}})) == 1);
825 myNN.single_predict({{6.2, 3.4, 5.4, 2.3}})) == 2);
NeuralNetwork(NeuralNetwork &&)=default
NeuralNetwork(const NeuralNetwork &model)=default
void fit(const std::vector< std::vector< std::valarray< double > > > &X_, const std::vector< std::vector< std::valarray< double > > > &Y_, const int &epochs=100, const double &learning_rate=0.01, const size_t &batch_size=32, const bool &shuffle=true)
NeuralNetwork & operator=(NeuralNetwork &&)=default
std::vector< std::vector< std::valarray< double > > > __detailed_single_prediction(const std::vector< std::valarray< double > > &X)
void evaluate_from_csv(const std::string &file_name, const bool &last_label, const bool &normalize, const int &slip_lines=1)
std::vector< std::valarray< double > > single_predict(const std::vector< std::valarray< double > > &X)
NeuralNetwork(const std::vector< std::pair< int, std::string > > &config, const std::vector< std::vector< std::valarray< double > > > &kernels)
void save_model(const std::string &_file_name)
void fit_from_csv(const std::string &file_name, const bool &last_label, const int &epochs, const double &learning_rate, const bool &normalize, const int &slip_lines=1, const size_t &batch_size=32, const bool &shuffle=true)
NeuralNetwork & operator=(const NeuralNetwork &model)=default
NeuralNetwork load_model(const std::string &file_name)
NeuralNetwork(const std::vector< std::pair< int, std::string > > &config)
std::pair< std::vector< std::vector< std::valarray< double > > >, std::vector< std::vector< std::valarray< double > > > > get_XY_from_csv(const std::string &file_name, const bool &last_label, const bool &normalize, const int &slip_lines=1)
std::vector< std::vector< std::valarray< double > > > batch_predict(const std::vector< std::vector< std::valarray< double > > > &X)
void evaluate(const std::vector< std::vector< std::valarray< double > > > &X, const std::vector< std::vector< std::valarray< double > > > &Y)
DenseLayer(const int &neurons, const std::string &activation, const std::pair< size_t, size_t > &kernel_shape, const bool &random_kernel)
DenseLayer & operator=(DenseLayer &&)=default
DenseLayer(const DenseLayer &layer)=default
DenseLayer(DenseLayer &&)=default
DenseLayer & operator=(const DenseLayer &layer)=default
DenseLayer(const int &neurons, const std::string &activation, const std::vector< std::valarray< double > > &kernel)
Various activation functions used in Neural network.
This namespace contains layers used in MLP.
std::valarray< T > insert_element(const std::valarray< T > &A, const T &ele)
size_t argmax(const std::vector< std::valarray< T > > &A)
std::vector< std::valarray< T > > multiply(const std::vector< std::valarray< T > > &A, const std::vector< std::valarray< T > > &B)
T sum(const std::vector< std::valarray< T > > &A)
std::vector< std::valarray< T > > transpose(const std::vector< std::valarray< T > > &A)
void unit_matrix_initialization(std::vector< std::valarray< T > > &A, const std::pair< size_t, size_t > &shape)
std::valarray< T > pop_front(const std::valarray< T > &A)
std::pair< size_t, size_t > get_shape(const std::vector< std::valarray< T > > &A)
void uniform_random_initialization(std::vector< std::valarray< T > > &A, const std::pair< size_t, size_t > &shape, const T &low, const T &high)
void zeroes_initialization(std::vector< std::valarray< T > > &A, const std::pair< size_t, size_t > &shape)
std::vector< std::vector< std::valarray< T > > > minmax_scaler(const std::vector< std::vector< std::valarray< T > > > &A, const T &low, const T &high)
std::vector< std::valarray< T > > hadamard_product(const std::vector< std::valarray< T > > &A, const std::vector< std::valarray< T > > &B)
std::vector< std::valarray< T > > apply_function(const std::vector< std::valarray< T > > &A, T(*func)(const T &))
std::valarray< T > pop_back(const std::valarray< T > &A)
void equal_shuffle(std::vector< std::vector< std::valarray< T > > > &A, std::vector< std::vector< std::valarray< T > > > &B)
Neural Network or Multilayer Perceptron.
Various utility functions used in Neural network.
double sigmoid(const double &x)
double dtanh(const double &x)
double identity_function(const double &x)
double tanh(const double &x)
double square(const double &x)
double dsigmoid(const double &x)
double drelu(const double &x)
double relu(const double &x)
Various functions for vectors associated with [NeuralNetwork (aka Multilayer Perceptron)] (https://en...