diff --git a/MLPP/Activation/Activation.cpp b/MLPP/Activation/Activation.cpp index 772251c..a96e209 100644 --- a/MLPP/Activation/Activation.cpp +++ b/MLPP/Activation/Activation.cpp @@ -566,6 +566,57 @@ namespace MLPP{ return a; } + double Activation::sign(double z, bool deriv){ + if(deriv){ + return 0; + } + if(z < 0){ + return -1; + } + else if(z == 0){ + return 0; + } + else{ + return 1; + } + } + + std::vector Activation::sign(std::vector z, bool deriv){ + if(deriv){ + std::vector deriv; + deriv.resize(z.size()); + for(int i = 0; i < z.size(); i++){ + deriv[i] = sign(z[i], 1); + } + return deriv; + } + std::vector a; + a.resize(z.size()); + + for(int i = 0; i < a.size(); i++){ + a[i] = sign(z[i]); + } + return a; + } + + std::vector> Activation::sign(std::vector> z, bool deriv){ + if(deriv){ + std::vector> deriv; + deriv.resize(z.size()); + for(int i = 0; i < z.size(); i++){ + deriv[i] = sign(z[i], 1); + } + return deriv; + } + std::vector> a; + a.resize(z.size()); + + for(int i = 0; i < a.size(); i++){ + a[i] = sign(z[i]); + } + return a; + } + double Activation::sinh(double z, bool deriv){ if(deriv){ return cosh(z); } return 0.5 * (exp(z) - exp(-z)); diff --git a/MLPP/Activation/Activation.hpp b/MLPP/Activation/Activation.hpp index 9925064..fe7b955 100644 --- a/MLPP/Activation/Activation.hpp +++ b/MLPP/Activation/Activation.hpp @@ -81,6 +81,10 @@ namespace MLPP{ std::vector GELU(std::vector z, bool deriv = 0); std::vector> GELU(std::vector> z, bool deriv = 0); + double sign(double z, bool deriv = 0); + std::vector sign(std::vector z, bool deriv = 0); + std::vector> sign(std::vector> z, bool deriv = 0); + double sinh(double z, bool deriv = 0); std::vector sinh(std::vector z, bool deriv = 0); std::vector> sinh(std::vector> z, bool deriv = 0); diff --git a/MLPP/Cost/Cost.cpp b/MLPP/Cost/Cost.cpp index 7ca3634..12a84a7 100644 --- a/MLPP/Cost/Cost.cpp +++ b/MLPP/Cost/Cost.cpp @@ -7,6 +7,7 @@ #include #include "Cost.hpp" #include "LinAlg/LinAlg.hpp" +#include "Regularization/Reg.hpp" namespace MLPP{ double Cost::MSE(std::vector y_hat, std::vector y){ @@ -341,4 +342,26 @@ namespace MLPP{ } return deriv; } + + double Cost::HingeLoss(std::vector y_hat, std::vector y, std::vector weights, double C){ + LinAlg alg; + Reg regularization; + return C * HingeLoss(y_hat, y) + regularization.regTerm(weights, 1, 0, "Ridge"); + } + double Cost::HingeLoss(std::vector> y_hat, std::vector> y, std::vector weights, double C){ + LinAlg alg; + Reg regularization; + return C * HingeLoss(y_hat, y) + regularization.regTerm(weights, 1, 0, "Ridge"); + } + + std::vector Cost::HingeLossDeriv(std::vector y_hat, std::vector y, double C){ + LinAlg alg; + Reg regularization; + return alg.scalarMultiply(C, HingeLossDeriv(y_hat, y)); + } + std::vector> Cost::HingeLossDeriv(std::vector> y_hat, std::vector> y, double C){ + LinAlg alg; + Reg regularization; + return alg.scalarMultiply(C, HingeLossDeriv(y_hat, y)); + } } \ No newline at end of file diff --git a/MLPP/Cost/Cost.hpp b/MLPP/Cost/Cost.hpp index f59465c..41d60b5 100644 --- a/MLPP/Cost/Cost.hpp +++ b/MLPP/Cost/Cost.hpp @@ -61,6 +61,12 @@ namespace MLPP{ std::vector HingeLossDeriv(std::vector y_hat, std::vector y); std::vector> HingeLossDeriv(std::vector> y_hat, std::vector> y); + + double HingeLoss(std::vector y_hat, std::vector y, std::vector weights, double C); + double HingeLoss(std::vector> y_hat, std::vector> y, std::vector weights, double C); + + std::vector HingeLossDeriv(std::vector y_hat, std::vector y, double C); + std::vector> HingeLossDeriv(std::vector> y_hat, std::vector> y, double C); private: diff --git a/MLPP/HiddenLayer/HiddenLayer.cpp b/MLPP/HiddenLayer/HiddenLayer.cpp index d60c873..b993799 100644 --- a/MLPP/HiddenLayer/HiddenLayer.cpp +++ b/MLPP/HiddenLayer/HiddenLayer.cpp @@ -52,6 +52,9 @@ namespace MLPP { activation_map["GELU"] = &Activation::GELU; activationTest_map["GELU"] = &Activation::GELU; + activation_map["Sign"] = &Activation::unitStep; + activationTest_map["Sign"] = &Activation::unitStep; + activation_map["UnitStep"] = &Activation::unitStep; activationTest_map["UnitStep"] = &Activation::unitStep; diff --git a/MLPP/MultiOutputLayer/MultiOutputLayer.cpp b/MLPP/MultiOutputLayer/MultiOutputLayer.cpp index 977c9bd..46a36c4 100644 --- a/MLPP/MultiOutputLayer/MultiOutputLayer.cpp +++ b/MLPP/MultiOutputLayer/MultiOutputLayer.cpp @@ -54,6 +54,9 @@ namespace MLPP { activation_map["GELU"] = &Activation::GELU; activationTest_map["GELU"] = &Activation::GELU; + activation_map["Sign"] = &Activation::unitStep; + activationTest_map["Sign"] = &Activation::unitStep; + activation_map["UnitStep"] = &Activation::unitStep; activationTest_map["UnitStep"] = &Activation::unitStep; diff --git a/MLPP/OutputLayer/OutputLayer.cpp b/MLPP/OutputLayer/OutputLayer.cpp index 9436e54..c39057c 100644 --- a/MLPP/OutputLayer/OutputLayer.cpp +++ b/MLPP/OutputLayer/OutputLayer.cpp @@ -51,6 +51,9 @@ namespace MLPP { activation_map["GELU"] = &Activation::GELU; activationTest_map["GELU"] = &Activation::GELU; + activation_map["Sign"] = &Activation::unitStep; + activationTest_map["Sign"] = &Activation::unitStep; + activation_map["UnitStep"] = &Activation::unitStep; activationTest_map["UnitStep"] = &Activation::unitStep; diff --git a/MLPP/Regularization/Reg.cpp b/MLPP/Regularization/Reg.cpp index 726beb0..06f0c69 100644 --- a/MLPP/Regularization/Reg.cpp +++ b/MLPP/Regularization/Reg.cpp @@ -7,6 +7,7 @@ #include #include #include "Reg.hpp" +#include "Activation/Activation.hpp" namespace MLPP{ @@ -85,14 +86,15 @@ namespace MLPP{ } double Reg::regDerivTerm(std::vector weights, double lambda, double alpha, std::string reg, int j){ + Activation act; if(reg == "Ridge"){ return lambda * weights[j]; } else if(reg == "Lasso"){ - return lambda * sign(weights[j]); + return lambda * act.sign(weights[j]); } else if(reg == "ElasticNet"){ - return alpha * lambda * sign(weights[j]) + (1 - alpha) * lambda * weights[j]; + return alpha * lambda * act.sign(weights[j]) + (1 - alpha) * lambda * weights[j]; } else { return 0; @@ -100,29 +102,18 @@ namespace MLPP{ } double Reg::regDerivTerm(std::vector> weights, double lambda, double alpha, std::string reg, int i, int j){ + Activation act; if(reg == "Ridge"){ return lambda * weights[i][j]; } else if(reg == "Lasso"){ - return lambda * sign(weights[i][j]); + return lambda * act.sign(weights[i][j]); } else if(reg == "ElasticNet"){ - return alpha * lambda * sign(weights[i][j]) + (1 - alpha) * lambda * weights[i][j]; + return alpha * lambda * act.sign(weights[i][j]) + (1 - alpha) * lambda * weights[i][j]; } else { return 0; } } - - int Reg::sign(double weight){ - if(weight < 0){ - return -1; - } - else if(weight == 0){ - return 0; - } - else{ - return 1; - } - } } diff --git a/MLPP/Regularization/Reg.hpp b/MLPP/Regularization/Reg.hpp index 37d2b80..cff6fb3 100644 --- a/MLPP/Regularization/Reg.hpp +++ b/MLPP/Regularization/Reg.hpp @@ -22,7 +22,6 @@ namespace MLPP{ private: double regDerivTerm(std::vector weights, double lambda, double alpha, std::string reg, int j); double regDerivTerm(std::vector> weights, double lambda, double alpha, std::string reg, int i, int j); - int sign(double weight); }; } diff --git a/MLPP/SVC/SVC.cpp b/MLPP/SVC/SVC.cpp index 6406624..034ec30 100644 --- a/MLPP/SVC/SVC.cpp +++ b/MLPP/SVC/SVC.cpp @@ -5,23 +5,20 @@ // #include "SVC.hpp" +#include "Activation/Activation.hpp" #include "LinAlg/LinAlg.hpp" -#include "Stat/Stat.hpp" #include "Regularization/Reg.hpp" #include "Utilities/Utilities.hpp" #include "Cost/Cost.hpp" #include -#include #include namespace MLPP{ - - SVC::SVC(std::vector> inputSet, std::vector outputSet, std::string reg, double lambda, double alpha) - : inputSet(inputSet), outputSet(outputSet), n(inputSet.size()), k(inputSet[0].size()), reg(reg), lambda(lambda), alpha(alpha) + SVC::SVC(std::vector> inputSet, std::vector outputSet, double C) + : inputSet(inputSet), outputSet(outputSet), n(inputSet.size()), k(inputSet[0].size()), C(C) { y_hat.resize(n); - weights = Utilities::weightInitialization(k); bias = Utilities::biasInitialization(); } @@ -35,6 +32,8 @@ namespace MLPP{ } void SVC::gradientDescent(double learning_rate, int max_epoch, bool UI){ + class Cost cost; + Activation avn; LinAlg alg; Reg regularization; double cost_prev = 0; @@ -42,31 +41,34 @@ namespace MLPP{ forwardPass(); while(true){ - cost_prev = Cost(y_hat, outputSet); - - std::vector error = alg.subtraction(y_hat, outputSet); + cost_prev = Cost(y_hat, outputSet, weights, C); + + weights = alg.subtraction(weights, alg.scalarMultiply(learning_rate/n, alg.mat_vec_mult(alg.transpose(inputSet), cost.HingeLossDeriv(z, outputSet, C)))); + weights = regularization.regWeights(weights, learning_rate/n, 0, "Ridge"); - // Calculating the weight gradients - weights = alg.subtraction(weights, alg.scalarMultiply(learning_rate/n, alg.mat_vec_mult(alg.transpose(inputSet), error))); - weights = regularization.regWeights(weights, lambda, alpha, reg); - // Calculating the bias gradients - bias -= learning_rate * alg.sum_elements(error) / n; + bias += learning_rate * alg.sum_elements(cost.HingeLossDeriv(y_hat, outputSet, C)) / n; + forwardPass(); + // UI PORTION if(UI) { - Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputSet)); + Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputSet, weights, C)); Utilities::UI(weights, bias); } epoch++; if(epoch > max_epoch) { break; } + } } void SVC::SGD(double learning_rate, int max_epoch, bool UI){ + class Cost cost; + Activation avn; LinAlg alg; Reg regularization; + double cost_prev = 0; int epoch = 1; @@ -77,21 +79,22 @@ namespace MLPP{ int outputIndex = distribution(generator); double y_hat = Evaluate(inputSet[outputIndex]); - cost_prev = Cost({y_hat}, {outputSet[outputIndex]}); + double z = propagate(inputSet[outputIndex]); + cost_prev = Cost({z}, {outputSet[outputIndex]}, weights, C); - double error = y_hat - outputSet[outputIndex]; + double costDeriv = cost.HingeLossDeriv({z}, {outputSet[outputIndex]}, C)[0]; - // Weight updation - weights = alg.subtraction(weights, alg.scalarMultiply(learning_rate * error, inputSet[outputIndex])); - weights = regularization.regWeights(weights, lambda, alpha, reg); + // Weight Updation + weights = alg.subtraction(weights, alg.scalarMultiply(learning_rate * costDeriv, inputSet[outputIndex])); + weights = regularization.regWeights(weights, learning_rate, 0, "Ridge"); // Bias updation - bias -= learning_rate * error; + bias -= learning_rate * costDeriv; y_hat = Evaluate({inputSet[outputIndex]}); if(UI) { - Utilities::CostInfo(epoch, cost_prev, Cost({y_hat}, {outputSet[outputIndex]})); + Utilities::CostInfo(epoch, cost_prev, Cost({z}, {outputSet[outputIndex]}, weights, C)); Utilities::UI(weights, bias); } epoch++; @@ -102,6 +105,8 @@ namespace MLPP{ } void SVC::MBGD(double learning_rate, int max_epoch, int mini_batch_size, bool UI){ + class Cost cost; + Activation avn; LinAlg alg; Reg regularization; double cost_prev = 0; @@ -114,20 +119,23 @@ namespace MLPP{ while(true){ for(int i = 0; i < n_mini_batch; i++){ std::vector y_hat = Evaluate(inputMiniBatches[i]); - cost_prev = Cost(y_hat, outputMiniBatches[i]); - - std::vector error = alg.subtraction(y_hat, outputMiniBatches[i]); + std::vector z = propagate(inputMiniBatches[i]); + cost_prev = Cost(z, outputMiniBatches[i], weights, C); // Calculating the weight gradients - weights = alg.subtraction(weights, alg.scalarMultiply(learning_rate/outputMiniBatches[i].size(), alg.mat_vec_mult(alg.transpose(inputMiniBatches[i]), error))); - weights = regularization.regWeights(weights, lambda, alpha, reg); - + weights = alg.subtraction(weights, alg.scalarMultiply(learning_rate/n, alg.mat_vec_mult(alg.transpose(inputMiniBatches[i]), cost.HingeLossDeriv(z, outputMiniBatches[i], C)))); + weights = regularization.regWeights(weights, learning_rate/n, 0, "Ridge"); + + // Calculating the bias gradients - bias -= learning_rate * alg.sum_elements(error) / outputMiniBatches[i].size(); + bias -= learning_rate * alg.sum_elements(cost.HingeLossDeriv(y_hat, outputMiniBatches[i], C)) / n; + + forwardPass(); + y_hat = Evaluate(inputMiniBatches[i]); if(UI) { - Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputMiniBatches[i])); + Utilities::CostInfo(epoch, cost_prev, Cost(z, outputMiniBatches[i], weights, C)); Utilities::UI(weights, bias); } } @@ -142,29 +150,46 @@ namespace MLPP{ return util.performance(y_hat, outputSet); } - void SVC::save(std::string fileName){ + void SVC::save(std::string fileName){ Utilities util; util.saveParameters(fileName, weights, bias); } - double SVC::Cost(std::vector y_hat, std::vector y){ - Reg regularization; + double SVC::Cost(std::vector z, std::vector y, std::vector weights, double C){ class Cost cost; - return cost.MSE(y_hat, y) + regularization.regTerm(weights, lambda, alpha, reg); + return cost.HingeLoss(z, y, weights, C); } std::vector SVC::Evaluate(std::vector> X){ LinAlg alg; + Activation avn; + return avn.sign(alg.scalarAdd(bias, alg.mat_vec_mult(X, weights))); + } + + std::vectorSVC::propagate(std::vector> X){ + LinAlg alg; + Activation avn; return alg.scalarAdd(bias, alg.mat_vec_mult(X, weights)); } double SVC::Evaluate(std::vector x){ LinAlg alg; + Activation avn; + return avn.sign(alg.dot(weights, x) + bias); + } + + double SVC::propagate(std::vector x){ + LinAlg alg; + Activation avn; return alg.dot(weights, x) + bias; } - // sign(wTx + b) + // sign ( wTx + b ) void SVC::forwardPass(){ - y_hat = Evaluate(inputSet); + LinAlg alg; + Activation avn; + + z = propagate(inputSet); + y_hat = avn.sign(z); } } \ No newline at end of file diff --git a/MLPP/SVC/SVC.hpp b/MLPP/SVC/SVC.hpp index 432520e..7426069 100644 --- a/MLPP/SVC/SVC.hpp +++ b/MLPP/SVC/SVC.hpp @@ -1,20 +1,22 @@ // // SVC.hpp // -// Created by Marc Melikyan on 9/10/21. +// Created by Marc Melikyan on 10/2/20. // #ifndef SVC_hpp #define SVC_hpp + #include #include -namespace MLPP{ +namespace MLPP { + class SVC{ public: - SVC(std::vector> inputSet, std::vector outputSet, std::string reg = "None", double lambda = 0.5, double alpha = 0.5); + SVC(std::vector> inputSet, std::vector outputSet, double C); std::vector modelSetTest(std::vector> X); double modelTest(std::vector x); void gradientDescent(double learning_rate, int max_epoch, bool UI = 1); @@ -24,27 +26,27 @@ namespace MLPP{ void save(std::string fileName); private: - double Cost(std::vector y_hat, std::vector y); + double Cost(std::vector y_hat, std::vector y, std::vector weights, double C); std::vector Evaluate(std::vector> X); + std::vector propagate(std::vector> X); double Evaluate(std::vector x); + double propagate(std::vector x); void forwardPass(); std::vector> inputSet; std::vector outputSet; + std::vector z; std::vector y_hat; std::vector weights; double bias; - + + double C; int n; int k; - // Regularization Params - std::string reg; - int lambda; - int alpha; /* This is the controlling param for Elastic Net*/ - - + // UI Portion + void UI(int epoch, double cost_prev); }; } diff --git a/a.out b/a.out index 593deed..e78ebeb 100755 Binary files a/a.out and b/a.out differ diff --git a/main.cpp b/main.cpp index ab1453e..4d010b3 100644 --- a/main.cpp +++ b/main.cpp @@ -42,6 +42,7 @@ #include "MLPP/Cost/Cost.hpp" #include "MLPP/Data/Data.hpp" #include "MLPP/Convolutions/Convolutions.hpp" +#include "MLPP/SVC/SVC.hpp" using namespace MLPP; @@ -196,6 +197,15 @@ int main() { // data.setData(4, "/Users/marcmelikyan/Desktop/Data/Iris.csv", inputSet, tempOutputSet); // std::vector> outputSet = data.oneHotRep(tempOutputSet, 3); + // SUPPORT VECTOR CLASSIFICATION + std::vector> inputSet; + std::vector outputSet; + data.setData(30, "/Users/marcmelikyan/Desktop/Data/BreastCancerSVM.csv", inputSet, outputSet); + SVC model(inputSet, outputSet, 1); + model.SGD(0.00001, 100000, 1); + alg.printVector(model.modelSetTest(inputSet)); + std::cout << "ACCURACY: " << 100 * model.score() << "%" << std::endl; + // SoftmaxReg model(inputSet, outputSet); // model.SGD(0.001, 20000, 0); // alg.printMatrix(model.modelSetTest(inputSet)); @@ -392,18 +402,18 @@ int main() { // OutlierFinder outlierFinder(2); // Any datapoint outside of 2 stds from the mean is marked as an outlier. // alg.printVector(outlierFinder.modelTest(inputSet)); - // Testing new Functions - double z_s = 0.001; - std::cout << avn.sinc(z_s) << std::endl; - std::cout << avn.sinc(z_s, 1) << std::endl; + // // Testing new Functions + // double z_s = 0.001; + // std::cout << avn.sinc(z_s) << std::endl; + // std::cout << avn.sinc(z_s, 1) << std::endl; - std::vector z_v = {0.001, 5}; - alg.printVector(avn.sinc(z_v)); - alg.printVector(avn.sinc(z_v, 1)); + // std::vector z_v = {0.001, 5}; + // alg.printVector(avn.sinc(z_v)); + // alg.printVector(avn.sinc(z_v, 1)); - std::vector> Z_m = {{0.001, 5}}; - alg.printMatrix(avn.sinc(Z_m)); - alg.printMatrix(avn.sinc(Z_m, 1)); + // std::vector> Z_m = {{0.001, 5}}; + // alg.printMatrix(avn.sinc(Z_m)); + // alg.printMatrix(avn.sinc(Z_m, 1)); // std::cout << alg.trace({{1,2}, {3,4}}) << std::endl; // alg.printMatrix(alg.pinverse({{1,2}, {3,4}}));