Improved Overall Error handling and reporting

This commit is contained in:
unknown
2020-08-20 12:19:34 +05:30
parent 98b94a2df3
commit d453702ff5
2 changed files with 47 additions and 29 deletions

View File

@@ -171,8 +171,8 @@ namespace machine_learning {
}
else {
// If supplied activation is invalid
std::cerr << "ERROR: Invalid argument for layer -> constructor -> activation, ";
std::cerr << "Expected from {none, sigmoid, relu, tanh} got ";
std::cerr << "ERROR (" << __func__ << ") : ";
std::cerr << "Invalid argument. Expected {none, sigmoid, relu, tanh} got ";
std::cerr << activation << std::endl;
std::exit(EXIT_FAILURE);
}
@@ -215,8 +215,8 @@ namespace machine_learning {
}
else {
// If supplied activation is invalid
std::cerr << "ERROR: Invalid argument for layer -> constructor -> activation, ";
std::cerr << "Expected from {none, sigmoid, relu, tanh} got ";
std::cerr << "ERROR (" << __func__ << ") : ";
std::cerr << "Invalid argument. Expected {none, sigmoid, relu, tanh} got ";
std::cerr << activation << std::endl;
std::exit(EXIT_FAILURE);
}
@@ -271,13 +271,15 @@ namespace machine_learning {
const std::vector <std::vector<std::valarray<double>>> &kernals) {
// First layer should not have activation
if(config.begin() -> second != "none") {
std::cerr << "ERROR: First layer can't have activation other than none";
std::cerr << "ERROR (" << __func__ << ") : ";
std::cerr << "First layer can't have activation other than none got " << config.begin() -> second;
std::cerr << std::endl;
std::exit(EXIT_FAILURE);
}
// Network should have atleast two layers
if(config.size() <= 1) {
std::cerr << "ERROR: Invalid size of network, ";
std::cerr << "ERROR (" << __func__ << ") : ";
std::cerr << "Invalid size of network, ";
std::cerr << "Atleast two layers are required";
std::exit(EXIT_FAILURE);
}
@@ -322,13 +324,15 @@ namespace machine_learning {
explicit NeuralNetwork(const std::vector <std::pair<int, std::string>> &config) {
// First layer should not have activation
if(config.begin() -> second != "none") {
std::cerr << "ERROR: First layer can't have activation other than none";
std::cerr << "ERROR (" << __func__ << ") : ";
std::cerr << "First layer can't have activation other than none got " << config.begin() -> second;
std::cerr << std::endl;
std::exit(EXIT_FAILURE);
}
// Network should have atleast two layers
if(config.size() <= 1) {
std::cerr << "ERROR: Invalid size of network, ";
std::cerr << "ERROR (" << __func__ << ") : ";
std::cerr << "Invalid size of network, ";
std::cerr << "Atleast two layers are required";
std::exit(EXIT_FAILURE);
}
@@ -392,7 +396,8 @@ namespace machine_learning {
in_file.open(file_name.c_str(), std::ios::in); // Open file
// If there is any problem in opening file
if(!in_file.is_open()) {
std::cerr << "ERROR: Unable to open file: "<< file_name << std::endl;
std::cerr << "ERROR (" << __func__ << ") : ";
std::cerr << "Unable to open file: "<< file_name << std::endl;
std::exit(EXIT_FAILURE);
}
std::vector <std::vector<std::valarray<double>>> X, Y; // To store X and Y
@@ -440,12 +445,12 @@ namespace machine_learning {
X.push_back({x_data});
Y.push_back({y_data});
}
in_file.close();
// Normalize training data if flag is set
if(normalize) {
// Scale data between 0 and 1 using min-max scaler
X = minmax_scaler(X, 0.01, 1.0);
}
in_file.close(); // Closing file
return make_pair(X, Y); // Return pair of X and Y
}
@@ -496,7 +501,8 @@ namespace machine_learning {
std::vector < std::vector <std::valarray<double>>> X = X_, Y = Y_;
// Both label and input data should have same size
if (X.size() != Y.size()) {
std::cerr << "ERROR : X and Y in fit have different sizes" << std::endl;
std::cerr << "ERROR (" << __func__ << ") : ";
std::cerr << "X and Y in fit have different sizes" << std::endl;
std::exit(EXIT_FAILURE);
}
std::cout << "INFO: Training Started" << std::endl;
@@ -652,7 +658,8 @@ namespace machine_learning {
out_file.open(file_name.c_str(), std::ofstream::out | std::ofstream::trunc);
// If there is any problem in opening file
if(!out_file.is_open()) {
std::cerr << "ERROR: Unable to open file: "<< file_name << std::endl;
std::cerr << "ERROR (" << __func__ << ") : ";
std::cerr << "Unable to open file: "<< file_name << std::endl;
std::exit(EXIT_FAILURE);
}
/**
@@ -710,6 +717,7 @@ namespace machine_learning {
}
std::cout << "INFO: Model saved successfully with name : ";
std::cout << file_name << std::endl;
out_file.close(); // Closing file
return;
}
@@ -723,7 +731,8 @@ namespace machine_learning {
in_file.open(file_name.c_str()); // Openinig file
// If there is any problem in opening file
if(!in_file.is_open()) {
std::cerr << "ERROR: Unable to open file: "<< file_name << std::endl;
std::cerr << "ERROR (" << __func__ << ") : ";
std::cerr << "Unable to open file: "<< file_name << std::endl;
std::exit(EXIT_FAILURE);
}
std::vector <std::pair<int, std::string>> config; // To store config
@@ -748,6 +757,7 @@ namespace machine_learning {
kernals.emplace_back(kernal);
}
std::cout << "INFO: Model loaded successfully" << std::endl;
in_file.close(); // Closing file
return NeuralNetwork(config, kernals); // Return instance of NeuralNetwork class
}
@@ -791,9 +801,9 @@ static void test() {
// Training Model
myNN.fit_from_csv("iris.csv", true, 100, 0.3, false, 2, 32, true);
// Testing predictions of model
assert(machine_learning::argmax(myNN.single_predict({{5,3.4,1.6,0.4}})) == 0);
assert(machine_learning::argmax(myNN.single_predict({{6.4,2.9,4.3,1.3}})) == 1);
assert(machine_learning::argmax(myNN.single_predict({{6.2,3.4,5.4,2.3}})) == 2);
assert(machine_learning::argmax(myNN.single_predict({{5, 3.4, 1.6, 0.4}})) == 0);
assert(machine_learning::argmax(myNN.single_predict({{6.4, 2.9, 4.3, 1.3}})) == 1);
assert(machine_learning::argmax(myNN.single_predict({{6.2, 3.4, 5.4, 2.3}})) == 2);
return;
}

View File

@@ -34,9 +34,9 @@ std::ostream &operator<<(std::ostream &out,
out.precision(4);
for(const auto &a : A) { // For each row in A
for(const auto &x : a) { // For each element in row
std::cerr << x << ' '; // print element
std::cout << x << ' '; // print element
}
std::cerr << std::endl;
std::cout << std::endl;
}
return out;
}
@@ -52,7 +52,7 @@ std::ostream &operator<<(std::ostream &out, const std::pair<T, T> &A) {
// Setting output precision to 4 in case of floating point numbers
out.precision(4);
// printing pair in the form (p, q)
std::cerr << "(" << A.first << ", " << A.second << ")";
std::cout << "(" << A.first << ", " << A.second << ")";
return out;
}
@@ -67,9 +67,9 @@ std::ostream &operator<<(std::ostream &out, const std::valarray<T> &A) {
// Setting output precision to 4 in case of floating point numbers
out.precision(4);
for(const auto &a : A) { // For every element in the vector.
std::cerr << a << ' '; // Print element
std::cout << a << ' '; // Print element
}
std::cerr << std::endl;
std::cout << std::endl;
return out;
}
@@ -135,7 +135,8 @@ void equal_shuffle(std::vector < std::vector <std::valarray<T>> > &A,
// If two vectors have different sizes
if(A.size() != B.size())
{
std::cerr << "ERROR : Can not equally shuffle two vectors with different sizes: ";
std::cerr << "ERROR (" << __func__ << ") : ";
std::cerr << "Can not equally shuffle two vectors with different sizes: ";
std::cerr << A.size() << " and " << B.size() << std::endl;
std::exit(EXIT_FAILURE);
}
@@ -245,7 +246,8 @@ std::pair<size_t, size_t> get_shape(const std::vector<std::valarray<T>> &A) {
for(const auto &a : A) {
// If supplied vector don't have same shape in all rows
if(a.size() != sub_size) {
std::cerr << "ERROR: (get_shape) Supplied vector is not 2D Matrix" << std::endl;
std::cerr << "ERROR (" << __func__ << ") : ";
std::cerr << "Supplied vector is not 2D Matrix" << std::endl;
std::exit(EXIT_FAILURE);
}
}
@@ -267,7 +269,8 @@ minmax_scaler(const std::vector<std::vector<std::valarray<T>>> &A, const T &low,
const auto shape = get_shape(B[0]); // Storing shape of B's every element
// As this function is used for scaling training data vector should be of shape (1, X)
if(shape.first != 1) {
std::cerr << "ERROR: (MinMax Scaling) Supplied vector is not supported for minmax scaling, shape: ";
std::cerr << "ERROR (" << __func__ << ") : ";
std::cerr << "Supplied vector is not supported for minmax scaling, shape: ";
std::cerr << shape << std::endl;
std::exit(EXIT_FAILURE);
}
@@ -297,7 +300,8 @@ size_t argmax(const std::vector<std::valarray<T>> &A) {
const auto shape = get_shape(A);
// As this function is used on predicted (or target) vector, shape should be (1, X)
if(shape.first != 1) {
std::cerr << "ERROR: (argmax) Supplied vector is ineligible for argmax" << std::endl;
std::cerr << "ERROR (" << __func__ << ") : ";
std::cerr << "Supplied vector is ineligible for argmax" << std::endl;
std::exit(EXIT_FAILURE);
}
// Return distance of max element from first element (i.e. index)
@@ -388,7 +392,8 @@ std::vector <std::valarray <T> > operator + (const std::vector<std::valarray<T>>
const auto shape_b = get_shape(B);
// If vectors don't have equal shape
if(shape_a.first != shape_b.first || shape_a.second != shape_b.second) {
std::cerr << "ERROR: (vector addition) Supplied vectors have different shapes ";
std::cerr << "ERROR (" << __func__ << ") : ";
std::cerr << "Supplied vectors have different shapes ";
std::cerr << shape_a << " and " << shape_b << std::endl;
std::exit(EXIT_FAILURE);
}
@@ -412,7 +417,8 @@ std::vector <std::valarray <T>> operator - (const std::vector<std::valarray<T>>
const auto shape_b = get_shape(B);
// If vectors don't have equal shape
if(shape_a.first != shape_b.first || shape_a.second != shape_b.second) {
std::cerr << "ERROR: (vector subtraction) Supplied vectors have different shapes ";
std::cerr << "ERROR (" << __func__ << ") : ";
std::cerr << "Supplied vectors have different shapes ";
std::cerr << shape_a << " and " << shape_b << std::endl;
std::exit(EXIT_FAILURE);
}
@@ -436,7 +442,8 @@ std::vector <std::valarray <T>> multiply(const std::vector<std::valarray<T>> &A,
const auto shape_b = get_shape(B);
// If vectors are not eligible for multiplication
if(shape_a.second != shape_b.first ) {
std::cerr << "ERROR: (multiply) Supplied vectors are not eligible for multiplication ";
std::cerr << "ERROR (" << __func__ << ") : ";
std::cerr << "Vectors are not eligible for multiplication ";
std::cerr << shape_a << " and " << shape_b << std::endl;
std::exit(EXIT_FAILURE);
}
@@ -468,7 +475,8 @@ std::vector <std::valarray <T>> hadamard_product(const std::vector<std::valarray
const auto shape_b = get_shape(B);
// If vectors are not eligible for hadamard product
if(shape_a.first != shape_b.first || shape_a.second != shape_b.second) {
std::cerr << "ERROR: (hadamard_product) Supplied vectors have different shapes ";
std::cerr << "ERROR (" << __func__ << ") : ";
std::cerr << "Vectors have different shapes ";
std::cerr << shape_a << " and " << shape_b << std::endl;
std::exit(EXIT_FAILURE);
}