mirror of
https://github.com/Relintai/MLPP.git
synced 2025-04-17 21:06:32 +02:00
Add files via upload
This commit is contained in:
commit
13e5c9c761
MLPP
ANN
Activation
AutoEncoder
BernoulliNB
CLogLogReg
Convolutions
Cost
Data
ExpReg
GaussMarkovChecker
GaussianNB
HiddenLayer
HypothesisTesting
KMeans
LinAlg
LinReg
LogReg
MLP
MultinomialNB
OutlierFinder
OutputLayer
PCA
ProbitReg
Regularization
SoftmaxNet
SoftmaxReg
Stat
TanhReg
UniLinReg
Utilities
kNN
162
MLPP/ANN/ANN.cpp
Normal file
162
MLPP/ANN/ANN.cpp
Normal file
@ -0,0 +1,162 @@
|
||||
//
|
||||
// ANN.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 11/4/20.
|
||||
//
|
||||
|
||||
#include "ANN.hpp"
|
||||
#include "Activation/Activation.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
#include "Regularization/Reg.hpp"
|
||||
#include "Utilities/Utilities.hpp"
|
||||
#include "Cost/Cost.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace MLPP {
|
||||
ANN::ANN(std::vector<std::vector<double>> inputSet, std::vector<double> outputSet)
|
||||
: inputSet(inputSet), outputSet(outputSet), n(inputSet.size()), k(inputSet[0].size())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ANN::~ANN(){
|
||||
delete outputLayer;
|
||||
}
|
||||
|
||||
std::vector<double> ANN::modelSetTest(std::vector<std::vector<double>> X){
|
||||
network[0].input = X;
|
||||
network[0].forwardPass();
|
||||
|
||||
for(int i = 1; i < network.size(); i++){
|
||||
network[i].input = network[i - 1].a;
|
||||
network[i].forwardPass();
|
||||
}
|
||||
outputLayer->input = network[network.size() - 1].a;
|
||||
outputLayer->forwardPass();
|
||||
return outputLayer->a;
|
||||
}
|
||||
|
||||
double ANN::modelTest(std::vector<double> x){
|
||||
|
||||
network[0].Test(x);
|
||||
for(int i = 1; i < network.size(); i++){
|
||||
network[i].Test(network[i - 1].a_test);
|
||||
}
|
||||
outputLayer->Test(network[network.size() - 1].a_test);
|
||||
return outputLayer->a_test;
|
||||
}
|
||||
|
||||
void ANN::gradientDescent(double learning_rate, int max_epoch, bool UI){
|
||||
class Cost cost;
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
Reg regularization;
|
||||
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
forwardPass();
|
||||
|
||||
while(true){
|
||||
cost_prev = Cost(y_hat, outputSet);
|
||||
|
||||
auto costDeriv = outputLayer->costDeriv_map[outputLayer->cost];
|
||||
auto outputAvn = outputLayer->activation_map[outputLayer->activation];
|
||||
outputLayer->delta = alg.hadamard_product((cost.*costDeriv)(y_hat, outputSet), (avn.*outputAvn)(outputLayer->z, 1));
|
||||
std::vector<double> outputWGrad = alg.mat_vec_mult(alg.transpose(outputLayer->input), outputLayer->delta);
|
||||
|
||||
outputLayer->weights = alg.subtraction(outputLayer->weights, alg.scalarMultiply(learning_rate/n, outputWGrad));
|
||||
outputLayer->weights = regularization.regWeights(outputLayer->weights, outputLayer->lambda, outputLayer->alpha, outputLayer->reg);
|
||||
outputLayer->bias -= learning_rate * alg.sum_elements(outputLayer->delta) / n;
|
||||
|
||||
auto hiddenLayerAvn = network[network.size() - 1].activation_map[network[network.size() - 1].activation];
|
||||
network[network.size() - 1].delta = alg.hadamard_product(alg.vecmult(outputLayer->delta, outputLayer->weights), (avn.*hiddenLayerAvn)(network[network.size() - 1].z, 1));
|
||||
std::vector<std::vector<double>> hiddenLayerWGrad = alg.matmult(alg.transpose(network[network.size() - 1].input), network[network.size() - 1].delta);
|
||||
|
||||
network[network.size() - 1].weights = alg.subtraction(network[network.size() - 1].weights, alg.scalarMultiply(learning_rate/n, hiddenLayerWGrad));
|
||||
network[network.size() - 1].weights = regularization.regWeights(network[network.size() - 1].weights, network[network.size() - 1].lambda, network[network.size() - 1].alpha, network[network.size() - 1].reg);
|
||||
network[network.size() - 1].bias = alg.subtractMatrixRows(network[network.size() - 1].bias, alg.scalarMultiply(learning_rate/n, network[network.size() - 1].delta));
|
||||
|
||||
for(int i = network.size() - 2; i >= 0; i--){
|
||||
auto hiddenLayerAvn = network[i].activation_map[network[i].activation];
|
||||
network[i].delta = alg.hadamard_product(alg.matmult(network[i + 1].delta, network[i + 1].weights), (avn.*hiddenLayerAvn)(network[i].z, 1));
|
||||
std::vector<std::vector<double>> hiddenLayerWGrad = alg.matmult(alg.transpose(network[i].input), network[i].delta);
|
||||
network[i].weights = alg.subtraction(network[i].weights, alg.scalarMultiply(learning_rate/n, hiddenLayerWGrad));
|
||||
network[i].weights = regularization.regWeights(network[i].weights, network[i].lambda, network[i].alpha, network[i].reg);
|
||||
network[i].bias = alg.subtractMatrixRows(network[i].bias, alg.scalarMultiply(learning_rate/n, network[i].delta));
|
||||
}
|
||||
|
||||
forwardPass();
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputSet));
|
||||
std::cout << "Layer " << network.size() + 1 << ": " << std::endl;
|
||||
Utilities::UI(outputLayer->weights, outputLayer->bias);
|
||||
std::cout << "Layer " << network.size() << ": " << std::endl;
|
||||
Utilities::UI(network[network.size() - 1].weights, network[network.size() - 1].bias);
|
||||
for(int i = network.size() - 2; i >= 0; i--){
|
||||
std::cout << "Layer " << i + 1 << ": " << std::endl;
|
||||
Utilities::UI(network[i].weights, network[i].bias);
|
||||
}
|
||||
}
|
||||
|
||||
epoch++;
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
}
|
||||
|
||||
double ANN::score(){
|
||||
Utilities util;
|
||||
forwardPass();
|
||||
return util.performance(y_hat, outputSet);
|
||||
}
|
||||
|
||||
void ANN::save(std::string fileName){
|
||||
Utilities util;
|
||||
util.saveParameters(fileName, network[0].weights, network[0].bias, 0, 1);
|
||||
for(int i = 1; i < network.size(); i++){
|
||||
util.saveParameters(fileName, network[i].weights, network[i].bias, 1, i + 1);
|
||||
}
|
||||
util.saveParameters(fileName, outputLayer->weights, outputLayer->bias, 1, network.size() + 1);
|
||||
}
|
||||
|
||||
void ANN::addLayer(int n_hidden, std::string activation, std::string weightInit, std::string reg, double lambda, double alpha){
|
||||
if(network.empty()){
|
||||
network.push_back(HiddenLayer(n_hidden, activation, inputSet, weightInit, reg, lambda, alpha));
|
||||
network[0].forwardPass();
|
||||
}
|
||||
else{
|
||||
network.push_back(HiddenLayer(n_hidden, activation, network[network.size() - 1].a, weightInit, reg, lambda, alpha));
|
||||
network[network.size() - 1].forwardPass();
|
||||
}
|
||||
}
|
||||
|
||||
void ANN::addOutputLayer(std::string activation, std::string loss, std::string weightInit, std::string reg, double lambda, double alpha){
|
||||
outputLayer = new OutputLayer(network[0].n_hidden, outputSet.size(), activation, loss, network[network.size() - 1].a, weightInit, reg, lambda, alpha);
|
||||
}
|
||||
|
||||
double ANN::Cost(std::vector<double> y_hat, std::vector<double> y){
|
||||
Reg regularization;
|
||||
class Cost cost;
|
||||
double totalRegTerm = 0;
|
||||
|
||||
auto cost_function = outputLayer->cost_map[outputLayer->cost];
|
||||
for(int i = 0; i < network.size() - 1; i++){
|
||||
totalRegTerm += regularization.regTerm(network[i].weights, network[i].lambda, network[i].alpha, network[i].reg);
|
||||
}
|
||||
return (cost.*cost_function)(y_hat, y) + totalRegTerm + regularization.regTerm(outputLayer->weights, outputLayer->lambda, outputLayer->alpha, outputLayer->reg);
|
||||
}
|
||||
|
||||
void ANN::forwardPass(){
|
||||
network[0].input = inputSet;
|
||||
network[0].forwardPass();
|
||||
|
||||
for(int i = 1; i < network.size(); i++){
|
||||
network[i].input = network[i - 1].a;
|
||||
network[i].forwardPass();
|
||||
}
|
||||
outputLayer->input = network[network.size() - 1].a;
|
||||
outputLayer->forwardPass();
|
||||
y_hat = outputLayer->a;
|
||||
}
|
||||
}
|
47
MLPP/ANN/ANN.hpp
Normal file
47
MLPP/ANN/ANN.hpp
Normal file
@ -0,0 +1,47 @@
|
||||
//
|
||||
// ANN.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 11/4/20.
|
||||
//
|
||||
|
||||
#ifndef ANN_hpp
|
||||
#define ANN_hpp
|
||||
|
||||
#include "HiddenLayer/HiddenLayer.hpp"
|
||||
#include "OutputLayer/OutputLayer.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace MLPP{
|
||||
|
||||
class ANN{
|
||||
public:
|
||||
ANN(std::vector<std::vector<double>> inputSet, std::vector<double> outputSet);
|
||||
~ANN();
|
||||
std::vector<double> modelSetTest(std::vector<std::vector<double>> X);
|
||||
double modelTest(std::vector<double> x);
|
||||
void gradientDescent(double learning_rate, int max_epoch, bool UI = 1);
|
||||
double score();
|
||||
void save(std::string fileName);
|
||||
|
||||
void addLayer(int n_hidden, std::string activation, std::string weightInit = "Default", std::string reg = "None", double lambda = 0.5, double alpha = 0.5);
|
||||
void addOutputLayer(std::string activation, std::string loss, std::string weightInit = "Default", std::string reg = "None", double lambda = 0.5, double alpha = 0.5);
|
||||
|
||||
private:
|
||||
double Cost(std::vector<double> y_hat, std::vector<double> y);
|
||||
void forwardPass();
|
||||
|
||||
std::vector<std::vector<double>> inputSet;
|
||||
std::vector<double> outputSet;
|
||||
std::vector<double> y_hat;
|
||||
|
||||
std::vector<HiddenLayer> network;
|
||||
OutputLayer *outputLayer;
|
||||
|
||||
int n;
|
||||
int k;
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* ANN_hpp */
|
1007
MLPP/Activation/Activation.cpp
Normal file
1007
MLPP/Activation/Activation.cpp
Normal file
File diff suppressed because it is too large
Load Diff
124
MLPP/Activation/Activation.hpp
Normal file
124
MLPP/Activation/Activation.hpp
Normal file
@ -0,0 +1,124 @@
|
||||
//
|
||||
// Activation.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 1/16/21.
|
||||
//
|
||||
|
||||
#ifndef Activation_hpp
|
||||
#define Activation_hpp
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace MLPP{
|
||||
class Activation{
|
||||
public:
|
||||
double linear(double z, bool deriv = 0);
|
||||
std::vector<double> linear(std::vector<double> z, bool deriv = 0);
|
||||
std::vector<std::vector<double>> linear(std::vector<std::vector<double>> z, bool deriv = 0);
|
||||
|
||||
double sigmoid(double z, bool deriv = 0);
|
||||
std::vector<double> sigmoid(std::vector<double> z, bool deriv = 0);
|
||||
std::vector<std::vector<double>> sigmoid(std::vector<std::vector<double>> z, bool deriv = 0);
|
||||
|
||||
std::vector<double> softmax(std::vector<double> z);
|
||||
std::vector<std::vector<double>> softmax(std::vector<std::vector<double>> z);
|
||||
|
||||
std::vector<double> adjSoftmax(std::vector<double> z);
|
||||
std::vector<std::vector<double>> adjSoftmax(std::vector<std::vector<double>> z);
|
||||
|
||||
std::vector<std::vector<double>> softmaxDeriv(std::vector<double> z);
|
||||
std::vector<std::vector<std::vector<double>>> softmaxDeriv(std::vector<std::vector<double>> z);
|
||||
|
||||
double softplus(double z, bool deriv = 0);
|
||||
std::vector<double> softplus(std::vector<double> z, bool deriv = 0);
|
||||
std::vector<std::vector<double>> softplus(std::vector<std::vector<double>> z, bool deriv = 0);
|
||||
|
||||
double gaussianCDF(double z, bool deriv = 0);
|
||||
std::vector<double> gaussianCDF(std::vector<double> z, bool deriv = 0);
|
||||
std::vector<std::vector<double>> gaussianCDF(std::vector<std::vector<double>> z, bool deriv = 0);
|
||||
|
||||
double cloglog(double z, bool deriv = 0);
|
||||
std::vector<double> cloglog(std::vector<double> z, bool deriv = 0);
|
||||
std::vector<std::vector<double>> cloglog(std::vector<std::vector<double>> z, bool deriv = 0);
|
||||
|
||||
double unitStep(double z, bool deriv = 0);
|
||||
std::vector<double> unitStep(std::vector<double> z, bool deriv = 0);
|
||||
std::vector<std::vector<double>> unitStep(std::vector<std::vector<double>> z, bool deriv = 0);
|
||||
|
||||
double swish(double z, bool deriv = 0);
|
||||
std::vector<double> swish(std::vector<double> z, bool deriv = 0);
|
||||
std::vector<std::vector<double>> swish(std::vector<std::vector<double>> z, bool deriv = 0);
|
||||
|
||||
double RELU(double z, bool deriv = 0);
|
||||
std::vector<double> RELU(std::vector<double> z, bool deriv = 0);
|
||||
std::vector<std::vector<double>> RELU(std::vector<std::vector<double>> z, bool deriv = 0);
|
||||
|
||||
double leakyReLU(double z, double c, bool deriv = 0);
|
||||
std::vector<double> leakyReLU(std::vector<double> z, double c, bool deriv = 0);
|
||||
|
||||
double ELU(double z, double c, bool deriv = 0);
|
||||
std::vector<double> ELU(std::vector<double> z, double c, bool deriv = 0);
|
||||
|
||||
double SELU(double z, double lambda, double c, bool deriv = 0);
|
||||
std::vector<double> SELU(std::vector<double> z, double lambda, double c, bool deriv = 0);
|
||||
std::vector<std::vector<double>> SELU(std::vector<std::vector<double>>, double lambda, double c, bool deriv = 0);
|
||||
|
||||
double GELU(double z, bool deriv = 0);
|
||||
std::vector<double> GELU(std::vector<double> z, bool deriv = 0);
|
||||
std::vector<std::vector<double>> GELU(std::vector<std::vector<double>> z, bool deriv = 0);
|
||||
|
||||
double sinh(double z, bool deriv = 0);
|
||||
std::vector<double> sinh(std::vector<double> z, bool deriv = 0);
|
||||
std::vector<std::vector<double>> sinh(std::vector<std::vector<double>> z, bool deriv = 0);
|
||||
|
||||
double cosh(double z, bool deriv = 0);
|
||||
std::vector<double> cosh(std::vector<double> z, bool deriv = 0);
|
||||
std::vector<std::vector<double>> cosh(std::vector<std::vector<double>> z, bool deriv = 0);
|
||||
|
||||
double tanh(double z, bool deriv = 0);
|
||||
std::vector<double> tanh(std::vector<double> z, bool deriv = 0);
|
||||
std::vector<std::vector<double>> tanh(std::vector<std::vector<double>> z, bool deriv = 0);
|
||||
|
||||
double csch(double z, bool deriv = 0);
|
||||
std::vector<double> csch(std::vector<double> z, bool deriv = 0);
|
||||
std::vector<std::vector<double>> csch( std::vector<std::vector<double>> z, bool deriv = 0);
|
||||
|
||||
double sech(double z, bool deriv = 0);
|
||||
std::vector<double> sech(std::vector<double> z, bool deriv = 0);
|
||||
std::vector<std::vector<double>> sech(std::vector<std::vector<double>> z, bool deriv = 0);
|
||||
|
||||
double coth(double z, bool deriv = 0);
|
||||
std::vector<double> coth(std::vector<double> z, bool deriv = 0);
|
||||
std::vector<std::vector<double>> coth(std::vector<std::vector<double>> z, bool deriv = 0);
|
||||
|
||||
double arsinh(double z, bool deriv = 0);
|
||||
std::vector<double> arsinh(std::vector<double> z, bool deriv = 0);
|
||||
std::vector<std::vector<double>> arsinh(std::vector<std::vector<double>> z, bool deriv = 0);
|
||||
|
||||
double arcosh(double z, bool deriv = 0);
|
||||
std::vector<double> arcosh(std::vector<double> z, bool deriv = 0);
|
||||
std::vector<std::vector<double>> arcosh(std::vector<std::vector<double>> z, bool deriv = 0);
|
||||
|
||||
double artanh(double z, bool deriv = 0);
|
||||
std::vector<double> artanh(std::vector<double> z, bool deriv = 0);
|
||||
std::vector<std::vector<double>> artanh(std::vector<std::vector<double>> z, bool deriv = 0);
|
||||
|
||||
double arcsch(double z, bool deriv = 0);
|
||||
std::vector<double> arcsch(std::vector<double> z, bool deriv = 0);
|
||||
std::vector<std::vector<double>> arcsch(std::vector<std::vector<double>> z, bool deriv = 0);
|
||||
|
||||
double arsech(double z, bool deriv = 0);
|
||||
std::vector<double> arsech(std::vector<double> z, bool deriv = 0);
|
||||
std::vector<std::vector<double>> arsech(std::vector<std::vector<double>> z, bool deriv = 0);
|
||||
|
||||
double arcoth(double z, bool deriv = 0);
|
||||
std::vector<double> arcoth(std::vector<double> z, bool deriv = 0);
|
||||
std::vector<std::vector<double>> arcoth(std::vector<std::vector<double>> z, bool deriv = 0);
|
||||
|
||||
std::vector<double> activation(std::vector<double> z, bool deriv, double(*function)(double, bool));
|
||||
|
||||
private:
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* Activation_hpp */
|
270
MLPP/AutoEncoder/AutoEncoder.cpp
Normal file
270
MLPP/AutoEncoder/AutoEncoder.cpp
Normal file
@ -0,0 +1,270 @@
|
||||
//
|
||||
// AutoEncoder.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 11/4/20.
|
||||
//
|
||||
|
||||
#include "AutoEncoder.hpp"
|
||||
#include "Activation/Activation.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
#include "Utilities/Utilities.hpp"
|
||||
#include "Cost/Cost.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
namespace MLPP {
|
||||
AutoEncoder::AutoEncoder(std::vector<std::vector<double>> inputSet, int n_hidden)
|
||||
: inputSet(inputSet), n_hidden(n_hidden), n(inputSet.size()), k(inputSet[0].size())
|
||||
{
|
||||
Activation avn;
|
||||
y_hat.resize(inputSet.size());
|
||||
|
||||
weights1 = Utilities::weightInitialization(k, n_hidden);
|
||||
weights2 = Utilities::weightInitialization(n_hidden, k);
|
||||
bias1 = Utilities::biasInitialization(n_hidden);
|
||||
bias2 = Utilities::biasInitialization(k);
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> AutoEncoder::modelSetTest(std::vector<std::vector<double>> X){
|
||||
return Evaluate(X);
|
||||
}
|
||||
|
||||
std::vector<double> AutoEncoder::modelTest(std::vector<double> x){
|
||||
return Evaluate(x);
|
||||
}
|
||||
|
||||
void AutoEncoder::gradientDescent(double learning_rate, int max_epoch, bool UI){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
forwardPass();
|
||||
|
||||
while(true){
|
||||
cost_prev = Cost(y_hat, inputSet);
|
||||
|
||||
// Calculating the errors
|
||||
std::vector<std::vector<double>> error = alg.subtraction(y_hat, inputSet);
|
||||
|
||||
// Calculating the weight/bias gradients for layer 2
|
||||
std::vector<std::vector<double>> D2_1 = alg.matmult(alg.transpose(a2), error);
|
||||
|
||||
// weights and bias updation for layer 2
|
||||
weights2 = alg.subtraction(weights2, alg.scalarMultiply(learning_rate/n, D2_1));
|
||||
|
||||
// Calculating the bias gradients for layer 2
|
||||
bias2 = alg.subtractMatrixRows(bias2, alg.scalarMultiply(learning_rate, error));
|
||||
|
||||
//Calculating the weight/bias for layer 1
|
||||
|
||||
std::vector<std::vector<double>> D1_1 = alg.matmult(error, alg.transpose(weights2));
|
||||
|
||||
std::vector<std::vector<double>> D1_2 = alg.hadamard_product(D1_1, avn.sigmoid(z2, 1));
|
||||
|
||||
std::vector<std::vector<double>> D1_3 = alg.matmult(alg.transpose(inputSet), D1_2);
|
||||
|
||||
|
||||
// weight an bias updation for layer 1
|
||||
weights1 = alg.subtraction(weights1, alg.scalarMultiply(learning_rate/n, D1_3));
|
||||
|
||||
bias1 = alg.subtractMatrixRows(bias1, alg.scalarMultiply(learning_rate/n, D1_2));
|
||||
|
||||
forwardPass();
|
||||
|
||||
// UI PORTION
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, inputSet));
|
||||
std::cout << "Layer 1:" << std::endl;
|
||||
Utilities::UI(weights1, bias1);
|
||||
std::cout << "Layer 2:" << std::endl;
|
||||
Utilities::UI(weights2, bias2);
|
||||
}
|
||||
epoch++;
|
||||
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AutoEncoder::SGD(double learning_rate, int max_epoch, bool UI){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
Utilities util;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
|
||||
while(true){
|
||||
std::random_device rd;
|
||||
std::default_random_engine generator(rd());
|
||||
std::uniform_int_distribution<int> distribution(0, int(n - 1));
|
||||
int outputIndex = distribution(generator);
|
||||
|
||||
std::vector<double> y_hat = Evaluate(inputSet[outputIndex]);
|
||||
auto [z2, a2] = propagate(inputSet[outputIndex]);
|
||||
cost_prev = Cost({y_hat}, {inputSet[outputIndex]});
|
||||
std::vector<double> error = alg.subtraction(y_hat, inputSet[outputIndex]);
|
||||
|
||||
// Weight updation for layer 2
|
||||
std::vector<std::vector<double>> D2_1 = alg.vecmult(error, a2);
|
||||
weights2 = alg.subtraction(weights2, alg.scalarMultiply(learning_rate, alg.transpose(D2_1)));
|
||||
|
||||
// Bias updation for layer 2
|
||||
bias2 = alg.subtraction(bias2, alg.scalarMultiply(learning_rate, error));
|
||||
|
||||
// Weight updation for layer 1
|
||||
std::vector<double> D1_1 = alg.mat_vec_mult(weights2, error);
|
||||
std::vector<double> D1_2 = alg.hadamard_product(D1_1, avn.sigmoid(z2, 1));
|
||||
std::vector<std::vector<double>> D1_3 = alg.vecmult(inputSet[outputIndex], D1_2);
|
||||
|
||||
weights1 = alg.subtraction(weights1, alg.scalarMultiply(learning_rate, D1_3));
|
||||
// Bias updation for layer 1
|
||||
|
||||
bias1 = alg.subtraction(bias1, alg.scalarMultiply(learning_rate, D1_2));
|
||||
|
||||
y_hat = Evaluate(inputSet[outputIndex]);
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost({y_hat}, {inputSet[outputIndex]}));
|
||||
std::cout << "Layer 1:" << std::endl;
|
||||
Utilities::UI(weights1, bias1);
|
||||
std::cout << "Layer 2:" << std::endl;
|
||||
Utilities::UI(weights2, bias2);
|
||||
}
|
||||
epoch++;
|
||||
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
forwardPass();
|
||||
}
|
||||
|
||||
void AutoEncoder::MBGD(double learning_rate, int max_epoch, int miniBatch_size, bool UI){
|
||||
Activation avn;
|
||||
LinAlg alg;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
|
||||
int n_miniBatch = n/miniBatch_size;
|
||||
|
||||
std::vector<std::vector<std::vector<double>>> inputMiniBatches;
|
||||
|
||||
// Creating the mini-batches
|
||||
for(int i = 0; i < n_miniBatch; i++){
|
||||
std::vector<std::vector<double>> currentInputSet;
|
||||
for(int j = 0; j < n/n_miniBatch; j++){
|
||||
currentInputSet.push_back(inputSet[n/n_miniBatch * i + j]);
|
||||
}
|
||||
inputMiniBatches.push_back(currentInputSet);
|
||||
}
|
||||
|
||||
if(double(n)/double(n_miniBatch) - int(n/n_miniBatch) != 0){
|
||||
for(int i = 0; i < n - n/n_miniBatch * n_miniBatch; i++){
|
||||
inputMiniBatches[n_miniBatch - 1].push_back(inputSet[n/n_miniBatch * n_miniBatch + i]);
|
||||
}
|
||||
}
|
||||
|
||||
while(true){
|
||||
for(int i = 0; i < n_miniBatch; i++){
|
||||
std::vector<std::vector<double>> y_hat = Evaluate(inputMiniBatches[i]);
|
||||
auto [z2, a2] = propagate(inputMiniBatches[i]);
|
||||
cost_prev = Cost(y_hat, inputMiniBatches[i]);
|
||||
|
||||
// Calculating the errors
|
||||
std::vector<std::vector<double>> error = alg.subtraction(y_hat, inputMiniBatches[i]);
|
||||
|
||||
// Calculating the weight/bias gradients for layer 2
|
||||
|
||||
std::vector<std::vector<double>> D2_1 = alg.matmult(alg.transpose(a2), error);
|
||||
|
||||
// weights and bias updation for layer 2
|
||||
weights2 = alg.subtraction(weights2, alg.scalarMultiply(learning_rate/inputMiniBatches[i].size(), D2_1));
|
||||
|
||||
// Bias Updation for layer 2
|
||||
bias2 = alg.subtractMatrixRows(bias2, alg.scalarMultiply(learning_rate, error));
|
||||
|
||||
//Calculating the weight/bias for layer 1
|
||||
|
||||
std::vector<std::vector<double>> D1_1 = alg.matmult(error, alg.transpose(weights2));
|
||||
|
||||
std::vector<std::vector<double>> D1_2 = alg.hadamard_product(D1_1, avn.sigmoid(z2, 1));
|
||||
|
||||
std::vector<std::vector<double>> D1_3 = alg.matmult(alg.transpose(inputMiniBatches[i]), D1_2);
|
||||
|
||||
|
||||
// weight an bias updation for layer 1
|
||||
weights1 = alg.subtraction(weights1, alg.scalarMultiply(learning_rate/inputMiniBatches[i].size(), D1_3));
|
||||
|
||||
bias1 = alg.subtractMatrixRows(bias1, alg.scalarMultiply(learning_rate/inputMiniBatches[i].size(), D1_2));
|
||||
|
||||
y_hat = Evaluate(inputMiniBatches[i]);
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, inputMiniBatches[i]));
|
||||
std::cout << "Layer 1:" << std::endl;
|
||||
Utilities::UI(weights1, bias1);
|
||||
std::cout << "Layer 2:" << std::endl;
|
||||
Utilities::UI(weights2, bias2);
|
||||
}
|
||||
}
|
||||
epoch++;
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
forwardPass();
|
||||
}
|
||||
|
||||
double AutoEncoder::score(){
|
||||
Utilities util;
|
||||
return util.performance(y_hat, inputSet);
|
||||
}
|
||||
|
||||
void AutoEncoder::save(std::string fileName){
|
||||
Utilities util;
|
||||
util.saveParameters(fileName, weights1, bias1, 0, 1);
|
||||
util.saveParameters(fileName, weights2, bias2, 1, 2);
|
||||
}
|
||||
|
||||
double AutoEncoder::Cost(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y){
|
||||
class Cost cost;
|
||||
return cost.MSE(y_hat, inputSet);
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> AutoEncoder::Evaluate(std::vector<std::vector<double>> X){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
std::vector<std::vector<double>> z2 = alg.mat_vec_add(alg.matmult(X, weights1), bias1);
|
||||
std::vector<std::vector<double>> a2 = avn.sigmoid(z2);
|
||||
return alg.mat_vec_add(alg.matmult(a2, weights2), bias2);
|
||||
}
|
||||
|
||||
std::tuple<std::vector<std::vector<double>>, std::vector<std::vector<double>>> AutoEncoder::propagate(std::vector<std::vector<double>> X){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
std::vector<std::vector<double>> z2 = alg.mat_vec_add(alg.matmult(X, weights1), bias1);
|
||||
std::vector<std::vector<double>> a2 = avn.sigmoid(z2);
|
||||
return {z2, a2};
|
||||
}
|
||||
|
||||
std::vector<double> AutoEncoder::Evaluate(std::vector<double> x){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
std::vector<double> z2 = alg.addition(alg.mat_vec_mult(alg.transpose(weights1), x), bias1);
|
||||
std::vector<double> a2 = avn.sigmoid(z2);
|
||||
return alg.addition(alg.mat_vec_mult(alg.transpose(weights2), a2), bias2);
|
||||
}
|
||||
|
||||
std::tuple<std::vector<double>, std::vector<double>> AutoEncoder::propagate(std::vector<double> x){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
std::vector<double> z2 = alg.addition(alg.mat_vec_mult(alg.transpose(weights1), x), bias1);
|
||||
std::vector<double> a2 = avn.sigmoid(z2);
|
||||
return {z2, a2};
|
||||
}
|
||||
|
||||
void AutoEncoder::forwardPass(){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
z2 = alg.mat_vec_add(alg.matmult(inputSet, weights1), bias1);
|
||||
a2 = avn.sigmoid(z2);
|
||||
y_hat = alg.mat_vec_add(alg.matmult(a2, weights2), bias2);
|
||||
}
|
||||
}
|
54
MLPP/AutoEncoder/AutoEncoder.hpp
Normal file
54
MLPP/AutoEncoder/AutoEncoder.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
//
|
||||
// AutoEncoder.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 11/4/20.
|
||||
//
|
||||
|
||||
#ifndef AutoEncoder_hpp
|
||||
#define AutoEncoder_hpp
|
||||
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <string>
|
||||
|
||||
namespace MLPP {
|
||||
|
||||
class AutoEncoder{
|
||||
public:
|
||||
AutoEncoder(std::vector<std::vector<double>> inputSet, int n_hidden);
|
||||
std::vector<std::vector<double>> modelSetTest(std::vector<std::vector<double>> X);
|
||||
std::vector<double> modelTest(std::vector<double> x);
|
||||
void gradientDescent(double learning_rate, int max_epoch, bool UI = 1);
|
||||
void SGD(double learning_rate, int max_epoch, bool UI = 1);
|
||||
void MBGD(double learning_rate, int max_epoch, int miniBatch_size, bool UI = 1);
|
||||
double score();
|
||||
void save(std::string fileName);
|
||||
|
||||
private:
|
||||
double Cost(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y);
|
||||
|
||||
std::vector<std::vector<double>> Evaluate(std::vector<std::vector<double>> X);
|
||||
std::tuple<std::vector<std::vector<double>>, std::vector<std::vector<double>>> propagate(std::vector<std::vector<double>> X);
|
||||
std::vector<double> Evaluate(std::vector<double> x);
|
||||
std::tuple<std::vector<double>, std::vector<double>> propagate(std::vector<double> x);
|
||||
void forwardPass();
|
||||
|
||||
std::vector<std::vector<double>> inputSet;
|
||||
std::vector<std::vector<double>> y_hat; // This is your latent representation
|
||||
|
||||
std::vector<std::vector<double>> weights1;
|
||||
std::vector<std::vector<double>> weights2;
|
||||
|
||||
std::vector<double> bias1;
|
||||
std::vector<double> bias2;
|
||||
|
||||
std::vector<std::vector<double>> z2;
|
||||
std::vector<std::vector<double>> a2;
|
||||
|
||||
int n;
|
||||
int k;
|
||||
int n_hidden;
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* AutoEncoder_hpp */
|
182
MLPP/BernoulliNB/BernoulliNB.cpp
Normal file
182
MLPP/BernoulliNB/BernoulliNB.cpp
Normal file
@ -0,0 +1,182 @@
|
||||
//
|
||||
// BernoulliNB.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 1/17/21.
|
||||
//
|
||||
|
||||
#include "BernoulliNB.hpp"
|
||||
#include "Utilities/Utilities.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
#include "Data/Data.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
namespace MLPP{
|
||||
BernoulliNB::BernoulliNB(std::vector<std::vector<double>> inputSet, std::vector<double> outputSet)
|
||||
: inputSet(inputSet), outputSet(outputSet), class_num(2)
|
||||
{
|
||||
y_hat.resize(outputSet.size());
|
||||
Evaluate();
|
||||
}
|
||||
|
||||
std::vector<double> BernoulliNB::modelSetTest(std::vector<std::vector<double>> X){
|
||||
std::vector<double> y_hat;
|
||||
for(int i = 0; i < X.size(); i++){
|
||||
y_hat.push_back(modelTest(X[i]));
|
||||
}
|
||||
return y_hat;
|
||||
}
|
||||
|
||||
double BernoulliNB::modelTest(std::vector<double> x){
|
||||
double score_0 = 1;
|
||||
double score_1 = 1;
|
||||
|
||||
std::vector<int> foundIndices;
|
||||
|
||||
for(int j = 0; j < x.size(); j++){
|
||||
for(int k = 0; k < vocab.size(); k++){
|
||||
if(x[j] == vocab[k]){
|
||||
score_0 *= theta[0][vocab[k]];
|
||||
score_1 *= theta[1][vocab[k]];
|
||||
|
||||
foundIndices.push_back(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < vocab.size(); i++){
|
||||
bool found = false;
|
||||
for(int j = 0; j < foundIndices.size(); j++){
|
||||
if(vocab[i] == vocab[foundIndices[j]]){
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if(!found){
|
||||
score_0 *= 1 - theta[0][vocab[i]];
|
||||
score_1 *= 1 - theta[1][vocab[i]];
|
||||
}
|
||||
}
|
||||
|
||||
score_0 *= prior_0;
|
||||
score_1 *= prior_1;
|
||||
|
||||
// Assigning the traning example to a class
|
||||
|
||||
if(score_0 > score_1){
|
||||
return 0;
|
||||
}
|
||||
else{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
double BernoulliNB::score(){
|
||||
Utilities util;
|
||||
return util.performance(y_hat, outputSet);
|
||||
}
|
||||
|
||||
void BernoulliNB::computeVocab(){
|
||||
LinAlg alg;
|
||||
Data data;
|
||||
vocab = data.vecToSet<double>(alg.flatten(inputSet));
|
||||
}
|
||||
|
||||
void BernoulliNB::computeTheta(){
|
||||
|
||||
// Resizing theta for the sake of ease & proper access of the elements.
|
||||
theta.resize(class_num);
|
||||
|
||||
// Setting all values in the hasmap by default to 0.
|
||||
for(int i = class_num - 1; i >= 0; i--){
|
||||
for(int j = 0; j < vocab.size(); j++){
|
||||
theta[i][vocab[j]] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < inputSet.size(); i++){
|
||||
for(int j = 0; j < inputSet[0].size(); j++){
|
||||
theta[outputSet[i]][inputSet[i][j]]++;
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < theta.size(); i++){
|
||||
for(int j = 0; j < theta[i].size(); j++){
|
||||
if(i == 0){
|
||||
theta[i][j] /= prior_0 * y_hat.size();
|
||||
}
|
||||
else{
|
||||
theta[i][j] /= prior_1 * y_hat.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BernoulliNB::Evaluate(){
|
||||
for(int i = 0; i < outputSet.size(); i++){
|
||||
// Pr(B | A) * Pr(A)
|
||||
double score_0 = 1;
|
||||
double score_1 = 1;
|
||||
|
||||
|
||||
double sum = 0;
|
||||
for(int i = 0; i < outputSet.size(); i++){
|
||||
if(outputSet[i] == 1){ sum += outputSet[i]; }
|
||||
}
|
||||
|
||||
// Easy computation of priors, i.e. Pr(C_k)
|
||||
prior_1 = sum / y_hat.size();
|
||||
prior_0 = 1 - prior_1;
|
||||
|
||||
// Evaluating Theta...
|
||||
computeTheta();
|
||||
|
||||
// Evaluating the vocab set...
|
||||
computeVocab();
|
||||
|
||||
std::vector<int> foundIndices;
|
||||
|
||||
for(int j = 0; j < inputSet.size(); j++){
|
||||
for(int k = 0; k < vocab.size(); k++){
|
||||
if(inputSet[i][j] == vocab[k]){
|
||||
score_0 += log(theta[0][vocab[k]]);
|
||||
score_1 += log(theta[1][vocab[k]]);
|
||||
|
||||
foundIndices.push_back(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < vocab.size(); i++){
|
||||
bool found = false;
|
||||
for(int j = 0; j < foundIndices.size(); j++){
|
||||
if(vocab[i] == vocab[foundIndices[j]]){
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if(!found){
|
||||
score_0 += log(1 - theta[0][vocab[i]]);
|
||||
score_1 += log(1 - theta[1][vocab[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
score_0 += log(prior_0);
|
||||
score_1 += log(prior_1);
|
||||
|
||||
score_0 = exp(score_0);
|
||||
score_1 = exp(score_1);
|
||||
|
||||
std::cout << score_0 << std::endl;
|
||||
std::cout << score_1 << std::endl;
|
||||
|
||||
// Assigning the traning example to a class
|
||||
|
||||
if(score_0 > score_1){
|
||||
y_hat[i] = 0;
|
||||
}
|
||||
else{
|
||||
y_hat[i] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
47
MLPP/BernoulliNB/BernoulliNB.hpp
Normal file
47
MLPP/BernoulliNB/BernoulliNB.hpp
Normal file
@ -0,0 +1,47 @@
|
||||
//
|
||||
// BernoulliNB.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 1/17/21.
|
||||
//
|
||||
|
||||
#ifndef BernoulliNB_hpp
|
||||
#define BernoulliNB_hpp
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace MLPP{
|
||||
class BernoulliNB{
|
||||
|
||||
public:
|
||||
BernoulliNB(std::vector<std::vector<double>> inputSet, std::vector<double> outputSet);
|
||||
std::vector<double> modelSetTest(std::vector<std::vector<double>> X);
|
||||
double modelTest(std::vector<double> x);
|
||||
double score();
|
||||
|
||||
private:
|
||||
|
||||
void computeVocab();
|
||||
void computeTheta();
|
||||
void Evaluate();
|
||||
|
||||
// Model Params
|
||||
double prior_1 = 0;
|
||||
double prior_0 = 0;
|
||||
|
||||
std::vector<std::map<double, int>> theta;
|
||||
std::vector<double> vocab;
|
||||
int class_num;
|
||||
|
||||
// Datasets
|
||||
std::vector<std::vector<double>> inputSet;
|
||||
std::vector<double> outputSet;
|
||||
std::vector<double> y_hat;
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif /* BernoulliNB_hpp */
|
||||
}
|
247
MLPP/CLogLogReg/CLogLogReg.cpp
Normal file
247
MLPP/CLogLogReg/CLogLogReg.cpp
Normal file
@ -0,0 +1,247 @@
|
||||
//
|
||||
// CLogLogReg.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 10/2/20.
|
||||
//
|
||||
|
||||
#include "CLogLogReg.hpp"
|
||||
#include "Activation/Activation.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
#include "Regularization/Reg.hpp"
|
||||
#include "Utilities/Utilities.hpp"
|
||||
#include "Cost/Cost.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
namespace MLPP{
|
||||
CLogLogReg::CLogLogReg(std::vector<std::vector<double>> inputSet, std::vector<double> 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)
|
||||
{
|
||||
y_hat.resize(n);
|
||||
weights = Utilities::weightInitialization(k);
|
||||
bias = Utilities::biasInitialization();
|
||||
}
|
||||
|
||||
std::vector<double> CLogLogReg::modelSetTest(std::vector<std::vector<double>> X){
|
||||
return Evaluate(X);
|
||||
}
|
||||
|
||||
double CLogLogReg::modelTest(std::vector<double> x){
|
||||
return Evaluate(x);
|
||||
}
|
||||
|
||||
void CLogLogReg::gradientDescent(double learning_rate, int max_epoch, bool UI){
|
||||
Reg regularization;
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
forwardPass();
|
||||
|
||||
while(true){
|
||||
cost_prev = Cost(y_hat, outputSet);
|
||||
|
||||
std::vector<double> error = alg.subtraction(y_hat, outputSet);
|
||||
|
||||
|
||||
// Calculating the weight gradients
|
||||
weights = alg.subtraction(weights, alg.scalarMultiply(learning_rate/n, alg.mat_vec_mult(alg.transpose(inputSet), alg.hadamard_product(error, avn.cloglog(z, 1)))));
|
||||
weights = regularization.regWeights(weights, lambda, alpha, reg);
|
||||
|
||||
// Calculating the bias gradients
|
||||
bias -= learning_rate * alg.sum_elements(alg.hadamard_product(error, avn.cloglog(z, 1))) / n;
|
||||
|
||||
forwardPass();
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputSet));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
epoch++;
|
||||
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
}
|
||||
|
||||
void CLogLogReg::MLE(double learning_rate, int max_epoch, bool UI){
|
||||
Reg regularization;
|
||||
Activation avn;
|
||||
LinAlg alg;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
forwardPass();
|
||||
|
||||
while(true){
|
||||
cost_prev = Cost(y_hat, outputSet);
|
||||
|
||||
std::vector<double> error = alg.subtraction(y_hat, outputSet);
|
||||
|
||||
weights = alg.addition(weights, alg.scalarMultiply(learning_rate/n, alg.mat_vec_mult(alg.transpose(inputSet), alg.hadamard_product(error, avn.cloglog(z, 1)))));
|
||||
weights = regularization.regWeights(weights, lambda, alpha, reg);
|
||||
|
||||
// Calculating the bias gradients
|
||||
bias += learning_rate * alg.sum_elements(alg.hadamard_product(error, avn.cloglog(z, 1))) / n;
|
||||
forwardPass();
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputSet));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
epoch++;
|
||||
|
||||
if(epoch > max_epoch) { break; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void CLogLogReg::SGD(double learning_rate, int max_epoch, bool UI){
|
||||
Reg regularization;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
forwardPass();
|
||||
|
||||
while(true){
|
||||
std::random_device rd;
|
||||
std::default_random_engine generator(rd());
|
||||
std::uniform_int_distribution<int> distribution(0, int(n - 1));
|
||||
int outputIndex = distribution(generator);
|
||||
|
||||
double y_hat = Evaluate(inputSet[outputIndex]);
|
||||
double z = propagate(inputSet[outputIndex]);
|
||||
|
||||
cost_prev = Cost({y_hat}, {outputSet[outputIndex]});
|
||||
|
||||
for(int i = 0; i < k; i++){
|
||||
|
||||
// Calculating the weight gradients
|
||||
double w_gradient = (y_hat - outputSet[outputIndex]) * exp(z-exp(z)) * inputSet[outputIndex][i];
|
||||
|
||||
|
||||
// Weight updation
|
||||
weights[i] -= learning_rate * w_gradient;
|
||||
}
|
||||
weights = regularization.regWeights(weights, lambda, alpha, reg);
|
||||
|
||||
|
||||
// Calculating the bias gradients
|
||||
double b_gradient = (y_hat - outputSet[outputIndex]) * exp(z-exp(z));
|
||||
|
||||
// Bias updation
|
||||
bias -= learning_rate * b_gradient;
|
||||
y_hat = Evaluate({inputSet[outputIndex]});
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost({y_hat}, {outputSet[outputIndex]}));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
epoch++;
|
||||
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
forwardPass();
|
||||
}
|
||||
|
||||
void CLogLogReg::MBGD(double learning_rate, int max_epoch, int miniBatch_size, bool UI){
|
||||
Reg regularization;
|
||||
Activation avn;
|
||||
LinAlg alg;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
|
||||
int n_miniBatch = n/miniBatch_size;
|
||||
|
||||
std::vector<std::vector<std::vector<double>>> inputMiniBatches;
|
||||
std::vector<std::vector<double>> outputMiniBatches;
|
||||
// Creating the mini-batches
|
||||
for(int i = 0; i < n_miniBatch; i++){
|
||||
std::vector<std::vector<double>> currentInputSet;
|
||||
std::vector<double> currentOutputSet;
|
||||
std::vector<double> currentPreActivationSet;
|
||||
for(int j = 0; j < n/n_miniBatch; j++){
|
||||
currentInputSet.push_back(inputSet[n/n_miniBatch * i + j]);
|
||||
currentOutputSet.push_back(outputSet[n/n_miniBatch * i + j]);
|
||||
}
|
||||
inputMiniBatches.push_back(currentInputSet);
|
||||
outputMiniBatches.push_back(currentOutputSet);
|
||||
}
|
||||
|
||||
if(double(n)/double(n_miniBatch) - int(n/n_miniBatch) != 0){
|
||||
for(int i = 0; i < n - n/n_miniBatch * n_miniBatch; i++){
|
||||
inputMiniBatches[n_miniBatch - 1].push_back(inputSet[n/n_miniBatch * n_miniBatch + i]);
|
||||
outputMiniBatches[n_miniBatch - 1].push_back(outputSet[n/n_miniBatch * n_miniBatch + i]);
|
||||
}
|
||||
}
|
||||
|
||||
while(true){
|
||||
for(int i = 0; i < n_miniBatch; i++){
|
||||
std::vector<double> y_hat = Evaluate(inputMiniBatches[i]);
|
||||
std::vector<double> z = propagate(inputMiniBatches[i]);
|
||||
cost_prev = Cost(y_hat, outputMiniBatches[i]);
|
||||
|
||||
std::vector<double> error = alg.subtraction(y_hat, outputMiniBatches[i]);
|
||||
|
||||
// Calculating the weight gradients
|
||||
weights = alg.subtraction(weights, alg.scalarMultiply(learning_rate/n, alg.mat_vec_mult(alg.transpose(inputMiniBatches[i]), alg.hadamard_product(error, avn.cloglog(z, 1)))));
|
||||
weights = regularization.regWeights(weights, lambda, alpha, reg);
|
||||
|
||||
// Calculating the bias gradients
|
||||
bias -= learning_rate * alg.sum_elements(alg.hadamard_product(error, avn.cloglog(z, 1))) / n;
|
||||
|
||||
forwardPass();
|
||||
|
||||
y_hat = Evaluate(inputMiniBatches[i]);
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputMiniBatches[i]));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
}
|
||||
epoch++;
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
forwardPass();
|
||||
}
|
||||
|
||||
double CLogLogReg::score(){
|
||||
Utilities util;
|
||||
return util.performance(y_hat, outputSet);
|
||||
}
|
||||
|
||||
double CLogLogReg::Cost(std::vector <double> y_hat, std::vector<double> y){
|
||||
Reg regularization;
|
||||
class Cost cost;
|
||||
return cost.MSE(y_hat, y) + regularization.regTerm(weights, lambda, alpha, reg);
|
||||
}
|
||||
|
||||
std::vector<double> CLogLogReg::Evaluate(std::vector<std::vector<double>> X){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
return avn.cloglog(alg.scalarAdd(bias, alg.mat_vec_mult(X, weights)));
|
||||
}
|
||||
|
||||
std::vector<double>CLogLogReg::propagate(std::vector<std::vector<double>> X){
|
||||
LinAlg alg;
|
||||
return alg.scalarAdd(bias, alg.mat_vec_mult(X, weights));
|
||||
}
|
||||
|
||||
double CLogLogReg::Evaluate(std::vector<double> x){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
return avn.cloglog(alg.dot(weights, x) + bias);
|
||||
}
|
||||
|
||||
double CLogLogReg::propagate(std::vector<double> x){
|
||||
LinAlg alg;
|
||||
return alg.dot(weights, x) + bias;
|
||||
}
|
||||
|
||||
// cloglog ( wTx + b )
|
||||
void CLogLogReg::forwardPass(){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
|
||||
z = propagate(inputSet);
|
||||
y_hat = avn.cloglog(z);
|
||||
}
|
||||
}
|
58
MLPP/CLogLogReg/CLogLogReg.hpp
Normal file
58
MLPP/CLogLogReg/CLogLogReg.hpp
Normal file
@ -0,0 +1,58 @@
|
||||
//
|
||||
// CLogLogReg.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 10/2/20.
|
||||
//
|
||||
|
||||
#ifndef CLogLogReg_hpp
|
||||
#define CLogLogReg_hpp
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace MLPP {
|
||||
|
||||
class CLogLogReg{
|
||||
|
||||
public:
|
||||
CLogLogReg(std::vector<std::vector<double>> inputSet, std::vector<double> outputSet, std::string reg = "None", double lambda = 0.5, double alpha = 0.5);
|
||||
std::vector<double> modelSetTest(std::vector<std::vector<double>> X);
|
||||
double modelTest(std::vector<double> x);
|
||||
void gradientDescent(double learning_rate, int max_epoch, bool UI = 1);
|
||||
void MLE(double learning_rate, int max_epoch, bool UI = 1);
|
||||
void SGD(double learning_rate, int max_epoch, bool UI = 1);
|
||||
void MBGD(double learning_rate, int max_epoch, int miniBatch_size, bool UI = 1);
|
||||
double score();
|
||||
private:
|
||||
|
||||
void weightInitialization(int k);
|
||||
void biasInitialization();
|
||||
double Cost(std::vector <double> y_hat, std::vector<double> y);
|
||||
|
||||
std::vector<double> Evaluate(std::vector<std::vector<double>> X);
|
||||
std::vector<double> propagate(std::vector<std::vector<double>> X);
|
||||
double Evaluate(std::vector<double> x);
|
||||
double propagate(std::vector<double> x);
|
||||
void forwardPass();
|
||||
|
||||
std::vector<std::vector<double>> inputSet;
|
||||
std::vector<double> outputSet;
|
||||
std::vector<double> y_hat;
|
||||
std::vector<double> z;
|
||||
std::vector<double> weights;
|
||||
double bias;
|
||||
|
||||
int n;
|
||||
int k;
|
||||
|
||||
// Regularization Params
|
||||
std::string reg;
|
||||
double lambda;
|
||||
double alpha; /* This is the controlling param for Elastic Net*/
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* CLogLogReg_hpp */
|
259
MLPP/Convolutions/Convolutions.cpp
Normal file
259
MLPP/Convolutions/Convolutions.cpp
Normal file
@ -0,0 +1,259 @@
|
||||
//
|
||||
// Convolutions.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 4/6/21.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include "Convolutions/Convolutions.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
#include "Stat/Stat.hpp"
|
||||
|
||||
namespace MLPP{
|
||||
|
||||
Convolutions::Convolutions()
|
||||
: prewittHorizontal({{1,1,1}, {0,0,0}, {-1,-1,-1}}), prewittVertical({{1,0,-1}, {1,0,-1}, {1,0,-1}}),
|
||||
sobelHorizontal({{1,2,1}, {0,0,0}, {-1,-2,-1}}), sobelVertical({{-1,0,1}, {-2,0,2}, {-1,0,1}}),
|
||||
scharrHorizontal({{3,10,3}, {0,0,0}, {-3,-10,-3}}), scharrVertical({{3,0,-3}, {10,0,-10}, {3,0,-3}}),
|
||||
robertsHorizontal({{0,1}, {-1,0}}), robertsVertical({{1,0}, {0,-1}})
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Convolutions::convolve(std::vector<std::vector<double>> input, std::vector<std::vector<double>> filter, int S, int P){
|
||||
LinAlg alg;
|
||||
std::vector<std::vector<double>> featureMap;
|
||||
int N = input.size();
|
||||
int F = filter.size();
|
||||
int mapSize = (N - F + 2*P) / S + 1; // This is computed as ⌊mapSize⌋ by def- thanks C++!
|
||||
|
||||
if(P != 0){
|
||||
std::vector<std::vector<double>> paddedInput;
|
||||
paddedInput.resize(N + 2*P);
|
||||
for(int i = 0; i < paddedInput.size(); i++){
|
||||
paddedInput[i].resize(N + 2*P);
|
||||
}
|
||||
for(int i = 0; i < paddedInput.size(); i++){
|
||||
for(int j = 0; j < paddedInput[i].size(); j++){
|
||||
if(i - P < 0 || j - P < 0 || i - P > input.size() - 1 || j - P > input[0].size() - 1){
|
||||
paddedInput[i][j] = 0;
|
||||
}
|
||||
else{
|
||||
paddedInput[i][j] = input[i - P][j - P];
|
||||
}
|
||||
}
|
||||
}
|
||||
input.resize(paddedInput.size());
|
||||
for(int i = 0; i < paddedInput.size(); i++){
|
||||
input[i].resize(paddedInput[i].size());
|
||||
}
|
||||
input = paddedInput;
|
||||
}
|
||||
|
||||
featureMap.resize(mapSize);
|
||||
for(int i = 0; i < mapSize; i++){
|
||||
featureMap[i].resize(mapSize);
|
||||
}
|
||||
|
||||
for(int i = 0; i < mapSize; i++){
|
||||
for(int j = 0; j < mapSize; j++){
|
||||
std::vector<double> convolvingInput;
|
||||
for(int k = 0; k < F; k++){
|
||||
for(int p = 0; p < F; p++){
|
||||
if(i == 0 && j == 0){
|
||||
convolvingInput.push_back(input[i + k][j + p]);
|
||||
}
|
||||
else if(i == 0){
|
||||
convolvingInput.push_back(input[i + k][j + (S - 1) + p]);
|
||||
}
|
||||
else if(j == 0){
|
||||
convolvingInput.push_back(input[i + (S - 1) + k][j + p]);
|
||||
}
|
||||
else{
|
||||
convolvingInput.push_back(input[i + (S - 1) + k][j + (S - 1) + p]);
|
||||
}
|
||||
}
|
||||
}
|
||||
featureMap[i][j] = alg.dot(convolvingInput, alg.flatten(filter));
|
||||
}
|
||||
}
|
||||
return featureMap;
|
||||
}
|
||||
|
||||
std::vector<std::vector<std::vector<double>>> Convolutions::convolve(std::vector<std::vector<std::vector<double>>> input, std::vector<std::vector<std::vector<double>>> filter, int S, int P){
|
||||
LinAlg alg;
|
||||
std::vector<std::vector<std::vector<double>>> featureMap;
|
||||
int N = input[0].size();
|
||||
int F = filter[0].size();
|
||||
int C = filter.size() / input.size();
|
||||
int mapSize = (N - F + 2*P) / S + 1; // This is computed as ⌊mapSize⌋ by def- thanks C++!
|
||||
|
||||
if(P != 0){
|
||||
for(int c = 0; c < input.size(); c++){
|
||||
std::vector<std::vector<double>> paddedInput;
|
||||
paddedInput.resize(N + 2*P);
|
||||
for(int i = 0; i < paddedInput.size(); i++){
|
||||
paddedInput[i].resize(N + 2*P);
|
||||
}
|
||||
for(int i = 0; i < paddedInput.size(); i++){
|
||||
for(int j = 0; j < paddedInput[i].size(); j++){
|
||||
if(i - P < 0 || j - P < 0 || i - P > input[c].size() - 1 || j - P > input[c][0].size() - 1){
|
||||
paddedInput[i][j] = 0;
|
||||
}
|
||||
else{
|
||||
paddedInput[i][j] = input[c][i - P][j - P];
|
||||
}
|
||||
}
|
||||
}
|
||||
input[c].resize(paddedInput.size());
|
||||
for(int i = 0; i < paddedInput.size(); i++){
|
||||
input[c][i].resize(paddedInput[i].size());
|
||||
}
|
||||
input[c] = paddedInput;
|
||||
}
|
||||
}
|
||||
|
||||
featureMap.resize(C);
|
||||
for(int i = 0; i < featureMap.size(); i++){
|
||||
featureMap[i].resize(mapSize);
|
||||
for(int j = 0; j < featureMap[i].size(); j++){
|
||||
featureMap[i][j].resize(mapSize);
|
||||
}
|
||||
}
|
||||
|
||||
for(int c = 0; c < C; c++){
|
||||
for(int i = 0; i < mapSize; i++){
|
||||
for(int j = 0; j < mapSize; j++){
|
||||
std::vector<double> convolvingInput;
|
||||
for(int t = 0; t < input.size(); t++){
|
||||
for(int k = 0; k < F; k++){
|
||||
for(int p = 0; p < F; p++){
|
||||
if(i == 0 && j == 0){
|
||||
convolvingInput.push_back(input[t][i + k][j + p]);
|
||||
}
|
||||
else if(i == 0){
|
||||
convolvingInput.push_back(input[t][i + k][j + (S - 1) + p]);
|
||||
}
|
||||
else if(j == 0){
|
||||
convolvingInput.push_back(input[t][i + (S - 1) + k][j + p]);
|
||||
}
|
||||
else{
|
||||
convolvingInput.push_back(input[t][i + (S - 1) + k][j + (S - 1) + p]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
featureMap[c][i][j] = alg.dot(convolvingInput, alg.flatten(filter));
|
||||
}
|
||||
}
|
||||
}
|
||||
return featureMap;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Convolutions::pool(std::vector<std::vector<double>> input, int F, int S, std::string type){
|
||||
LinAlg alg;
|
||||
std::vector<std::vector<double>> pooledMap;
|
||||
int N = input.size();
|
||||
int mapSize = floor((N - F) / S + 1);
|
||||
|
||||
pooledMap.resize(mapSize);
|
||||
for(int i = 0; i < mapSize; i++){
|
||||
pooledMap[i].resize(mapSize);
|
||||
}
|
||||
|
||||
for(int i = 0; i < mapSize; i++){
|
||||
for(int j = 0; j < mapSize; j++){
|
||||
std::vector<double> poolingInput;
|
||||
for(int k = 0; k < F; k++){
|
||||
for(int p = 0; p < F; p++){
|
||||
if(i == 0 && j == 0){
|
||||
poolingInput.push_back(input[i + k][j + p]);
|
||||
}
|
||||
else if(i == 0){
|
||||
poolingInput.push_back(input[i + k][j + (S - 1) + p]);
|
||||
}
|
||||
else if(j == 0){
|
||||
poolingInput.push_back(input[i + (S - 1) + k][j + p]);
|
||||
}
|
||||
else{
|
||||
poolingInput.push_back(input[i + (S - 1) + k][j + (S - 1) + p]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(type == "Average"){
|
||||
Stat stat;
|
||||
pooledMap[i][j] = stat.mean(poolingInput);
|
||||
}
|
||||
else if(type == "Min"){
|
||||
pooledMap[i][j] = alg.min(poolingInput);
|
||||
}
|
||||
else{
|
||||
pooledMap[i][j] = alg.max(poolingInput);
|
||||
}
|
||||
}
|
||||
}
|
||||
return pooledMap;
|
||||
}
|
||||
|
||||
std::vector<std::vector<std::vector<double>>> Convolutions::pool(std::vector<std::vector<std::vector<double>>> input, int F, int S, std::string type){
|
||||
std::vector<std::vector<std::vector<double>>> pooledMap;
|
||||
for(int i = 0; i < input.size(); i++){
|
||||
pooledMap.push_back(pool(input[i], F, S, type));
|
||||
}
|
||||
return pooledMap;
|
||||
}
|
||||
|
||||
double Convolutions::globalPool(std::vector<std::vector<double>> input, std::string type){
|
||||
LinAlg alg;
|
||||
if(type == "Average"){
|
||||
Stat stat;
|
||||
return stat.mean(alg.flatten(input));
|
||||
}
|
||||
else if(type == "Min"){
|
||||
return alg.min(alg.flatten(input));
|
||||
}
|
||||
else{
|
||||
return alg.max(alg.flatten(input));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<double> Convolutions::globalPool(std::vector<std::vector<std::vector<double>>> input, std::string type){
|
||||
std::vector<double> pooledMap;
|
||||
for(int i = 0; i < input.size(); i++){
|
||||
pooledMap.push_back(globalPool(input[i], type));
|
||||
}
|
||||
return pooledMap;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Convolutions::getPrewittHorizontal(){
|
||||
return prewittHorizontal;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Convolutions::getPrewittVertical(){
|
||||
return prewittVertical;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Convolutions::getSobelHorizontal(){
|
||||
return sobelHorizontal;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Convolutions::getSobelVertical(){
|
||||
return sobelVertical;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Convolutions::getScharrHorizontal(){
|
||||
return scharrHorizontal;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Convolutions::getScharrVertical(){
|
||||
return scharrVertical;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Convolutions::getRobertsHorizontal(){
|
||||
return robertsHorizontal;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Convolutions::getRobertsVertical(){
|
||||
return robertsVertical;
|
||||
}
|
||||
}
|
39
MLPP/Convolutions/Convolutions.hpp
Normal file
39
MLPP/Convolutions/Convolutions.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef Convolutions_hpp
|
||||
#define Convolutions_hpp
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace MLPP{
|
||||
class Convolutions{
|
||||
public:
|
||||
Convolutions();
|
||||
std::vector<std::vector<double>> convolve(std::vector<std::vector<double>> input, std::vector<std::vector<double>> filter, int S, int P = 0);
|
||||
std::vector<std::vector<std::vector<double>>> convolve(std::vector<std::vector<std::vector<double>>> input, std::vector<std::vector<std::vector<double>>> filter, int S, int P = 0);
|
||||
std::vector<std::vector<double>> pool(std::vector<std::vector<double>> input, int F, int S, std::string type);
|
||||
std::vector<std::vector<std::vector<double>>> pool(std::vector<std::vector<std::vector<double>>> input, int F, int S, std::string type);
|
||||
double globalPool(std::vector<std::vector<double>> input, std::string type);
|
||||
std::vector<double> globalPool(std::vector<std::vector<std::vector<double>>> input, std::string type);
|
||||
|
||||
std::vector<std::vector<double>> getPrewittHorizontal();
|
||||
std::vector<std::vector<double>> getPrewittVertical();
|
||||
std::vector<std::vector<double>> getSobelHorizontal();
|
||||
std::vector<std::vector<double>> getSobelVertical();
|
||||
std::vector<std::vector<double>> getScharrHorizontal();
|
||||
std::vector<std::vector<double>> getScharrVertical();
|
||||
std::vector<std::vector<double>> getRobertsHorizontal();
|
||||
std::vector<std::vector<double>> getRobertsVertical();
|
||||
|
||||
private:
|
||||
std::vector<std::vector<double>> prewittHorizontal;
|
||||
std::vector<std::vector<double>> prewittVertical;
|
||||
std::vector<std::vector<double>> sobelHorizontal;
|
||||
std::vector<std::vector<double>> sobelVertical;
|
||||
std::vector<std::vector<double>> scharrHorizontal;
|
||||
std::vector<std::vector<double>> scharrVertical;
|
||||
std::vector<std::vector<double>> robertsHorizontal;
|
||||
std::vector<std::vector<double>> robertsVertical;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif // Convolutions_hpp
|
344
MLPP/Cost/Cost.cpp
Normal file
344
MLPP/Cost/Cost.cpp
Normal file
@ -0,0 +1,344 @@
|
||||
//
|
||||
// Reg.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 1/16/21.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include "Cost.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
|
||||
namespace MLPP{
|
||||
double Cost::MSE(std::vector <double> y_hat, std::vector<double> y){
|
||||
double sum = 0;
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
sum += (y_hat[i] - y[i]) * (y_hat[i] - y[i]);
|
||||
}
|
||||
return sum / 2 * y_hat.size();
|
||||
}
|
||||
|
||||
double Cost::MSE(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y){
|
||||
double sum = 0;
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
for(int j = 0; j < y_hat[i].size(); j++){
|
||||
sum += (y_hat[i][j] - y[i][j]) * (y_hat[i][j] - y[i][j]);
|
||||
}
|
||||
}
|
||||
return sum / 2 * y_hat.size();
|
||||
}
|
||||
|
||||
std::vector<double> Cost::MSEDeriv(std::vector <double> y_hat, std::vector<double> y){
|
||||
LinAlg alg;
|
||||
return alg.subtraction(y_hat, y);
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Cost::MSEDeriv(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y){
|
||||
LinAlg alg;
|
||||
return alg.subtraction(y_hat, y);
|
||||
}
|
||||
|
||||
double Cost::RMSE(std::vector <double> y_hat, std::vector<double> y){
|
||||
double sum = 0;
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
sum += (y_hat[i] - y[i]) * (y_hat[i] - y[i]);
|
||||
}
|
||||
return sqrt(sum / y_hat.size());
|
||||
}
|
||||
|
||||
double Cost::RMSE(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y){
|
||||
double sum = 0;
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
for(int j = 0; j < y_hat[i].size(); j++){
|
||||
sum += (y_hat[i][j] - y[i][j]) * (y_hat[i][j] - y[i][j]);
|
||||
}
|
||||
}
|
||||
return sqrt(sum / y_hat.size());
|
||||
}
|
||||
|
||||
std::vector<double> Cost::RMSEDeriv(std::vector <double> y_hat, std::vector<double> y){
|
||||
LinAlg alg;
|
||||
return alg.scalarMultiply(1/(2*sqrt(MSE(y_hat, y))), MSEDeriv(y_hat, y));
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Cost::RMSEDeriv(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y){
|
||||
LinAlg alg;
|
||||
return alg.scalarMultiply(1/(2/sqrt(MSE(y_hat, y))), MSEDeriv(y_hat, y));
|
||||
}
|
||||
|
||||
double Cost::MAE(std::vector <double> y_hat, std::vector<double> y){
|
||||
double sum = 0;
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
sum += abs((y_hat[i] - y[i]));
|
||||
}
|
||||
return sum / y_hat.size();
|
||||
}
|
||||
|
||||
double Cost::MAE(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y){
|
||||
double sum = 0;
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
for(int j = 0; j < y_hat[i].size(); j++){
|
||||
sum += abs((y_hat[i][j] - y[i][j]));
|
||||
}
|
||||
}
|
||||
return sum / y_hat.size();
|
||||
}
|
||||
|
||||
std::vector<double> Cost::MAEDeriv(std::vector <double> y_hat, std::vector <double> y){
|
||||
std::vector<double> deriv;
|
||||
deriv.resize(y_hat.size());
|
||||
for(int i = 0; i < deriv.size(); i++){
|
||||
if(y_hat[i] < 0){
|
||||
deriv[i] = -1;
|
||||
}
|
||||
else if(y_hat[i] == 0){
|
||||
deriv[i] = 0;
|
||||
}
|
||||
else{
|
||||
deriv[i] = 1;
|
||||
|
||||
}
|
||||
}
|
||||
return deriv;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Cost::MAEDeriv(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y){
|
||||
std::vector<std::vector<double>> deriv;
|
||||
deriv.resize(y_hat.size());
|
||||
for(int i = 0; i < deriv.size(); i++){
|
||||
deriv.resize(y_hat[i].size());
|
||||
}
|
||||
for(int i = 0; i < deriv.size(); i++){
|
||||
for(int j = 0; j < deriv[i].size(); j++){
|
||||
if(y_hat[i][j] < 0){
|
||||
deriv[i][j] = -1;
|
||||
}
|
||||
else if(y_hat[i][j] == 0){
|
||||
deriv[i][j] = 0;
|
||||
}
|
||||
else{
|
||||
deriv[i][j] = 1;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return deriv;
|
||||
}
|
||||
|
||||
double Cost::MBE(std::vector <double> y_hat, std::vector<double> y){
|
||||
double sum = 0;
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
sum += (y_hat[i] - y[i]);
|
||||
}
|
||||
return sum / y_hat.size();
|
||||
}
|
||||
|
||||
double Cost::MBE(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y){
|
||||
double sum = 0;
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
for(int j = 0; j < y_hat[i].size(); j++){
|
||||
sum += (y_hat[i][j] - y[i][j]);
|
||||
}
|
||||
}
|
||||
return sum / y_hat.size();
|
||||
}
|
||||
|
||||
std::vector<double> Cost::MBEDeriv(std::vector <double> y_hat, std::vector<double> y){
|
||||
LinAlg alg;
|
||||
return alg.onevec(y_hat.size());
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Cost::MBEDeriv(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y){
|
||||
LinAlg alg;
|
||||
return alg.onemat(y_hat.size(), y_hat[0].size());
|
||||
}
|
||||
|
||||
double Cost::LogLoss(std::vector <double> y_hat, std::vector<double> y){
|
||||
double sum = 0;
|
||||
double eps = 1e-8;
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
sum += -(y[i] * log(y_hat[i] + eps) + (1 - y[i]) * log(1 - y_hat[i] + eps));
|
||||
}
|
||||
|
||||
return sum / y_hat.size();
|
||||
}
|
||||
|
||||
double Cost::LogLoss(std::vector <std::vector<double>> y_hat, std::vector <std::vector<double>> y){
|
||||
double sum = 0;
|
||||
double eps = 1e-8;
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
for(int j = 0; j < y_hat[i].size(); j++){
|
||||
sum += -(y[i][j] * log(y_hat[i][j] + eps) + (1 - y[i][j]) * log(1 - y_hat[i][j] + eps));
|
||||
}
|
||||
}
|
||||
|
||||
return sum / y_hat.size();
|
||||
}
|
||||
|
||||
std::vector<double> Cost::LogLossDeriv(std::vector <double> y_hat, std::vector<double> y){
|
||||
LinAlg alg;
|
||||
return alg.addition(alg.scalarMultiply(-1, alg.elementWiseDivision(y, y_hat)), alg.elementWiseDivision(alg.scalarMultiply(-1, alg.scalarAdd(-1, y)), alg.scalarMultiply(-1, alg.scalarAdd(-1, y_hat))));
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Cost::LogLossDeriv(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y){
|
||||
LinAlg alg;
|
||||
return alg.addition(alg.scalarMultiply(-1, alg.elementWiseDivision(y, y_hat)), alg.elementWiseDivision(alg.scalarMultiply(-1, alg.scalarAdd(-1, y)), alg.scalarMultiply(-1, alg.scalarAdd(-1, y_hat))));
|
||||
}
|
||||
|
||||
double Cost::CrossEntropy(std::vector<double> y_hat, std::vector<double> y){
|
||||
double sum = 0;
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
sum += y[i] * log(y_hat[i]);
|
||||
}
|
||||
|
||||
return -1 * sum;
|
||||
}
|
||||
|
||||
double Cost::CrossEntropy(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y){
|
||||
double sum = 0;
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
for(int j = 0; j < y_hat[i].size(); j++){
|
||||
sum += y[i][j] * log(y_hat[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
return -1 * sum;
|
||||
}
|
||||
|
||||
std::vector<double> Cost::CrossEntropyDeriv(std::vector<double> y_hat, std::vector<double> y){
|
||||
LinAlg alg;
|
||||
return alg.scalarMultiply(-1, alg.elementWiseDivision(y, y_hat));
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Cost::CrossEntropyDeriv(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y){
|
||||
LinAlg alg;
|
||||
return alg.scalarMultiply(-1, alg.elementWiseDivision(y, y_hat));
|
||||
}
|
||||
|
||||
double Cost::HuberLoss(std::vector <double> y_hat, std::vector<double> y, double delta){
|
||||
LinAlg alg;
|
||||
double sum = 0;
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
if(abs(y[i] - y_hat[i]) <= delta){
|
||||
sum += (y[i] - y_hat[i]) * (y[i] - y_hat[i]);
|
||||
}
|
||||
else{
|
||||
sum += 2 * delta * abs(y[i] - y_hat[i]) - delta * delta;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
double Cost::HuberLoss(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y, double delta){
|
||||
LinAlg alg;
|
||||
double sum = 0;
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
for(int j = 0; j < y_hat[i].size(); j++){
|
||||
if(abs(y[i][j] - y_hat[i][j]) <= delta){
|
||||
sum += (y[i][j] - y_hat[i][j]) * (y[i][j] - y_hat[i][j]);
|
||||
}
|
||||
else{
|
||||
sum += 2 * delta * abs(y[i][j] - y_hat[i][j]) - delta * delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
std::vector<double> Cost::HuberLossDeriv(std::vector <double> y_hat, std::vector<double> y, double delta){
|
||||
LinAlg alg;
|
||||
double sum = 0;
|
||||
std::vector<double> deriv;
|
||||
deriv.resize(y_hat.size());
|
||||
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
if(abs(y[i] - y_hat[i]) <= delta){
|
||||
deriv.push_back(-(y[i] - y_hat[i]));
|
||||
}
|
||||
else{
|
||||
if(y_hat[i] > 0 || y_hat[i] < 0){
|
||||
deriv.push_back(2 * delta * (y_hat[i]/abs(y_hat[i])));
|
||||
}
|
||||
else{
|
||||
deriv.push_back(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return deriv;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Cost::HuberLossDeriv(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y, double delta){
|
||||
LinAlg alg;
|
||||
double sum = 0;
|
||||
std::vector<std::vector<double>> deriv;
|
||||
deriv.resize(y_hat.size());
|
||||
for(int i = 0; i < deriv.size(); i++){
|
||||
deriv[i].resize(y_hat[i].size());
|
||||
}
|
||||
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
for(int j = 0; j < y_hat[i].size(); j++){
|
||||
if(abs(y[i][j] - y_hat[i][j]) <= delta){
|
||||
deriv[i].push_back(-(y[i][j] - y_hat[i][j]));
|
||||
}
|
||||
else{
|
||||
if(y_hat[i][j] > 0 || y_hat[i][j] < 0){
|
||||
deriv[i].push_back(2 * delta * (y_hat[i][j]/abs(y_hat[i][j])));
|
||||
}
|
||||
else{
|
||||
deriv[i].push_back(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return deriv;
|
||||
}
|
||||
|
||||
double Cost::HingeLoss(std::vector <double> y_hat, std::vector<double> y){
|
||||
double sum = 0;
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
sum += fmax(0, 1 - y[i] * y_hat[i]);
|
||||
}
|
||||
|
||||
return sum / y_hat.size();
|
||||
}
|
||||
|
||||
double Cost::HingeLoss(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y){
|
||||
double sum = 0;
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
for(int j = 0; j < y_hat[i].size(); j++){
|
||||
sum += fmax(0, 1 - y[i][j] * y_hat[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
return sum / y_hat.size();
|
||||
}
|
||||
|
||||
std::vector<double> Cost::HingeLossDeriv(std::vector <double> y_hat, std::vector<double> y){
|
||||
std::vector<double> deriv;
|
||||
deriv.resize(y_hat.size());
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
if(1 - y[i] * y_hat[i] > 0){
|
||||
deriv[i] = -y[i];
|
||||
}
|
||||
else{
|
||||
deriv[i] = 0;
|
||||
}
|
||||
}
|
||||
return deriv;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Cost::HingeLossDeriv(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y){
|
||||
std::vector<std::vector<double>> deriv;
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
for(int j = 0; j < y_hat[i].size(); j++){
|
||||
if(1 - y[i][j] * y_hat[i][j] > 0){
|
||||
deriv[i][j] = -y[i][j];
|
||||
}
|
||||
else{
|
||||
deriv[i][j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return deriv;
|
||||
}
|
||||
}
|
70
MLPP/Cost/Cost.hpp
Normal file
70
MLPP/Cost/Cost.hpp
Normal file
@ -0,0 +1,70 @@
|
||||
//
|
||||
// Cost.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 1/16/21.
|
||||
//
|
||||
|
||||
#ifndef Cost_hpp
|
||||
#define Cost_hpp
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace MLPP{
|
||||
class Cost{
|
||||
public:
|
||||
// Regression Costs
|
||||
double MSE(std::vector <double> y_hat, std::vector<double> y);
|
||||
double MSE(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y);
|
||||
|
||||
std::vector<double> MSEDeriv(std::vector <double> y_hat, std::vector<double> y);
|
||||
std::vector<std::vector<double>> MSEDeriv(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y);
|
||||
|
||||
double RMSE(std::vector <double> y_hat, std::vector<double> y);
|
||||
double RMSE(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y);
|
||||
|
||||
std::vector<double> RMSEDeriv(std::vector <double> y_hat, std::vector<double> y);
|
||||
std::vector<std::vector<double>> RMSEDeriv(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y);
|
||||
|
||||
double MAE(std::vector <double> y_hat, std::vector<double> y);
|
||||
double MAE(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y);
|
||||
|
||||
std::vector<double> MAEDeriv(std::vector <double> y_hat, std::vector <double> y);
|
||||
std::vector<std::vector<double>> MAEDeriv(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y);
|
||||
|
||||
double MBE(std::vector <double> y_hat, std::vector <double> y);
|
||||
double MBE(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y);
|
||||
|
||||
std::vector<double> MBEDeriv(std::vector <double> y_hat, std::vector <double> y);
|
||||
std::vector<std::vector<double>> MBEDeriv(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y);
|
||||
|
||||
// Classification Costs
|
||||
double LogLoss(std::vector <double> y_hat, std::vector<double> y);
|
||||
double LogLoss(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y);
|
||||
|
||||
std::vector<double> LogLossDeriv(std::vector <double> y_hat, std::vector<double> y);
|
||||
std::vector<std::vector<double>> LogLossDeriv(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y);
|
||||
|
||||
double CrossEntropy(std::vector<double> y_hat, std::vector<double> y);
|
||||
double CrossEntropy(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y);
|
||||
|
||||
std::vector<double> CrossEntropyDeriv(std::vector<double> y_hat, std::vector<double> y);
|
||||
std::vector<std::vector<double>> CrossEntropyDeriv(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y);
|
||||
|
||||
double HuberLoss(std::vector <double> y_hat, std::vector<double> y, double delta);
|
||||
double HuberLoss(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y, double delta);
|
||||
|
||||
std::vector<double> HuberLossDeriv(std::vector <double> y_hat, std::vector<double> y, double delta);
|
||||
std::vector<std::vector<double>> HuberLossDeriv(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y, double delta);
|
||||
|
||||
double HingeLoss(std::vector <double> y_hat, std::vector<double> y);
|
||||
double HingeLoss(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y);
|
||||
|
||||
std::vector<double> HingeLossDeriv(std::vector <double> y_hat, std::vector<double> y);
|
||||
std::vector<std::vector<double>> HingeLossDeriv(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y);
|
||||
|
||||
|
||||
private:
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* Cost_hpp */
|
567
MLPP/Data/Data.cpp
Normal file
567
MLPP/Data/Data.cpp
Normal file
@ -0,0 +1,567 @@
|
||||
//
|
||||
// Data.cpp
|
||||
// MLP
|
||||
//
|
||||
// Created by Marc Melikyan on 11/4/20.
|
||||
//
|
||||
|
||||
#include "Data.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
#include "Stat/Stat.hpp"
|
||||
#include "SoftmaxNet/SoftmaxNet.hpp"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
namespace MLPP{
|
||||
// MULTIVARIATE SUPERVISED
|
||||
|
||||
void Data::setData(int k, std::string fileName, std::vector<std::vector<double>>& inputSet, std::vector<double>& outputSet){
|
||||
LinAlg alg;
|
||||
std::string inputTemp;
|
||||
std::string outputTemp;
|
||||
|
||||
inputSet.resize(k);
|
||||
|
||||
std::ifstream dataFile(fileName);
|
||||
if(!dataFile.is_open()){
|
||||
std::cout << fileName << " failed to open." << std::endl;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
while(std::getline(dataFile, line)){
|
||||
std::stringstream ss(line);
|
||||
|
||||
for(int i = 0; i < k; i++){
|
||||
std::getline(ss, inputTemp, ',');
|
||||
inputSet[i].push_back(std::stod(inputTemp));
|
||||
|
||||
}
|
||||
|
||||
std::getline(ss, outputTemp, ',');
|
||||
outputSet.push_back(std::stod(outputTemp));
|
||||
}
|
||||
inputSet = alg.transpose(inputSet);
|
||||
dataFile.close();
|
||||
}
|
||||
|
||||
void Data::printData(std::vector <std::string> inputName, std::string outputName, std::vector<std::vector<double>> inputSet, std::vector<double> outputSet){
|
||||
LinAlg alg;
|
||||
inputSet = alg.transpose(inputSet);
|
||||
for(int i = 0; i < inputSet.size(); i++){
|
||||
std::cout << inputName[i] << std::endl;
|
||||
for(int j = 0; j < inputSet[i].size(); j++){
|
||||
std::cout << inputSet[i][j] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << outputName << std::endl;
|
||||
for(int i = 0; i < outputSet.size(); i++){
|
||||
std::cout << outputSet[i] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// UNSUPERVISED
|
||||
|
||||
void Data::setData(int k, std::string fileName, std::vector<std::vector<double>>& inputSet){
|
||||
LinAlg alg;
|
||||
std::string inputTemp;
|
||||
|
||||
inputSet.resize(k);
|
||||
|
||||
std::ifstream dataFile(fileName);
|
||||
if(!dataFile.is_open()){
|
||||
std::cout << fileName << " failed to open." << std::endl;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
while(std::getline(dataFile, line)){
|
||||
std::stringstream ss(line);
|
||||
|
||||
for(int i = 0; i < k; i++){
|
||||
std::getline(ss, inputTemp, ',');
|
||||
inputSet[i].push_back(std::stod(inputTemp));
|
||||
|
||||
}
|
||||
}
|
||||
inputSet = alg.transpose(inputSet);
|
||||
dataFile.close();
|
||||
}
|
||||
|
||||
void Data::printData(std::vector <std::string> inputName, std::vector<std::vector<double>> inputSet){
|
||||
LinAlg alg;
|
||||
inputSet = alg.transpose(inputSet);
|
||||
for(int i = 0; i < inputSet.size(); i++){
|
||||
std::cout << inputName[i] << std::endl;
|
||||
for(int j = 0; j < inputSet[i].size(); j++){
|
||||
std::cout << inputSet[i][j] << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SIMPLE
|
||||
|
||||
void Data::setData(std::string fileName, std::vector <double>& inputSet, std::vector <double>& outputSet){
|
||||
std::string inputTemp, outputTemp;
|
||||
|
||||
std::ifstream dataFile(fileName);
|
||||
if(!dataFile.is_open()){
|
||||
std::cout << "The file failed to open." << std::endl;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
|
||||
|
||||
while(std::getline(dataFile, line)){
|
||||
std::stringstream ss(line);
|
||||
|
||||
std::getline(ss, inputTemp, ',');
|
||||
std::getline(ss, outputTemp, ',');
|
||||
|
||||
inputSet.push_back(std::stod(inputTemp));
|
||||
outputSet.push_back(std::stod(outputTemp));
|
||||
}
|
||||
|
||||
dataFile.close();
|
||||
}
|
||||
|
||||
void Data::printData(std::string& inputName, std::string& outputName, std::vector <double>& inputSet, std::vector <double>& outputSet){
|
||||
std::cout << inputName << std::endl;
|
||||
for(int i = 0; i < inputSet.size(); i++){
|
||||
std::cout << inputSet[i] << std::endl;
|
||||
}
|
||||
|
||||
std::cout << outputName << std::endl;
|
||||
for(int i = 0; i < inputSet.size(); i++){
|
||||
std::cout << outputSet[i] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Images
|
||||
|
||||
void Data::getImage(std::string fileName, std::vector<double>& image){
|
||||
std::ifstream img(fileName, std::ios::binary);
|
||||
if(!img.is_open()){
|
||||
std::cout << "The file failed to open." << std::endl;
|
||||
}
|
||||
std::vector<double> v{std::istreambuf_iterator<char>{img}, {}};
|
||||
image = v;
|
||||
}
|
||||
|
||||
// TEXT-BASED & NLP
|
||||
std::string Data::toLower(std::string text){
|
||||
for(int i = 0; i < text.size(); i++){
|
||||
text[i] = tolower(text[i]);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
std::vector<char> Data::split(std::string text){
|
||||
std::vector<char> split_data;
|
||||
for(int i = 0; i < text.size(); i++){
|
||||
split_data.push_back(text[i]);
|
||||
}
|
||||
return split_data;
|
||||
}
|
||||
|
||||
std::vector<std::string> Data::splitSentences(std::string data){
|
||||
std::vector<std::string> sentences;
|
||||
std::string currentStr = "";
|
||||
|
||||
for(int i = 0; i < data.length(); i++){
|
||||
currentStr.push_back(data[i]);
|
||||
if(data[i] == '.' && data[i + 1] != '.'){
|
||||
sentences.push_back(currentStr);
|
||||
currentStr = "";
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return sentences;
|
||||
}
|
||||
|
||||
std::vector<std::string> Data::removeSpaces(std::vector<std::string> data){
|
||||
for(int i = 0; i < data.size(); i++){
|
||||
auto it = data[i].begin();
|
||||
for(int j = 0; j < data[i].length(); j++){
|
||||
if(data[i][j] == ' '){
|
||||
data[i].erase(it);
|
||||
}
|
||||
it++;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
std::vector<std::string> Data::removeNullByte(std::vector<std::string> data){
|
||||
for(int i = 0; i < data.size(); i++){
|
||||
if(data[i] == "\0"){
|
||||
data.erase(data.begin() + i);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
std::vector<std::string> Data::segment(std::string text){
|
||||
std::vector<std::string> segmented_data;
|
||||
int prev_delim = 0;
|
||||
for(int i = 0; i < text.length(); i++){
|
||||
if(text[i] == ' '){
|
||||
segmented_data.push_back(text.substr(prev_delim, i - prev_delim));
|
||||
prev_delim = i + 1;
|
||||
}
|
||||
else if(text[i] == ',' || text[i] == '!' || text[i] == '.' || text[i] == '-'){
|
||||
segmented_data.push_back(text.substr(prev_delim, i - prev_delim));
|
||||
std::string punc;
|
||||
punc.push_back(text[i]);
|
||||
segmented_data.push_back(punc);
|
||||
prev_delim = i + 2;
|
||||
i++;
|
||||
}
|
||||
else if(i == text.length() - 1){
|
||||
segmented_data.push_back(text.substr(prev_delim, text.length() - prev_delim)); // hehe oops- forgot this
|
||||
}
|
||||
}
|
||||
|
||||
return segmented_data;
|
||||
}
|
||||
|
||||
std::vector<double> Data::tokenize(std::string text){
|
||||
int max_num = 0;
|
||||
bool new_num = true;
|
||||
std::vector<std::string> segmented_data = segment(text);
|
||||
std::vector<double> tokenized_data;
|
||||
tokenized_data.resize(segmented_data.size());
|
||||
for(int i = 0; i < segmented_data.size(); i++){
|
||||
for(int j = i - 1; j >= 0; j--){
|
||||
if(segmented_data[i] == segmented_data[j]){
|
||||
tokenized_data[i] = tokenized_data[j];
|
||||
new_num = false;
|
||||
}
|
||||
}
|
||||
if(!new_num){
|
||||
new_num = true;
|
||||
}
|
||||
else{
|
||||
max_num++;
|
||||
tokenized_data[i] = max_num;
|
||||
}
|
||||
}
|
||||
return tokenized_data;
|
||||
}
|
||||
|
||||
std::vector<std::string> Data::removeStopWords(std::string text){
|
||||
std::vector<std::string> stopWords = {"i", "me", "my", "myself", "we", "our", "ours", "ourselves", "you", "your", "yours", "yourself", "yourselves", "he", "him", "his", "himself", "she", "her", "hers", "herself", "it", "its", "itself", "they", "them", "their", "theirs", "themselves", "what", "which", "who", "whom", "this", "that", "these", "those", "am", "is", "are", "was", "were", "be", "been", "being", "have", "has", "had", "having", "do", "does", "did", "doing", "a", "an", "the", "and", "but", "if", "or", "because", "as", "until", "while", "of", "at", "by", "for", "with", "about", "against", "between", "into", "through", "during", "before", "after", "above", "below", "to", "from", "up", "down", "in", "out", "on", "off", "over", "under", "again", "further", "then", "once", "here", "there", "when", "where", "why", "how", "all", "any", "both", "each", "few", "more", "most", "other", "some", "such", "no", "nor", "not", "only", "own", "same", "so", "than", "too", "very", "s", "t", "can", "will", "just", "don", "should", "now"};
|
||||
std::vector<std::string> segmented_data = removeSpaces(segment(toLower(text)));
|
||||
|
||||
for(int i = 0; i < stopWords.size(); i++){
|
||||
for(int j = 0; j < segmented_data.size(); j++){
|
||||
if(segmented_data[j] == stopWords[i]){
|
||||
segmented_data.erase(segmented_data.begin() + j);
|
||||
}
|
||||
}
|
||||
}
|
||||
return segmented_data;
|
||||
}
|
||||
|
||||
std::vector<std::string> Data::removeStopWords(std::vector<std::string> segmented_data){
|
||||
std::vector<std::string> stopWords = {"i", "me", "my", "myself", "we", "our", "ours", "ourselves", "you", "your", "yours", "yourself", "yourselves", "he", "him", "his", "himself", "she", "her", "hers", "herself", "it", "its", "itself", "they", "them", "their", "theirs", "themselves", "what", "which", "who", "whom", "this", "that", "these", "those", "am", "is", "are", "was", "were", "be", "been", "being", "have", "has", "had", "having", "do", "does", "did", "doing", "a", "an", "the", "and", "but", "if", "or", "because", "as", "until", "while", "of", "at", "by", "for", "with", "about", "against", "between", "into", "through", "during", "before", "after", "above", "below", "to", "from", "up", "down", "in", "out", "on", "off", "over", "under", "again", "further", "then", "once", "here", "there", "when", "where", "why", "how", "all", "any", "both", "each", "few", "more", "most", "other", "some", "such", "no", "nor", "not", "only", "own", "same", "so", "than", "too", "very", "s", "t", "can", "will", "just", "don", "should", "now"};
|
||||
for(int i = 0; i < segmented_data.size(); i++){
|
||||
for(int j = 0; j < stopWords.size(); j++){
|
||||
if(segmented_data[i] == stopWords[j]){
|
||||
segmented_data.erase(segmented_data.begin() + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return segmented_data;
|
||||
}
|
||||
|
||||
std::string Data::stemming(std::string text){
|
||||
|
||||
// Our list of suffixes which we use to compare against
|
||||
std::vector<std::string> suffixes = {"eer", "er", "ion", "ity", "ment", "ness", "or", "sion", "ship", "th", "able", "ible", "al", "ant", "ary", "ful", "ic", "ious", "ous", "ive", "less", "y", "ed", "en", "ing", "ize", "ise", "ly", "ward", "wise"};
|
||||
int padding_size = 4;
|
||||
char padding = ' '; // our padding
|
||||
|
||||
for(int i = 0; i < padding_size; i++){
|
||||
text[text.length() + i] = padding; // ' ' will be our padding value
|
||||
}
|
||||
|
||||
|
||||
for(int i = 0; i < text.size(); i++){
|
||||
for(int j = 0; j < suffixes.size(); j++){
|
||||
if(text.substr(i, suffixes[j].length()) == suffixes[j] && (text[i + suffixes[j].length()] == ' ' || text[i + suffixes[j].length()] == ',' || text[i + suffixes[j].length()] == '-' || text[i + suffixes[j].length()] == '.' || text[i + suffixes[j].length()] == '!')){
|
||||
text.erase(i, suffixes[j].length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Data::BOW(std::vector<std::string> sentences, std::string type){
|
||||
/*
|
||||
STEPS OF BOW:
|
||||
1) To lowercase (done by removeStopWords function by def)
|
||||
2) Removing stop words
|
||||
3) Obtain a list of the used words
|
||||
4) Create a one hot encoded vector of the words and sentences
|
||||
5) Sentence.size() x list.size() matrix
|
||||
*/
|
||||
|
||||
std::vector<std::string> wordList = removeNullByte(removeStopWords(createWordList(sentences)));
|
||||
|
||||
std::vector<std::vector<std::string>> segmented_sentences;
|
||||
segmented_sentences.resize(sentences.size());
|
||||
|
||||
for(int i = 0; i < sentences.size(); i++){
|
||||
segmented_sentences[i] = removeStopWords(sentences[i]);
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> bow;
|
||||
|
||||
bow.resize(sentences.size());
|
||||
for(int i = 0; i < bow.size(); i++){
|
||||
bow[i].resize(wordList.size());
|
||||
}
|
||||
|
||||
|
||||
for(int i = 0; i < segmented_sentences.size(); i++){
|
||||
for(int j = 0; j < segmented_sentences[i].size(); j++){
|
||||
for(int k = 0; k < wordList.size(); k++){
|
||||
if(segmented_sentences[i][j] == wordList[k]){
|
||||
if(type == "Binary"){
|
||||
bow[i][k] = 1;
|
||||
}
|
||||
else{
|
||||
bow[i][k]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bow;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Data::TFIDF(std::vector<std::string> sentences){
|
||||
LinAlg alg;
|
||||
std::vector<std::string> wordList = removeNullByte(removeStopWords(createWordList(sentences)));
|
||||
|
||||
std::vector<std::vector<std::string>> segmented_sentences;
|
||||
segmented_sentences.resize(sentences.size());
|
||||
|
||||
for(int i = 0; i < sentences.size(); i++){
|
||||
segmented_sentences[i] = removeStopWords(sentences[i]);
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> TF;
|
||||
std::vector<int> frequency;
|
||||
frequency.resize(wordList.size());
|
||||
TF.resize(segmented_sentences.size());
|
||||
for(int i = 0; i < TF.size(); i++){
|
||||
TF[i].resize(wordList.size());
|
||||
}
|
||||
for(int i = 0; i < segmented_sentences.size(); i++){
|
||||
std::vector<bool> present(wordList.size(), 0);
|
||||
for(int j = 0; j < segmented_sentences[i].size(); j++){
|
||||
for(int k = 0; k < wordList.size(); k++){
|
||||
if(segmented_sentences[i][j] == wordList[k]){
|
||||
TF[i][k]++;
|
||||
if(!present[k]){
|
||||
frequency[k]++;
|
||||
present[k] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TF[i] = alg.scalarMultiply(double(1) / double(segmented_sentences[i].size()), TF[i]);
|
||||
}
|
||||
|
||||
std::vector<double> IDF;
|
||||
IDF.resize(frequency.size());
|
||||
|
||||
for(int i = 0; i < IDF.size(); i++){
|
||||
IDF[i] = log((double)segmented_sentences.size() / (double)frequency[i]);
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> TFIDF;
|
||||
TFIDF.resize(segmented_sentences.size());
|
||||
for(int i = 0; i < TFIDF.size(); i++){
|
||||
TFIDF[i].resize(wordList.size());
|
||||
}
|
||||
|
||||
for(int i = 0; i < TFIDF.size(); i++){
|
||||
for(int j = 0; j < TFIDF[i].size(); j++){
|
||||
TFIDF[i][j] = TF[i][j] * IDF[j];
|
||||
}
|
||||
}
|
||||
|
||||
return TFIDF;
|
||||
}
|
||||
|
||||
std::tuple<std::vector<std::vector<double>>, std::vector<std::string>> Data::word2Vec(std::vector<std::string> sentences, std::string type, int windowSize, int dimension, double learning_rate, int max_epoch){
|
||||
std::vector<std::string> wordList = removeNullByte(removeStopWords(createWordList(sentences)));
|
||||
|
||||
std::vector<std::vector<std::string>> segmented_sentences;
|
||||
segmented_sentences.resize(sentences.size());
|
||||
|
||||
for(int i = 0; i < sentences.size(); i++){
|
||||
segmented_sentences[i] = removeStopWords(sentences[i]);
|
||||
}
|
||||
|
||||
std::vector<std::string> inputStrings;
|
||||
std::vector<std::string> outputStrings;
|
||||
|
||||
for(int i = 0; i < segmented_sentences.size(); i++){
|
||||
for(int j = 0; j < segmented_sentences[i].size(); j++){
|
||||
for(int k = windowSize; k > 0; k--){
|
||||
if(j - k >= 0){
|
||||
inputStrings.push_back(segmented_sentences[i][j]);
|
||||
|
||||
outputStrings.push_back(segmented_sentences[i][j - k]);
|
||||
}
|
||||
if(j + k <= segmented_sentences[i].size() - 1){
|
||||
inputStrings.push_back(segmented_sentences[i][j]);
|
||||
outputStrings.push_back(segmented_sentences[i][j + k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int inputSize = inputStrings.size();
|
||||
|
||||
inputStrings.insert(inputStrings.end(), outputStrings.begin(), outputStrings.end());
|
||||
|
||||
std::vector<std::vector<double>> BOW = Data::BOW(inputStrings, "Binary");
|
||||
|
||||
std::vector<std::vector<double>> inputSet;
|
||||
std::vector<std::vector<double>> outputSet;
|
||||
|
||||
for(int i = 0; i < inputSize; i++){
|
||||
inputSet.push_back(BOW[i]);
|
||||
}
|
||||
|
||||
for(int i = inputSize; i < BOW.size(); i++){
|
||||
outputSet.push_back(BOW[i]);
|
||||
}
|
||||
LinAlg alg;
|
||||
SoftmaxNet* model;
|
||||
if(type == "Skipgram"){
|
||||
model = new SoftmaxNet(outputSet, inputSet, dimension);
|
||||
}
|
||||
else { // else = CBOW. We maintain it is a default, however.
|
||||
model = new SoftmaxNet(inputSet, outputSet, dimension);
|
||||
}
|
||||
model->gradientDescent(learning_rate, max_epoch, 1);
|
||||
|
||||
std::vector<std::vector<double>> wordEmbeddings = model->getEmbeddings();
|
||||
delete model;
|
||||
return {wordEmbeddings, wordList};
|
||||
}
|
||||
|
||||
std::vector<std::string> Data::createWordList(std::vector<std::string> sentences){
|
||||
std::string combinedText = "";
|
||||
for(int i = 0; i < sentences.size(); i++){
|
||||
if(i != 0){ combinedText += " "; }
|
||||
combinedText += sentences[i];
|
||||
}
|
||||
|
||||
return removeSpaces(vecToSet(removeStopWords(combinedText)));
|
||||
}
|
||||
|
||||
// EXTRA
|
||||
void Data::setInputNames(std::string fileName, std::vector<std::string>& inputNames){
|
||||
std::string inputNameTemp;
|
||||
std::ifstream dataFile(fileName);
|
||||
if(!dataFile.is_open()){
|
||||
std::cout << fileName << " failed to open." << std::endl;
|
||||
}
|
||||
|
||||
while (std::getline(dataFile, inputNameTemp))
|
||||
{
|
||||
inputNames.push_back(inputNameTemp);
|
||||
}
|
||||
|
||||
dataFile.close();
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Data::featureScaling(std::vector<std::vector<double>> X){
|
||||
LinAlg alg;
|
||||
X = alg.transpose(X);
|
||||
std::vector<double> max_elements, min_elements;
|
||||
max_elements.resize(X.size());
|
||||
min_elements.resize(X.size());
|
||||
|
||||
for(int i = 0; i < X.size(); i++){
|
||||
max_elements[i] = alg.max(X[i]);
|
||||
min_elements[i] = alg.min(X[i]);
|
||||
}
|
||||
|
||||
for(int i = 0; i < X.size(); i++){
|
||||
for(int j = 0; j < X[i].size(); j++){
|
||||
X[i][j] = (X[i][j] - min_elements[i]) / (max_elements[i] - min_elements[i]);
|
||||
}
|
||||
}
|
||||
return alg.transpose(X);
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::vector<double>> Data::meanNormalization(std::vector<std::vector<double>> X){
|
||||
LinAlg alg;
|
||||
Stat stat;
|
||||
// (X_j - mu_j) / std_j, for every j
|
||||
|
||||
X = meanCentering(X);
|
||||
for(int i = 0; i < X.size(); i++){
|
||||
X[i] = alg.scalarMultiply(1/stat.standardDeviation(X[i]), X[i]);
|
||||
}
|
||||
return X;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Data::meanCentering(std::vector<std::vector<double>> X){
|
||||
LinAlg alg;
|
||||
Stat stat;
|
||||
for(int i = 0; i < X.size(); i++){
|
||||
double mean_i = stat.mean(X[i]);
|
||||
for(int j = 0; j < X[i].size(); j++){
|
||||
X[i][j] -= mean_i;
|
||||
}
|
||||
}
|
||||
return X;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Data::oneHotRep(std::vector<double> tempOutputSet, int n_class){
|
||||
std::vector<std::vector<double>> outputSet;
|
||||
outputSet.resize(tempOutputSet.size());
|
||||
for(int i = 0; i < tempOutputSet.size(); i++){
|
||||
for(int j = 0; j <= n_class - 1; j++){
|
||||
if(tempOutputSet[i] == j){
|
||||
outputSet[i].push_back(1);
|
||||
}
|
||||
else{
|
||||
outputSet[i].push_back(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return outputSet;
|
||||
}
|
||||
|
||||
std::vector<double> Data::reverseOneHot(std::vector<std::vector<double>> tempOutputSet){
|
||||
std::vector<double> outputSet;
|
||||
int n_class = tempOutputSet[0].size();
|
||||
for(int i = 0; i < tempOutputSet.size(); i++){
|
||||
int current_class = 1;
|
||||
for(int j = 0; j < tempOutputSet[i].size(); j++){
|
||||
if(tempOutputSet[i][j] == 1){
|
||||
break;
|
||||
}
|
||||
else{
|
||||
current_class++;
|
||||
}
|
||||
}
|
||||
outputSet.push_back(current_class);
|
||||
}
|
||||
|
||||
return outputSet;
|
||||
}
|
||||
}
|
82
MLPP/Data/Data.hpp
Normal file
82
MLPP/Data/Data.hpp
Normal file
@ -0,0 +1,82 @@
|
||||
//
|
||||
// Data.hpp
|
||||
// MLP
|
||||
//
|
||||
// Created by Marc Melikyan on 11/4/20.
|
||||
//
|
||||
|
||||
#ifndef Data_hpp
|
||||
#define Data_hpp
|
||||
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace MLPP{
|
||||
class Data{
|
||||
public:
|
||||
// Supervised
|
||||
void setData(int k, std::string fileName, std::vector<std::vector<double>>& inputSet, std::vector<double>& outputSet);
|
||||
void printData(std::vector <std::string> inputName, std::string outputName, std::vector<std::vector<double>> inputSet, std::vector<double> outputSet);
|
||||
|
||||
// Unsupervised
|
||||
void setData(int k, std::string fileName, std::vector<std::vector<double>>& inputSet);
|
||||
void printData(std::vector <std::string> inputName, std::vector<std::vector<double>> inputSet);
|
||||
|
||||
// Simple
|
||||
void setData(std::string fileName, std::vector <double>& inputSet, std::vector <double>& outputSet);
|
||||
void printData(std::string& inputName, std::string& outputName, std::vector <double>& inputSet, std::vector <double>& outputSet);
|
||||
|
||||
// Images
|
||||
void getImage(std::string fileName, std::vector<double>& image);
|
||||
|
||||
// Text-Based & NLP
|
||||
std::string toLower(std::string text);
|
||||
std::vector<char> split(std::string text);
|
||||
std::vector<std::string> splitSentences(std::string data);
|
||||
std::vector<std::string> removeSpaces(std::vector<std::string> data);
|
||||
std::vector<std::string> removeNullByte(std::vector<std::string> data);
|
||||
std::vector<std::string> segment(std::string text);
|
||||
std::vector<double> tokenize(std::string text);
|
||||
std::vector<std::string> removeStopWords(std::string text);
|
||||
std::vector<std::string> removeStopWords(std::vector<std::string> segmented_data);
|
||||
|
||||
std::string stemming(std::string text);
|
||||
|
||||
std::vector<std::vector<double>> BOW(std::vector<std::string> sentences, std::string = "Default");
|
||||
std::vector<std::vector<double>> TFIDF(std::vector<std::string> sentences);
|
||||
std::tuple<std::vector<std::vector<double>>, std::vector<std::string>> word2Vec(std::vector<std::string> sentences, std::string type, int windowSize, int dimension, double learning_rate, int max_epoch);
|
||||
|
||||
std::vector<std::string> createWordList(std::vector<std::string> sentences);
|
||||
|
||||
// Extra
|
||||
void setInputNames(std::string fileName, std::vector<std::string>& inputNames);
|
||||
std::vector<std::vector<double>> featureScaling(std::vector<std::vector<double>> X);
|
||||
std::vector<std::vector<double>> meanNormalization(std::vector<std::vector<double>> X);
|
||||
std::vector<std::vector<double>> meanCentering(std::vector<std::vector<double>> X);
|
||||
std::vector<std::vector<double>> oneHotRep (std::vector<double> tempOutputSet, int n_class);
|
||||
std::vector<double> reverseOneHot(std::vector<std::vector<double>> tempOutputSet);
|
||||
|
||||
template <class T>
|
||||
std::vector<T> vecToSet(std::vector<T> inputSet){
|
||||
std::vector<T> setInputSet;
|
||||
for(int i = 0; i < inputSet.size(); i++){
|
||||
bool new_element = true;
|
||||
for(int j = 0; j < setInputSet.size(); j++){
|
||||
if(setInputSet[j] == inputSet[i]){
|
||||
new_element = false;
|
||||
}
|
||||
}
|
||||
if(new_element){
|
||||
setInputSet.push_back(inputSet[i]);
|
||||
}
|
||||
}
|
||||
return setInputSet;
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* Data_hpp */
|
261
MLPP/ExpReg/ExpReg.cpp
Normal file
261
MLPP/ExpReg/ExpReg.cpp
Normal file
@ -0,0 +1,261 @@
|
||||
//
|
||||
// ExpReg.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 10/2/20.
|
||||
//
|
||||
|
||||
#include "ExpReg.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
#include "Stat/Stat.hpp"
|
||||
#include "Regularization/Reg.hpp"
|
||||
#include "Utilities/Utilities.hpp"
|
||||
#include "Cost/Cost.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
namespace MLPP{
|
||||
ExpReg::ExpReg(std::vector<std::vector<double>> inputSet, std::vector<double> 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)
|
||||
{
|
||||
y_hat.resize(n);
|
||||
weights = Utilities::weightInitialization(k);
|
||||
initial = Utilities::weightInitialization(k);
|
||||
bias = Utilities::biasInitialization();
|
||||
}
|
||||
|
||||
std::vector<double> ExpReg::modelSetTest(std::vector<std::vector<double>> X){
|
||||
return Evaluate(X);
|
||||
}
|
||||
|
||||
double ExpReg::modelTest(std::vector<double> x){
|
||||
return Evaluate(x);
|
||||
}
|
||||
|
||||
void ExpReg::gradientDescent(double learning_rate, int max_epoch, bool UI){
|
||||
Reg regularization;
|
||||
LinAlg alg;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
forwardPass();
|
||||
|
||||
while(true){
|
||||
cost_prev = Cost(y_hat, outputSet);
|
||||
|
||||
std::vector<double> error = alg.subtraction(y_hat, outputSet);
|
||||
|
||||
for(int i = 0; i < k; i++){
|
||||
|
||||
// Calculating the weight gradient
|
||||
double sum = 0;
|
||||
for(int j = 0; j < n; j++){
|
||||
sum += error[j] * inputSet[j][i] * pow(weights[i], inputSet[j][i] - 1);
|
||||
}
|
||||
double w_gradient = sum / n;
|
||||
|
||||
// Calculating the initial gradient
|
||||
double sum2 = 0;
|
||||
for(int j = 0; j < n; j++){
|
||||
sum2 += error[j] * pow(weights[i], inputSet[j][i]);
|
||||
}
|
||||
|
||||
|
||||
double i_gradient = sum2 / n;
|
||||
|
||||
// Weight/initial updation
|
||||
weights[i] -= learning_rate * w_gradient;
|
||||
initial[i] -= learning_rate * i_gradient;
|
||||
|
||||
}
|
||||
weights = regularization.regWeights(weights, lambda, alpha, reg);
|
||||
|
||||
// Calculating the bias gradient
|
||||
double sum = 0;
|
||||
for(int j = 0; j < n; j++){
|
||||
sum += (y_hat[j] - outputSet[j]);
|
||||
}
|
||||
double b_gradient = sum / n;
|
||||
|
||||
// bias updation
|
||||
bias -= learning_rate * b_gradient;
|
||||
forwardPass();
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputSet));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
epoch++;
|
||||
|
||||
if(epoch > max_epoch) { break; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void ExpReg::SGD(double learning_rate, int max_epoch, bool UI){
|
||||
Reg regularization;
|
||||
Utilities util;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
|
||||
while(true){
|
||||
std::random_device rd;
|
||||
std::default_random_engine generator(rd());
|
||||
std::uniform_int_distribution<int> distribution(0, int(n - 1));
|
||||
int outputIndex = distribution(generator);
|
||||
|
||||
double y_hat = Evaluate(inputSet[outputIndex]);
|
||||
cost_prev = Cost({y_hat}, {outputSet[outputIndex]});
|
||||
|
||||
|
||||
for(int i = 0; i < k; i++){
|
||||
|
||||
// Calculating the weight gradients
|
||||
|
||||
double w_gradient = (y_hat - outputSet[outputIndex]) * inputSet[outputIndex][i] * pow(weights[i], inputSet[outputIndex][i] - 1);
|
||||
double i_gradient = (y_hat - outputSet[outputIndex]) * pow(weights[i], inputSet[outputIndex][i]);
|
||||
|
||||
// Weight/initial updation
|
||||
weights[i] -= learning_rate * w_gradient;
|
||||
initial[i] -= learning_rate * i_gradient;
|
||||
}
|
||||
weights = regularization.regWeights(weights, lambda, alpha, reg);
|
||||
|
||||
// Calculating the bias gradients
|
||||
double b_gradient = (y_hat - outputSet[outputIndex]);
|
||||
|
||||
// Bias updation
|
||||
bias -= learning_rate * b_gradient;
|
||||
y_hat = Evaluate({inputSet[outputIndex]});
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost({y_hat}, {outputSet[outputIndex]}));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
epoch++;
|
||||
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
forwardPass();
|
||||
}
|
||||
|
||||
void ExpReg::MBGD(double learning_rate, int max_epoch, int miniBatch_size, bool UI){
|
||||
Reg regularization;
|
||||
LinAlg alg;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
|
||||
int n_miniBatch = n/miniBatch_size;
|
||||
|
||||
std::vector<std::vector<std::vector<double>>> inputMiniBatches;
|
||||
std::vector<std::vector<double>> outputMiniBatches;
|
||||
|
||||
// Creating the mini-batches
|
||||
for(int i = 0; i < n_miniBatch; i++){
|
||||
std::vector<std::vector<double>> currentInputSet;
|
||||
std::vector<double> currentOutputSet;
|
||||
for(int j = 0; j < n/n_miniBatch; j++){
|
||||
currentInputSet.push_back(inputSet[n/n_miniBatch * i + j]);
|
||||
currentOutputSet.push_back(outputSet[n/n_miniBatch * i + j]);
|
||||
}
|
||||
inputMiniBatches.push_back(currentInputSet);
|
||||
outputMiniBatches.push_back(currentOutputSet);
|
||||
}
|
||||
|
||||
if(double(n)/double(n_miniBatch) - int(n/n_miniBatch) != 0){
|
||||
for(int i = 0; i < n - n/n_miniBatch * n_miniBatch; i++){
|
||||
inputMiniBatches[n_miniBatch - 1].push_back(inputSet[n/n_miniBatch * n_miniBatch + i]);
|
||||
outputMiniBatches[n_miniBatch - 1].push_back(outputSet[n/n_miniBatch * n_miniBatch + i]);
|
||||
}
|
||||
}
|
||||
|
||||
while(true){
|
||||
for(int i = 0; i < n_miniBatch; i++){
|
||||
std::vector<double> y_hat = Evaluate(inputMiniBatches[i]);
|
||||
cost_prev = Cost(y_hat, outputMiniBatches[i]);
|
||||
std::vector<double> error = alg.subtraction(y_hat, outputMiniBatches[i]);
|
||||
|
||||
for(int j = 0; j < k; j++){
|
||||
// Calculating the weight gradient
|
||||
double sum = 0;
|
||||
for(int k = 0; k < outputMiniBatches[i].size(); k++){
|
||||
sum += error[k] * inputMiniBatches[i][k][j] * pow(weights[j], inputMiniBatches[i][k][j] - 1);
|
||||
}
|
||||
double w_gradient = sum / outputMiniBatches[i].size();
|
||||
|
||||
// Calculating the initial gradient
|
||||
double sum2 = 0;
|
||||
for(int k = 0; k < outputMiniBatches[i].size(); k++){
|
||||
sum2 += error[k] * pow(weights[j], inputMiniBatches[i][k][j]);
|
||||
}
|
||||
|
||||
|
||||
double i_gradient = sum2 / outputMiniBatches[i].size();
|
||||
|
||||
// Weight/initial updation
|
||||
weights[j] -= learning_rate * w_gradient;
|
||||
initial[j] -= learning_rate * i_gradient;
|
||||
}
|
||||
weights = regularization.regWeights(weights, lambda, alpha, reg);
|
||||
|
||||
// Calculating the bias gradient
|
||||
double sum = 0;
|
||||
for(int j = 0; j < outputMiniBatches[i].size(); j++){
|
||||
sum += (y_hat[j] - outputMiniBatches[i][j]);
|
||||
}
|
||||
double b_gradient = sum / outputMiniBatches[i].size();
|
||||
y_hat = Evaluate(inputMiniBatches[i]);
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputMiniBatches[i]));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
}
|
||||
epoch++;
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
forwardPass();
|
||||
}
|
||||
|
||||
double ExpReg::score(){
|
||||
Utilities util;
|
||||
return util.performance(y_hat, outputSet);
|
||||
}
|
||||
|
||||
void ExpReg::save(std::string fileName){
|
||||
Utilities util;
|
||||
util.saveParameters(fileName, weights, initial, bias);
|
||||
}
|
||||
|
||||
double ExpReg::Cost(std::vector <double> y_hat, std::vector<double> y){
|
||||
Reg regularization;
|
||||
class Cost cost;
|
||||
return cost.MSE(y_hat, y) + regularization.regTerm(weights, lambda, alpha, reg);
|
||||
}
|
||||
|
||||
std::vector<double> ExpReg::Evaluate(std::vector<std::vector<double>> X){
|
||||
std::vector<double> y_hat;
|
||||
y_hat.resize(X.size());
|
||||
for(int i = 0; i < X.size(); i++){
|
||||
y_hat[i] = 0;
|
||||
for(int j = 0; j < X[i].size(); j++){
|
||||
y_hat[i] += initial[j] * pow(weights[j], X[i][j]);
|
||||
}
|
||||
y_hat[i] += bias;
|
||||
}
|
||||
return y_hat;
|
||||
}
|
||||
|
||||
double ExpReg::Evaluate(std::vector<double> x){
|
||||
double y_hat = 0;
|
||||
for(int i = 0; i < x.size(); i++){
|
||||
y_hat += initial[i] * pow(weights[i], x[i]);
|
||||
}
|
||||
|
||||
return y_hat + bias;
|
||||
}
|
||||
|
||||
// a * w^x + b
|
||||
void ExpReg::forwardPass(){
|
||||
y_hat = Evaluate(inputSet);
|
||||
}
|
||||
}
|
51
MLPP/ExpReg/ExpReg.hpp
Normal file
51
MLPP/ExpReg/ExpReg.hpp
Normal file
@ -0,0 +1,51 @@
|
||||
//
|
||||
// ExpReg.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 10/2/20.
|
||||
//
|
||||
|
||||
#ifndef ExpReg_hpp
|
||||
#define ExpReg_hpp
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace MLPP{
|
||||
class ExpReg{
|
||||
|
||||
public:
|
||||
ExpReg(std::vector<std::vector<double>> inputSet, std::vector<double> outputSet, std::string reg = "None", double lambda = 0.5, double alpha = 0.5);
|
||||
std::vector<double> modelSetTest(std::vector<std::vector<double>> X);
|
||||
double modelTest(std::vector<double> x);
|
||||
void gradientDescent(double learning_rate, int max_epoch, bool UI = 1);
|
||||
void SGD(double learning_rate, int max_epoch, bool UI = 1);
|
||||
void MBGD(double learning_rate, int max_epoch, int miniBatch_size, bool UI = 1);
|
||||
double score();
|
||||
void save(std::string fileName);
|
||||
private:
|
||||
|
||||
double Cost(std::vector <double> y_hat, std::vector<double> y);
|
||||
|
||||
std::vector<double> Evaluate(std::vector<std::vector<double>> X);
|
||||
double Evaluate(std::vector<double> x);
|
||||
void forwardPass();
|
||||
|
||||
std::vector<std::vector<double>> inputSet;
|
||||
std::vector<double> outputSet;
|
||||
std::vector<double> y_hat;
|
||||
std::vector<double> weights;
|
||||
std::vector<double> initial;
|
||||
double bias;
|
||||
|
||||
int n;
|
||||
int k;
|
||||
|
||||
// Regularization Params
|
||||
std::string reg;
|
||||
double lambda;
|
||||
double alpha; /* This is the controlling param for Elastic Net*/
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* ExpReg_hpp */
|
59
MLPP/GaussMarkovChecker/GaussMarkovChecker.cpp
Normal file
59
MLPP/GaussMarkovChecker/GaussMarkovChecker.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
//
|
||||
// GaussMarkovChecker.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 11/13/20.
|
||||
//
|
||||
|
||||
#include "GaussMarkovChecker.hpp"
|
||||
#include "Stat/Stat.hpp"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
namespace MLPP{
|
||||
void GaussMarkovChecker::checkGMConditions(std::vector<double> eps){
|
||||
bool condition1 = arithmeticMean(eps);
|
||||
bool condition2 = homoscedasticity(eps);
|
||||
bool condition3 = exogeneity(eps);
|
||||
|
||||
if(condition1 && condition2 && condition3){
|
||||
std::cout << "Gauss-Markov conditions were not violated. You may use OLS to obtain a BLUE estimator" << std::endl;
|
||||
}
|
||||
else{
|
||||
std::cout << "A test of the expected value of 0 of the error terms returned " << std::boolalpha << condition1 << ", a test of homoscedasticity has returned " << std::boolalpha << condition2 << ", and a test of exogenity has returned " << std::boolalpha << "." << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool GaussMarkovChecker::arithmeticMean(std::vector<double> eps){
|
||||
Stat stat;
|
||||
if(stat.mean(eps) == 0) {
|
||||
return 1;
|
||||
}
|
||||
else { return 0; }
|
||||
}
|
||||
|
||||
bool GaussMarkovChecker::homoscedasticity(std::vector<double> eps){
|
||||
Stat stat;
|
||||
double currentVar = (eps[0] - stat.mean(eps)) * (eps[0] - stat.mean(eps)) / eps.size();
|
||||
for(int i = 0; i < eps.size(); i++){
|
||||
if(currentVar != (eps[i] - stat.mean(eps)) * (eps[i] - stat.mean(eps)) / eps.size()){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool GaussMarkovChecker::exogeneity(std::vector<double> eps){
|
||||
Stat stat;
|
||||
for(int i = 0; i < eps.size(); i++){
|
||||
for(int j = 0; j < eps.size(); j++){
|
||||
if(i != j){
|
||||
if((eps[i] - stat.mean(eps)) * (eps[j] - stat.mean(eps)) / eps.size() != 0){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
27
MLPP/GaussMarkovChecker/GaussMarkovChecker.hpp
Normal file
27
MLPP/GaussMarkovChecker/GaussMarkovChecker.hpp
Normal file
@ -0,0 +1,27 @@
|
||||
//
|
||||
// GaussMarkovChecker.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 11/13/20.
|
||||
//
|
||||
|
||||
#ifndef GaussMarkovChecker_hpp
|
||||
#define GaussMarkovChecker_hpp
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace MLPP{
|
||||
class GaussMarkovChecker{
|
||||
public:
|
||||
void checkGMConditions(std::vector<double> eps);
|
||||
|
||||
// Independent, 3 Gauss-Markov Conditions
|
||||
bool arithmeticMean(std::vector<double> eps); // 1) Arithmetic Mean of 0.
|
||||
bool homoscedasticity(std::vector<double> eps); // 2) Homoscedasticity
|
||||
bool exogeneity(std::vector<double> eps); // 3) Cov of any 2 non-equal eps values = 0.
|
||||
private:
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* GaussMarkovChecker_hpp */
|
91
MLPP/GaussianNB/GaussianNB.cpp
Normal file
91
MLPP/GaussianNB/GaussianNB.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
//
|
||||
// GaussianNB.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 1/17/21.
|
||||
//
|
||||
|
||||
#include "GaussianNB.hpp"
|
||||
#include "Stat/Stat.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
#include "Utilities/Utilities.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
namespace MLPP{
|
||||
GaussianNB::GaussianNB(std::vector<std::vector<double>> inputSet, std::vector<double> outputSet, int class_num)
|
||||
: inputSet(inputSet), outputSet(outputSet), class_num(class_num)
|
||||
{
|
||||
y_hat.resize(outputSet.size());
|
||||
Evaluate();
|
||||
LinAlg alg;
|
||||
}
|
||||
|
||||
std::vector<double> GaussianNB::modelSetTest(std::vector<std::vector<double>> X){
|
||||
std::vector<double> y_hat;
|
||||
for(int i = 0; i < X.size(); i++){
|
||||
y_hat.push_back(modelTest(X[i]));
|
||||
}
|
||||
return y_hat;
|
||||
}
|
||||
|
||||
double GaussianNB::modelTest(std::vector<double> x){
|
||||
Stat stat;
|
||||
LinAlg alg;
|
||||
|
||||
double score[class_num];
|
||||
double y_hat_i = 1;
|
||||
for(int i = class_num - 1; i >= 0; i--){
|
||||
y_hat_i += log(priors[i] * (1 / sqrt(2 * M_PI * sigma[i] * sigma[i])) * exp(-(x[i] * mu[i]) * (x[i] * mu[i]) / (2 * sigma[i] * sigma[i])));
|
||||
score[i] = exp(y_hat_i);
|
||||
}
|
||||
return std::distance(score, std::max_element(score, score + sizeof(score) / sizeof(double)));
|
||||
}
|
||||
|
||||
double GaussianNB::score(){
|
||||
Utilities util;
|
||||
return util.performance(y_hat, outputSet);
|
||||
}
|
||||
|
||||
void GaussianNB::Evaluate(){
|
||||
Stat stat;
|
||||
LinAlg alg;
|
||||
|
||||
// Computing mu_k_y and sigma_k_y
|
||||
mu.resize(class_num);
|
||||
sigma.resize(class_num);
|
||||
for(int i = class_num - 1; i >= 0; i--){
|
||||
std::vector<double> set;
|
||||
for(int j = 0; j < inputSet.size(); j++){
|
||||
for(int k = 0; k < inputSet[j].size(); k++){
|
||||
if(outputSet[j] == i){
|
||||
set.push_back(inputSet[j][k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
mu[i] = stat.mean(set);
|
||||
sigma[i] = stat.standardDeviation(set);
|
||||
}
|
||||
|
||||
// Priors
|
||||
priors.resize(class_num);
|
||||
for(int i = 0; i < outputSet.size(); i++){
|
||||
priors[int(outputSet[i])]++;
|
||||
}
|
||||
priors = alg.scalarMultiply( double(1)/double(outputSet.size()), priors);
|
||||
|
||||
for(int i = 0; i < outputSet.size(); i++){
|
||||
double score[class_num];
|
||||
double y_hat_i = 1;
|
||||
for(int j = class_num - 1; j >= 0; j--){
|
||||
for(int k = 0; k < inputSet[i].size(); k++){
|
||||
y_hat_i += log(priors[j] * (1 / sqrt(2 * M_PI * sigma[j] * sigma[j])) * exp(-(inputSet[i][k] * mu[j]) * (inputSet[i][k] * mu[j]) / (2 * sigma[j] * sigma[j])));
|
||||
}
|
||||
score[j] = exp(y_hat_i);
|
||||
std::cout << score[j] << std::endl;
|
||||
}
|
||||
y_hat[i] = std::distance(score, std::max_element(score, score + sizeof(score) / sizeof(double)));
|
||||
std::cout << std::distance(score, std::max_element(score, score + sizeof(score) / sizeof(double))) << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
42
MLPP/GaussianNB/GaussianNB.hpp
Normal file
42
MLPP/GaussianNB/GaussianNB.hpp
Normal file
@ -0,0 +1,42 @@
|
||||
//
|
||||
// GaussianNB.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 1/17/21.
|
||||
//
|
||||
|
||||
#ifndef GaussianNB_hpp
|
||||
#define GaussianNB_hpp
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace MLPP{
|
||||
class GaussianNB{
|
||||
|
||||
public:
|
||||
GaussianNB(std::vector<std::vector<double>> inputSet, std::vector<double> outputSet, int class_num);
|
||||
std::vector<double> modelSetTest(std::vector<std::vector<double>> X);
|
||||
double modelTest(std::vector<double> x);
|
||||
double score();
|
||||
|
||||
private:
|
||||
|
||||
void Evaluate();
|
||||
|
||||
int class_num;
|
||||
|
||||
std::vector<double> priors;
|
||||
std::vector<double> mu;
|
||||
std::vector<double> sigma;
|
||||
|
||||
std::vector<std::vector<double>> inputSet;
|
||||
std::vector<double> outputSet;
|
||||
|
||||
std::vector<double> y_hat;
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif /* GaussianNB_hpp */
|
||||
}
|
99
MLPP/HiddenLayer/HiddenLayer.cpp
Normal file
99
MLPP/HiddenLayer/HiddenLayer.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
//
|
||||
// HiddenLayer.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 11/4/20.
|
||||
//
|
||||
|
||||
#include "HiddenLayer.hpp"
|
||||
#include "Activation/Activation.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
#include "Utilities/Utilities.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
namespace MLPP {
|
||||
HiddenLayer::HiddenLayer(int n_hidden, std::string activation, std::vector<std::vector<double>> input, std::string weightInit, std::string reg, double lambda, double alpha)
|
||||
: n_hidden(n_hidden), activation(activation), input(input), weightInit(weightInit), reg(reg), lambda(lambda), alpha(alpha)
|
||||
{
|
||||
weights = Utilities::weightInitialization(input[0].size(), n_hidden, weightInit);
|
||||
bias = Utilities::biasInitialization(n_hidden);
|
||||
|
||||
activation_map["Linear"] = &Activation::linear;
|
||||
activationTest_map["Linear"] = &Activation::linear;
|
||||
|
||||
activation_map["Sigmoid"] = &Activation::sigmoid;
|
||||
activationTest_map["Sigmoid"] = &Activation::sigmoid;
|
||||
|
||||
activation_map["Swish"] = &Activation::swish;
|
||||
activationTest_map["Swish"] = &Activation::swish;
|
||||
|
||||
activation_map["Softplus"] = &Activation::softplus;
|
||||
activationTest_map["Softplus"] = &Activation::softplus;
|
||||
|
||||
activation_map["CLogLog"] = &Activation::cloglog;
|
||||
activationTest_map["CLogLog"] = &Activation::cloglog;
|
||||
|
||||
activation_map["Sinh"] = &Activation::sinh;
|
||||
activationTest_map["Sinh"] = &Activation::sinh;
|
||||
|
||||
activation_map["Cosh"] = &Activation::cosh;
|
||||
activationTest_map["Cosh"] = &Activation::cosh;
|
||||
|
||||
activation_map["Tanh"] = &Activation::tanh;
|
||||
activationTest_map["Tanh"] = &Activation::tanh;
|
||||
|
||||
activation_map["Csch"] = &Activation::csch;
|
||||
activationTest_map["Csch"] = &Activation::csch;
|
||||
|
||||
activation_map["Sech"] = &Activation::sech;
|
||||
activationTest_map["Sech"] = &Activation::sech;
|
||||
|
||||
activation_map["Coth"] = &Activation::coth;
|
||||
activationTest_map["Coth"] = &Activation::coth;
|
||||
|
||||
activation_map["Arsinh"] = &Activation::arsinh;
|
||||
activationTest_map["Arsinh"] = &Activation::arsinh;
|
||||
|
||||
activation_map["Arcosh"] = &Activation::arcosh;
|
||||
activationTest_map["Arcosh"] = &Activation::arcosh;
|
||||
|
||||
activation_map["Artanh"] = &Activation::artanh;
|
||||
activationTest_map["Artanh"] = &Activation::artanh;
|
||||
|
||||
activation_map["Arcsch"] = &Activation::arcsch;
|
||||
activationTest_map["Arcsch"] = &Activation::arcsch;
|
||||
|
||||
activation_map["Arsech"] = &Activation::arsech;
|
||||
activationTest_map["Arsech"] = &Activation::arsech;
|
||||
|
||||
activation_map["Arcoth"] = &Activation::arcoth;
|
||||
activationTest_map["Arcoth"] = &Activation::arcoth;
|
||||
|
||||
activation_map["GaussianCDF"] = &Activation::gaussianCDF;
|
||||
activationTest_map["GaussianCDF"] = &Activation::gaussianCDF;
|
||||
|
||||
activation_map["RELU"] = &Activation::RELU;
|
||||
activationTest_map["RELU"] = &Activation::RELU;
|
||||
|
||||
activation_map["GELU"] = &Activation::GELU;
|
||||
activationTest_map["GELU"] = &Activation::GELU;
|
||||
|
||||
activation_map["UnitStep"] = &Activation::unitStep;
|
||||
activationTest_map["UnitStep"] = &Activation::unitStep;
|
||||
}
|
||||
|
||||
void HiddenLayer::forwardPass(){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
z = alg.mat_vec_add(alg.matmult(input, weights), bias);
|
||||
a = (avn.*activation_map[activation])(z, 0);
|
||||
}
|
||||
|
||||
void HiddenLayer::Test(std::vector<double> x){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
z_test = alg.addition(alg.mat_vec_mult(alg.transpose(weights), x), bias);
|
||||
a_test = (avn.*activationTest_map[activation])(z_test, 0);
|
||||
}
|
||||
}
|
52
MLPP/HiddenLayer/HiddenLayer.hpp
Normal file
52
MLPP/HiddenLayer/HiddenLayer.hpp
Normal file
@ -0,0 +1,52 @@
|
||||
//
|
||||
// HiddenLayer.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 11/4/20.
|
||||
//
|
||||
|
||||
#ifndef HiddenLayer_hpp
|
||||
#define HiddenLayer_hpp
|
||||
|
||||
#include "Activation/Activation.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace MLPP {
|
||||
class HiddenLayer{
|
||||
public:
|
||||
HiddenLayer(int n_hidden, std::string activation, std::vector<std::vector<double>> input, std::string weightInit, std::string reg, double lambda, double alpha);
|
||||
|
||||
int n_hidden;
|
||||
std::string activation;
|
||||
|
||||
std::vector<std::vector<double>> input;
|
||||
|
||||
std::vector<std::vector<double>> weights;
|
||||
std::vector<double> bias;
|
||||
|
||||
std::vector<std::vector<double>> z;
|
||||
std::vector<std::vector<double>> a;
|
||||
|
||||
std::map<std::string, std::vector<std::vector<double>> (Activation::*)(std::vector<std::vector<double>>, bool)> activation_map;
|
||||
std::map<std::string, std::vector<double> (Activation::*)(std::vector<double>, bool)> activationTest_map;
|
||||
|
||||
std::vector<double> z_test;
|
||||
std::vector<double> a_test;
|
||||
|
||||
std::vector<std::vector<double>> delta;
|
||||
|
||||
// Regularization Params
|
||||
std::string reg;
|
||||
double lambda; /* Regularization Parameter */
|
||||
double alpha; /* This is the controlling param for Elastic Net*/
|
||||
|
||||
std::string weightInit;
|
||||
|
||||
void forwardPass();
|
||||
void Test(std::vector<double> x);
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* HiddenLayer_hpp */
|
19
MLPP/HypothesisTesting/HypothesisTesting.cpp
Normal file
19
MLPP/HypothesisTesting/HypothesisTesting.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
//
|
||||
// HypothesisTesting.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 3/10/21.
|
||||
//
|
||||
|
||||
#include "HypothesisTesting.hpp"
|
||||
|
||||
namespace MLPP{
|
||||
|
||||
std::tuple<bool, double> HypothesisTesting::chiSquareTest(std::vector<double> observed, std::vector<double> expected){
|
||||
double df = observed.size() - 1; // These are our degrees of freedom
|
||||
double sum = 0;
|
||||
for(int i = 0; i < observed.size(); i++){
|
||||
sum += (observed[i] - expected[i]) * (observed[i] - expected[i]) / expected[i];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
24
MLPP/HypothesisTesting/HypothesisTesting.hpp
Normal file
24
MLPP/HypothesisTesting/HypothesisTesting.hpp
Normal file
@ -0,0 +1,24 @@
|
||||
//
|
||||
// HypothesisTesting.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 3/10/21.
|
||||
//
|
||||
|
||||
#ifndef HypothesisTesting_hpp
|
||||
#define HypothesisTesting_hpp
|
||||
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
||||
namespace MLPP{
|
||||
class HypothesisTesting{
|
||||
|
||||
public:
|
||||
std::tuple<bool, double> chiSquareTest(std::vector<double> observed, std::vector<double> expected);
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* HypothesisTesting_hpp */
|
236
MLPP/KMeans/KMeans.cpp
Normal file
236
MLPP/KMeans/KMeans.cpp
Normal file
@ -0,0 +1,236 @@
|
||||
//
|
||||
// KMeans.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 10/2/20.
|
||||
//
|
||||
|
||||
#include "KMeans.hpp"
|
||||
#include "Utilities/Utilities.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
namespace MLPP{
|
||||
KMeans::KMeans(std::vector<std::vector<double>> inputSet, int k, std::string init_type)
|
||||
: inputSet(inputSet), k(k), init_type(init_type)
|
||||
{
|
||||
if(init_type == "KMeans++"){
|
||||
kmeansppInitialization(k);
|
||||
}
|
||||
else{
|
||||
centroidInitialization(k);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> KMeans::modelSetTest(std::vector<std::vector<double>> X){
|
||||
std::vector<std::vector<double>> closestCentroids;
|
||||
for(int i = 0; i < inputSet.size(); i++){
|
||||
std::vector<double> closestCentroid = mu[0];
|
||||
for(int j = 0; j < r[0].size(); j++){
|
||||
if(euclideanDistance(X[i], mu[j]) < euclideanDistance(X[i], closestCentroid)){
|
||||
closestCentroid = mu[j];
|
||||
}
|
||||
}
|
||||
closestCentroids.push_back(closestCentroid);
|
||||
}
|
||||
return closestCentroids;
|
||||
}
|
||||
|
||||
std::vector<double> KMeans::modelTest(std::vector<double> x){
|
||||
std::vector<double> closestCentroid = mu[0];
|
||||
for(int j = 0; j < mu.size(); j++){
|
||||
if(euclideanDistance(x, mu[j]) < euclideanDistance(x, closestCentroid)){
|
||||
closestCentroid = mu[j];
|
||||
}
|
||||
}
|
||||
return closestCentroid;
|
||||
}
|
||||
|
||||
void KMeans::train(int epoch_num, bool UI){
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
|
||||
Evaluate();
|
||||
|
||||
while(true){
|
||||
|
||||
// STEPS OF THE ALGORITHM
|
||||
// 1. DETERMINE r_nk
|
||||
// 2. DETERMINE J
|
||||
// 3. DETERMINE mu_k
|
||||
|
||||
// STOP IF CONVERGED, ELSE REPEAT
|
||||
|
||||
cost_prev = Cost();
|
||||
|
||||
computeMu();
|
||||
Evaluate();
|
||||
|
||||
// UI PORTION
|
||||
if(UI) { Utilities::CostInfo(epoch, cost_prev, Cost()); }
|
||||
epoch++;
|
||||
|
||||
if(epoch > epoch_num) { break; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
double KMeans::score(){
|
||||
return Cost();
|
||||
}
|
||||
|
||||
std::vector<double> KMeans::silhouette_scores(){
|
||||
std::vector<std::vector<double>> closestCentroids = modelSetTest(inputSet);
|
||||
std::vector<double> silhouette_scores;
|
||||
for(int i = 0; i < inputSet.size(); i++){
|
||||
// COMPUTING a[i]
|
||||
double a = 0;
|
||||
for(int j = 0; j < inputSet.size(); j++){
|
||||
if(i != j && r[i] == r[j]){
|
||||
a += euclideanDistance(inputSet[i], inputSet[j]);
|
||||
}
|
||||
}
|
||||
// NORMALIZE a[i]
|
||||
a /= closestCentroids[i].size() - 1;
|
||||
|
||||
|
||||
// COMPUTING b[i]
|
||||
double b = INT_MAX;
|
||||
for(int j = 0; j < mu.size(); j++){
|
||||
if(closestCentroids[i] != mu[j]){
|
||||
double sum = 0;
|
||||
for(int k = 0; k < inputSet.size(); k++){
|
||||
sum += euclideanDistance(inputSet[i], inputSet[k]);
|
||||
}
|
||||
// NORMALIZE b[i]
|
||||
double k_clusterSize = 0;
|
||||
for(int k = 0; k < closestCentroids.size(); k++){
|
||||
if(closestCentroids[k] == mu[j]){
|
||||
k_clusterSize++;
|
||||
}
|
||||
}
|
||||
if(sum / k_clusterSize < b) { b = sum / k_clusterSize; }
|
||||
}
|
||||
}
|
||||
silhouette_scores.push_back((b - a)/fmax(a, b));
|
||||
// Or the expanded version:
|
||||
// if(a < b) {
|
||||
// silhouette_scores.push_back(1 - a/b);
|
||||
// }
|
||||
// else if(a == b){
|
||||
// silhouette_scores.push_back(0);
|
||||
// }
|
||||
// else{
|
||||
// silhouette_scores.push_back(b/a - 1);
|
||||
// }
|
||||
}
|
||||
return silhouette_scores;
|
||||
}
|
||||
|
||||
// This simply computes r_nk
|
||||
void KMeans::Evaluate(){
|
||||
r.resize(inputSet.size());
|
||||
|
||||
for(int i = 0; i < r.size(); i++){
|
||||
r[i].resize(k);
|
||||
}
|
||||
|
||||
for(int i = 0; i < r.size(); i++){
|
||||
std::vector<double> closestCentroid = mu[0];
|
||||
for(int j = 0; j < r[0].size(); j++){
|
||||
if(euclideanDistance(inputSet[i], mu[j]) < euclideanDistance(inputSet[i], closestCentroid)){
|
||||
closestCentroid = mu[j];
|
||||
}
|
||||
}
|
||||
for(int j = 0; j < r[0].size(); j++){
|
||||
if(mu[j] == closestCentroid) {
|
||||
r[i][j] = 1;
|
||||
}
|
||||
else { r[i][j] = 0; }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// This simply computes or re-computes mu_k
|
||||
void KMeans::computeMu(){
|
||||
LinAlg alg;
|
||||
for(int i = 0; i < mu.size(); i++){
|
||||
std::vector<double> num;
|
||||
num.resize(r.size());
|
||||
|
||||
for(int i = 0; i < num.size(); i++){
|
||||
num[i] = 0;
|
||||
}
|
||||
|
||||
int den = 0;
|
||||
for(int j = 0; j < r.size(); j++){
|
||||
num = alg.addition(num, alg.scalarMultiply(r[j][i], inputSet[j]));
|
||||
}
|
||||
for(int j = 0; j < r.size(); j++){
|
||||
den += r[j][i];
|
||||
}
|
||||
mu[i] = alg.scalarMultiply(1/den, num);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void KMeans::centroidInitialization(int k){
|
||||
mu.resize(k);
|
||||
|
||||
for(int i = 0; i < k; i++){
|
||||
std::random_device rd;
|
||||
std::default_random_engine generator(rd());
|
||||
std::uniform_int_distribution<int> distribution(0, int(inputSet.size() - 1));
|
||||
|
||||
mu[i].resize(inputSet.size());
|
||||
mu[i] = inputSet[distribution(generator)];
|
||||
}
|
||||
}
|
||||
|
||||
void KMeans::kmeansppInitialization(int k){
|
||||
std::random_device rd;
|
||||
std::default_random_engine generator(rd());
|
||||
std::uniform_int_distribution<int> distribution(0, int(inputSet.size() - 1));
|
||||
mu.push_back(inputSet[distribution(generator)]);
|
||||
|
||||
for(int i = 0; i < k - 1; i++){
|
||||
std::vector<double> farthestCentroid;
|
||||
for(int j = 0; j < inputSet.size(); j++){
|
||||
double max_dist = 0;
|
||||
/* SUM ALL THE SQUARED DISTANCES, CHOOSE THE ONE THAT'S FARTHEST
|
||||
AS TO SPREAD OUT THE CLUSTER CENTROIDS. */
|
||||
double sum = 0;
|
||||
for(int k = 0; k < mu.size(); k++){
|
||||
sum += euclideanDistance(inputSet[j], mu[k]);
|
||||
}
|
||||
if(sum * sum > max_dist){
|
||||
farthestCentroid = inputSet[j];
|
||||
max_dist = sum * sum;
|
||||
}
|
||||
}
|
||||
mu.push_back(farthestCentroid);
|
||||
}
|
||||
}
|
||||
|
||||
double KMeans::Cost(){
|
||||
LinAlg alg;
|
||||
double sum = 0;
|
||||
for(int i = 0; i < r.size(); i++){
|
||||
for(int j = 0; j < r[0].size(); j++){
|
||||
sum += r[i][j] * alg.norm_sq(alg.subtraction(inputSet[i], mu[j]));
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
// Multidimensional Euclidean Distance
|
||||
double KMeans::euclideanDistance(std::vector<double> A, std::vector<double> B){
|
||||
double dist = 0;
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
dist += (A[i] - B[i])*(A[i] - B[i]);
|
||||
}
|
||||
return sqrt(dist);
|
||||
}
|
||||
}
|
45
MLPP/KMeans/KMeans.hpp
Normal file
45
MLPP/KMeans/KMeans.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
//
|
||||
// KMeans.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 10/2/20.
|
||||
//
|
||||
|
||||
#ifndef KMeans_hpp
|
||||
#define KMeans_hpp
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace MLPP{
|
||||
class KMeans{
|
||||
|
||||
public:
|
||||
KMeans(std::vector<std::vector<double>> inputSet, int k, std::string init_type = "Default");
|
||||
std::vector<std::vector<double>> modelSetTest(std::vector<std::vector<double>> X);
|
||||
std::vector<double> modelTest(std::vector<double> x);
|
||||
void train(int epoch_num, bool UI = 1);
|
||||
double score();
|
||||
std::vector<double> silhouette_scores();
|
||||
private:
|
||||
|
||||
void Evaluate();
|
||||
void computeMu();
|
||||
|
||||
void centroidInitialization(int k);
|
||||
void kmeansppInitialization(int k);
|
||||
double Cost();
|
||||
|
||||
std::vector<std::vector<double>> inputSet;
|
||||
std::vector<std::vector<double>> mu;
|
||||
std::vector<std::vector<double>> r;
|
||||
|
||||
double euclideanDistance(std::vector<double> A, std::vector<double> B);
|
||||
|
||||
double accuracy_threshold;
|
||||
int k;
|
||||
|
||||
std::string init_type;
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* KMeans_hpp */
|
744
MLPP/LinAlg/LinAlg.cpp
Normal file
744
MLPP/LinAlg/LinAlg.cpp
Normal file
@ -0,0 +1,744 @@
|
||||
//
|
||||
// LinAlg.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 1/8/21.
|
||||
//
|
||||
|
||||
#include "LinAlg.hpp"
|
||||
#include "Stat/Stat.hpp"
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <cmath>
|
||||
|
||||
namespace MLPP{
|
||||
|
||||
std::vector<std::vector<double>> LinAlg::addition(std::vector<std::vector<double>> A, std::vector<std::vector<double>> B){
|
||||
std::vector<std::vector<double>> C;
|
||||
C.resize(A.size());
|
||||
for(int i = 0; i < C.size(); i++){
|
||||
C[i].resize(A[0].size());
|
||||
}
|
||||
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
for(int j = 0; j < A[0].size(); j++){
|
||||
C[i][j] = A[i][j] + B[i][j];
|
||||
}
|
||||
}
|
||||
return C;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> LinAlg::subtraction(std::vector<std::vector<double>> A, std::vector<std::vector<double>> B){
|
||||
std::vector<std::vector<double>> C;
|
||||
C.resize(A.size());
|
||||
for(int i = 0; i < C.size(); i++){
|
||||
C[i].resize(A[0].size());
|
||||
}
|
||||
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
for(int j = 0; j < A[0].size(); j++){
|
||||
C[i][j] = A[i][j] - B[i][j];
|
||||
}
|
||||
}
|
||||
return C;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> LinAlg::matmult(std::vector<std::vector<double>> A, std::vector<std::vector<double>> B){
|
||||
std::vector<std::vector<double>> C;
|
||||
C.resize(A.size());
|
||||
for(int i = 0; i < C.size(); i++){
|
||||
C[i].resize(B[0].size());
|
||||
}
|
||||
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
for(int j = 0; j < B[0].size(); j++){
|
||||
for(int k = 0; k < B.size(); k++){
|
||||
C[i][j] += A[i][k] * B[k][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
return C;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> LinAlg::hadamard_product(std::vector<std::vector<double>> A, std::vector<std::vector<double>> B){
|
||||
std::vector<std::vector<double>> C;
|
||||
C.resize(A.size());
|
||||
for(int i = 0; i < C.size(); i++){
|
||||
C[i].resize(A[0].size());
|
||||
}
|
||||
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
for(int j = 0; j < A[0].size(); j++){
|
||||
C[i][j] = A[i][j] * B[i][j];
|
||||
}
|
||||
}
|
||||
return C;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> LinAlg::elementWiseDivision(std::vector<std::vector<double>> A, std::vector<std::vector<double>> B){
|
||||
std::vector<std::vector<double>> C;
|
||||
C.resize(A.size());
|
||||
for(int i = 0; i < C.size(); i++){
|
||||
C[i].resize(A[0].size());
|
||||
}
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
for(int j = 0; j < A[i].size(); j++){
|
||||
C[i][j] = A[i][j] / B[i][j];
|
||||
}
|
||||
}
|
||||
return C;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> LinAlg::transpose(std::vector<std::vector<double>> A){
|
||||
std::vector<std::vector<double>> AT;
|
||||
AT.resize(A[0].size());
|
||||
for(int i = 0; i < AT.size(); i++){
|
||||
AT[i].resize(A.size());
|
||||
}
|
||||
|
||||
for(int i = 0; i < A[0].size(); i++){
|
||||
for(int j = 0; j < A.size(); j++){
|
||||
AT[i][j] = A[j][i];
|
||||
}
|
||||
}
|
||||
return AT;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> LinAlg::scalarMultiply(double scalar, std::vector<std::vector<double>> A){
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
for(int j = 0; j < A[i].size(); j++){
|
||||
A[i][j] *= scalar;
|
||||
}
|
||||
}
|
||||
return A;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> LinAlg::scalarAdd(double scalar, std::vector<std::vector<double>> A){
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
for(int j = 0; j < A[i].size(); j++){
|
||||
A[i][j] += scalar;
|
||||
}
|
||||
}
|
||||
return A;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> LinAlg::log(std::vector<std::vector<double>> A){
|
||||
std::vector<std::vector<double>> B;
|
||||
B.resize(A.size());
|
||||
for(int i = 0; i < B.size(); i++){
|
||||
B[i].resize(A[0].size());
|
||||
}
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
for(int j = 0; j < A[i].size(); j++){
|
||||
B[i][j] = std::log(A[i][j]);
|
||||
}
|
||||
}
|
||||
return B;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> LinAlg::log10(std::vector<std::vector<double>> A){
|
||||
std::vector<std::vector<double>> B;
|
||||
B.resize(A.size());
|
||||
for(int i = 0; i < B.size(); i++){
|
||||
B[i].resize(A[0].size());
|
||||
}
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
for(int j = 0; j < A[i].size(); j++){
|
||||
B[i][j] = std::log10(A[i][j]);
|
||||
}
|
||||
}
|
||||
return B;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> LinAlg::exp(std::vector<std::vector<double>> A){
|
||||
std::vector<std::vector<double>> B;
|
||||
B.resize(A.size());
|
||||
for(int i = 0; i < B.size(); i++){
|
||||
B[i].resize(A[0].size());
|
||||
}
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
for(int j = 0; j < A[i].size(); j++){
|
||||
B[i][j] = std::exp(A[i][j]);
|
||||
}
|
||||
}
|
||||
return B;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> LinAlg::erf(std::vector<std::vector<double>> A){
|
||||
std::vector<std::vector<double>> B;
|
||||
B.resize(A.size());
|
||||
for(int i = 0; i < B.size(); i++){
|
||||
B[i].resize(A[0].size());
|
||||
}
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
for(int j = 0; j < A[i].size(); j++){
|
||||
B[i][j] = std::erf(A[i][j]);
|
||||
}
|
||||
}
|
||||
return B;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> LinAlg::exponentiate(std::vector<std::vector<double>> A, double p){
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
for(int j = 0; j < A[i].size(); j++){
|
||||
A[i][j] = pow(A[i][j], p);
|
||||
}
|
||||
}
|
||||
return A;
|
||||
}
|
||||
|
||||
double LinAlg::det(std::vector<std::vector<double>> A, int d){
|
||||
|
||||
double deter = 0;
|
||||
std::vector<std::vector<double>> B;
|
||||
B.resize(d);
|
||||
for(int i = 0; i < d; i++){
|
||||
B[i].resize(d);
|
||||
}
|
||||
|
||||
/* This is the base case in which the input is a 2x2 square matrix.
|
||||
Recursion is performed unless and until we reach this base case,
|
||||
such that we recieve a scalar as the result. */
|
||||
if(d == 2){
|
||||
return A[0][0] * A[1][1] - A[0][1] * A[1][0];
|
||||
}
|
||||
|
||||
else{
|
||||
for(int i = 0; i < d; i++){
|
||||
int sub_i = 0;
|
||||
for(int j = 1; j < d; j++){
|
||||
int sub_j = 0;
|
||||
for(int k = 0; k < d; k++){
|
||||
if(k == i){
|
||||
continue;
|
||||
}
|
||||
B[sub_i][sub_j] = A[j][k];
|
||||
sub_j++;
|
||||
}
|
||||
sub_i++;
|
||||
}
|
||||
deter += pow(-1, i) * A[0][i] * det(B, d-1);
|
||||
}
|
||||
}
|
||||
return deter;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> LinAlg::cofactor(std::vector<std::vector<double>> A, int n, int i, int j){
|
||||
std::vector<std::vector<double>> cof;
|
||||
cof.resize(A.size());
|
||||
for(int i = 0; i < cof.size(); i++){
|
||||
cof[i].resize(A.size());
|
||||
}
|
||||
int sub_i = 0, sub_j = 0;
|
||||
|
||||
for (int row = 0; row < n; row++){
|
||||
for (int col = 0; col < n; col++){
|
||||
if (row != i && col != j) {
|
||||
cof[sub_i][sub_j++] = A[row][col];
|
||||
|
||||
if (sub_j == n - 1){
|
||||
sub_j = 0;
|
||||
sub_i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return cof;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> LinAlg::adjoint(std::vector<std::vector<double>> A){
|
||||
|
||||
//Resizing the initial adjoint matrix
|
||||
std::vector<std::vector<double>> adj;
|
||||
adj.resize(A.size());
|
||||
for(int i = 0; i < adj.size(); i++){
|
||||
adj[i].resize(A.size());
|
||||
}
|
||||
|
||||
// Checking for the case where the given N x N matrix is a scalar
|
||||
if(A.size() == 1){
|
||||
adj[0][0] = 1;
|
||||
return adj;
|
||||
}
|
||||
|
||||
if(A.size() == 2){
|
||||
adj[0][0] = A[1][1];
|
||||
adj[1][1] = A[0][0];
|
||||
|
||||
adj[0][1] = -A[0][1];
|
||||
adj[1][0] = -A[1][0];
|
||||
return adj;
|
||||
}
|
||||
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
for(int j = 0; j < A.size(); j++){
|
||||
std::vector<std::vector<double>> cof = cofactor(A, int(A.size()), i, j);
|
||||
// 1 if even, -1 if odd
|
||||
int sign = (i + j) % 2 == 0 ? 1 : -1;
|
||||
adj[j][i] = sign * det(cof, int(A.size()) - 1);
|
||||
}
|
||||
}
|
||||
return adj;
|
||||
}
|
||||
|
||||
// The inverse can be computed as (1 / determinant(A)) * adjoint(A)
|
||||
std::vector<std::vector<double>> LinAlg::inverse(std::vector<std::vector<double>> A){
|
||||
return scalarMultiply(1/det(A, int(A.size())), adjoint(A));
|
||||
}
|
||||
|
||||
// This is simply the Moore-Penrose least squares approximation of the inverse.
|
||||
std::vector<std::vector<double>> LinAlg::pinverse(std::vector<std::vector<double>> A){
|
||||
return matmult(inverse(matmult(transpose(A), A)), transpose(A));
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> LinAlg::zeromat(int n, int m){
|
||||
std::vector<std::vector<double>> zeromat;
|
||||
zeromat.resize(n);
|
||||
for(int i = 0; i < zeromat.size(); i++){
|
||||
zeromat[i].resize(m);
|
||||
}
|
||||
return zeromat;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> LinAlg::onemat(int n, int m){
|
||||
std::vector<std::vector<double>> onemat;
|
||||
onemat.resize(n);
|
||||
for(int i = 0; i < onemat.size(); i++){
|
||||
onemat[i].resize(m);
|
||||
}
|
||||
for(int i = 0; i < onemat.size(); i++){
|
||||
for(int j = 0; j < onemat[i].size(); j++){
|
||||
onemat[i][j] = 1;
|
||||
}
|
||||
}
|
||||
return onemat;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> LinAlg::round(std::vector<std::vector<double>> A){
|
||||
std::vector<std::vector<double>> B;
|
||||
B.resize(A.size());
|
||||
for(int i = 0; i < B.size(); i++){
|
||||
B[i].resize(A[0].size());
|
||||
}
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
for(int j = 0; j < A[i].size(); j++){
|
||||
B[i][j] = std::round(A[i][j]);
|
||||
}
|
||||
}
|
||||
return B;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> LinAlg::identity(double d){
|
||||
std::vector<std::vector<double>> identityMat;
|
||||
identityMat.resize(d);
|
||||
for(int i = 0; i < identityMat.size(); i++){
|
||||
identityMat[i].resize(d);
|
||||
}
|
||||
for(int i = 0; i < identityMat.size(); i++){
|
||||
for(int j = 0; j < identityMat.size(); j++){
|
||||
if(i == j){
|
||||
identityMat[i][j] = 1;
|
||||
}
|
||||
else { identityMat[i][j] = 0; }
|
||||
}
|
||||
}
|
||||
return identityMat;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> LinAlg::cov(std::vector<std::vector<double>> A){
|
||||
Stat stat;
|
||||
std::vector<std::vector<double>> covMat;
|
||||
covMat.resize(A.size());
|
||||
for(int i = 0; i < covMat.size(); i++){
|
||||
covMat[i].resize(A.size());
|
||||
}
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
for(int j = 0; j < A.size(); j++){
|
||||
covMat[i][j] = stat.covariance(A[i], A[j]);
|
||||
}
|
||||
}
|
||||
return covMat;
|
||||
}
|
||||
|
||||
std::tuple<std::vector<std::vector<double>>, std::vector<std::vector<double>>> LinAlg::eig(std::vector<std::vector<double>> A){
|
||||
/*
|
||||
A (the entered parameter) in most use cases will be X'X, XX', etc. and must be symmetric.
|
||||
That simply means that 1) X' = X and 2) X is a square matrix. This function that computes the
|
||||
eigenvalues of a matrix is utilizing Jacobi's method.
|
||||
*/
|
||||
|
||||
double diagonal = true; // Perform the iterative Jacobi algorithm unless and until we reach a diagonal matrix which yields us the eigenvals.
|
||||
|
||||
std::map<int, int> val_to_vec;
|
||||
std::vector<std::vector<double>> a_new;
|
||||
std::vector<std::vector<double>> eigenvectors = identity(A.size());
|
||||
do{
|
||||
double a_ij = A[0][1];
|
||||
double sub_i = 0;
|
||||
double sub_j = 1;
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
for(int j = 0; j < A[i].size(); j++){
|
||||
if(i != j && abs(A[i][j]) > a_ij){
|
||||
a_ij = A[i][j];
|
||||
sub_i = i;
|
||||
sub_j = j;
|
||||
}
|
||||
else if(i != j && abs(A[i][j]) == a_ij){
|
||||
if(i < sub_i){
|
||||
a_ij = A[i][j];
|
||||
sub_i = i;
|
||||
sub_j = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double a_ii = A[sub_i][sub_i];
|
||||
double a_jj = A[sub_j][sub_j];
|
||||
double a_ji = A[sub_j][sub_i];
|
||||
double theta;
|
||||
|
||||
if(a_ii == a_jj) {
|
||||
theta = M_PI / 4;
|
||||
}
|
||||
else{
|
||||
theta = 0.5 * atan(2 * a_ij / (a_ii - a_jj));
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> P = identity(A.size());
|
||||
P[sub_i][sub_j] = -sin(theta);
|
||||
P[sub_i][sub_i] = cos(theta);
|
||||
P[sub_j][sub_j] = cos(theta);
|
||||
P[sub_j][sub_i] = sin(theta);
|
||||
|
||||
a_new = matmult(matmult(inverse(P), A), P);
|
||||
|
||||
for(int i = 0; i < a_new.size(); i++){
|
||||
for(int j = 0; j < a_new[i].size(); j++){
|
||||
if(i != j && std::round(a_new[i][j]) == 0){
|
||||
a_new[i][j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool non_zero = false;
|
||||
for(int i = 0; i < a_new.size(); i++){
|
||||
for(int j = 0; j < a_new[i].size(); j++){
|
||||
if(i != j && std::round(a_new[i][j]) != 0){
|
||||
non_zero = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(non_zero) {
|
||||
diagonal = false;
|
||||
}
|
||||
else{
|
||||
diagonal = true;
|
||||
}
|
||||
|
||||
if(a_new == A){
|
||||
diagonal = true;
|
||||
for(int i = 0; i < a_new.size(); i++){
|
||||
for(int j = 0; j < a_new[i].size(); j++){
|
||||
if(i != j){
|
||||
a_new[i][j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eigenvectors = matmult(eigenvectors, P);
|
||||
A = a_new;
|
||||
|
||||
} while(!diagonal);
|
||||
|
||||
std::vector<std::vector<double>> a_new_prior = a_new;
|
||||
|
||||
// Bubble Sort
|
||||
for(int i = 0; i < a_new.size() - 1; i++){
|
||||
for(int j = 0; j < a_new.size() - 1 - i; j++){
|
||||
if(a_new[j][j] < a_new[j + 1][j + 1]){
|
||||
double temp = a_new[j + 1][j + 1];
|
||||
a_new[j + 1][j + 1] = a_new[j][j];
|
||||
a_new[j][j] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for(int i = 0; i < a_new.size(); i++){
|
||||
for(int j = 0; j < a_new.size(); j++){
|
||||
if(a_new[i][i] == a_new_prior[j][j]){
|
||||
val_to_vec[i] = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> eigen_temp = eigenvectors;
|
||||
for(int i = 0; i < eigenvectors.size(); i++){
|
||||
for(int j = 0; j < eigenvectors[i].size(); j++){
|
||||
eigenvectors[i][j] = eigen_temp[i][val_to_vec[j]];
|
||||
}
|
||||
}
|
||||
return {eigenvectors, a_new};
|
||||
|
||||
}
|
||||
|
||||
std::tuple<std::vector<std::vector<double>>, std::vector<std::vector<double>>, std::vector<std::vector<double>>> LinAlg::SVD(std::vector<std::vector<double>> A){
|
||||
auto [left_eigenvecs, eigenvals] = eig(matmult(A, transpose(A)));
|
||||
auto [right_eigenvecs, right_eigenvals] = eig(matmult(transpose(A), A));
|
||||
|
||||
std::vector<std::vector<double>> singularvals = exponentiate(eigenvals, 0.5);
|
||||
std::vector<std::vector<double>> sigma = zeromat(A.size(), A[0].size());
|
||||
for(int i = 0; i < singularvals.size(); i++){
|
||||
for(int j = 0; j < singularvals[i].size(); j++){
|
||||
sigma[i][j] = singularvals[i][j];
|
||||
}
|
||||
}
|
||||
return {left_eigenvecs, sigma, right_eigenvecs};
|
||||
}
|
||||
|
||||
double LinAlg::sum_elements(std::vector<std::vector<double>> A){
|
||||
double sum = 0;
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
for(int j = 0; j < A[i].size(); j++){
|
||||
sum += A[i][j];
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
std::vector<double> LinAlg::flatten(std::vector<std::vector<double>> A){
|
||||
std::vector<double> a;
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
for(int j = 0; j < A[i].size(); j++){
|
||||
a.push_back(A[i][j]);
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
void LinAlg::printMatrix(std::vector<std::vector<double>> A){
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
for(int j = 0; j < A[i].size(); j++){
|
||||
std::cout << A[i][j] << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> LinAlg::vecmult(std::vector<double> a, std::vector<double> b){
|
||||
std::vector<std::vector<double>> C;
|
||||
C.resize(a.size());
|
||||
for(int i = 0; i < C.size(); i++){
|
||||
C[i] = scalarMultiply(a[i], b);
|
||||
}
|
||||
return C;
|
||||
}
|
||||
|
||||
std::vector<double> LinAlg::hadamard_product(std::vector<double> a, std::vector<double> b){
|
||||
std::vector<double> c;
|
||||
c.resize(a.size());
|
||||
|
||||
for(int i = 0; i < a.size(); i++){
|
||||
c[i] = a[i] * b[i];
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
std::vector<double> LinAlg::elementWiseDivision(std::vector<double> a, std::vector<double> b){
|
||||
std::vector<double> c;
|
||||
c.resize(a.size());
|
||||
|
||||
for(int i = 0; i < a.size(); i++){
|
||||
c[i] = a[i] / b[i];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
std::vector<double> LinAlg::scalarMultiply(double scalar, std::vector<double> a){
|
||||
for(int i = 0; i < a.size(); i++){
|
||||
a[i] *= scalar;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
std::vector<double> LinAlg::scalarAdd(double scalar, std::vector<double> a){
|
||||
for(int i = 0; i < a.size(); i++){
|
||||
a[i] += scalar;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
std::vector<double> LinAlg::addition(std::vector<double> a, std::vector<double> b){
|
||||
std::vector<double> c;
|
||||
c.resize(a.size());
|
||||
for(int i = 0; i < a.size(); i++){
|
||||
c[i] = a[i] + b[i];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
std::vector<double> LinAlg::subtraction(std::vector<double> a, std::vector<double> b){
|
||||
std::vector<double> c;
|
||||
c.resize(a.size());
|
||||
for(int i = 0; i < a.size(); i++){
|
||||
c[i] = a[i] - b[i];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
std::vector<double> LinAlg::subtractMatrixRows(std::vector<double> a, std::vector<std::vector<double>> B){
|
||||
for(int i = 0; i < B.size(); i++){
|
||||
a = subtraction(a, B[i]);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
std::vector<double> LinAlg::log(std::vector<double> a){
|
||||
std::vector<double> b;
|
||||
b.resize(a.size());
|
||||
for(int i = 0; i < a.size(); i++){
|
||||
b[i] = std::log(a[i]);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
std::vector<double> LinAlg::log10(std::vector<double> a){
|
||||
std::vector<double> b;
|
||||
b.resize(a.size());
|
||||
for(int i = 0; i < a.size(); i++){
|
||||
b[i] = std::log10(a[i]);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
std::vector<double> LinAlg::exp(std::vector<double> a){
|
||||
std::vector<double> b;
|
||||
b.resize(a.size());
|
||||
for(int i = 0; i < a.size(); i++){
|
||||
b[i] = std::exp(a[i]);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
std::vector<double> LinAlg::erf(std::vector<double> a){
|
||||
std::vector<double> b;
|
||||
b.resize(a.size());
|
||||
for(int i = 0; i < a.size(); i++){
|
||||
b[i] = std::erf(a[i]);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
double LinAlg::dot(std::vector<double> a, std::vector<double> b){
|
||||
double c = 0;
|
||||
for(int i = 0; i < a.size(); i++){
|
||||
c += a[i] * b[i];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
std::vector<double> LinAlg::onevec(int n){
|
||||
std::vector<double> onevec;
|
||||
onevec.resize(n);
|
||||
for(int i = 0; i < onevec.size(); i++){
|
||||
onevec[i] = 1;
|
||||
}
|
||||
return onevec;
|
||||
}
|
||||
|
||||
double LinAlg::max(std::vector<double> a){
|
||||
int max = a[0];
|
||||
for(int i = 0; i < a.size(); i++){
|
||||
if(a[i] > max){
|
||||
max = a[i];
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
double LinAlg::min(std::vector<double> a){
|
||||
int min = a[0];
|
||||
for(int i = 0; i < a.size(); i++){
|
||||
if(a[i] < min){
|
||||
min = a[i];
|
||||
}
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
std::vector<double> LinAlg::round(std::vector<double> a){
|
||||
std::vector<double> b;
|
||||
b.resize(a.size());
|
||||
for(int i = 0; i < a.size(); i++){
|
||||
b[i] = std::round(a[i]);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
double LinAlg::norm_sq(std::vector<double> a){
|
||||
double n_sq = 0;
|
||||
for(int i = 0; i < a.size(); i++){
|
||||
n_sq += a[i] * a[i];
|
||||
}
|
||||
return n_sq;
|
||||
}
|
||||
|
||||
double LinAlg::sum_elements(std::vector<double> a){
|
||||
double sum = 0;
|
||||
for(int i = 0; i < a.size(); i++){
|
||||
sum += a[i];
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
double LinAlg::cosineSimilarity(std::vector<double> a, std::vector<double> b){
|
||||
return dot(a, b) / (sqrt(norm_sq(a)) * sqrt(norm_sq(b)));
|
||||
}
|
||||
|
||||
void LinAlg::printVector(std::vector<double> a){
|
||||
for(int i = 0; i < a.size(); i++){
|
||||
std::cout << a[i] << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> LinAlg::mat_vec_add(std::vector<std::vector<double>> A, std::vector<double> b){
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
for(int j = 0; j < A[i].size(); j++){
|
||||
A[i][j] += b[j];
|
||||
}
|
||||
}
|
||||
return A;
|
||||
}
|
||||
|
||||
std::vector<double> LinAlg::mat_vec_mult(std::vector<std::vector<double>> A, std::vector<double> b){
|
||||
std::vector<double> c;
|
||||
c.resize(A.size());
|
||||
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
for(int k = 0; k < b.size(); k++){
|
||||
c[i] += A[i][k] * b[k];
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
std::vector<double> LinAlg::flatten(std::vector<std::vector<std::vector<double>>> A){
|
||||
std::vector<double> c;
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
std::vector<double> flattenedVec = flatten(A[i]);
|
||||
c.insert(c.end(), flattenedVec.begin(), flattenedVec.end());
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
void LinAlg::printTensor(std::vector<std::vector<std::vector<double>>> A){
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
printMatrix(A[i]);
|
||||
if(i != A.size() - 1) { std::cout << std::endl; }
|
||||
}
|
||||
}
|
||||
}
|
136
MLPP/LinAlg/LinAlg.hpp
Normal file
136
MLPP/LinAlg/LinAlg.hpp
Normal file
@ -0,0 +1,136 @@
|
||||
//
|
||||
// LinAlg.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 1/8/21.
|
||||
//
|
||||
|
||||
#ifndef LinAlg_hpp
|
||||
#define LinAlg_hpp
|
||||
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
||||
namespace MLPP{
|
||||
class LinAlg{
|
||||
public:
|
||||
|
||||
// MATRIX FUNCTIONS
|
||||
|
||||
std::vector<std::vector<double>> addition(std::vector<std::vector<double>> A, std::vector<std::vector<double>> B);
|
||||
|
||||
std::vector<std::vector<double>> subtraction(std::vector<std::vector<double>> A, std::vector<std::vector<double>> B);
|
||||
|
||||
std::vector<std::vector<double>> matmult(std::vector<std::vector<double>> A, std::vector<std::vector<double>> B);
|
||||
|
||||
std::vector<std::vector<double>> hadamard_product(std::vector<std::vector<double>> A, std::vector<std::vector<double>> B);
|
||||
|
||||
std::vector<std::vector<double>> kronecker_product(std::vector<std::vector<double>> A, std::vector<std::vector<double>> B);
|
||||
|
||||
std::vector<std::vector<double>> elementWiseDivision(std::vector<std::vector<double>> A, std::vector<std::vector<double>> B);
|
||||
|
||||
std::vector<std::vector<double>> transpose(std::vector<std::vector<double>> A);
|
||||
|
||||
std::vector<std::vector<double>> scalarMultiply(double scalar, std::vector<std::vector<double>> A);
|
||||
|
||||
std::vector<std::vector<double>> scalarAdd(double scalar, std::vector<std::vector<double>> A);
|
||||
|
||||
std::vector<std::vector<double>> log(std::vector<std::vector<double>> A);
|
||||
|
||||
std::vector<std::vector<double>> log10(std::vector<std::vector<double>> A);
|
||||
|
||||
std::vector<std::vector<double>> exp(std::vector<std::vector<double>> A);
|
||||
|
||||
std::vector<std::vector<double>> erf(std::vector<std::vector<double>> A);
|
||||
|
||||
std::vector<std::vector<double>> exponentiate(std::vector<std::vector<double>> A, double p);
|
||||
|
||||
double det(std::vector<std::vector<double>> A, int d);
|
||||
|
||||
std::vector<std::vector<double>> cofactor(std::vector<std::vector<double>> A, int n, int i, int j);
|
||||
|
||||
std::vector<std::vector<double>> adjoint(std::vector<std::vector<double>> A);
|
||||
|
||||
std::vector<std::vector<double>> inverse(std::vector<std::vector<double>> A);
|
||||
|
||||
std::vector<std::vector<double>> pinverse(std::vector<std::vector<double>> A);
|
||||
|
||||
std::vector<std::vector<double>> zeromat(int n, int m);
|
||||
|
||||
std::vector<std::vector<double>> onemat(int n, int m);
|
||||
|
||||
std::vector<std::vector<double>> round(std::vector<std::vector<double>> A);
|
||||
|
||||
std::vector<std::vector<double>> identity(double d);
|
||||
|
||||
std::vector<std::vector<double>> cov(std::vector<std::vector<double>> A);
|
||||
|
||||
std::tuple<std::vector<std::vector<double>>, std::vector<std::vector<double>>> eig(std::vector<std::vector<double>> A);
|
||||
|
||||
std::tuple<std::vector<std::vector<double>>, std::vector<std::vector<double>>, std::vector<std::vector<double>>> SVD(std::vector<std::vector<double>> A);
|
||||
|
||||
double sum_elements(std::vector<std::vector<double>> A);
|
||||
|
||||
std::vector<double> flatten(std::vector<std::vector<double>> A);
|
||||
|
||||
void printMatrix(std::vector<std::vector<double>> A);
|
||||
|
||||
// VECTOR FUNCTIONS
|
||||
|
||||
std::vector<std::vector<double>> vecmult(std::vector<double> a, std::vector<double> b); // This multiplies a, bT
|
||||
|
||||
std::vector<double> hadamard_product(std::vector<double> a, std::vector<double> b);
|
||||
|
||||
std::vector<double> elementWiseDivision(std::vector<double> a, std::vector<double> b);
|
||||
|
||||
std::vector<double> scalarMultiply(double scalar, std::vector<double> a);
|
||||
|
||||
std::vector<double> scalarAdd(double scalar, std::vector<double> a);
|
||||
|
||||
std::vector<double> addition(std::vector<double> a, std::vector<double> b);
|
||||
|
||||
std::vector<double> subtraction(std::vector<double> a, std::vector<double> b);
|
||||
|
||||
std::vector<double> subtractMatrixRows(std::vector<double> a, std::vector<std::vector<double>> B);
|
||||
|
||||
std::vector<double> log(std::vector<double> a);
|
||||
|
||||
std::vector<double> log10(std::vector<double> a);
|
||||
|
||||
std::vector<double> exp(std::vector<double> a);
|
||||
|
||||
std::vector<double> erf(std::vector<double> a);
|
||||
|
||||
double dot(std::vector<double> a, std::vector<double> b);
|
||||
|
||||
std::vector<double> onevec(int n);
|
||||
|
||||
double max(std::vector<double> a);
|
||||
|
||||
double min(std::vector<double> a);
|
||||
|
||||
std::vector<double> round(std::vector<double> a);
|
||||
|
||||
double norm_sq(std::vector<double> a);
|
||||
|
||||
double sum_elements(std::vector<double> a);
|
||||
|
||||
double cosineSimilarity(std::vector<double> a, std::vector<double> b);
|
||||
|
||||
void printVector(std::vector<double> a);
|
||||
|
||||
// MATRIX-VECTOR FUNCTIONS
|
||||
std::vector<std::vector<double>> mat_vec_add(std::vector<std::vector<double>> A, std::vector<double> b);
|
||||
|
||||
std::vector<double> mat_vec_mult(std::vector<std::vector<double>> A, std::vector<double> b);
|
||||
|
||||
// TENSOR FUNCTIONS
|
||||
std::vector<double> flatten(std::vector<std::vector<std::vector<double>>> A);
|
||||
void printTensor(std::vector<std::vector<std::vector<double>>> A);
|
||||
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* LinAlg_hpp */
|
232
MLPP/LinReg/LinReg.cpp
Normal file
232
MLPP/LinReg/LinReg.cpp
Normal file
@ -0,0 +1,232 @@
|
||||
//
|
||||
// LinReg.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 10/2/20.
|
||||
//
|
||||
|
||||
#include "LinReg.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
#include "Stat/Stat.hpp"
|
||||
#include "Regularization/Reg.hpp"
|
||||
#include "Utilities/Utilities.hpp"
|
||||
#include "Cost/Cost.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <random>
|
||||
|
||||
namespace MLPP{
|
||||
|
||||
LinReg::LinReg(std::vector<std::vector<double>> inputSet, std::vector<double> 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)
|
||||
{
|
||||
y_hat.resize(n);
|
||||
|
||||
weights = Utilities::weightInitialization(k);
|
||||
bias = Utilities::biasInitialization();
|
||||
}
|
||||
|
||||
std::vector<double> LinReg::modelSetTest(std::vector<std::vector<double>> X){
|
||||
return Evaluate(X);
|
||||
}
|
||||
|
||||
double LinReg::modelTest(std::vector<double> x){
|
||||
return Evaluate(x);
|
||||
}
|
||||
|
||||
void LinReg::gradientDescent(double learning_rate, int max_epoch, bool UI){
|
||||
Reg regularization;
|
||||
LinAlg alg;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
forwardPass();
|
||||
|
||||
while(true){
|
||||
cost_prev = Cost(y_hat, outputSet);
|
||||
|
||||
std::vector<double> error = alg.subtraction(y_hat, outputSet);
|
||||
|
||||
// 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;
|
||||
forwardPass();
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputSet));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
epoch++;
|
||||
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
}
|
||||
|
||||
void LinReg::SGD(double learning_rate, int max_epoch, bool UI){
|
||||
Reg regularization;
|
||||
Utilities util;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
|
||||
while(true){
|
||||
std::random_device rd;
|
||||
std::default_random_engine generator(rd());
|
||||
std::uniform_int_distribution<int> distribution(0, int(n - 1));
|
||||
int outputIndex = distribution(generator);
|
||||
|
||||
double y_hat = Evaluate(inputSet[outputIndex]);
|
||||
cost_prev = Cost({y_hat}, {outputSet[outputIndex]});
|
||||
|
||||
|
||||
for(int i = 0; i < k; i++){
|
||||
|
||||
// Calculating the weight gradients
|
||||
|
||||
double w_gradient = (y_hat - outputSet[outputIndex]) * inputSet[outputIndex][i];
|
||||
|
||||
|
||||
// Weight updation
|
||||
weights[i] -= learning_rate * w_gradient;
|
||||
}
|
||||
weights = regularization.regWeights(weights, lambda, alpha, reg);
|
||||
|
||||
// Calculating the bias gradients
|
||||
double b_gradient = (y_hat - outputSet[outputIndex]);
|
||||
|
||||
// Bias updation
|
||||
bias -= learning_rate * b_gradient;
|
||||
y_hat = Evaluate({inputSet[outputIndex]});
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost({y_hat}, {outputSet[outputIndex]}));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
epoch++;
|
||||
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
forwardPass();
|
||||
}
|
||||
|
||||
void LinReg::MBGD(double learning_rate, int max_epoch, int miniBatch_size, bool UI){
|
||||
Reg regularization;
|
||||
LinAlg alg;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
|
||||
int n_miniBatch = n/miniBatch_size;
|
||||
|
||||
std::vector<std::vector<std::vector<double>>> inputMiniBatches;
|
||||
std::vector<std::vector<double>> outputMiniBatches;
|
||||
// Creating the mini-batches
|
||||
for(int i = 0; i < n_miniBatch; i++){
|
||||
std::vector<std::vector<double>> currentInputSet;
|
||||
std::vector<double> currentOutputSet;
|
||||
for(int j = 0; j < n/n_miniBatch; j++){
|
||||
currentInputSet.push_back(inputSet[n/n_miniBatch * i + j]);
|
||||
currentOutputSet.push_back(outputSet[n/n_miniBatch * i + j]);
|
||||
}
|
||||
inputMiniBatches.push_back(currentInputSet);
|
||||
outputMiniBatches.push_back(currentOutputSet);
|
||||
}
|
||||
|
||||
if(double(n)/double(n_miniBatch) - int(n/n_miniBatch) != 0){
|
||||
for(int i = 0; i < n - n/n_miniBatch * n_miniBatch; i++){
|
||||
inputMiniBatches[n_miniBatch - 1].push_back(inputSet[n/n_miniBatch * n_miniBatch + i]);
|
||||
outputMiniBatches[n_miniBatch - 1].push_back(outputSet[n/n_miniBatch * n_miniBatch + i]);
|
||||
}
|
||||
}
|
||||
|
||||
while(true){
|
||||
for(int i = 0; i < n_miniBatch; i++){
|
||||
std::vector<double> y_hat = Evaluate(inputMiniBatches[i]);
|
||||
cost_prev = Cost(y_hat, outputMiniBatches[i]);
|
||||
|
||||
std::vector<double> error = alg.subtraction(y_hat, outputMiniBatches[i]);
|
||||
|
||||
// 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);
|
||||
|
||||
// Calculating the bias gradients
|
||||
bias -= learning_rate * alg.sum_elements(error) / outputMiniBatches[i].size();
|
||||
y_hat = Evaluate(inputMiniBatches[i]);
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputMiniBatches[i]));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
}
|
||||
epoch++;
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
forwardPass();
|
||||
}
|
||||
|
||||
void LinReg::normalEquation(){
|
||||
LinAlg alg;
|
||||
Stat stat;
|
||||
std::vector<double> x_means;
|
||||
|
||||
x_means.resize(alg.transpose(inputSet).size());
|
||||
for(int i = 0; i < alg.transpose(inputSet).size(); i++){
|
||||
x_means[i] = (stat.mean(alg.transpose(inputSet)[i]));
|
||||
}
|
||||
|
||||
try{
|
||||
std::vector<double> temp;
|
||||
temp.resize(k);
|
||||
temp = alg.mat_vec_mult(alg.inverse(alg.matmult(alg.transpose(inputSet), inputSet)), alg.mat_vec_mult(alg.transpose(inputSet), outputSet));
|
||||
if(isnan(temp[0])){
|
||||
throw 99;
|
||||
}
|
||||
else{
|
||||
if(reg == "Ridge") {
|
||||
weights = alg.mat_vec_mult(alg.inverse(alg.addition(alg.matmult(alg.transpose(inputSet), inputSet), alg.scalarMultiply(lambda, alg.identity(k)))), alg.mat_vec_mult(alg.transpose(inputSet), outputSet));
|
||||
}
|
||||
else{ weights = alg.mat_vec_mult(alg.inverse(alg.matmult(alg.transpose(inputSet), inputSet)), alg.mat_vec_mult(alg.transpose(inputSet), outputSet)); }
|
||||
|
||||
bias = stat.mean(outputSet) - alg.dot(weights, x_means);
|
||||
|
||||
forwardPass();
|
||||
}
|
||||
}
|
||||
catch(int err_num){
|
||||
std::cout << "ERR " << err_num << ": Resulting matrix was noninvertible/degenerate, and so the normal equation could not be performed. Try utilizing gradient descent." << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
double LinReg::score(){
|
||||
Utilities util;
|
||||
return util.performance(y_hat, outputSet);
|
||||
}
|
||||
|
||||
void LinReg::save(std::string fileName){
|
||||
Utilities util;
|
||||
util.saveParameters(fileName, weights, bias);
|
||||
}
|
||||
|
||||
double LinReg::Cost(std::vector <double> y_hat, std::vector<double> y){
|
||||
Reg regularization;
|
||||
class Cost cost;
|
||||
return cost.MSE(y_hat, y) + regularization.regTerm(weights, lambda, alpha, reg);
|
||||
}
|
||||
|
||||
std::vector<double> LinReg::Evaluate(std::vector<std::vector<double>> X){
|
||||
LinAlg alg;
|
||||
return alg.scalarAdd(bias, alg.mat_vec_mult(X, weights));
|
||||
}
|
||||
|
||||
double LinReg::Evaluate(std::vector<double> x){
|
||||
LinAlg alg;
|
||||
return alg.dot(weights, x) + bias;
|
||||
}
|
||||
|
||||
// wTx + b
|
||||
void LinReg::forwardPass(){
|
||||
y_hat = Evaluate(inputSet);
|
||||
}
|
||||
}
|
52
MLPP/LinReg/LinReg.hpp
Normal file
52
MLPP/LinReg/LinReg.hpp
Normal file
@ -0,0 +1,52 @@
|
||||
//
|
||||
// LinReg.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 10/2/20.
|
||||
//
|
||||
|
||||
#ifndef LinReg_hpp
|
||||
#define LinReg_hpp
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace MLPP{
|
||||
class LinReg{
|
||||
|
||||
public:
|
||||
LinReg(std::vector<std::vector<double>> inputSet, std::vector<double> outputSet, std::string reg = "None", double lambda = 0.5, double alpha = 0.5);
|
||||
std::vector<double> modelSetTest(std::vector<std::vector<double>> X);
|
||||
double modelTest(std::vector<double> x);
|
||||
void gradientDescent(double learning_rate, int max_epoch, bool UI = 1);
|
||||
void SGD(double learning_rate, int max_epoch, bool UI = 1);
|
||||
void MBGD(double learning_rate, int max_epoch, int miniBatch_size, bool UI = 1);
|
||||
void normalEquation();
|
||||
double score();
|
||||
void save(std::string fileName);
|
||||
private:
|
||||
|
||||
double Cost(std::vector <double> y_hat, std::vector<double> y);
|
||||
|
||||
std::vector<double> Evaluate(std::vector<std::vector<double>> X);
|
||||
double Evaluate(std::vector<double> x);
|
||||
void forwardPass();
|
||||
|
||||
std::vector<std::vector<double>> inputSet;
|
||||
std::vector<double> outputSet;
|
||||
std::vector<double> y_hat;
|
||||
std::vector<double> weights;
|
||||
double bias;
|
||||
|
||||
int n;
|
||||
int k;
|
||||
|
||||
// Regularization Params
|
||||
std::string reg;
|
||||
int lambda;
|
||||
int alpha; /* This is the controlling param for Elastic Net*/
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* LinReg_hpp */
|
229
MLPP/LogReg/LogReg.cpp
Normal file
229
MLPP/LogReg/LogReg.cpp
Normal file
@ -0,0 +1,229 @@
|
||||
//
|
||||
// LogReg.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 10/2/20.
|
||||
//
|
||||
|
||||
#include "LogReg.hpp"
|
||||
#include "Activation/Activation.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
#include "Regularization/Reg.hpp"
|
||||
#include "Utilities/Utilities.hpp"
|
||||
#include "Cost/Cost.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
namespace MLPP{
|
||||
LogReg::LogReg(std::vector<std::vector<double>> inputSet, std::vector<double> 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)
|
||||
{
|
||||
y_hat.resize(n);
|
||||
weights = Utilities::weightInitialization(k);
|
||||
bias = Utilities::biasInitialization();
|
||||
}
|
||||
|
||||
std::vector<double> LogReg::modelSetTest(std::vector<std::vector<double>> X){
|
||||
return Evaluate(X);
|
||||
}
|
||||
|
||||
double LogReg::modelTest(std::vector<double> x){
|
||||
return Evaluate(x);
|
||||
}
|
||||
|
||||
void LogReg::gradientDescent(double learning_rate, int max_epoch, bool UI){
|
||||
Reg regularization;
|
||||
LinAlg alg;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
forwardPass();
|
||||
|
||||
while(true){
|
||||
cost_prev = Cost(y_hat, outputSet);
|
||||
|
||||
std::vector<double> error = alg.subtraction(y_hat, outputSet);
|
||||
|
||||
// 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;
|
||||
forwardPass();
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputSet));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
epoch++;
|
||||
|
||||
if(epoch > max_epoch) { break; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void LogReg::MLE(double learning_rate, int max_epoch, bool UI){
|
||||
Reg regularization;
|
||||
LinAlg alg;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
forwardPass();
|
||||
|
||||
while(true){
|
||||
cost_prev = Cost(y_hat, outputSet);
|
||||
|
||||
std::vector<double> error = alg.subtraction(outputSet, y_hat);
|
||||
|
||||
// Calculating the weight gradients
|
||||
weights = alg.addition(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;
|
||||
forwardPass();
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputSet));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
epoch++;
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
}
|
||||
|
||||
void LogReg::SGD(double learning_rate, int max_epoch, bool UI){
|
||||
Reg regularization;
|
||||
Utilities util;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
|
||||
while(true){
|
||||
std::random_device rd;
|
||||
std::default_random_engine generator(rd());
|
||||
std::uniform_int_distribution<int> distribution(0, int(n - 1));
|
||||
int outputIndex = distribution(generator);
|
||||
|
||||
double y_hat = Evaluate(inputSet[outputIndex]);
|
||||
cost_prev = Cost({y_hat}, {outputSet[outputIndex]});
|
||||
|
||||
|
||||
for(int i = 0; i < k; i++){
|
||||
|
||||
// Calculating the weight gradients
|
||||
|
||||
double w_gradient = (y_hat - outputSet[outputIndex]) * inputSet[outputIndex][i];
|
||||
|
||||
|
||||
// Weight updation
|
||||
weights[i] -= learning_rate * w_gradient;
|
||||
}
|
||||
weights = regularization.regWeights(weights, lambda, alpha, reg);
|
||||
|
||||
// Calculating the bias gradients
|
||||
double b_gradient = (y_hat - outputSet[outputIndex]);
|
||||
|
||||
// Bias updation
|
||||
bias -= learning_rate * b_gradient;
|
||||
y_hat = Evaluate({inputSet[outputIndex]});
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost({y_hat}, {outputSet[outputIndex]}));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
epoch++;
|
||||
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
forwardPass();
|
||||
}
|
||||
|
||||
void LogReg::MBGD(double learning_rate, int max_epoch, int miniBatch_size, bool UI){
|
||||
Reg regularization;
|
||||
LinAlg alg;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
|
||||
int n_miniBatch = n/miniBatch_size;
|
||||
|
||||
std::vector<std::vector<std::vector<double>>> inputMiniBatches;
|
||||
std::vector<std::vector<double>> outputMiniBatches;
|
||||
|
||||
// Creating the mini-batches
|
||||
for(int i = 0; i < n_miniBatch; i++){
|
||||
std::vector<std::vector<double>> currentInputSet;
|
||||
std::vector<double> currentOutputSet;
|
||||
for(int j = 0; j < n/n_miniBatch; j++){
|
||||
currentInputSet.push_back(inputSet[n/n_miniBatch * i + j]);
|
||||
currentOutputSet.push_back(outputSet[n/n_miniBatch * i + j]);
|
||||
}
|
||||
inputMiniBatches.push_back(currentInputSet);
|
||||
outputMiniBatches.push_back(currentOutputSet);
|
||||
}
|
||||
|
||||
if(double(n)/double(n_miniBatch) - int(n/n_miniBatch) != 0){
|
||||
for(int i = 0; i < n - n/n_miniBatch * n_miniBatch; i++){
|
||||
inputMiniBatches[n_miniBatch - 1].push_back(inputSet[n/n_miniBatch * n_miniBatch + i]);
|
||||
outputMiniBatches[n_miniBatch - 1].push_back(outputSet[n/n_miniBatch * n_miniBatch + i]);
|
||||
}
|
||||
}
|
||||
|
||||
while(true){
|
||||
for(int i = 0; i < n_miniBatch; i++){
|
||||
std::vector<double> y_hat = Evaluate(inputMiniBatches[i]);
|
||||
cost_prev = Cost(y_hat, outputMiniBatches[i]);
|
||||
|
||||
std::vector<double> error = alg.subtraction(y_hat, outputMiniBatches[i]);
|
||||
|
||||
// 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);
|
||||
|
||||
// Calculating the bias gradients
|
||||
bias -= learning_rate * alg.sum_elements(error) / outputMiniBatches[i].size();
|
||||
y_hat = Evaluate(inputMiniBatches[i]);
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputMiniBatches[i]));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
}
|
||||
epoch++;
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
forwardPass();
|
||||
}
|
||||
|
||||
double LogReg::score(){
|
||||
Utilities util;
|
||||
return util.performance(y_hat, outputSet);
|
||||
}
|
||||
|
||||
void LogReg::save(std::string fileName){
|
||||
Utilities util;
|
||||
util.saveParameters(fileName, weights, bias);
|
||||
}
|
||||
|
||||
double LogReg::Cost(std::vector <double> y_hat, std::vector<double> y){
|
||||
Reg regularization;
|
||||
class Cost cost;
|
||||
return cost.LogLoss(y_hat, y) + regularization.regTerm(weights, lambda, alpha, reg);
|
||||
}
|
||||
|
||||
|
||||
std::vector<double> LogReg::Evaluate(std::vector<std::vector<double>> X){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
return avn.sigmoid(alg.scalarAdd(bias, alg.mat_vec_mult(X, weights)));
|
||||
}
|
||||
|
||||
double LogReg::Evaluate(std::vector<double> x){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
return avn.sigmoid(alg.dot(weights, x) + bias);
|
||||
}
|
||||
|
||||
// sigmoid ( wTx + b )
|
||||
void LogReg::forwardPass(){
|
||||
y_hat = Evaluate(inputSet);
|
||||
}
|
||||
}
|
53
MLPP/LogReg/LogReg.hpp
Normal file
53
MLPP/LogReg/LogReg.hpp
Normal file
@ -0,0 +1,53 @@
|
||||
//
|
||||
// LogReg.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 10/2/20.
|
||||
//
|
||||
|
||||
#ifndef LogReg_hpp
|
||||
#define LogReg_hpp
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace MLPP {
|
||||
|
||||
class LogReg{
|
||||
|
||||
public:
|
||||
LogReg(std::vector<std::vector<double>> inputSet, std::vector<double> outputSet, std::string reg = "None", double lambda = 0.5, double alpha = 0.5);
|
||||
std::vector<double> modelSetTest(std::vector<std::vector<double>> X);
|
||||
double modelTest(std::vector<double> x);
|
||||
void gradientDescent(double learning_rate, int max_epoch, bool UI = 1);
|
||||
void MLE(double learning_rate, int max_epoch, bool UI = 1);
|
||||
void SGD(double learning_rate, int max_epoch, bool UI = 1);
|
||||
void MBGD(double learning_rate, int max_epoch, int miniBatch_size, bool UI = 1);
|
||||
double score();
|
||||
void save(std::string fileName);
|
||||
private:
|
||||
|
||||
double Cost(std::vector <double> y_hat, std::vector<double> y);
|
||||
|
||||
std::vector<double> Evaluate(std::vector<std::vector<double>> X);
|
||||
double Evaluate(std::vector<double> x);
|
||||
void forwardPass();
|
||||
|
||||
std::vector<std::vector<double>> inputSet;
|
||||
std::vector<double> outputSet;
|
||||
std::vector<double> y_hat;
|
||||
std::vector<double> weights;
|
||||
double bias;
|
||||
|
||||
int n;
|
||||
int k;
|
||||
double learning_rate;
|
||||
|
||||
// Regularization Params
|
||||
std::string reg;
|
||||
double lambda; /* Regularization Parameter */
|
||||
double alpha; /* This is the controlling param for Elastic Net*/
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* LogReg_hpp */
|
292
MLPP/MLP/MLP.cpp
Normal file
292
MLPP/MLP/MLP.cpp
Normal file
@ -0,0 +1,292 @@
|
||||
//
|
||||
// MLP.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 11/4/20.
|
||||
//
|
||||
|
||||
#include "MLP.hpp"
|
||||
#include "Activation/Activation.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
#include "Regularization/Reg.hpp"
|
||||
#include "Utilities/Utilities.hpp"
|
||||
#include "Cost/Cost.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
namespace MLPP {
|
||||
MLP::MLP(std::vector<std::vector<double>> inputSet, std::vector<double> outputSet, int n_hidden, std::string reg, double lambda, double alpha)
|
||||
: inputSet(inputSet), outputSet(outputSet), n_hidden(n_hidden), n(inputSet.size()), k(inputSet[0].size()), reg(reg), lambda(lambda), alpha(alpha)
|
||||
{
|
||||
Activation avn;
|
||||
y_hat.resize(n);
|
||||
|
||||
weights1 = Utilities::weightInitialization(k, n_hidden);
|
||||
weights2 = Utilities::weightInitialization(n_hidden);
|
||||
bias1 = Utilities::biasInitialization(n_hidden);
|
||||
bias2 = Utilities::biasInitialization();
|
||||
}
|
||||
|
||||
std::vector<double> MLP::modelSetTest(std::vector<std::vector<double>> X){
|
||||
return Evaluate(X);
|
||||
}
|
||||
|
||||
double MLP::modelTest(std::vector<double> x){
|
||||
return Evaluate(x);
|
||||
}
|
||||
|
||||
void MLP::gradientDescent(double learning_rate, int max_epoch, bool UI){
|
||||
Reg regularization;
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
forwardPass();
|
||||
|
||||
while(true){
|
||||
cost_prev = Cost(y_hat, outputSet);
|
||||
|
||||
// Calculating the errors
|
||||
std::vector<double> error = alg.subtraction(y_hat, outputSet);
|
||||
|
||||
// Calculating the weight/bias gradients for layer 2
|
||||
|
||||
std::vector<double> D2_1 = alg.mat_vec_mult(alg.transpose(a2), error);
|
||||
|
||||
// weights and bias updation for layer 2
|
||||
weights2 = alg.subtraction(weights2, alg.scalarMultiply(learning_rate/n, D2_1));
|
||||
weights2 = regularization.regWeights(weights2, lambda, alpha, reg);
|
||||
|
||||
bias2 -= learning_rate * alg.sum_elements(error) / n;
|
||||
|
||||
//Calculating the weight/bias for layer 1
|
||||
|
||||
std::vector<std::vector<double>> D1_1;
|
||||
D1_1.resize(n);
|
||||
|
||||
D1_1 = alg.vecmult(error, weights2);
|
||||
|
||||
std::vector<std::vector<double>> D1_2 = alg.hadamard_product(D1_1, avn.sigmoid(z2, 1));
|
||||
|
||||
std::vector<std::vector<double>> D1_3 = alg.matmult(alg.transpose(inputSet), D1_2);
|
||||
|
||||
|
||||
// weight an bias updation for layer 1
|
||||
weights1 = alg.subtraction(weights1, alg.scalarMultiply(learning_rate/n, D1_3));
|
||||
weights1 = regularization.regWeights(weights1, lambda, alpha, reg);
|
||||
|
||||
bias1 = alg.subtractMatrixRows(bias1, alg.scalarMultiply(learning_rate/n, D1_2));
|
||||
|
||||
forwardPass();
|
||||
|
||||
// UI PORTION
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputSet));
|
||||
std::cout << "Layer 1:" << std::endl;
|
||||
Utilities::UI(weights1, bias1);
|
||||
std::cout << "Layer 2:" << std::endl;
|
||||
Utilities::UI(weights2, bias2);
|
||||
}
|
||||
epoch++;
|
||||
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MLP::SGD(double learning_rate, int max_epoch, bool UI){
|
||||
Reg regularization;
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
Utilities util;
|
||||
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
while(true){
|
||||
std::random_device rd;
|
||||
std::default_random_engine generator(rd());
|
||||
std::uniform_int_distribution<int> distribution(0, int(n - 1));
|
||||
int outputIndex = distribution(generator);
|
||||
|
||||
double y_hat = Evaluate(inputSet[outputIndex]);
|
||||
auto [z2, a2] = propagate(inputSet[outputIndex]);
|
||||
cost_prev = Cost({y_hat}, {outputSet[outputIndex]});
|
||||
double error = y_hat - outputSet[outputIndex];
|
||||
|
||||
// Weight updation for layer 2
|
||||
std::vector<double> D2_1 = alg.scalarMultiply(error, a2);
|
||||
weights2 = alg.subtraction(weights2, alg.scalarMultiply(learning_rate, D2_1));
|
||||
weights2 = regularization.regWeights(weights2, lambda, alpha, reg);
|
||||
|
||||
// Bias updation for layer 2
|
||||
bias2 -= learning_rate * error;
|
||||
|
||||
// Weight updation for layer 1
|
||||
std::vector<double> D1_1 = alg.scalarMultiply(error, weights2);
|
||||
std::vector<double> D1_2 = alg.hadamard_product(D1_1, avn.sigmoid(z2, 1));
|
||||
std::vector<std::vector<double>> D1_3 = alg.vecmult(inputSet[outputIndex], D1_2);
|
||||
|
||||
weights1 = alg.subtraction(weights1, alg.scalarMultiply(learning_rate, D1_3));
|
||||
weights1 = regularization.regWeights(weights1, lambda, alpha, reg);
|
||||
// Bias updation for layer 1
|
||||
|
||||
bias1 = alg.subtraction(bias1, alg.scalarMultiply(learning_rate, D1_2));
|
||||
|
||||
y_hat = Evaluate(inputSet[outputIndex]);
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost({y_hat}, {outputSet[outputIndex]}));
|
||||
std::cout << "Layer 1:" << std::endl;
|
||||
Utilities::UI(weights1, bias1);
|
||||
std::cout << "Layer 2:" << std::endl;
|
||||
Utilities::UI(weights2, bias2);
|
||||
}
|
||||
epoch++;
|
||||
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
forwardPass();
|
||||
}
|
||||
|
||||
void MLP::MBGD(double learning_rate, int max_epoch, int miniBatch_size, bool UI){
|
||||
Reg regularization;
|
||||
Activation avn;
|
||||
LinAlg alg;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
|
||||
int n_miniBatch = n/miniBatch_size;
|
||||
|
||||
std::vector<std::vector<std::vector<double>>> inputMiniBatches;
|
||||
std::vector<std::vector<double>> outputMiniBatches;
|
||||
|
||||
// Creating the mini-batches
|
||||
for(int i = 0; i < n_miniBatch; i++){
|
||||
std::vector<std::vector<double>> currentInputSet;
|
||||
std::vector<double> currentOutputSet;
|
||||
for(int j = 0; j < n/n_miniBatch; j++){
|
||||
currentInputSet.push_back(inputSet[n/n_miniBatch * i + j]);
|
||||
currentOutputSet.push_back(outputSet[n/n_miniBatch * i + j]);
|
||||
}
|
||||
inputMiniBatches.push_back(currentInputSet);
|
||||
outputMiniBatches.push_back(currentOutputSet);
|
||||
}
|
||||
|
||||
if(double(n)/double(n_miniBatch) - int(n/n_miniBatch) != 0){
|
||||
for(int i = 0; i < n - n/n_miniBatch * n_miniBatch; i++){
|
||||
inputMiniBatches[n_miniBatch - 1].push_back(inputSet[n/n_miniBatch * n_miniBatch + i]);
|
||||
outputMiniBatches[n_miniBatch - 1].push_back(outputSet[n/n_miniBatch * n_miniBatch + i]);
|
||||
}
|
||||
}
|
||||
|
||||
while(true){
|
||||
for(int i = 0; i < n_miniBatch; i++){
|
||||
std::vector<double> y_hat = Evaluate(inputMiniBatches[i]);
|
||||
auto [z2, a2] = propagate(inputMiniBatches[i]);
|
||||
cost_prev = Cost(y_hat, outputMiniBatches[i]);
|
||||
|
||||
// Calculating the errors
|
||||
std::vector<double> error = alg.subtraction(y_hat, outputMiniBatches[i]);
|
||||
|
||||
// Calculating the weight/bias gradients for layer 2
|
||||
|
||||
std::vector<double> D2_1 = alg.mat_vec_mult(alg.transpose(a2), error);
|
||||
|
||||
// weights and bias updation for layser 2
|
||||
weights2 = alg.subtraction(weights2, alg.scalarMultiply(learning_rate/outputMiniBatches[i].size(), D2_1));
|
||||
weights2 = regularization.regWeights(weights2, lambda, alpha, reg);
|
||||
|
||||
// Calculating the bias gradients for layer 2
|
||||
double b_gradient = alg.sum_elements(error);
|
||||
|
||||
// Bias Updation for layer 2
|
||||
bias2 -= learning_rate * alg.sum_elements(error) / outputMiniBatches[i].size();
|
||||
|
||||
//Calculating the weight/bias for layer 1
|
||||
|
||||
std::vector<std::vector<double>> D1_1 = alg.vecmult(error, weights2);
|
||||
|
||||
std::vector<std::vector<double>> D1_2 = alg.hadamard_product(D1_1, avn.sigmoid(z2, 1));
|
||||
|
||||
std::vector<std::vector<double>> D1_3 = alg.matmult(alg.transpose(inputMiniBatches[i]), D1_2);
|
||||
|
||||
|
||||
// weight an bias updation for layer 1
|
||||
weights1 = alg.subtraction(weights1, alg.scalarMultiply(learning_rate/outputMiniBatches[i].size(), D1_3));
|
||||
weights1 = regularization.regWeights(weights1, lambda, alpha, reg);
|
||||
|
||||
bias1 = alg.subtractMatrixRows(bias1, alg.scalarMultiply(learning_rate/outputMiniBatches[i].size(), D1_2));
|
||||
|
||||
y_hat = Evaluate(inputMiniBatches[i]);
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputMiniBatches[i]));
|
||||
std::cout << "Layer 1:" << std::endl;
|
||||
Utilities::UI(weights1, bias1);
|
||||
std::cout << "Layer 2:" << std::endl;
|
||||
Utilities::UI(weights2, bias2);
|
||||
}
|
||||
}
|
||||
epoch++;
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
forwardPass();
|
||||
}
|
||||
|
||||
double MLP::score(){
|
||||
Utilities util;
|
||||
return util.performance(y_hat, outputSet);
|
||||
}
|
||||
|
||||
void MLP::save(std::string fileName){
|
||||
Utilities util;
|
||||
util.saveParameters(fileName, weights1, bias1, 0, 1);
|
||||
util.saveParameters(fileName, weights2, bias2, 1, 2);
|
||||
}
|
||||
|
||||
double MLP::Cost(std::vector <double> y_hat, std::vector<double> y){
|
||||
Reg regularization;
|
||||
class Cost cost;
|
||||
return cost.LogLoss(y_hat, y) + regularization.regTerm(weights2, lambda, alpha, reg) + regularization.regTerm(weights1, lambda, alpha, reg);
|
||||
}
|
||||
|
||||
std::vector<double> MLP::Evaluate(std::vector<std::vector<double>> X){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
std::vector<std::vector<double>> z2 = alg.mat_vec_add(alg.matmult(X, weights1), bias1);
|
||||
std::vector<std::vector<double>> a2 = avn.sigmoid(z2);
|
||||
return avn.sigmoid(alg.scalarAdd(bias2, alg.mat_vec_mult(a2, weights2)));
|
||||
}
|
||||
|
||||
std::tuple<std::vector<std::vector<double>>, std::vector<std::vector<double>>> MLP::propagate(std::vector<std::vector<double>> X){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
std::vector<std::vector<double>> z2 = alg.mat_vec_add(alg.matmult(X, weights1), bias1);
|
||||
std::vector<std::vector<double>> a2 = avn.sigmoid(z2);
|
||||
return {z2, a2};
|
||||
}
|
||||
|
||||
double MLP::Evaluate(std::vector<double> x){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
std::vector<double> z2 = alg.addition(alg.mat_vec_mult(alg.transpose(weights1), x), bias1);
|
||||
std::vector<double> a2 = avn.sigmoid(z2);
|
||||
return avn.sigmoid(alg.dot(weights2, a2) + bias2);
|
||||
}
|
||||
|
||||
std::tuple<std::vector<double>, std::vector<double>> MLP::propagate(std::vector<double> x){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
std::vector<double> z2 = alg.addition(alg.mat_vec_mult(alg.transpose(weights1), x), bias1);
|
||||
std::vector<double> a2 = avn.sigmoid(z2);
|
||||
return {z2, a2};
|
||||
}
|
||||
|
||||
void MLP::forwardPass(){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
z2 = alg.mat_vec_add(alg.matmult(inputSet, weights1), bias1);
|
||||
a2 = avn.sigmoid(z2);
|
||||
y_hat = avn.sigmoid(alg.scalarAdd(bias2, alg.mat_vec_mult(a2, weights2)));
|
||||
}
|
||||
}
|
61
MLPP/MLP/MLP.hpp
Normal file
61
MLPP/MLP/MLP.hpp
Normal file
@ -0,0 +1,61 @@
|
||||
//
|
||||
// MLP.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 11/4/20.
|
||||
//
|
||||
|
||||
#ifndef MLP_hpp
|
||||
#define MLP_hpp
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace MLPP {
|
||||
|
||||
class MLP{
|
||||
public:
|
||||
MLP(std::vector<std::vector<double>> inputSet, std::vector<double> outputSet, int n_hidden, std::string reg = "None", double lambda = 0.5, double alpha = 0.5);
|
||||
std::vector<double> modelSetTest(std::vector<std::vector<double>> X);
|
||||
double modelTest(std::vector<double> x);
|
||||
void gradientDescent(double learning_rate, int max_epoch, bool UI = 1);
|
||||
void SGD(double learning_rate, int max_epoch, bool UI = 1);
|
||||
void MBGD(double learning_rate, int max_epoch, int miniBatch_size, bool UI = 1);
|
||||
double score();
|
||||
void save(std::string fileName);
|
||||
|
||||
private:
|
||||
double Cost(std::vector <double> y_hat, std::vector<double> y);
|
||||
|
||||
std::vector<double> Evaluate(std::vector<std::vector<double>> X);
|
||||
std::tuple<std::vector<std::vector<double>>, std::vector<std::vector<double>>> propagate(std::vector<std::vector<double>> X);
|
||||
double Evaluate(std::vector<double> x);
|
||||
std::tuple<std::vector<double>, std::vector<double>> propagate(std::vector<double> x);
|
||||
void forwardPass();
|
||||
|
||||
std::vector<std::vector<double>> inputSet;
|
||||
std::vector<double> outputSet;
|
||||
std::vector<double> y_hat;
|
||||
|
||||
std::vector<std::vector<double>> weights1;
|
||||
std::vector<double> weights2;
|
||||
|
||||
std::vector<double> bias1;
|
||||
double bias2;
|
||||
|
||||
std::vector<std::vector<double>> z2;
|
||||
std::vector<std::vector<double>> a2;
|
||||
|
||||
int n;
|
||||
int k;
|
||||
int n_hidden;
|
||||
|
||||
|
||||
// Regularization Params
|
||||
std::string reg;
|
||||
double lambda; /* Regularization Parameter */
|
||||
double alpha; /* This is the controlling param for Elastic Net*/
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* MLP_hpp */
|
120
MLPP/MultinomialNB/MultinomialNB.cpp
Normal file
120
MLPP/MultinomialNB/MultinomialNB.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
//
|
||||
// MultinomialNB.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 1/17/21.
|
||||
//
|
||||
|
||||
#include "MultinomialNB.hpp"
|
||||
#include "Utilities/Utilities.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
namespace MLPP{
|
||||
MultinomialNB::MultinomialNB(std::vector<std::vector<double>> inputSet, std::vector<double> outputSet, int class_num)
|
||||
: inputSet(inputSet), outputSet(outputSet), class_num(class_num)
|
||||
{
|
||||
y_hat.resize(outputSet.size());
|
||||
Evaluate();
|
||||
}
|
||||
|
||||
std::vector<double> MultinomialNB::modelSetTest(std::vector<std::vector<double>> X){
|
||||
std::vector<double> y_hat;
|
||||
for(int i = 0; i < X.size(); i++){
|
||||
y_hat.push_back(modelTest(X[i]));
|
||||
}
|
||||
return y_hat;
|
||||
}
|
||||
|
||||
double MultinomialNB::modelTest(std::vector<double> x){
|
||||
double score[class_num];
|
||||
computeTheta();
|
||||
|
||||
for(int j = 0; j < x.size(); j++){
|
||||
for(int k = 0; k < vocab.size(); k++){
|
||||
if(x[j] == vocab[k]){
|
||||
for(int p = class_num - 1; p >= 0; p--){
|
||||
score[p] += log(theta[p][vocab[k]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < priors.size(); i++){
|
||||
score[i] += log(priors[i]);
|
||||
}
|
||||
|
||||
return std::distance(score, std::max_element(score, score + sizeof(score) / sizeof(double)));
|
||||
}
|
||||
|
||||
double MultinomialNB::score(){
|
||||
Utilities util;
|
||||
return util.performance(y_hat, outputSet);
|
||||
}
|
||||
|
||||
void MultinomialNB::computeTheta(){
|
||||
|
||||
// Resizing theta for the sake of ease & proper access of the elements.
|
||||
theta.resize(class_num);
|
||||
|
||||
// Setting all values in the hasmap by default to 0.
|
||||
for(int i = class_num - 1; i >= 0; i--){
|
||||
for(int j = 0; j < vocab.size(); j++){
|
||||
theta[i][vocab[j]] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < inputSet.size(); i++){
|
||||
for(int j = 0; j < inputSet[0].size(); j++){
|
||||
theta[outputSet[i]][inputSet[i][j]]++;
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < theta.size(); i++){
|
||||
for(int j = 0; j < theta[i].size(); j++){
|
||||
theta[i][j] /= priors[i] * y_hat.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MultinomialNB::Evaluate(){
|
||||
LinAlg alg;
|
||||
for(int i = 0; i < outputSet.size(); i++){
|
||||
// Pr(B | A) * Pr(A)
|
||||
double score[class_num];
|
||||
|
||||
// Easy computation of priors, i.e. Pr(C_k)
|
||||
priors.resize(class_num);
|
||||
for(int i = 0; i < outputSet.size(); i++){
|
||||
priors[int(outputSet[i])]++;
|
||||
}
|
||||
priors = alg.scalarMultiply( double(1)/double(outputSet.size()), priors);
|
||||
|
||||
// Evaluating Theta...
|
||||
computeTheta();
|
||||
|
||||
for(int j = 0; j < inputSet.size(); j++){
|
||||
for(int k = 0; k < vocab.size(); k++){
|
||||
if(inputSet[i][j] == vocab[k]){
|
||||
for(int p = class_num - 1; p >= 0; p--){
|
||||
score[p] += log(theta[i][vocab[k]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < priors.size(); i++){
|
||||
score[i] += log(priors[i]);
|
||||
score[i] = exp(score[i]);
|
||||
}
|
||||
|
||||
for(int i = 0; i < 2; i++){
|
||||
std::cout << score[i] << std::endl;
|
||||
}
|
||||
|
||||
// Assigning the traning example's y_hat to a class
|
||||
y_hat[i] = std::distance(score, std::max_element(score, score + sizeof(score) / sizeof(double)));
|
||||
}
|
||||
}
|
||||
}
|
45
MLPP/MultinomialNB/MultinomialNB.hpp
Normal file
45
MLPP/MultinomialNB/MultinomialNB.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
//
|
||||
// MultinomialNB.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 1/17/21.
|
||||
//
|
||||
|
||||
#ifndef MultinomialNB_hpp
|
||||
#define MultinomialNB_hpp
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace MLPP{
|
||||
class MultinomialNB{
|
||||
|
||||
public:
|
||||
MultinomialNB(std::vector<std::vector<double>> inputSet, std::vector<double> outputSet, int class_num);
|
||||
std::vector<double> modelSetTest(std::vector<std::vector<double>> X);
|
||||
double modelTest(std::vector<double> x);
|
||||
double score();
|
||||
|
||||
private:
|
||||
|
||||
void computeTheta();
|
||||
void Evaluate();
|
||||
|
||||
// Model Params
|
||||
std::vector<double> priors;
|
||||
|
||||
std::vector<std::map<double, int>> theta;
|
||||
std::vector<double> vocab;
|
||||
int class_num;
|
||||
|
||||
// Datasets
|
||||
std::vector<std::vector<double>> inputSet;
|
||||
std::vector<double> outputSet;
|
||||
std::vector<double> y_hat;
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif /* MultinomialNB_hpp */
|
||||
}
|
43
MLPP/OutlierFinder/OutlierFinder.cpp
Normal file
43
MLPP/OutlierFinder/OutlierFinder.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
//
|
||||
// OutlierFinder.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 11/13/20.
|
||||
//
|
||||
|
||||
#include "OutlierFinder.hpp"
|
||||
#include "Stat/Stat.hpp"
|
||||
#include <iostream>
|
||||
|
||||
namespace MLPP{
|
||||
OutlierFinder::OutlierFinder(int threshold)
|
||||
: threshold(threshold){
|
||||
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> OutlierFinder::modelSetTest(std::vector<std::vector<double>> inputSet){
|
||||
Stat op;
|
||||
std::vector<std::vector<double>> outliers;
|
||||
outliers.resize(inputSet.size());
|
||||
for(int i = 0; i < inputSet.size(); i++){
|
||||
for(int j = 0; j < inputSet[i].size(); j++){
|
||||
double z = (inputSet[i][j] - op.mean(inputSet[i])) / op.standardDeviation(inputSet[i]);
|
||||
if(abs(z) > threshold){
|
||||
outliers[i].push_back(inputSet[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return outliers;
|
||||
}
|
||||
|
||||
std::vector<double> OutlierFinder::modelTest(std::vector<double> inputSet){
|
||||
Stat op;
|
||||
std::vector<double> outliers;
|
||||
for(int i = 0; i < inputSet.size(); i++){
|
||||
double z = (inputSet[i] - op.mean(inputSet)) / op.standardDeviation(inputSet);
|
||||
if(abs(z) > threshold){
|
||||
outliers.push_back(inputSet[i]);
|
||||
}
|
||||
}
|
||||
return outliers;
|
||||
}
|
||||
}
|
27
MLPP/OutlierFinder/OutlierFinder.hpp
Normal file
27
MLPP/OutlierFinder/OutlierFinder.hpp
Normal file
@ -0,0 +1,27 @@
|
||||
//
|
||||
// OutlierFinder.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 11/13/20.
|
||||
//
|
||||
|
||||
#ifndef OutlierFinder_hpp
|
||||
#define OutlierFinder_hpp
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace MLPP{
|
||||
class OutlierFinder{
|
||||
public:
|
||||
// Cnstr
|
||||
OutlierFinder(int threshold);
|
||||
|
||||
std::vector<std::vector<double>> modelSetTest(std::vector<std::vector<double>> inputSet);
|
||||
std::vector<double> modelTest(std::vector<double> inputSet);
|
||||
|
||||
// Variables required
|
||||
int threshold;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* OutlierFinder_hpp */
|
BIN
MLPP/OutlierFinder/OutlierFinder.hpp.gch
Normal file
BIN
MLPP/OutlierFinder/OutlierFinder.hpp.gch
Normal file
Binary file not shown.
113
MLPP/OutputLayer/OutputLayer.cpp
Normal file
113
MLPP/OutputLayer/OutputLayer.cpp
Normal file
@ -0,0 +1,113 @@
|
||||
//
|
||||
// OutputLayer.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 11/4/20.
|
||||
//
|
||||
|
||||
#include "OutputLayer.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
#include "Utilities/Utilities.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
namespace MLPP {
|
||||
OutputLayer::OutputLayer(int n_hidden, int outputSize, std::string activation, std::string cost, std::vector<std::vector<double>> input, std::string weightInit, std::string reg, double lambda, double alpha)
|
||||
: n_hidden(n_hidden), outputSize(outputSize), activation(activation), cost(cost), input(input), weightInit(weightInit), reg(reg), lambda(lambda), alpha(alpha)
|
||||
{
|
||||
weights = Utilities::weightInitialization(n_hidden, weightInit);
|
||||
bias = Utilities::biasInitialization();
|
||||
|
||||
activation_map["Linear"] = &Activation::linear;
|
||||
activationTest_map["Linear"] = &Activation::linear;
|
||||
|
||||
activation_map["Sigmoid"] = &Activation::sigmoid;
|
||||
activationTest_map["Sigmoid"] = &Activation::sigmoid;
|
||||
|
||||
activation_map["Swish"] = &Activation::swish;
|
||||
activationTest_map["Swish"] = &Activation::swish;
|
||||
|
||||
activation_map["Softplus"] = &Activation::softplus;
|
||||
activationTest_map["Softplus"] = &Activation::softplus;
|
||||
|
||||
activation_map["CLogLog"] = &Activation::cloglog;
|
||||
activationTest_map["CLogLog"] = &Activation::cloglog;
|
||||
|
||||
activation_map["Sinh"] = &Activation::sinh;
|
||||
activationTest_map["Sinh"] = &Activation::sinh;
|
||||
|
||||
activation_map["Cosh"] = &Activation::cosh;
|
||||
activationTest_map["Cosh"] = &Activation::cosh;
|
||||
|
||||
activation_map["Tanh"] = &Activation::tanh;
|
||||
activationTest_map["Tanh"] = &Activation::tanh;
|
||||
|
||||
activation_map["Csch"] = &Activation::csch;
|
||||
activationTest_map["Csch"] = &Activation::csch;
|
||||
|
||||
activation_map["Sech"] = &Activation::sech;
|
||||
activationTest_map["Sech"] = &Activation::sech;
|
||||
|
||||
activation_map["Coth"] = &Activation::coth;
|
||||
activationTest_map["Coth"] = &Activation::coth;
|
||||
|
||||
activation_map["Arsinh"] = &Activation::arsinh;
|
||||
activationTest_map["Arsinh"] = &Activation::arsinh;
|
||||
|
||||
activation_map["Arcosh"] = &Activation::arcosh;
|
||||
activationTest_map["Arcosh"] = &Activation::arcosh;
|
||||
|
||||
activation_map["Artanh"] = &Activation::artanh;
|
||||
activationTest_map["Artanh"] = &Activation::artanh;
|
||||
|
||||
activation_map["Arcsch"] = &Activation::arcsch;
|
||||
activationTest_map["Arcsch"] = &Activation::arcsch;
|
||||
|
||||
activation_map["Arsech"] = &Activation::arsech;
|
||||
activationTest_map["Arsech"] = &Activation::arsech;
|
||||
|
||||
activation_map["Arcoth"] = &Activation::arcoth;
|
||||
activationTest_map["Arcoth"] = &Activation::arcoth;
|
||||
|
||||
activation_map["GaussianCDF"] = &Activation::gaussianCDF;
|
||||
activationTest_map["GaussianCDF"] = &Activation::gaussianCDF;
|
||||
|
||||
activation_map["RELU"] = &Activation::RELU;
|
||||
activationTest_map["RELU"] = &Activation::RELU;
|
||||
|
||||
activation_map["GELU"] = &Activation::GELU;
|
||||
activationTest_map["GELU"] = &Activation::GELU;
|
||||
|
||||
activation_map["UnitStep"] = &Activation::unitStep;
|
||||
activationTest_map["UnitStep"] = &Activation::unitStep;
|
||||
|
||||
costDeriv_map["MSE"] = &Cost::MSEDeriv;
|
||||
cost_map["MSE"] = &Cost::MSE;
|
||||
costDeriv_map["RMSE"] = &Cost::RMSEDeriv;
|
||||
cost_map["RMSE"] = &Cost::RMSE;
|
||||
costDeriv_map["MAE"] = &Cost::MAEDeriv;
|
||||
cost_map["MAE"] = &Cost::MAE;
|
||||
costDeriv_map["MBE"] = &Cost::MBEDeriv;
|
||||
cost_map["MBE"] = &Cost::MBE;
|
||||
costDeriv_map["LogLoss"] = &Cost::LogLossDeriv;
|
||||
cost_map["LogLoss"] = &Cost::LogLoss;
|
||||
costDeriv_map["CrossEntropy"] = &Cost::CrossEntropyDeriv;
|
||||
cost_map["CrossEntropy"] = &Cost::CrossEntropy;
|
||||
costDeriv_map["HingeLoss"] = &Cost::HingeLossDeriv;
|
||||
cost_map["HingeLoss"] = &Cost::HingeLoss;
|
||||
}
|
||||
|
||||
void OutputLayer::forwardPass(){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
z = alg.scalarAdd(bias, alg.mat_vec_mult(input, weights));
|
||||
a = (avn.*activation_map[activation])(z, 0);
|
||||
}
|
||||
|
||||
void OutputLayer::Test(std::vector<double> x){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
z_test = alg.dot(weights, x) + bias;
|
||||
a_test = (avn.*activationTest_map[activation])(z_test, 0);
|
||||
}
|
||||
}
|
57
MLPP/OutputLayer/OutputLayer.hpp
Normal file
57
MLPP/OutputLayer/OutputLayer.hpp
Normal file
@ -0,0 +1,57 @@
|
||||
//
|
||||
// OutputLayer.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 11/4/20.
|
||||
//
|
||||
|
||||
#ifndef OutputLayer_hpp
|
||||
#define OutputLayer_hpp
|
||||
|
||||
#include "Activation/Activation.hpp"
|
||||
#include "Cost/Cost.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace MLPP {
|
||||
class OutputLayer{
|
||||
public:
|
||||
OutputLayer(int n_hidden, int outputSize, std::string activation, std::string cost, std::vector<std::vector<double>> input, std::string weightInit, std::string reg, double lambda, double alpha);
|
||||
|
||||
int n_hidden;
|
||||
int outputSize;
|
||||
std::string activation;
|
||||
std::string cost;
|
||||
|
||||
std::vector<std::vector<double>> input;
|
||||
|
||||
std::vector<double> weights;
|
||||
double bias;
|
||||
|
||||
std::vector<double> z;
|
||||
std::vector<double> a;
|
||||
|
||||
std::map<std::string, std::vector<double> (Activation::*)(std::vector<double>, bool)> activation_map;
|
||||
std::map<std::string, double (Activation::*)(double, bool)> activationTest_map;
|
||||
std::map<std::string, double (Cost::*)(std::vector<double>, std::vector<double>)> cost_map;
|
||||
std::map<std::string, std::vector<double> (Cost::*)(std::vector<double>, std::vector<double>)> costDeriv_map;
|
||||
|
||||
double z_test;
|
||||
double a_test;
|
||||
|
||||
std::vector<double> delta;
|
||||
|
||||
// Regularization Params
|
||||
std::string reg;
|
||||
double lambda; /* Regularization Parameter */
|
||||
double alpha; /* This is the controlling param for Elastic Net*/
|
||||
|
||||
std::string weightInit;
|
||||
|
||||
void forwardPass();
|
||||
void Test(std::vector<double> x);
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* OutputLayer_hpp */
|
56
MLPP/PCA/PCA.cpp
Normal file
56
MLPP/PCA/PCA.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
//
|
||||
// PCA.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 10/2/20.
|
||||
//
|
||||
|
||||
#include "PCA.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
#include "Data/Data.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
namespace MLPP{
|
||||
|
||||
PCA::PCA(std::vector<std::vector<double>> inputSet, int k)
|
||||
: inputSet(inputSet), k(k)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> PCA::principalComponents(){
|
||||
LinAlg alg;
|
||||
Data data;
|
||||
|
||||
auto [U, S, Vt] = alg.SVD(alg.cov(inputSet));
|
||||
X_normalized = data.meanCentering(inputSet);
|
||||
U_reduce.resize(U.size());
|
||||
for(int i = 0; i < k; i++){
|
||||
for(int j = 0; j < U.size(); j++){
|
||||
U_reduce[j].push_back(U[j][i]);
|
||||
}
|
||||
}
|
||||
Z = alg.matmult(alg.transpose(U_reduce), X_normalized);
|
||||
return Z;
|
||||
}
|
||||
// Simply tells us the percentage of variance maintained.
|
||||
double PCA::score(){
|
||||
LinAlg alg;
|
||||
std::vector<std::vector<double>> X_approx = alg.matmult(U_reduce, Z);
|
||||
double num, den = 0;
|
||||
for(int i = 0; i < X_normalized.size(); i++){
|
||||
num += alg.norm_sq(alg.subtraction(X_normalized[i], X_approx[i]));
|
||||
}
|
||||
num /= X_normalized.size();
|
||||
for(int i = 0; i < X_normalized.size(); i++){
|
||||
den += alg.norm_sq(X_normalized[i]);
|
||||
}
|
||||
|
||||
den /= X_normalized.size();
|
||||
if(den == 0){
|
||||
den+=1e-10; // For numerical sanity as to not recieve a domain error
|
||||
}
|
||||
return 1 - num/den;
|
||||
}
|
||||
}
|
28
MLPP/PCA/PCA.hpp
Normal file
28
MLPP/PCA/PCA.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
//
|
||||
// PCA.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 10/2/20.
|
||||
//
|
||||
|
||||
#ifndef PCA_hpp
|
||||
#define PCA_hpp
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace MLPP{
|
||||
class PCA{
|
||||
|
||||
public:
|
||||
PCA(std::vector<std::vector<double>> inputSet, int k);
|
||||
std::vector<std::vector<double>> principalComponents();
|
||||
double score();
|
||||
private:
|
||||
std::vector<std::vector<double>> inputSet;
|
||||
std::vector<std::vector<double>> X_normalized;
|
||||
std::vector<std::vector<double>> U_reduce;
|
||||
std::vector<std::vector<double>> Z;
|
||||
int k;
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* PCA_hpp */
|
249
MLPP/ProbitReg/ProbitReg.cpp
Normal file
249
MLPP/ProbitReg/ProbitReg.cpp
Normal file
@ -0,0 +1,249 @@
|
||||
//
|
||||
// ProbitReg.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 10/2/20.
|
||||
//
|
||||
|
||||
#include "ProbitReg.hpp"
|
||||
#include "Activation/Activation.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
#include "Regularization/Reg.hpp"
|
||||
#include "Utilities/Utilities.hpp"
|
||||
#include "Cost/Cost.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
namespace MLPP{
|
||||
ProbitReg::ProbitReg(std::vector<std::vector<double>> inputSet, std::vector<double> 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)
|
||||
{
|
||||
y_hat.resize(n);
|
||||
weights = Utilities::weightInitialization(k);
|
||||
bias = Utilities::biasInitialization();
|
||||
}
|
||||
|
||||
std::vector<double> ProbitReg::modelSetTest(std::vector<std::vector<double>> X){
|
||||
return Evaluate(X);
|
||||
}
|
||||
|
||||
double ProbitReg::modelTest(std::vector<double> x){
|
||||
return Evaluate(x);
|
||||
}
|
||||
|
||||
void ProbitReg::gradientDescent(double learning_rate, int max_epoch, bool UI){
|
||||
Reg regularization;
|
||||
Activation avn;
|
||||
LinAlg alg;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
forwardPass();
|
||||
|
||||
while(true){
|
||||
cost_prev = Cost(y_hat, outputSet);
|
||||
|
||||
std::vector<double> error = alg.subtraction(y_hat, outputSet);
|
||||
|
||||
// Calculating the weight gradients
|
||||
weights = alg.subtraction(weights, alg.scalarMultiply(learning_rate/n, alg.mat_vec_mult(alg.transpose(inputSet), alg.hadamard_product(error, avn.gaussianCDF(z, 1)))));
|
||||
weights = regularization.regWeights(weights, lambda, alpha, reg);
|
||||
|
||||
// Calculating the bias gradients
|
||||
bias -= learning_rate * alg.sum_elements(alg.hadamard_product(error, avn.gaussianCDF(z, 1))) / n;
|
||||
forwardPass();
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputSet));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
epoch++;
|
||||
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
}
|
||||
|
||||
void ProbitReg::MLE(double learning_rate, int max_epoch, bool UI){
|
||||
Activation avn;
|
||||
Reg regularization;
|
||||
LinAlg alg;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
forwardPass();
|
||||
|
||||
while(true){
|
||||
cost_prev = Cost(y_hat, outputSet);
|
||||
|
||||
std::vector<double> error = alg.subtraction(outputSet, y_hat);
|
||||
|
||||
// Calculating the weight gradients
|
||||
weights = alg.addition(weights, alg.scalarMultiply(learning_rate/n, alg.mat_vec_mult(alg.transpose(inputSet), alg.hadamard_product(error, avn.gaussianCDF(z, 1)))));
|
||||
weights = regularization.regWeights(weights, lambda, alpha, reg);
|
||||
|
||||
// Calculating the bias gradients
|
||||
bias += learning_rate * alg.sum_elements(alg.hadamard_product(error, avn.gaussianCDF(z, 1))) / n;
|
||||
forwardPass();
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputSet));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
epoch++;
|
||||
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
}
|
||||
|
||||
void ProbitReg::SGD(double learning_rate, int max_epoch, bool UI){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
Reg regularization;
|
||||
Utilities util;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
|
||||
while(true){
|
||||
std::random_device rd;
|
||||
std::default_random_engine generator(rd());
|
||||
std::uniform_int_distribution<int> distribution(0, int(n - 1));
|
||||
int outputIndex = distribution(generator);
|
||||
|
||||
double y_hat = Evaluate(inputSet[outputIndex]);
|
||||
double z = propagate(inputSet[outputIndex]);
|
||||
cost_prev = Cost({y_hat}, {outputSet[outputIndex]});
|
||||
|
||||
|
||||
for(int i = 0; i < k; i++){
|
||||
|
||||
// Calculating the weight gradients
|
||||
|
||||
double w_gradient = (y_hat - outputSet[outputIndex]) * ((1 / sqrt(2 * M_PI)) * exp(-z * z / 2)) * inputSet[outputIndex][i];
|
||||
|
||||
std::cout << exp(-z * z / 2) << std::endl;
|
||||
// Weight updation
|
||||
weights[i] -= learning_rate * w_gradient;
|
||||
}
|
||||
weights = regularization.regWeights(weights, lambda, alpha, reg);
|
||||
|
||||
// Calculating the bias gradients
|
||||
double b_gradient = (y_hat - outputSet[outputIndex]);
|
||||
|
||||
// Bias updation
|
||||
bias -= learning_rate * b_gradient * ((1 / sqrt(2 * M_PI)) * exp(-z * z / 2));
|
||||
y_hat = Evaluate({inputSet[outputIndex]});
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost({y_hat}, {outputSet[outputIndex]}));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
epoch++;
|
||||
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
forwardPass();
|
||||
}
|
||||
|
||||
void ProbitReg::MBGD(double learning_rate, int max_epoch, int miniBatch_size, bool UI){
|
||||
Reg regularization;
|
||||
Activation avn;
|
||||
LinAlg alg;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
|
||||
int n_miniBatch = n/miniBatch_size;
|
||||
|
||||
std::vector<std::vector<std::vector<double>>> inputMiniBatches;
|
||||
std::vector<std::vector<double>> outputMiniBatches;
|
||||
|
||||
// Creating the mini-batches
|
||||
for(int i = 0; i < n_miniBatch; i++){
|
||||
std::vector<std::vector<double>> currentInputSet;
|
||||
std::vector<double> currentOutputSet;
|
||||
for(int j = 0; j < n/n_miniBatch; j++){
|
||||
currentInputSet.push_back(inputSet[n/n_miniBatch * i + j]);
|
||||
currentOutputSet.push_back(outputSet[n/n_miniBatch * i + j]);
|
||||
}
|
||||
inputMiniBatches.push_back(currentInputSet);
|
||||
outputMiniBatches.push_back(currentOutputSet);
|
||||
}
|
||||
|
||||
if(double(n)/double(n_miniBatch) - int(n/n_miniBatch) != 0){
|
||||
for(int i = 0; i < n - n/n_miniBatch * n_miniBatch; i++){
|
||||
inputMiniBatches[n_miniBatch - 1].push_back(inputSet[n/n_miniBatch * n_miniBatch + i]);
|
||||
outputMiniBatches[n_miniBatch - 1].push_back(outputSet[n/n_miniBatch * n_miniBatch + i]);
|
||||
}
|
||||
}
|
||||
|
||||
while(true){
|
||||
for(int i = 0; i < n_miniBatch; i++){
|
||||
std::vector<double> y_hat = Evaluate(inputMiniBatches[i]);
|
||||
std::vector<double> z = propagate(inputMiniBatches[i]);
|
||||
cost_prev = Cost(y_hat, outputMiniBatches[i]);
|
||||
|
||||
std::vector<double> error = alg.subtraction(y_hat, outputMiniBatches[i]);
|
||||
|
||||
// Calculating the weight gradients
|
||||
weights = alg.subtraction(weights, alg.scalarMultiply(learning_rate/outputMiniBatches.size(), alg.mat_vec_mult(alg.transpose(inputMiniBatches[i]), alg.hadamard_product(error, avn.gaussianCDF(z, 1)))));
|
||||
weights = regularization.regWeights(weights, lambda, alpha, reg);
|
||||
|
||||
// Calculating the bias gradients
|
||||
bias -= learning_rate * alg.sum_elements(alg.hadamard_product(error, avn.gaussianCDF(z, 1))) / outputMiniBatches.size();
|
||||
y_hat = Evaluate(inputMiniBatches[i]);
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputMiniBatches[i]));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
}
|
||||
epoch++;
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
forwardPass();
|
||||
}
|
||||
|
||||
double ProbitReg::score(){
|
||||
Utilities util;
|
||||
return util.performance(y_hat, outputSet);
|
||||
}
|
||||
|
||||
void ProbitReg::save(std::string fileName){
|
||||
Utilities util;
|
||||
util.saveParameters(fileName, weights, bias);
|
||||
}
|
||||
|
||||
double ProbitReg::Cost(std::vector <double> y_hat, std::vector<double> y){
|
||||
Reg regularization;
|
||||
class Cost cost;
|
||||
return cost.MSE(y_hat, y) + regularization.regTerm(weights, lambda, alpha, reg);
|
||||
}
|
||||
|
||||
std::vector<double> ProbitReg::Evaluate(std::vector<std::vector<double>> X){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
return avn.gaussianCDF(alg.scalarAdd(bias, alg.mat_vec_mult(X, weights)));
|
||||
}
|
||||
|
||||
std::vector<double>ProbitReg::propagate(std::vector<std::vector<double>> X){
|
||||
LinAlg alg;
|
||||
return alg.scalarAdd(bias, alg.mat_vec_mult(X, weights));
|
||||
}
|
||||
|
||||
double ProbitReg::Evaluate(std::vector<double> x){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
return avn.gaussianCDF(alg.dot(weights, x) + bias);
|
||||
}
|
||||
|
||||
double ProbitReg::propagate(std::vector<double> x){
|
||||
LinAlg alg;
|
||||
return alg.dot(weights, x) + bias;
|
||||
}
|
||||
|
||||
// gaussianCDF ( wTx + b )
|
||||
void ProbitReg::forwardPass(){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
|
||||
z = propagate(inputSet);
|
||||
y_hat = avn.gaussianCDF(z);
|
||||
}
|
||||
}
|
57
MLPP/ProbitReg/ProbitReg.hpp
Normal file
57
MLPP/ProbitReg/ProbitReg.hpp
Normal file
@ -0,0 +1,57 @@
|
||||
//
|
||||
// ProbitReg.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 10/2/20.
|
||||
//
|
||||
|
||||
#ifndef ProbitReg_hpp
|
||||
#define ProbitReg_hpp
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace MLPP {
|
||||
|
||||
class ProbitReg{
|
||||
|
||||
public:
|
||||
ProbitReg(std::vector<std::vector<double>> inputSet, std::vector<double> outputSet, std::string reg = "None", double lambda = 0.5, double alpha = 0.5);
|
||||
std::vector<double> modelSetTest(std::vector<std::vector<double>> X);
|
||||
double modelTest(std::vector<double> x);
|
||||
void gradientDescent(double learning_rate, int max_epoch = 0, bool UI = 1);
|
||||
void MLE(double learning_rate, int max_epoch = 0, bool UI = 1);
|
||||
void SGD(double learning_rate, int max_epoch = 0, bool UI = 1);
|
||||
void MBGD(double learning_rate, int max_epoch, int miniBatch_size, bool UI = 1);
|
||||
double score();
|
||||
void save(std::string fileName);
|
||||
private:
|
||||
|
||||
double Cost(std::vector <double> y_hat, std::vector<double> y);
|
||||
|
||||
std::vector<double> Evaluate(std::vector<std::vector<double>> X);
|
||||
std::vector<double> propagate(std::vector<std::vector<double>> X);
|
||||
double Evaluate(std::vector<double> x);
|
||||
double propagate(std::vector<double> x);
|
||||
void forwardPass();
|
||||
|
||||
std::vector<std::vector<double>> inputSet;
|
||||
std::vector<double> outputSet;
|
||||
std::vector<double> z;
|
||||
std::vector<double> y_hat;
|
||||
std::vector<double> weights;
|
||||
double bias;
|
||||
|
||||
int n;
|
||||
int k;
|
||||
|
||||
// Regularization Params
|
||||
std::string reg;
|
||||
double lambda;
|
||||
double alpha; /* This is the controlling param for Elastic Net*/
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* ProbitReg_hpp */
|
128
MLPP/Regularization/Reg.cpp
Normal file
128
MLPP/Regularization/Reg.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
//
|
||||
// Reg.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 1/16/21.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include "Reg.hpp"
|
||||
|
||||
namespace MLPP{
|
||||
|
||||
double Reg::regTerm(std::vector<double> weights, double lambda, double alpha, std::string reg){
|
||||
if(reg == "Ridge"){
|
||||
double reg = 0;
|
||||
for(int i = 0; i < weights.size(); i++){
|
||||
reg += weights[i] * weights[i];
|
||||
}
|
||||
return reg * lambda / 2;
|
||||
}
|
||||
else if(reg == "Lasso"){
|
||||
double reg = 0;
|
||||
for(int i = 0; i < weights.size(); i++){
|
||||
reg += abs(weights[i]);
|
||||
}
|
||||
return reg * lambda;
|
||||
}
|
||||
else if(reg == "ElasticNet"){
|
||||
double reg = 0;
|
||||
for(int i = 0; i < weights.size(); i++){
|
||||
reg += alpha * abs(weights[i]); // Lasso Reg
|
||||
reg += ((1 - alpha) / 2) * weights[i] * weights[i]; // Ridge Reg
|
||||
}
|
||||
return reg * lambda;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
double Reg::regTerm(std::vector<std::vector<double>> weights, double lambda, double alpha, std::string reg){
|
||||
if(reg == "Ridge"){
|
||||
double reg = 0;
|
||||
for(int i = 0; i < weights.size(); i++){
|
||||
for(int j = 0; j < weights[i].size(); j++){
|
||||
reg += weights[i][j] * weights[i][j];
|
||||
}
|
||||
}
|
||||
return reg * lambda / 2;
|
||||
}
|
||||
else if(reg == "Lasso"){
|
||||
double reg = 0;
|
||||
for(int i = 0; i < weights.size(); i++){
|
||||
for(int j = 0; j < weights[i].size(); j++){
|
||||
reg += abs(weights[i][j]);
|
||||
}
|
||||
}
|
||||
return reg * lambda;
|
||||
}
|
||||
else if(reg == "ElasticNet"){
|
||||
double reg = 0;
|
||||
for(int i = 0; i < weights.size(); i++){
|
||||
for(int j = 0; j < weights[i].size(); j++){
|
||||
reg += alpha * abs(weights[i][j]); // Lasso Reg
|
||||
reg += ((1 - alpha) / 2) * weights[i][j] * weights[i][j]; // Ridge Reg
|
||||
}
|
||||
}
|
||||
return reg * lambda;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<double> Reg::regWeights(std::vector<double> weights, double lambda, double alpha, std::string reg){
|
||||
for(int i = 0; i < weights.size(); i++){
|
||||
weights[i] -= regDerivTerm(weights, lambda, alpha, reg, i);
|
||||
}
|
||||
return weights;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Reg::regWeights(std::vector<std::vector<double>> weights, double lambda, double alpha, std::string reg){
|
||||
for(int i = 0; i < weights.size(); i++){
|
||||
for(int j = 0; j < weights[i].size(); j++){
|
||||
weights[i][j] -= regDerivTerm(weights, lambda, alpha, reg, i, j);
|
||||
}
|
||||
}
|
||||
return weights;
|
||||
}
|
||||
|
||||
double Reg::regDerivTerm(std::vector<double> weights, double lambda, double alpha, std::string reg, int j){
|
||||
if(reg == "Ridge"){
|
||||
return lambda * weights[j];
|
||||
}
|
||||
else if(reg == "Lasso"){
|
||||
return lambda * sign(weights[j]);
|
||||
}
|
||||
else if(reg == "ElasticNet"){
|
||||
return alpha * lambda * sign(weights[j]) + (1 - alpha) * lambda * weights[j];
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
double Reg::regDerivTerm(std::vector<std::vector<double>> weights, double lambda, double alpha, std::string reg, int i, int j){
|
||||
if(reg == "Ridge"){
|
||||
return lambda * weights[i][j];
|
||||
}
|
||||
else if(reg == "Lasso"){
|
||||
return lambda * sign(weights[i][j]);
|
||||
}
|
||||
else if(reg == "ElasticNet"){
|
||||
return alpha * lambda * 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;
|
||||
}
|
||||
}
|
||||
}
|
29
MLPP/Regularization/Reg.hpp
Normal file
29
MLPP/Regularization/Reg.hpp
Normal file
@ -0,0 +1,29 @@
|
||||
//
|
||||
// Reg.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 1/16/21.
|
||||
//
|
||||
|
||||
#ifndef Reg_hpp
|
||||
#define Reg_hpp
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace MLPP{
|
||||
class Reg{
|
||||
public:
|
||||
|
||||
double regTerm(std::vector<double> weights, double lambda, double alpha, std::string reg);
|
||||
double regTerm(std::vector<std::vector<double>> weights, double lambda, double alpha, std::string reg);
|
||||
|
||||
std::vector<double> regWeights(std::vector<double> weights, double lambda, double alpha, std::string reg);
|
||||
std::vector<std::vector<double>> regWeights(std::vector<std::vector<double>> weights, double lambda, double alpha, std::string reg);
|
||||
|
||||
private:
|
||||
double regDerivTerm(std::vector<double> weights, double lambda, double alpha, std::string reg, int j);
|
||||
double regDerivTerm(std::vector<std::vector<double>> weights, double lambda, double alpha, std::string reg, int i, int j);
|
||||
int sign(double weight);
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* Reg_hpp */
|
294
MLPP/SoftmaxNet/SoftmaxNet.cpp
Normal file
294
MLPP/SoftmaxNet/SoftmaxNet.cpp
Normal file
@ -0,0 +1,294 @@
|
||||
//
|
||||
// SoftmaxNet.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 10/2/20.
|
||||
//
|
||||
|
||||
#include "SoftmaxNet.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
#include "Data/Data.hpp"
|
||||
#include "Regularization/Reg.hpp"
|
||||
#include "Activation/Activation.hpp"
|
||||
#include "Utilities/Utilities.hpp"
|
||||
#include "Cost/Cost.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
namespace MLPP{
|
||||
SoftmaxNet::SoftmaxNet(std::vector<std::vector<double>> inputSet, std::vector<std::vector<double>> outputSet, int n_hidden, std::string reg, double lambda, double alpha)
|
||||
: inputSet(inputSet), outputSet(outputSet), n(inputSet.size()), k(inputSet[0].size()), n_hidden(n_hidden), n_class(outputSet[0].size()), reg(reg), lambda(lambda), alpha(alpha)
|
||||
{
|
||||
y_hat.resize(n);
|
||||
|
||||
weights1 = Utilities::weightInitialization(k, n_hidden);
|
||||
weights2 = Utilities::weightInitialization(n_hidden, n_class);
|
||||
bias1 = Utilities::biasInitialization(n_hidden);
|
||||
bias2 = Utilities::biasInitialization(n_class);
|
||||
}
|
||||
|
||||
std::vector<double> SoftmaxNet::modelTest(std::vector<double> x){
|
||||
return Evaluate(x);
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> SoftmaxNet::modelSetTest(std::vector<std::vector<double>> X){
|
||||
return Evaluate(X);
|
||||
}
|
||||
|
||||
void SoftmaxNet::gradientDescent(double learning_rate, int max_epoch, bool UI){
|
||||
Reg regularization;
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
|
||||
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
forwardPass();
|
||||
|
||||
while(true){
|
||||
cost_prev = Cost(y_hat, outputSet);
|
||||
|
||||
// Calculating the errors
|
||||
std::vector<std::vector<double>> error = alg.subtraction(y_hat, outputSet);
|
||||
|
||||
// Calculating the weight/bias gradients for layer 2
|
||||
|
||||
std::vector<std::vector<double>> D2_1 = alg.matmult(alg.transpose(a2), error);
|
||||
|
||||
// weights and bias updation for layer 2
|
||||
weights2 = alg.subtraction(weights2, alg.scalarMultiply(learning_rate, D2_1));
|
||||
weights2 = regularization.regWeights(weights2, lambda, alpha, reg);
|
||||
|
||||
bias2 = alg.subtractMatrixRows(bias2, alg.scalarMultiply(learning_rate, error));
|
||||
|
||||
//Calculating the weight/bias for layer 1
|
||||
|
||||
std::vector<std::vector<double>> D1_1 = alg.matmult(error, alg.transpose(weights2));
|
||||
|
||||
std::vector<std::vector<double>> D1_2 = alg.hadamard_product(D1_1, avn.sigmoid(z2, 1));
|
||||
|
||||
std::vector<std::vector<double>> D1_3 = alg.matmult(alg.transpose(inputSet), D1_2);
|
||||
|
||||
|
||||
// weight an bias updation for layer 1
|
||||
weights1 = alg.subtraction(weights1, alg.scalarMultiply(learning_rate, D1_3));
|
||||
weights1 = regularization.regWeights(weights1, lambda, alpha, reg);
|
||||
|
||||
bias1 = alg.subtractMatrixRows(bias1, alg.scalarMultiply(learning_rate, D1_2));
|
||||
|
||||
forwardPass();
|
||||
|
||||
// UI PORTION
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputSet));
|
||||
std::cout << "Layer 1:" << std::endl;
|
||||
Utilities::UI(weights1, bias1);
|
||||
std::cout << "Layer 2:" << std::endl;
|
||||
Utilities::UI(weights2, bias2);
|
||||
}
|
||||
epoch++;
|
||||
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SoftmaxNet::SGD(double learning_rate, int max_epoch, bool UI){
|
||||
Reg regularization;
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
Utilities util;
|
||||
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
while(true){
|
||||
std::random_device rd;
|
||||
std::default_random_engine generator(rd());
|
||||
std::uniform_int_distribution<int> distribution(0, int(n - 1));
|
||||
int outputIndex = distribution(generator);
|
||||
|
||||
std::vector<double> y_hat = Evaluate(inputSet[outputIndex]);
|
||||
auto [z2, a2] = propagate(inputSet[outputIndex]);
|
||||
cost_prev = Cost({y_hat}, {outputSet[outputIndex]});
|
||||
std::vector<double> error = alg.subtraction(y_hat, outputSet[outputIndex]);
|
||||
|
||||
// Weight updation for layer 2
|
||||
std::vector<std::vector<double>> D2_1 = alg.vecmult(error, a2);
|
||||
weights2 = alg.subtraction(weights2, alg.scalarMultiply(learning_rate, alg.transpose(D2_1)));
|
||||
weights2 = regularization.regWeights(weights2, lambda, alpha, reg);
|
||||
|
||||
// Bias updation for layer 2
|
||||
bias2 = alg.subtraction(bias2, alg.scalarMultiply(learning_rate, error));
|
||||
|
||||
// Weight updation for layer 1
|
||||
std::vector<double> D1_1 = alg.mat_vec_mult(weights2, error);
|
||||
std::vector<double> D1_2 = alg.hadamard_product(D1_1, avn.sigmoid(z2, 1));
|
||||
std::vector<std::vector<double>> D1_3 = alg.vecmult(inputSet[outputIndex], D1_2);
|
||||
|
||||
weights1 = alg.subtraction(weights1, alg.scalarMultiply(learning_rate, D1_3));
|
||||
weights1 = regularization.regWeights(weights1, lambda, alpha, reg);
|
||||
// Bias updation for layer 1
|
||||
|
||||
bias1 = alg.subtraction(bias1, alg.scalarMultiply(learning_rate, D1_2));
|
||||
|
||||
y_hat = Evaluate(inputSet[outputIndex]);
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost({y_hat}, {outputSet[outputIndex]}));
|
||||
std::cout << "Layer 1:" << std::endl;
|
||||
Utilities::UI(weights1, bias1);
|
||||
std::cout << "Layer 2:" << std::endl;
|
||||
Utilities::UI(weights2, bias2);
|
||||
}
|
||||
epoch++;
|
||||
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
forwardPass();
|
||||
}
|
||||
|
||||
void SoftmaxNet::MBGD(double learning_rate, int max_epoch, int miniBatch_size, bool UI){
|
||||
Reg regularization;
|
||||
Activation avn;
|
||||
LinAlg alg;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
|
||||
int n_miniBatch = n/miniBatch_size;
|
||||
|
||||
std::vector<std::vector<std::vector<double>>> inputMiniBatches;
|
||||
std::vector<std::vector<std::vector<double>>> outputMiniBatches;
|
||||
|
||||
//Creating the mini-batches
|
||||
for(int i = 0; i < n_miniBatch; i++){
|
||||
std::vector<std::vector<double>> currentInputSet;
|
||||
std::vector<std::vector<double>> currentOutputSet;
|
||||
for(int j = 0; j < n/n_miniBatch; j++){
|
||||
currentInputSet.push_back(inputSet[n/n_miniBatch * i + j]);
|
||||
currentOutputSet.push_back(outputSet[n/n_miniBatch * i + j]);
|
||||
}
|
||||
inputMiniBatches.push_back(currentInputSet);
|
||||
outputMiniBatches.push_back(currentOutputSet);
|
||||
}
|
||||
|
||||
if(double(n)/double(n_miniBatch) - int(n/n_miniBatch) != 0){
|
||||
for(int i = 0; i < n - n/n_miniBatch * n_miniBatch; i++){
|
||||
inputMiniBatches[n_miniBatch - 1].push_back(inputSet[n/n_miniBatch * n_miniBatch + i]);
|
||||
outputMiniBatches[n_miniBatch - 1].push_back(outputSet[n/n_miniBatch * n_miniBatch + i]);
|
||||
}
|
||||
}
|
||||
|
||||
while(true){
|
||||
for(int i = 0; i < n_miniBatch; i++){
|
||||
std::vector<std::vector<double>> y_hat = Evaluate(inputMiniBatches[i]);
|
||||
auto [z2, a2] = propagate(inputMiniBatches[i]);
|
||||
cost_prev = Cost(y_hat, outputMiniBatches[i]);
|
||||
|
||||
// Calculating the errors
|
||||
std::vector<std::vector<double>> error = alg.subtraction(y_hat, outputMiniBatches[i]);
|
||||
|
||||
// Calculating the weight/bias gradients for layer 2
|
||||
|
||||
std::vector<std::vector<double>> D2_1 = alg.matmult(alg.transpose(a2), error);
|
||||
|
||||
// weights and bias updation for layser 2
|
||||
weights2 = alg.subtraction(weights2, alg.scalarMultiply(learning_rate, D2_1));
|
||||
weights2 = regularization.regWeights(weights2, lambda, alpha, reg);
|
||||
|
||||
// Bias Updation for layer 2
|
||||
bias2 = alg.subtractMatrixRows(bias2, alg.scalarMultiply(learning_rate, error));
|
||||
|
||||
//Calculating the weight/bias for layer 1
|
||||
|
||||
std::vector<std::vector<double>> D1_1 = alg.matmult(error, alg.transpose(weights2));
|
||||
|
||||
std::vector<std::vector<double>> D1_2 = alg.hadamard_product(D1_1, avn.sigmoid(z2, 1));
|
||||
|
||||
std::vector<std::vector<double>> D1_3 = alg.matmult(alg.transpose(inputMiniBatches[i]), D1_2);
|
||||
|
||||
|
||||
// weight an bias updation for layer 1
|
||||
weights1 = alg.subtraction(weights1, alg.scalarMultiply(learning_rate, D1_3));
|
||||
weights1 = regularization.regWeights(weights1, lambda, alpha, reg);
|
||||
|
||||
bias1 = alg.subtractMatrixRows(bias1, alg.scalarMultiply(learning_rate, D1_2));
|
||||
|
||||
y_hat = Evaluate(inputMiniBatches[i]);
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputMiniBatches[i]));
|
||||
std::cout << "Layer 1:" << std::endl;
|
||||
Utilities::UI(weights1, bias1);
|
||||
std::cout << "Layer 2:" << std::endl;
|
||||
Utilities::UI(weights2, bias2);
|
||||
}
|
||||
}
|
||||
epoch++;
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
forwardPass();
|
||||
}
|
||||
|
||||
double SoftmaxNet::score(){
|
||||
Utilities util;
|
||||
return util.performance(y_hat, outputSet);
|
||||
}
|
||||
|
||||
void SoftmaxNet::save(std::string fileName){
|
||||
Utilities util;
|
||||
util.saveParameters(fileName, weights1, bias1, 0, 1);
|
||||
util.saveParameters(fileName, weights2, bias2, 1, 2);
|
||||
|
||||
LinAlg alg;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> SoftmaxNet::getEmbeddings(){
|
||||
return weights1;
|
||||
}
|
||||
|
||||
double SoftmaxNet::Cost(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y){
|
||||
Reg regularization;
|
||||
Data data;
|
||||
class Cost cost;
|
||||
return cost.CrossEntropy(y_hat, y) + regularization.regTerm(weights1, lambda, alpha, reg) + regularization.regTerm(weights2, lambda, alpha, reg);
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> SoftmaxNet::Evaluate(std::vector<std::vector<double>> X){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
std::vector<std::vector<double>> z2 = alg.mat_vec_add(alg.matmult(X, weights1), bias1);
|
||||
std::vector<std::vector<double>> a2 = avn.sigmoid(z2);
|
||||
return avn.adjSoftmax(alg.mat_vec_add(alg.matmult(a2, weights2), bias2));
|
||||
}
|
||||
|
||||
std::tuple<std::vector<std::vector<double>>, std::vector<std::vector<double>>> SoftmaxNet::propagate(std::vector<std::vector<double>> X){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
std::vector<std::vector<double>> z2 = alg.mat_vec_add(alg.matmult(X, weights1), bias1);
|
||||
std::vector<std::vector<double>> a2 = avn.sigmoid(z2);
|
||||
return {z2, a2};
|
||||
}
|
||||
|
||||
std::vector<double> SoftmaxNet::Evaluate(std::vector<double> x){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
std::vector<double> z2 = alg.addition(alg.mat_vec_mult(alg.transpose(weights1), x), bias1);
|
||||
std::vector<double> a2 = avn.sigmoid(z2);
|
||||
return avn.adjSoftmax(alg.addition(alg.mat_vec_mult(alg.transpose(weights2), a2), bias2));
|
||||
}
|
||||
|
||||
std::tuple<std::vector<double>, std::vector<double>> SoftmaxNet::propagate(std::vector<double> x){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
std::vector<double> z2 = alg.addition(alg.mat_vec_mult(alg.transpose(weights1), x), bias1);
|
||||
std::vector<double> a2 = avn.sigmoid(z2);
|
||||
return {z2, a2};
|
||||
}
|
||||
|
||||
void SoftmaxNet::forwardPass(){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
z2 = alg.mat_vec_add(alg.matmult(inputSet, weights1), bias1);
|
||||
a2 = avn.sigmoid(z2);
|
||||
y_hat = avn.adjSoftmax(alg.mat_vec_add(alg.matmult(a2, weights2), bias2));
|
||||
}
|
||||
}
|
66
MLPP/SoftmaxNet/SoftmaxNet.hpp
Normal file
66
MLPP/SoftmaxNet/SoftmaxNet.hpp
Normal file
@ -0,0 +1,66 @@
|
||||
//
|
||||
// SoftmaxNet.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 10/2/20.
|
||||
//
|
||||
|
||||
#ifndef SoftmaxNet_hpp
|
||||
#define SoftmaxNet_hpp
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace MLPP {
|
||||
|
||||
class SoftmaxNet{
|
||||
|
||||
public:
|
||||
SoftmaxNet(std::vector<std::vector<double>> inputSet, std::vector<std::vector<double>> outputSet, int n_hidden, std::string reg = "None", double lambda = 0.5, double alpha = 0.5);
|
||||
std::vector<double> modelTest(std::vector<double> x);
|
||||
std::vector<std::vector<double>> modelSetTest(std::vector<std::vector<double>> X);
|
||||
void gradientDescent(double learning_rate, int max_epoch, bool UI = 1);
|
||||
void SGD(double learning_rate, int max_epoch, bool UI = 1);
|
||||
void MBGD(double learning_rate, int max_epoch, int miniBatch_size, bool UI = 1);
|
||||
double score();
|
||||
void save(std::string fileName);
|
||||
|
||||
std::vector<std::vector<double>> getEmbeddings(); // This class is used (mostly) for word2Vec. This function returns our embeddings.
|
||||
private:
|
||||
|
||||
double Cost(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y);
|
||||
|
||||
std::vector<std::vector<double>> Evaluate(std::vector<std::vector<double>> X);
|
||||
std::tuple<std::vector<std::vector<double>>, std::vector<std::vector<double>>> propagate(std::vector<std::vector<double>> X);
|
||||
std::vector<double> Evaluate(std::vector<double> x);
|
||||
std::tuple<std::vector<double>, std::vector<double>> propagate(std::vector<double> x);
|
||||
void forwardPass();
|
||||
|
||||
std::vector<std::vector<double>> inputSet;
|
||||
std::vector<std::vector<double>> outputSet;
|
||||
std::vector<std::vector<double>> y_hat;
|
||||
|
||||
std::vector<std::vector<double>> weights1;
|
||||
std::vector<std::vector<double>> weights2;
|
||||
|
||||
std::vector<double> bias1;
|
||||
std::vector<double> bias2;
|
||||
|
||||
std::vector<std::vector<double>> z2;
|
||||
std::vector<std::vector<double>> a2;
|
||||
|
||||
int n;
|
||||
int k;
|
||||
int n_class;
|
||||
int n_hidden;
|
||||
|
||||
// Regularization Params
|
||||
std::string reg;
|
||||
double lambda;
|
||||
double alpha; /* This is the controlling param for Elastic Net*/
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* SoftmaxNet_hpp */
|
213
MLPP/SoftmaxReg/SoftmaxReg.cpp
Normal file
213
MLPP/SoftmaxReg/SoftmaxReg.cpp
Normal file
@ -0,0 +1,213 @@
|
||||
//
|
||||
// SoftmaxReg.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 10/2/20.
|
||||
//
|
||||
|
||||
#include "SoftmaxReg.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
#include "Regularization/Reg.hpp"
|
||||
#include "Activation/Activation.hpp"
|
||||
#include "Utilities/Utilities.hpp"
|
||||
#include "Cost/Cost.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
namespace MLPP{
|
||||
SoftmaxReg::SoftmaxReg(std::vector<std::vector<double>> inputSet, std::vector<std::vector<double>> outputSet, std::string reg, double lambda, double alpha)
|
||||
: inputSet(inputSet), outputSet(outputSet), n(inputSet.size()), k(inputSet[0].size()), n_class(outputSet[0].size()), reg(reg), lambda(lambda), alpha(alpha)
|
||||
{
|
||||
y_hat.resize(n);
|
||||
weights = Utilities::weightInitialization(k, n_class);
|
||||
bias = Utilities::biasInitialization(n_class);
|
||||
}
|
||||
|
||||
std::vector<double> SoftmaxReg::modelTest(std::vector<double> x){
|
||||
return Evaluate(x);
|
||||
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> SoftmaxReg::modelSetTest(std::vector<std::vector<double>> X){
|
||||
return Evaluate(X);
|
||||
}
|
||||
|
||||
void SoftmaxReg::gradientDescent(double learning_rate, int max_epoch, bool UI){
|
||||
Reg regularization;
|
||||
LinAlg alg;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
forwardPass();
|
||||
|
||||
while(true){
|
||||
cost_prev = Cost(y_hat, outputSet);
|
||||
std::vector<std::vector<double>> error = alg.subtraction(y_hat, outputSet);
|
||||
|
||||
|
||||
//Calculating the weight gradients
|
||||
std::vector<std::vector<double>> w_gradient = alg.matmult(alg.transpose(inputSet), error);
|
||||
|
||||
//Weight updation
|
||||
weights = alg.subtraction(weights, alg.scalarMultiply(learning_rate, w_gradient));
|
||||
weights = regularization.regWeights(weights, lambda, alpha, reg);
|
||||
|
||||
|
||||
// Calculating the bias gradients
|
||||
//double b_gradient = alg.sum_elements(error);
|
||||
|
||||
// Bias Updation
|
||||
bias = alg.subtractMatrixRows(bias, alg.scalarMultiply(learning_rate, error));
|
||||
|
||||
forwardPass();
|
||||
|
||||
// UI PORTION
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputSet));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
epoch++;
|
||||
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
}
|
||||
|
||||
void SoftmaxReg::SGD(double learning_rate, int max_epoch, bool UI){
|
||||
Reg regularization;
|
||||
LinAlg alg;
|
||||
Utilities util;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
|
||||
while(true){
|
||||
std::random_device rd;
|
||||
std::default_random_engine generator(rd());
|
||||
std::uniform_int_distribution<int> distribution(0, int(n - 1));
|
||||
double outputIndex = distribution(generator);
|
||||
|
||||
std::vector<double> y_hat = Evaluate(inputSet[outputIndex]);
|
||||
cost_prev = Cost({y_hat}, {outputSet[outputIndex]});
|
||||
|
||||
// Calculating the weight gradients
|
||||
std::vector<std::vector<double>> w_gradient = alg.vecmult(inputSet[outputIndex], alg.subtraction(y_hat, outputSet[outputIndex]));
|
||||
|
||||
// Weight Updation
|
||||
weights = alg.subtraction(weights, alg.scalarMultiply(learning_rate, w_gradient));
|
||||
weights = regularization.regWeights(weights, lambda, alpha, reg);
|
||||
|
||||
// Calculating the bias gradients
|
||||
std::vector<double> b_gradient = alg.subtraction(y_hat, outputSet[outputIndex]);
|
||||
|
||||
// Bias updation
|
||||
bias = alg.subtraction(bias, alg.scalarMultiply(learning_rate, b_gradient));
|
||||
|
||||
y_hat = Evaluate({inputSet[outputIndex]});
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost({y_hat}, {outputSet[outputIndex]}));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
epoch++;
|
||||
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
forwardPass();
|
||||
|
||||
}
|
||||
|
||||
void SoftmaxReg::MBGD(double learning_rate, int max_epoch, int miniBatch_size, bool UI){
|
||||
Reg regularization;
|
||||
LinAlg alg;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
|
||||
int n_miniBatch = n/miniBatch_size;
|
||||
|
||||
std::vector<std::vector<std::vector<double>>> inputMiniBatches;
|
||||
std::vector<std::vector<std::vector<double>>> outputMiniBatches;
|
||||
|
||||
// Creating the mini-batches
|
||||
for(int i = 0; i < n_miniBatch; i++){
|
||||
std::vector<std::vector<double>> currentInputSet;
|
||||
std::vector<std::vector<double>> currentOutputSet;
|
||||
for(int j = 0; j < n/n_miniBatch; j++){
|
||||
currentInputSet.push_back(inputSet[n/n_miniBatch * i + j]);
|
||||
currentOutputSet.push_back(outputSet[n/n_miniBatch * i + j]);
|
||||
}
|
||||
inputMiniBatches.push_back(currentInputSet);
|
||||
outputMiniBatches.push_back(currentOutputSet);
|
||||
}
|
||||
|
||||
if(double(n)/double(n_miniBatch) - int(n/n_miniBatch) != 0){
|
||||
for(int i = 0; i < n - n/n_miniBatch * n_miniBatch; i++){
|
||||
inputMiniBatches[n_miniBatch - 1].push_back(inputSet[n/n_miniBatch * n_miniBatch + i]);
|
||||
outputMiniBatches[n_miniBatch - 1].push_back(outputSet[n/n_miniBatch * n_miniBatch + i]);
|
||||
}
|
||||
}
|
||||
|
||||
while(true){
|
||||
for(int i = 0; i < n_miniBatch; i++){
|
||||
std::vector<std::vector<double>> y_hat = Evaluate(inputMiniBatches[i]);
|
||||
cost_prev = Cost(y_hat, outputMiniBatches[i]);
|
||||
|
||||
std::vector<std::vector<double>> error = alg.subtraction(y_hat, outputMiniBatches[i]);
|
||||
|
||||
// Calculating the weight gradients
|
||||
std::vector<std::vector<double>> w_gradient = alg.matmult(alg.transpose(inputMiniBatches[i]), error);
|
||||
|
||||
//Weight updation
|
||||
weights = alg.subtraction(weights, alg.scalarMultiply(learning_rate, w_gradient));
|
||||
weights = regularization.regWeights(weights, lambda, alpha, reg);
|
||||
|
||||
// Calculating the bias gradients
|
||||
bias = alg.subtractMatrixRows(bias, alg.scalarMultiply(learning_rate, error));
|
||||
y_hat = Evaluate(inputMiniBatches[i]);
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputMiniBatches[i]));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
}
|
||||
epoch++;
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
forwardPass();
|
||||
}
|
||||
|
||||
double SoftmaxReg::score(){
|
||||
Utilities util;
|
||||
return util.performance(y_hat, outputSet);
|
||||
}
|
||||
|
||||
void SoftmaxReg::save(std::string fileName){
|
||||
Utilities util;
|
||||
util.saveParameters(fileName, weights, bias);
|
||||
}
|
||||
|
||||
double SoftmaxReg::Cost(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y){
|
||||
Reg regularization;
|
||||
class Cost cost;
|
||||
return cost.CrossEntropy(y_hat, y) + regularization.regTerm(weights, lambda, alpha, reg);
|
||||
}
|
||||
|
||||
std::vector<double> SoftmaxReg::Evaluate(std::vector<double> x){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
return avn.softmax(alg.addition(bias, alg.mat_vec_mult(alg.transpose(weights), x)));
|
||||
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> SoftmaxReg::Evaluate(std::vector<std::vector<double>> X){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
|
||||
return avn.softmax(alg.mat_vec_add(alg.matmult(X, weights), bias));
|
||||
}
|
||||
|
||||
// softmax ( wTx + b )
|
||||
void SoftmaxReg::forwardPass(){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
|
||||
y_hat = avn.softmax(alg.mat_vec_add(alg.matmult(inputSet, weights), bias));
|
||||
}
|
||||
}
|
54
MLPP/SoftmaxReg/SoftmaxReg.hpp
Normal file
54
MLPP/SoftmaxReg/SoftmaxReg.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
//
|
||||
// SoftmaxReg.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 10/2/20.
|
||||
//
|
||||
|
||||
#ifndef SoftmaxReg_hpp
|
||||
#define SoftmaxReg_hpp
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace MLPP {
|
||||
|
||||
class SoftmaxReg{
|
||||
|
||||
public:
|
||||
SoftmaxReg(std::vector<std::vector<double>> inputSet, std::vector<std::vector<double>> outputSet, std::string reg = "None", double lambda = 0.5, double alpha = 0.5);
|
||||
std::vector<double> modelTest(std::vector<double> x);
|
||||
std::vector<std::vector<double>> modelSetTest(std::vector<std::vector<double>> X);
|
||||
void gradientDescent(double learning_rate, int max_epoch, bool UI = 1);
|
||||
void SGD(double learning_rate, int max_epoch, bool UI = 1);
|
||||
void MBGD(double learning_rate, int max_epoch, int miniBatch_size, bool UI = 1);
|
||||
double score();
|
||||
void save(std::string fileName);
|
||||
private:
|
||||
|
||||
double Cost(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y);
|
||||
|
||||
std::vector<std::vector<double>> Evaluate(std::vector<std::vector<double>> X);
|
||||
std::vector<double> Evaluate(std::vector<double> x);
|
||||
void forwardPass();
|
||||
|
||||
std::vector<std::vector<double>> inputSet;
|
||||
std::vector<std::vector<double>> outputSet;
|
||||
std::vector<std::vector<double>> y_hat;
|
||||
std::vector<std::vector<double>> weights;
|
||||
std::vector<double> bias;
|
||||
|
||||
int n;
|
||||
int k;
|
||||
int n_class;
|
||||
|
||||
// Regularization Params
|
||||
std::string reg;
|
||||
double lambda;
|
||||
double alpha; /* This is the controlling param for Elastic Net*/
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* SoftmaxReg_hpp */
|
168
MLPP/Stat/Stat.cpp
Normal file
168
MLPP/Stat/Stat.cpp
Normal file
@ -0,0 +1,168 @@
|
||||
//
|
||||
// Stat.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 9/29/20.
|
||||
//
|
||||
|
||||
#include "Stat.hpp"
|
||||
#include "Activation/Activation.hpp"
|
||||
#include <cmath>
|
||||
|
||||
namespace MLPP{
|
||||
double Stat::b0Estimation(std::vector<double> x, std::vector<double> y){
|
||||
return mean(y) - b1Estimation(x, y) * mean(x);
|
||||
}
|
||||
|
||||
double Stat::b1Estimation(std::vector<double> x, std::vector<double> y){
|
||||
return covariance(x, y) / variance(x);
|
||||
}
|
||||
|
||||
double Stat::mean(std::vector<double> x){
|
||||
double sum = 0;
|
||||
for(int i = 0; i < x.size(); i++){
|
||||
sum += x[i];
|
||||
}
|
||||
return sum / x.size();
|
||||
}
|
||||
|
||||
double Stat::variance(std::vector<double> x){
|
||||
double sum = 0;
|
||||
for(int i = 0; i < x.size(); i++){
|
||||
sum += (x[i] - mean(x)) * (x[i] - mean(x));
|
||||
}
|
||||
return sum / (x.size() - 1);
|
||||
}
|
||||
|
||||
double Stat::covariance(std::vector<double> x, std::vector<double> y){
|
||||
double sum = 0;
|
||||
for(int i = 0; i < x.size(); i++){
|
||||
sum += (x[i] - mean(x)) * (y[i] - mean(y));
|
||||
}
|
||||
return sum / (x.size() - 1);
|
||||
}
|
||||
|
||||
double Stat::correlation(std::vector<double> x, std::vector<double> y){
|
||||
return covariance(x, y) / (standardDeviation(x) * standardDeviation(y));
|
||||
}
|
||||
|
||||
double Stat::R2(std::vector<double> x, std::vector<double> y){
|
||||
return correlation(x, y) * correlation(x, y);
|
||||
}
|
||||
|
||||
double Stat::weightedMean(std::vector<double> x, std::vector<double> weights){
|
||||
double sum = 0;
|
||||
double weights_sum = 0;
|
||||
for(int i = 0; i < x.size(); i++){
|
||||
sum += x[i] * weights[i];
|
||||
weights_sum += weights[i];
|
||||
}
|
||||
return sum / weights_sum;
|
||||
}
|
||||
|
||||
double Stat::geometricMean(std::vector<double> x){
|
||||
double product = 1;
|
||||
for(int i = 0; i < x.size(); i++){
|
||||
product *= x[i];
|
||||
}
|
||||
return std::pow(product, 1.0/x.size());
|
||||
}
|
||||
|
||||
double Stat::harmonicMean(std::vector<double> x){
|
||||
double sum = 0;
|
||||
for(int i = 0; i < x.size(); i++){
|
||||
sum += 1/x[i];
|
||||
}
|
||||
return x.size()/sum;
|
||||
}
|
||||
|
||||
double Stat::RMS(std::vector<double> x){
|
||||
double sum = 0;
|
||||
for(int i = 0; i < x.size(); i++){
|
||||
sum += x[i] * x[i];
|
||||
}
|
||||
return sqrt(sum / x.size());
|
||||
}
|
||||
|
||||
double Stat::powerMean(std::vector<double> x, double p){
|
||||
double sum = 0;
|
||||
for(int i = 0; i < x.size(); i++){
|
||||
sum += pow(x[i], p);
|
||||
}
|
||||
return pow(sum / x.size(), 1/p);
|
||||
}
|
||||
|
||||
double Stat::lehmerMean(std::vector<double> x, double p){
|
||||
double num = 0;
|
||||
double den = 0;
|
||||
for(int i = 0; i < x.size(); i++){
|
||||
num += pow(x[i], p);
|
||||
den += pow(x[i], p - 1);
|
||||
}
|
||||
return num/den;
|
||||
}
|
||||
|
||||
double Stat::weightedLehmerMean(std::vector<double> x, std::vector<double> weights, double p){
|
||||
double num = 0;
|
||||
double den = 0;
|
||||
for(int i = 0; i < x.size(); i++){
|
||||
num += weights[i] * pow(x[i], p);
|
||||
den += weights[i] * pow(x[i], p - 1);
|
||||
}
|
||||
return num/den;
|
||||
}
|
||||
|
||||
double Stat::heronianMean(double A, double B){
|
||||
return (A + sqrt(A * B) + B) / 3;
|
||||
}
|
||||
|
||||
double Stat::contraharmonicMean(std::vector<double> x){
|
||||
return lehmerMean(x, 2);
|
||||
}
|
||||
|
||||
double Stat::heinzMean(double A, double B, double x){
|
||||
return (pow(A, x) * pow(B, 1 - x) + pow(A, 1 - x) * pow(B, x)) / 2;
|
||||
}
|
||||
|
||||
double Stat::neumanSandorMean(double a, double b){
|
||||
Activation avn;
|
||||
return (a - b) / 2 * avn.arsinh((a - b)/(a + b));
|
||||
}
|
||||
|
||||
double Stat::stolarskyMean(double x, double y, double p){
|
||||
if(x == y){
|
||||
return x;
|
||||
}
|
||||
return pow((pow(x, p) - pow(y, p)) / (p * (x - y)), 1/(p - 1));
|
||||
}
|
||||
|
||||
double Stat::identricMean(double x, double y){
|
||||
if(x == y){
|
||||
return x;
|
||||
}
|
||||
return (1/M_E) * pow(pow(x, x) / pow(y, y), 1/(x-y));
|
||||
}
|
||||
|
||||
double Stat::logMean(double x, double y){
|
||||
if(x == y){
|
||||
return x;
|
||||
}
|
||||
return (y - x) / (log(y) - log(x));
|
||||
}
|
||||
|
||||
double Stat::standardDeviation(std::vector<double> x){
|
||||
return std::sqrt(variance(x));
|
||||
}
|
||||
|
||||
double Stat::absAvgDeviation(std::vector<double> x){
|
||||
double sum = 0;
|
||||
for(int i = 0; i < x.size(); i++){
|
||||
sum += std::abs(x[i] - mean(x));
|
||||
}
|
||||
return sum / x.size();
|
||||
}
|
||||
|
||||
double Stat::chebyshevIneq(double k){
|
||||
//Pr(|X - mu| >= k * sigma) <= 1/k^2, X may or may not belong to a Gaussian Distribution
|
||||
return 1 - 1 / (k * k);
|
||||
}
|
||||
}
|
53
MLPP/Stat/Stat.hpp
Normal file
53
MLPP/Stat/Stat.hpp
Normal file
@ -0,0 +1,53 @@
|
||||
//
|
||||
// Stat.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 9/29/20.
|
||||
//
|
||||
|
||||
#ifndef Stat_hpp
|
||||
#define Stat_hpp
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace MLPP{
|
||||
class Stat{
|
||||
|
||||
public:
|
||||
double b0Estimation(std::vector<double> x, std::vector<double> y);
|
||||
double b1Estimation(std::vector<double> x, std::vector<double> y);
|
||||
|
||||
// Statistical Functions
|
||||
double mean(std::vector <double> x);
|
||||
double variance(std::vector <double> x);
|
||||
double covariance(std::vector <double> x, std::vector <double> y);
|
||||
double correlation(std::vector <double> x, std::vector<double> y);
|
||||
double R2(std::vector <double> x, std::vector<double> y);
|
||||
|
||||
// Extras
|
||||
double weightedMean(std::vector<double> x, std::vector<double> weights);
|
||||
double geometricMean(std::vector <double> x);
|
||||
double harmonicMean(std::vector <double> x);
|
||||
double RMS(std::vector<double> x);
|
||||
double powerMean(std::vector<double> x, double p);
|
||||
double lehmerMean(std::vector<double> x, double p);
|
||||
double weightedLehmerMean(std::vector<double> x, std::vector<double> weights, double p);
|
||||
double contraharmonicMean(std::vector<double> x);
|
||||
double heronianMean(double A, double B);
|
||||
double heinzMean(double A, double B, double x);
|
||||
double neumanSandorMean(double a, double b);
|
||||
double stolarskyMean(double x, double y, double p);
|
||||
double identricMean(double x, double y);
|
||||
double logMean(double x, double y);
|
||||
double standardDeviation(std::vector <double> x);
|
||||
double absAvgDeviation(std::vector <double> x);
|
||||
double chebyshevIneq(double k);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* Stat_hpp */
|
222
MLPP/TanhReg/TanhReg.cpp
Normal file
222
MLPP/TanhReg/TanhReg.cpp
Normal file
@ -0,0 +1,222 @@
|
||||
//
|
||||
// TanhReg.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 10/2/20.
|
||||
//
|
||||
|
||||
#include "TanhReg.hpp"
|
||||
#include "Activation/Activation.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
#include "Regularization/Reg.hpp"
|
||||
#include "Utilities/Utilities.hpp"
|
||||
#include "Cost/Cost.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
namespace MLPP{
|
||||
TanhReg::TanhReg(std::vector<std::vector<double>> inputSet, std::vector<double> 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)
|
||||
{
|
||||
y_hat.resize(n);
|
||||
weights = Utilities::weightInitialization(k);
|
||||
bias = Utilities::biasInitialization();
|
||||
}
|
||||
|
||||
std::vector<double> TanhReg::modelSetTest(std::vector<std::vector<double>> X){
|
||||
return Evaluate(X);
|
||||
}
|
||||
|
||||
double TanhReg::modelTest(std::vector<double> x){
|
||||
return Evaluate(x);
|
||||
}
|
||||
|
||||
void TanhReg::gradientDescent(double learning_rate, int max_epoch, bool UI){
|
||||
Reg regularization;
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
forwardPass();
|
||||
|
||||
while(true){
|
||||
cost_prev = Cost(y_hat, outputSet);
|
||||
|
||||
std::vector<double> error = alg.subtraction(y_hat, outputSet);
|
||||
|
||||
weights = alg.subtraction(weights, alg.scalarMultiply(learning_rate/n, alg.mat_vec_mult(alg.transpose(inputSet), alg.hadamard_product(error, avn.tanh(z, 1)))));
|
||||
weights = regularization.regWeights(weights, lambda, alpha, reg);
|
||||
|
||||
|
||||
// Calculating the bias gradients
|
||||
bias -= learning_rate * alg.sum_elements(alg.hadamard_product(error, avn.tanh(z, 1))) / n;
|
||||
|
||||
forwardPass();
|
||||
|
||||
// UI PORTION
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputSet));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
epoch++;
|
||||
|
||||
if(epoch > max_epoch) { break; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void TanhReg::SGD(double learning_rate, int max_epoch, bool UI){
|
||||
Reg regularization;
|
||||
Utilities util;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
|
||||
while(true){
|
||||
std::random_device rd;
|
||||
std::default_random_engine generator(rd());
|
||||
std::uniform_int_distribution<int> distribution(0, int(n - 1));
|
||||
int outputIndex = distribution(generator);
|
||||
|
||||
double y_hat = Evaluate(inputSet[outputIndex]);
|
||||
cost_prev = Cost({y_hat}, {outputSet[outputIndex]});
|
||||
|
||||
|
||||
for(int i = 0; i < k; i++){
|
||||
|
||||
// Calculating the weight gradients
|
||||
|
||||
double w_gradient = (y_hat - outputSet[outputIndex]) * (1 - y_hat * y_hat) * inputSet[outputIndex][i];
|
||||
|
||||
|
||||
// Weight updation
|
||||
weights[i] -= learning_rate * w_gradient;
|
||||
}
|
||||
weights = regularization.regWeights(weights, lambda, alpha, reg);
|
||||
|
||||
// Calculating the bias gradients
|
||||
double b_gradient = (y_hat - outputSet[outputIndex]) * (1 - y_hat * y_hat);
|
||||
|
||||
// Bias updation
|
||||
bias -= learning_rate * b_gradient;
|
||||
y_hat = Evaluate({inputSet[outputIndex]});
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost({y_hat}, {outputSet[outputIndex]}));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
epoch++;
|
||||
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
forwardPass();
|
||||
}
|
||||
|
||||
void TanhReg::MBGD(double learning_rate, int max_epoch, int miniBatch_size, bool UI){
|
||||
Reg regularization;
|
||||
Activation avn;
|
||||
LinAlg alg;
|
||||
double cost_prev = 0;
|
||||
int epoch = 1;
|
||||
|
||||
int n_miniBatch = n/miniBatch_size;
|
||||
|
||||
std::vector<std::vector<std::vector<double>>> inputMiniBatches;
|
||||
std::vector<std::vector<double>> outputMiniBatches;
|
||||
// Creating the mini-batches
|
||||
for(int i = 0; i < n_miniBatch; i++){
|
||||
std::vector<std::vector<double>> currentInputSet;
|
||||
std::vector<double> currentOutputSet;
|
||||
std::vector<double> currentPreActivationSet;
|
||||
for(int j = 0; j < n/n_miniBatch; j++){
|
||||
currentInputSet.push_back(inputSet[n/n_miniBatch * i + j]);
|
||||
currentOutputSet.push_back(outputSet[n/n_miniBatch * i + j]);
|
||||
}
|
||||
inputMiniBatches.push_back(currentInputSet);
|
||||
outputMiniBatches.push_back(currentOutputSet);
|
||||
}
|
||||
|
||||
if(double(n)/double(n_miniBatch) - int(n/n_miniBatch) != 0){
|
||||
for(int i = 0; i < n - n/n_miniBatch * n_miniBatch; i++){
|
||||
inputMiniBatches[n_miniBatch - 1].push_back(inputSet[n/n_miniBatch * n_miniBatch + i]);
|
||||
outputMiniBatches[n_miniBatch - 1].push_back(outputSet[n/n_miniBatch * n_miniBatch + i]);
|
||||
}
|
||||
}
|
||||
|
||||
while(true){
|
||||
for(int i = 0; i < n_miniBatch; i++){
|
||||
std::vector<double> y_hat = Evaluate(inputMiniBatches[i]);
|
||||
std::vector<double> z = propagate(inputMiniBatches[i]);
|
||||
cost_prev = Cost(y_hat, outputMiniBatches[i]);
|
||||
|
||||
std::vector<double> error = alg.subtraction(y_hat, outputMiniBatches[i]);
|
||||
|
||||
// Calculating the weight gradients
|
||||
weights = alg.subtraction(weights, alg.scalarMultiply(learning_rate/n, alg.mat_vec_mult(alg.transpose(inputMiniBatches[i]), alg.hadamard_product(error, avn.tanh(z, 1)))));
|
||||
weights = regularization.regWeights(weights, lambda, alpha, reg);
|
||||
|
||||
|
||||
// Calculating the bias gradients
|
||||
bias -= learning_rate * alg.sum_elements(alg.hadamard_product(error, avn.tanh(z, 1))) / n;
|
||||
|
||||
forwardPass();
|
||||
|
||||
y_hat = Evaluate(inputMiniBatches[i]);
|
||||
|
||||
if(UI) {
|
||||
Utilities::CostInfo(epoch, cost_prev, Cost(y_hat, outputMiniBatches[i]));
|
||||
Utilities::UI(weights, bias);
|
||||
}
|
||||
}
|
||||
epoch++;
|
||||
if(epoch > max_epoch) { break; }
|
||||
}
|
||||
forwardPass();
|
||||
}
|
||||
|
||||
double TanhReg::score(){
|
||||
Utilities util;
|
||||
return util.performance(y_hat, outputSet);
|
||||
}
|
||||
|
||||
void TanhReg::save(std::string fileName){
|
||||
Utilities util;
|
||||
util.saveParameters(fileName, weights, bias);
|
||||
}
|
||||
|
||||
double TanhReg::Cost(std::vector <double> y_hat, std::vector<double> y){
|
||||
Reg regularization;
|
||||
class Cost cost;
|
||||
return cost.MSE(y_hat, y) + regularization.regTerm(weights, lambda, alpha, reg);
|
||||
}
|
||||
|
||||
std::vector<double> TanhReg::Evaluate(std::vector<std::vector<double>> X){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
return avn.tanh(alg.scalarAdd(bias, alg.mat_vec_mult(X, weights)));
|
||||
}
|
||||
|
||||
std::vector<double>TanhReg::propagate(std::vector<std::vector<double>> X){
|
||||
LinAlg alg;
|
||||
return alg.scalarAdd(bias, alg.mat_vec_mult(X, weights));
|
||||
}
|
||||
|
||||
double TanhReg::Evaluate(std::vector<double> x){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
return avn.tanh(alg.dot(weights, x) + bias);
|
||||
}
|
||||
|
||||
double TanhReg::propagate(std::vector<double> x){
|
||||
LinAlg alg;
|
||||
return alg.dot(weights, x) + bias;
|
||||
}
|
||||
|
||||
// Tanh ( wTx + b )
|
||||
void TanhReg::forwardPass(){
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
|
||||
z = propagate(inputSet);
|
||||
y_hat = avn.tanh(z);
|
||||
}
|
||||
}
|
59
MLPP/TanhReg/TanhReg.hpp
Normal file
59
MLPP/TanhReg/TanhReg.hpp
Normal file
@ -0,0 +1,59 @@
|
||||
//
|
||||
// TanhReg.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 10/2/20.
|
||||
//
|
||||
|
||||
#ifndef TanhReg_hpp
|
||||
#define TanhReg_hpp
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace MLPP {
|
||||
|
||||
class TanhReg{
|
||||
|
||||
public:
|
||||
TanhReg(std::vector<std::vector<double>> inputSet, std::vector<double> outputSet, std::string reg = "None", double lambda = 0.5, double alpha = 0.5);
|
||||
std::vector<double> modelSetTest(std::vector<std::vector<double>> X);
|
||||
double modelTest(std::vector<double> x);
|
||||
void gradientDescent(double learning_rate, int max_epoch, bool UI = 1);
|
||||
void SGD(double learning_rate, int max_epoch, bool UI = 1);
|
||||
void MBGD(double learning_rate, int max_epoch, int miniBatch_size, bool UI = 1);
|
||||
double score();
|
||||
void save(std::string fileName);
|
||||
private:
|
||||
|
||||
double Cost(std::vector <double> y_hat, std::vector<double> y);
|
||||
|
||||
std::vector<double> Evaluate(std::vector<std::vector<double>> X);
|
||||
std::vector<double> propagate(std::vector<std::vector<double>> X);
|
||||
double Evaluate(std::vector<double> x);
|
||||
double propagate(std::vector<double> x);
|
||||
void forwardPass();
|
||||
|
||||
std::vector<std::vector<double>> inputSet;
|
||||
std::vector<double> outputSet;
|
||||
std::vector<double> z;
|
||||
std::vector<double> y_hat;
|
||||
std::vector<double> weights;
|
||||
double bias;
|
||||
|
||||
int n;
|
||||
int k;
|
||||
|
||||
// UI Portion
|
||||
void UI(int epoch, double cost_prev);
|
||||
|
||||
// Regularization Params
|
||||
std::string reg;
|
||||
double lambda;
|
||||
double alpha; /* This is the controlling param for Elastic Net*/
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* TanhReg_hpp */
|
37
MLPP/UniLinReg/UniLinReg.cpp
Normal file
37
MLPP/UniLinReg/UniLinReg.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
//
|
||||
// UniLinReg.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 9/29/20.
|
||||
//
|
||||
|
||||
#include "UniLinReg.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
#include "Stat/Stat.hpp"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
// General Multivariate Linear Regression Model
|
||||
// ŷ = b0 + b1x1 + b2x2 + ... + bkxk
|
||||
|
||||
|
||||
// Univariate Linear Regression Model
|
||||
// ŷ = b0 + b1x1
|
||||
|
||||
namespace MLPP{
|
||||
UniLinReg::UniLinReg(std::vector<double> x, std::vector<double> y)
|
||||
: inputSet(x), outputSet(y)
|
||||
{
|
||||
Stat estimator;
|
||||
b1 = estimator.b1Estimation(inputSet, outputSet);
|
||||
b0 = estimator.b0Estimation(inputSet, outputSet);
|
||||
}
|
||||
|
||||
std::vector<double> UniLinReg::modelSetTest(std::vector<double> x){
|
||||
LinAlg alg;
|
||||
return alg.scalarAdd(b0, alg.scalarMultiply(b1, x));
|
||||
}
|
||||
|
||||
double UniLinReg::modelTest(double input){
|
||||
return b0 + b1 * input;
|
||||
}
|
||||
}
|
30
MLPP/UniLinReg/UniLinReg.hpp
Normal file
30
MLPP/UniLinReg/UniLinReg.hpp
Normal file
@ -0,0 +1,30 @@
|
||||
//
|
||||
// UniLinReg.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 9/29/20.
|
||||
//
|
||||
|
||||
#ifndef UniLinReg_hpp
|
||||
#define UniLinReg_hpp
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace MLPP{
|
||||
class UniLinReg{
|
||||
|
||||
public:
|
||||
UniLinReg(std::vector <double> x, std::vector<double> y);
|
||||
std::vector<double> modelSetTest(std::vector<double> x);
|
||||
double modelTest(double x);
|
||||
|
||||
private:
|
||||
std::vector <double> inputSet;
|
||||
std::vector <double> outputSet;
|
||||
|
||||
double b0;
|
||||
double b1;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* UniLinReg_hpp */
|
307
MLPP/Utilities/Utilities.cpp
Normal file
307
MLPP/Utilities/Utilities.cpp
Normal file
@ -0,0 +1,307 @@
|
||||
//
|
||||
// Reg.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 1/16/21.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <random>
|
||||
#include <fstream>
|
||||
#include "Utilities.hpp"
|
||||
|
||||
namespace MLPP{
|
||||
|
||||
std::vector<double> Utilities::weightInitialization(int n, std::string type){
|
||||
std::random_device rd;
|
||||
std::default_random_engine generator(rd());
|
||||
|
||||
std::vector<double> weights;
|
||||
for(int i = 0; i < n; i++){
|
||||
if(type == "XavierNormal"){
|
||||
std::normal_distribution<double> distribution(0, sqrt(2 / (n + 1)));
|
||||
weights.push_back(distribution(generator));
|
||||
}
|
||||
else if(type == "XavierUniform"){
|
||||
std::uniform_real_distribution<double> distribution(-sqrt(6 / (n + 1)), sqrt(6 / (n + 1)));
|
||||
weights.push_back(distribution(generator));
|
||||
}
|
||||
else if(type == "HeNormal"){
|
||||
std::normal_distribution<double> distribution(0, sqrt(2 / n));
|
||||
weights.push_back(distribution(generator));
|
||||
}
|
||||
else if(type == "HeUniform"){
|
||||
std::uniform_real_distribution<double> distribution(-sqrt(6 / n), sqrt(6 / n));
|
||||
weights.push_back(distribution(generator));
|
||||
}
|
||||
else if(type == "Uniform"){
|
||||
std::uniform_real_distribution<double> distribution(-1/sqrt(n), 1/sqrt(n));
|
||||
weights.push_back(distribution(generator));
|
||||
}
|
||||
else{
|
||||
std::uniform_real_distribution<double> distribution(0, 1);
|
||||
weights.push_back(distribution(generator));
|
||||
}
|
||||
}
|
||||
return weights;
|
||||
}
|
||||
|
||||
double Utilities::biasInitialization(){
|
||||
std::random_device rd;
|
||||
std::default_random_engine generator(rd());
|
||||
std::uniform_real_distribution<double> distribution(0,1);
|
||||
|
||||
return distribution(generator);
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> Utilities::weightInitialization(int n, int m, std::string type){
|
||||
std::random_device rd;
|
||||
std::default_random_engine generator(rd());
|
||||
|
||||
std::vector<std::vector<double>> weights;
|
||||
weights.resize(n);
|
||||
|
||||
for(int i = 0; i < n; i++){
|
||||
for(int j = 0; j < m; j++){
|
||||
if(type == "XavierNormal"){
|
||||
std::normal_distribution<double> distribution(0, sqrt(2 / (n + m)));
|
||||
weights[i].push_back(distribution(generator));
|
||||
}
|
||||
else if(type == "XavierUniform"){
|
||||
std::uniform_real_distribution<double> distribution(-sqrt(6 / (n + m)), sqrt(6 / (n + m)));
|
||||
weights[i].push_back(distribution(generator));
|
||||
}
|
||||
else if(type == "HeNormal"){
|
||||
std::normal_distribution<double> distribution(0, sqrt(2 / n));
|
||||
weights[i].push_back(distribution(generator));
|
||||
}
|
||||
else if(type == "HeUniform"){
|
||||
std::uniform_real_distribution<double> distribution(-sqrt(6 / n), sqrt(6 / n));
|
||||
weights[i].push_back(distribution(generator));
|
||||
}
|
||||
else if(type == "Uniform"){
|
||||
std::uniform_real_distribution<double> distribution(-1/sqrt(n), 1/sqrt(n));
|
||||
weights[i].push_back(distribution(generator));
|
||||
}
|
||||
else{
|
||||
std::uniform_real_distribution<double> distribution(0, 1);
|
||||
weights[i].push_back(distribution(generator));
|
||||
}
|
||||
}
|
||||
}
|
||||
return weights;
|
||||
}
|
||||
|
||||
std::vector<double> Utilities::biasInitialization(int n){
|
||||
std::vector<double> bias;
|
||||
std::random_device rd;
|
||||
std::default_random_engine generator(rd());
|
||||
std::uniform_real_distribution<double> distribution(0,1);
|
||||
|
||||
for(int i = 0; i < n; i++){
|
||||
bias.push_back(distribution(generator));
|
||||
}
|
||||
return bias;
|
||||
}
|
||||
|
||||
double Utilities::performance(std::vector<double> y_hat, std::vector<double> outputSet){
|
||||
double correct = 0;
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
if(std::round(y_hat[i]) == outputSet[i]){
|
||||
correct++;
|
||||
}
|
||||
}
|
||||
return correct/y_hat.size();
|
||||
}
|
||||
|
||||
double Utilities::performance(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y){
|
||||
double correct = 0;
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
int sub_correct = 0;
|
||||
for(int j = 0; j < y_hat[i].size(); j++){
|
||||
if(std::round(y_hat[i][j]) == y[i][j]){
|
||||
sub_correct++;
|
||||
}
|
||||
if(sub_correct == y_hat[0].size()){
|
||||
correct++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return correct/y_hat.size();
|
||||
}
|
||||
|
||||
void Utilities::saveParameters(std::string fileName, std::vector<double> weights, double bias, bool app, int layer){
|
||||
std::string layer_info = "";
|
||||
std::ofstream saveFile;
|
||||
|
||||
if(layer > -1){
|
||||
layer_info = " for layer " + std::to_string(layer);
|
||||
}
|
||||
|
||||
if(app){
|
||||
saveFile.open(fileName.c_str(), std::ios_base::app);
|
||||
}
|
||||
else { saveFile.open(fileName.c_str()); }
|
||||
|
||||
if(!saveFile.is_open()){
|
||||
std::cout << fileName << " failed to open." << std::endl;
|
||||
}
|
||||
|
||||
saveFile << "Weight(s)" << layer_info << std::endl;
|
||||
for(int i = 0; i < weights.size(); i++){
|
||||
saveFile << weights[i] << std::endl;
|
||||
}
|
||||
saveFile << "Bias" << layer_info << std::endl;
|
||||
saveFile << bias << std::endl;
|
||||
|
||||
saveFile.close();
|
||||
}
|
||||
|
||||
void Utilities::saveParameters(std::string fileName, std::vector<double> weights, std::vector<double> initial, double bias, bool app, int layer){
|
||||
std::string layer_info = "";
|
||||
std::ofstream saveFile;
|
||||
|
||||
if(layer > -1){
|
||||
layer_info = " for layer " + std::to_string(layer);
|
||||
}
|
||||
|
||||
if(app){
|
||||
saveFile.open(fileName.c_str(), std::ios_base::app);
|
||||
}
|
||||
else { saveFile.open(fileName.c_str()); }
|
||||
|
||||
if(!saveFile.is_open()){
|
||||
std::cout << fileName << " failed to open." << std::endl;
|
||||
}
|
||||
|
||||
saveFile << "Weight(s)" << layer_info << std::endl;
|
||||
for(int i = 0; i < weights.size(); i++){
|
||||
saveFile << weights[i] << std::endl;
|
||||
}
|
||||
|
||||
saveFile << "Initial(s)" << layer_info << std::endl;
|
||||
for(int i = 0; i < initial.size(); i++){
|
||||
saveFile << initial[i] << std::endl;
|
||||
}
|
||||
|
||||
saveFile << "Bias" << layer_info << std::endl;
|
||||
saveFile << bias << std::endl;
|
||||
|
||||
saveFile.close();
|
||||
}
|
||||
|
||||
void Utilities::saveParameters(std::string fileName, std::vector<std::vector<double>> weights, std::vector<double> bias, bool app, int layer){
|
||||
std::string layer_info = "";
|
||||
std::ofstream saveFile;
|
||||
|
||||
if(layer > -1){
|
||||
layer_info = " for layer " + std::to_string(layer);
|
||||
}
|
||||
|
||||
if(app){
|
||||
saveFile.open(fileName.c_str(), std::ios_base::app);
|
||||
}
|
||||
else { saveFile.open(fileName.c_str()); }
|
||||
|
||||
if(!saveFile.is_open()){
|
||||
std::cout << fileName << " failed to open." << std::endl;
|
||||
}
|
||||
|
||||
saveFile << "Weight(s)" << layer_info << std::endl;
|
||||
for(int i = 0; i < weights.size(); i++){
|
||||
for(int j = 0; j < weights[i].size(); j++){
|
||||
saveFile << weights[i][j] << std::endl;
|
||||
}
|
||||
}
|
||||
saveFile << "Bias(es)" << layer_info << std::endl;
|
||||
for(int i = 0; i < bias.size(); i++){
|
||||
saveFile << bias[i] << std::endl;
|
||||
}
|
||||
|
||||
saveFile.close();
|
||||
}
|
||||
|
||||
void Utilities::UI(std::vector<double> weights, double bias){
|
||||
std::cout << "Values of the weight(s):" << std::endl;
|
||||
for(int i = 0; i < weights.size(); i++){
|
||||
std::cout << weights[i] << std::endl;
|
||||
}
|
||||
std:: cout << "Value of the bias:" << std::endl;
|
||||
std::cout << bias << std::endl;
|
||||
}
|
||||
|
||||
void Utilities::UI(std::vector<std::vector<double>> weights, std::vector<double> bias){
|
||||
std::cout << "Values of the weight(s):" << std::endl;
|
||||
for(int i = 0; i < weights.size(); i++){
|
||||
for(int j = 0; j < weights[i].size(); j++){
|
||||
std::cout << weights[i][j] << std::endl;
|
||||
}
|
||||
}
|
||||
std::cout << "Value of the biases:" << std::endl;
|
||||
for(int i = 0; i < bias.size(); i++){
|
||||
std::cout << bias[i] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void Utilities::UI(std::vector<double> weights, std::vector<double> initial, double bias){
|
||||
std::cout << "Values of the weight(s):" << std::endl;
|
||||
for(int i = 0; i < weights.size(); i++){
|
||||
std::cout << weights[i] << std::endl;
|
||||
}
|
||||
std::cout << "Values of the initial(s):" << std::endl;
|
||||
for(int i = 0; i < initial.size(); i++){
|
||||
std::cout << initial[i] << std::endl;
|
||||
}
|
||||
std:: cout << "Value of the bias:" << std::endl;
|
||||
std::cout << bias << std::endl;
|
||||
}
|
||||
|
||||
void Utilities::CostInfo(int epoch, double cost_prev, double Cost){
|
||||
std::cout << "-----------------------------------" << std::endl;
|
||||
std::cout << "This is epoch: " << epoch << std::endl;
|
||||
std::cout << "The cost function has been minimized by " << cost_prev - Cost << std::endl;
|
||||
std::cout << "Current Cost:" << std::endl;
|
||||
std::cout << Cost << std::endl;
|
||||
}
|
||||
|
||||
std::tuple<double, double, double, double> Utilities::TF_PN(std::vector<double> y_hat, std::vector<double> y){
|
||||
double TP, FP, TN, FN = 0;
|
||||
for(int i = 0; i < y_hat.size(); i++){
|
||||
if(y_hat[i] == y[i]){
|
||||
if(y_hat[i] == 1){
|
||||
TP++;
|
||||
}
|
||||
else{
|
||||
TN++;
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(y_hat[i] == 1){
|
||||
FP++;
|
||||
}
|
||||
else{
|
||||
FN++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return {TP, FP, TN, FN};
|
||||
}
|
||||
|
||||
double Utilities::recall(std::vector<double> y_hat, std::vector<double> y){
|
||||
auto [TP, FP, TN, FN] = TF_PN(y_hat, y);
|
||||
return TP / (TP + FN);
|
||||
}
|
||||
|
||||
double Utilities::precision(std::vector<double> y_hat, std::vector<double> y){
|
||||
auto [TP, FP, TN, FN] = TF_PN(y_hat, y);
|
||||
return TP / (TP + FP);
|
||||
}
|
||||
|
||||
double Utilities::accuracy(std::vector<double> y_hat, std::vector<double> y){
|
||||
auto [TP, FP, TN, FN] = TF_PN(y_hat, y);
|
||||
return (TP + TN) / (TP + FP + FN + TN);
|
||||
}
|
||||
double Utilities::f1_score(std::vector<double> y_hat, std::vector<double> y){
|
||||
return 2 * precision(y_hat, y) * recall(y_hat, y) / (precision(y_hat, y) + recall(y_hat, y));
|
||||
}
|
||||
}
|
51
MLPP/Utilities/Utilities.hpp
Normal file
51
MLPP/Utilities/Utilities.hpp
Normal file
@ -0,0 +1,51 @@
|
||||
//
|
||||
// Utilities.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 1/16/21.
|
||||
//
|
||||
|
||||
#ifndef Utilities_hpp
|
||||
#define Utilities_hpp
|
||||
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <string>
|
||||
|
||||
namespace MLPP{
|
||||
class Utilities{
|
||||
public:
|
||||
// Weight Init
|
||||
static std::vector<double> weightInitialization(int n, std::string type = "Default");
|
||||
static double biasInitialization();
|
||||
|
||||
static std::vector<std::vector<double>> weightInitialization(int n, int m, std::string type = "Default");
|
||||
static std::vector<double> biasInitialization(int n);
|
||||
|
||||
// Cost/Performance related Functions
|
||||
double performance(std::vector<double> y_hat, std::vector<double> y);
|
||||
double performance(std::vector<std::vector<double>> y_hat, std::vector<std::vector<double>> y);
|
||||
|
||||
// Parameter Saving Functions
|
||||
void saveParameters(std::string fileName, std::vector<double> weights, double bias, bool app = 0, int layer = -1);
|
||||
void saveParameters(std::string fileName, std::vector<double> weights, std::vector<double> initial, double bias, bool app = 0, int layer = -1);
|
||||
void saveParameters(std::string fileName, std::vector<std::vector<double>> weights, std::vector<double> bias, bool app = 0, int layer = -1);
|
||||
|
||||
// Gradient Descent related
|
||||
static void UI(std::vector<double> weights, double bias);
|
||||
static void UI(std::vector<double> weights, std::vector<double> initial, double bias);
|
||||
static void UI(std::vector<std::vector<double>>, std::vector<double> bias);
|
||||
|
||||
static void CostInfo(int epoch, double cost_prev, double Cost);
|
||||
|
||||
// F1 score, Precision/Recall, TP, FP, TN, FN, etc.
|
||||
std::tuple<double, double, double, double> TF_PN(std::vector<double> y_hat, std::vector<double> y); //TF_PN = "True", "False", "Positive", "Negative"
|
||||
double recall(std::vector<double> y_hat, std::vector<double> y);
|
||||
double precision(std::vector<double> y_hat, std::vector<double> y);
|
||||
double accuracy(std::vector<double> y_hat, std::vector<double> y);
|
||||
double f1_score(std::vector<double> y_hat, std::vector<double> y);
|
||||
|
||||
private:
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* Utilities_hpp */
|
94
MLPP/kNN/kNN.cpp
Normal file
94
MLPP/kNN/kNN.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
//
|
||||
// kNN.cpp
|
||||
//
|
||||
// Created by Marc Melikyan on 10/2/20.
|
||||
//
|
||||
|
||||
#include "kNN.hpp"
|
||||
#include "LinAlg/LinAlg.hpp"
|
||||
#include "Utilities/Utilities.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
namespace MLPP{
|
||||
kNN::kNN(std::vector<std::vector<double>> inputSet, std::vector<double> outputSet, int k)
|
||||
: inputSet(inputSet), outputSet(outputSet), k(k)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::vector<double> kNN::modelSetTest(std::vector<std::vector<double>> X){
|
||||
std::vector<double> y_hat;
|
||||
for(int i = 0; i < X.size(); i++){
|
||||
y_hat.push_back(modelTest(X[i]));
|
||||
}
|
||||
return y_hat;
|
||||
}
|
||||
|
||||
int kNN::modelTest(std::vector<double> x){
|
||||
return determineClass(nearestNeighbors(x));
|
||||
}
|
||||
|
||||
double kNN::score(){
|
||||
Utilities util;
|
||||
return util.performance(modelSetTest(inputSet), outputSet);
|
||||
}
|
||||
|
||||
int kNN::determineClass(std::vector<double> knn){
|
||||
std::map<int, int> class_nums;
|
||||
for(int i = 0; i < outputSet.size(); i++){
|
||||
class_nums[outputSet[i]] = 0;
|
||||
}
|
||||
for(int i = 0; i < knn.size(); i++){
|
||||
for(int j = 0; j < outputSet.size(); j++){
|
||||
if(knn[i] == outputSet[j]){
|
||||
class_nums[outputSet[j]]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
int max = class_nums[outputSet[0]];
|
||||
int final_class = outputSet[0];
|
||||
|
||||
for(int i = 0; i < outputSet.size(); i++){
|
||||
if(class_nums[outputSet[i]] > max){
|
||||
max = class_nums[outputSet[i]];
|
||||
}
|
||||
}
|
||||
for(auto [c, v] : class_nums){
|
||||
if(v == max){
|
||||
final_class = c;
|
||||
}
|
||||
}
|
||||
return final_class;
|
||||
}
|
||||
|
||||
std::vector<double> kNN::nearestNeighbors(std::vector<double> x){
|
||||
// The nearest neighbors
|
||||
std::vector<double> knn;
|
||||
|
||||
std::vector<std::vector<double>> inputUseSet = inputSet;
|
||||
//Perfom this loop unless and until all k nearest neighbors are found, appended, and returned
|
||||
for(int i = 0; i < k; i++){
|
||||
int neighbor = 0;
|
||||
for(int j = 0; j < inputUseSet.size(); j++){
|
||||
if(euclideanDistance(x, inputUseSet[j]) < euclideanDistance(x, inputUseSet[neighbor])){
|
||||
neighbor = j;
|
||||
}
|
||||
}
|
||||
knn.push_back(neighbor);
|
||||
inputUseSet.erase(inputUseSet.begin() + neighbor);
|
||||
}
|
||||
return knn;
|
||||
}
|
||||
|
||||
// Multidimensional Euclidean Distance
|
||||
double kNN::euclideanDistance(std::vector<double> A, std::vector<double> B){
|
||||
double dist = 0;
|
||||
for(int i = 0; i < A.size(); i++){
|
||||
dist += (A[i] - B[i])*(A[i] - B[i]);
|
||||
}
|
||||
return sqrt(dist);
|
||||
}
|
||||
}
|
38
MLPP/kNN/kNN.hpp
Normal file
38
MLPP/kNN/kNN.hpp
Normal file
@ -0,0 +1,38 @@
|
||||
//
|
||||
// kNN.hpp
|
||||
//
|
||||
// Created by Marc Melikyan on 10/2/20.
|
||||
//
|
||||
|
||||
#ifndef kNN_hpp
|
||||
#define kNN_hpp
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace MLPP{
|
||||
class kNN{
|
||||
|
||||
public:
|
||||
kNN(std::vector<std::vector<double>> inputSet, std::vector<double> outputSet, int k);
|
||||
std::vector<double> modelSetTest(std::vector<std::vector<double>> X);
|
||||
int modelTest(std::vector<double> x);
|
||||
double score();
|
||||
|
||||
private:
|
||||
|
||||
// Private Model Functions
|
||||
std::vector<double> nearestNeighbors(std::vector<double> x);
|
||||
int determineClass(std::vector<double> knn);
|
||||
|
||||
// Helper Functions
|
||||
double euclideanDistance(std::vector<double> A, std::vector<double> B);
|
||||
|
||||
// Model Inputs and Parameters
|
||||
std::vector<std::vector<double>> inputSet;
|
||||
std::vector<double> outputSet;
|
||||
int k;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* kNN_hpp */
|
353
main.cpp
Normal file
353
main.cpp
Normal file
@ -0,0 +1,353 @@
|
||||
//
|
||||
// main.cpp
|
||||
// TEST_APP
|
||||
//
|
||||
// Created by Marc on 1/20/21.
|
||||
//
|
||||
|
||||
// THINGS CURRENTLY TO DO:
|
||||
// POLYMORPHIC IMPLEMENTATION OF REGRESSION CLASSES
|
||||
// EXTEND SGD/MBGD SUPPORT FOR DYN. SIZED ANN
|
||||
// STANDARDIZE ACTIVATIONS/OPTIMIZATIONS
|
||||
// FINISH ADDING ALL ACTIVATIONS TO ANN
|
||||
|
||||
// HYPOTHESIS TESTING CLASS
|
||||
// GAUSS MARKOV CHECKER CLASS
|
||||
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
#include <vector>
|
||||
#include "MLPP/UniLinReg/UniLinReg.hpp"
|
||||
#include "MLPP/LinReg/LinReg.hpp"
|
||||
#include "MLPP/LogReg/LogReg.hpp"
|
||||
#include "MLPP/CLogLogReg/CLogLogReg.hpp"
|
||||
#include "MLPP/ExpReg/ExpReg.hpp"
|
||||
#include "MLPP/ProbitReg/ProbitReg.hpp"
|
||||
#include "MLPP/SoftmaxReg/SoftmaxReg.hpp"
|
||||
#include "MLPP/TanhReg/TanhReg.hpp"
|
||||
#include "MLPP/MLP/MLP.hpp"
|
||||
#include "MLPP/SoftmaxNet/SoftmaxNet.hpp"
|
||||
#include "MLPP/AutoEncoder/AutoEncoder.hpp"
|
||||
#include "MLPP/ANN/ANN.hpp"
|
||||
#include "MLPP/MultinomialNB/MultinomialNB.hpp"
|
||||
#include "MLPP/BernoulliNB/BernoulliNB.hpp"
|
||||
#include "MLPP/GaussianNB/GaussianNB.hpp"
|
||||
#include "MLPP/KMeans/KMeans.hpp"
|
||||
#include "MLPP/kNN/kNN.hpp"
|
||||
#include "MLPP/PCA/PCA.hpp"
|
||||
#include "MLPP/OutlierFinder/OutlierFinder.hpp"
|
||||
#include "MLPP/Stat/Stat.hpp"
|
||||
#include "MLPP/LinAlg/LinAlg.hpp"
|
||||
#include "MLPP/Activation/Activation.hpp"
|
||||
#include "MLPP/Data/Data.hpp"
|
||||
#include "MLPP/Convolutions/Convolutions.hpp"
|
||||
|
||||
|
||||
using namespace MLPP;
|
||||
|
||||
int main() {
|
||||
|
||||
// OBJECTS
|
||||
Stat stat;
|
||||
LinAlg alg;
|
||||
Activation avn;
|
||||
Data data;
|
||||
Convolutions conv;
|
||||
|
||||
// DATA SETS
|
||||
// std::vector<std::vector<double>> inputSet = {{1,2,3,4,5,6,7,8,9,10}, {3,5,9,12,15,18,21,24,27,30}};
|
||||
// std::vector<double> outputSet = {2,4,6,8,10,12,14,16,18,20};
|
||||
|
||||
// std::vector<std::vector<double>> inputSet = {{1,2,3,4,5,6,7,8}, {0,0,0,0,1,1,1,1}};
|
||||
// std::vector<double> outputSet = {0,0,0,0,1,1,1,1};
|
||||
|
||||
// std::vector<std::vector<double>> inputSet = {{4,3,0,-3,-4}, {0,0,0,1,1}};
|
||||
// std::vector<double> outputSet = {1,1,0,-1,-1};
|
||||
|
||||
// std::vector<std::vector<double>> inputSet = {{0,1,2,3,4}};
|
||||
// std::vector<double> outputSet = {1,2,4,8,16};
|
||||
|
||||
//std::vector<std::vector<double>> inputSet = {{32, 0, 7}, {2, 28, 17}, {0, 9, 23}};
|
||||
|
||||
// std::vector<std::vector<double>> inputSet = {{1,1,0,0,1}, {0,0,1,1,1}, {0,1,1,0,1}};
|
||||
// std::vector<double> outputSet = {0,1,0,1,1};
|
||||
|
||||
// std::vector<std::vector<double>> inputSet = {{0,0,1,1}, {0,1,0,1}};
|
||||
// std::vector<double> outputSet = {0,1,1,0};
|
||||
|
||||
// // STATISTICS
|
||||
// std::vector<double> x = {1,2,3,4,5,6,7,8,9,10};
|
||||
// std::vector<double> y = {10,9,8,7,6,5,4,3,2,1};
|
||||
// std::vector<double> w = {0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1};
|
||||
|
||||
// std::cout << "Arithmetic Mean: " << stat.mean(x) << std::endl;
|
||||
// std::cout << "Variance: " << stat.variance(x) << std::endl;
|
||||
// std::cout << "Covariance: " << stat.covariance(x, y) << std::endl;
|
||||
// std::cout << "Correlation: " << stat.correlation(x, y) << std::endl;
|
||||
// std::cout << "R^2: " << stat.R2(x, y) << std::endl;
|
||||
// std::cout << "Weighted Mean: " << stat.weightedMean(x, w) << std::endl;
|
||||
// std::cout << "Geometric Mean: " << stat.geometricMean(x) << std::endl;
|
||||
// std::cout << "Harmonic Mean: " << stat.harmonicMean(x) << std::endl;
|
||||
// std::cout << "Root Mean Square (Quadratic mean): " << stat.RMS(x) << std::endl;
|
||||
// std::cout << "Power Mean (p = 5): " << stat.powerMean(x, 5) << std::endl;
|
||||
// std::cout << "Lehmer Mean (p = 5): " << stat.lehmerMean(x, 5) << std::endl;
|
||||
// std::cout << "Weighted Lehmer Mean (p = 5): " << stat.weightedLehmerMean(x, w, 5) << std::endl;
|
||||
// std::cout << "Contraharmonic Mean: " << stat.contraharmonicMean(x) << std::endl;
|
||||
// std::cout << "Hernonian Mean: " << stat.heronianMean(1, 10) << std::endl;
|
||||
// std::cout << "Heinz Mean (x = 1): " << stat.heinzMean(1, 10, 1) << std::endl;
|
||||
// std::cout << "Neuman-Sandor Mean: " << stat.neumanSandorMean(1, 10) << std::endl;
|
||||
// std::cout << "Stolarsky Mean (p = 5): " << stat.stolarskyMean(1, 10, 5) << std::endl;
|
||||
// std::cout << "Identric Mean: " << stat.identricMean(1, 10) << std::endl;
|
||||
// std::cout << "Logarithmic Mean: " << stat.logMean(1, 10) << std::endl;
|
||||
// std::cout << "Standard Deviation: " << stat.standardDeviation(x) << std::endl;
|
||||
// std::cout << "Absolute Average Deviation: " << stat.absAvgDeviation(x) << std::endl;
|
||||
// // Returns 1 - (1/k^2)
|
||||
// std::cout << "Chebyshev Inequality: " << stat.chebyshevIneq(2) << std::endl;
|
||||
|
||||
// // LINEAR ALGEBRA
|
||||
// std::vector<std::vector<double>> A = {
|
||||
// {1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
|
||||
// {1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
|
||||
// };
|
||||
// std::vector<double> a = {4, 3, 1, 3};
|
||||
// std::vector<double> b = {3, 5, 6, 1};
|
||||
|
||||
// alg.printMatrix(alg.matmult(alg.transpose(A), A));
|
||||
// std::cout << std::endl;
|
||||
// std::cout << alg.dot(a, b) << std::endl;
|
||||
// std::cout << std::endl;
|
||||
// alg.printMatrix(alg.hadamard_product(A, A));
|
||||
// std::cout << std::endl;
|
||||
// alg.printMatrix(alg.identity(10));
|
||||
|
||||
// // UNIVARIATE LINEAR REGRESSION
|
||||
// // Univariate, simple linear regression case where k = 1
|
||||
// std::vector<double> inputSet;
|
||||
// std::vector<double> outputSet;
|
||||
// // Analytical solution used for calculating the parameters.
|
||||
// data.setData("/Users/marcmelikyan/Desktop/Data/FiresAndCrime.csv", inputSet, outputSet);
|
||||
// UniLinReg model(inputSet, outputSet);
|
||||
// alg.printVector(model.modelSetTest(inputSet));
|
||||
|
||||
// // MULIVARIATE LINEAR REGRESSION
|
||||
// std::vector<std::vector<double>> inputSet = {{1,2,3,4,5,6,7,8,9,10}, {3,5,9,12,15,18,21,24,27,30}};
|
||||
// std::vector<double> outputSet = {2,4,6,8,10,12,14,16,18,20};
|
||||
// LinReg model(alg.transpose(inputSet), outputSet); // Can use Lasso, Ridge, ElasticNet Reg
|
||||
// model.normalEquation();
|
||||
// model.gradientDescent(0.001, 30000, 1);
|
||||
// model.SGD(0.001, 30000, 1);
|
||||
// model.MBGD(0.001, 10000, 2, 1);
|
||||
// alg.printVector(model.modelSetTest((alg.transpose(inputSet))));
|
||||
// std::cout << "ACCURACY: " << 100 * model.score() << "%" << std::endl;
|
||||
|
||||
// // LOGISTIC REGRESSION
|
||||
// std::vector<std::vector<double>> inputSet;
|
||||
// std::vector<double> outputSet;
|
||||
// data.setData(30, "/Users/marcmelikyan/Desktop/Data/BreastCancer.csv", inputSet, outputSet);
|
||||
// LogReg model(inputSet, outputSet);
|
||||
// //model.SGD(0.1, 50000, 0);
|
||||
// model.MLE(0.1, 10000, 0);
|
||||
// alg.printVector(model.modelSetTest(inputSet));
|
||||
// std::cout << "ACCURACY: " << 100 * model.score() << "%" << std::endl;
|
||||
|
||||
// // PROBIT REGRESSION
|
||||
// std::vector<std::vector<double>> inputSet;
|
||||
// std::vector<double> outputSet;
|
||||
// data.setData(30, "/Users/marcmelikyan/Desktop/Data/BreastCancer.csv", inputSet, outputSet);
|
||||
// ProbitReg model(inputSet, outputSet);
|
||||
// model.gradientDescent(0.0001, 10000, 1);
|
||||
// alg.printVector(model.modelSetTest(inputSet));
|
||||
// std::cout << "ACCURACY: " << 100 * model.score() << "%" << std::endl;
|
||||
|
||||
// // CLOGLOG REGRESSION
|
||||
// std::vector<std::vector<double>> inputSet = {{1,2,3,4,5,6,7,8}, {0,0,0,0,1,1,1,1}};
|
||||
// std::vector<double> outputSet = {0,0,0,0,1,1,1,1};
|
||||
// CLogLogReg model(alg.transpose(inputSet), outputSet);
|
||||
// model.SGD(0.1, 10000, 0);
|
||||
// alg.printVector(model.modelSetTest(alg.transpose(inputSet)));
|
||||
// std::cout << "ACCURACY: " << 100 * model.score() << "%" << std::endl;
|
||||
|
||||
// // EXPREG REGRESSION
|
||||
// std::vector<std::vector<double>> inputSet = {{0,1,2,3,4}};
|
||||
// std::vector<double> outputSet = {1,2,4,8,16};
|
||||
// ExpReg model(alg.transpose(inputSet), outputSet);
|
||||
// model.SGD(0.001, 10000, 0);
|
||||
// alg.printVector(model.modelSetTest(alg.transpose(inputSet)));
|
||||
// std::cout << "ACCURACY: " << 100 * model.score() << "%" << std::endl;
|
||||
|
||||
// // TANH REGRESSION
|
||||
// std::vector<std::vector<double>> inputSet = {{4,3,0,-3,-4}, {0,0,0,1,1}};
|
||||
// std::vector<double> outputSet = {1,1,0,-1,-1};
|
||||
// TanhReg model(alg.transpose(inputSet), outputSet);
|
||||
// model.SGD(0.1, 10000, 0);
|
||||
// alg.printVector(model.modelSetTest(alg.transpose(inputSet)));
|
||||
// std::cout << "ACCURACY: " << 100 * model.score() << "%" << std::endl;
|
||||
|
||||
// // SOFTMAX REGRESSION
|
||||
// std::vector<std::vector<double>> inputSet;
|
||||
// std::vector<double> tempOutputSet;
|
||||
// data.setData(4, "/Users/marcmelikyan/Desktop/Data/Iris.csv", inputSet, tempOutputSet);
|
||||
// std::vector<std::vector<double>> outputSet = data.oneHotRep(tempOutputSet, 3);
|
||||
|
||||
// SoftmaxReg model(inputSet, outputSet);
|
||||
// model.SGD(0.001, 20000, 0);
|
||||
// alg.printMatrix(model.modelSetTest(inputSet));
|
||||
// std::cout << "ACCURACY: " << 100 * model.score() << "%" << std::endl;
|
||||
|
||||
// // MLP
|
||||
// std::vector<std::vector<double>> inputSet = {{0,0,1,1}, {0,1,0,1}};
|
||||
// std::vector<double> outputSet = {0,1,1,0};
|
||||
// MLP model(alg.transpose(inputSet), outputSet, 2);
|
||||
// model.gradientDescent(0.1, 10000, 0);
|
||||
// alg.printVector(model.modelSetTest(alg.transpose(inputSet)));
|
||||
// std::cout << "ACCURACY: " << 100 * model.score() << "%" << std::endl;
|
||||
|
||||
// // SOFTMAX NETWORK
|
||||
// std::vector<std::vector<double>> inputSet;
|
||||
// std::vector<double> tempOutputSet;
|
||||
// data.setData(4, "/Users/marcmelikyan/Desktop/Data/Iris.csv", inputSet, tempOutputSet);
|
||||
// std::vector<std::vector<double>> outputSet = data.oneHotRep(tempOutputSet, 3);
|
||||
|
||||
// SoftmaxNet model(inputSet, outputSet, 2);
|
||||
// model.gradientDescent(0.001, 10000, 0);
|
||||
// alg.printMatrix(model.modelSetTest(inputSet));
|
||||
// std::cout << "ACCURACY: " << 100 * model.score() << "%" << std::endl;
|
||||
|
||||
// // AUTOENCODER
|
||||
// std::vector<std::vector<double>> inputSet = {{1,2,3,4,5,6,7,8,9,10}, {3,5,9,12,15,18,21,24,27,30}};
|
||||
// AutoEncoder model(alg.transpose(inputSet), 5);
|
||||
// model.SGD(0.001, 300000, 0);
|
||||
// alg.printMatrix(model.modelSetTest(alg.transpose(inputSet)));
|
||||
// std::cout << "ACCURACY: " << 100 * model.score() << "%" << std::endl;
|
||||
|
||||
// // DYNAMICALLY SIZED ANN
|
||||
// // Possible Weight Init Methods: Default, Uniform, HeNormal, HeUniform, XavierNormal, XavierUniform
|
||||
// // Possible Activations: Linear, Sigmoid, Swish, CLogLog, Ar{Sinh, Cosh, Tanh, Csch, Sech, Coth}, GaussianCDF, GELU, UnitStep
|
||||
// // Possible Loss Functions: MSE, RMSE, MBE, LogLoss, CrossEntropy, HingeLoss
|
||||
// std::vector<std::vector<double>> inputSet = {{0,0,1,1}, {0,1,0,1}};
|
||||
// std::vector<double> outputSet = {0,1,1,0};
|
||||
// ANN ann(alg.transpose(inputSet), outputSet);
|
||||
// ann.addLayer(10, "RELU", "Default", "Ridge", 0.0001);
|
||||
// ann.addLayer(10, "Sigmoid", "Default");
|
||||
// ann.addOutputLayer("Sigmoid", "LogLoss", "XavierNormal");
|
||||
// ann.gradientDescent(0.1, 80000, 0);
|
||||
// alg.printVector(ann.modelSetTest(alg.transpose(inputSet)));
|
||||
// std::cout << "ACCURACY: " << 100 * ann.score() << "%" << std::endl;
|
||||
|
||||
// // NAIVE BAYES
|
||||
// std::vector<std::vector<double>> inputSet = {{1,1,1,1,1}, {0,0,1,1,1}, {0,0,1,0,1}};
|
||||
// std::vector<double> outputSet = {0,1,0,1,1};
|
||||
|
||||
// MultinomialNB MNB(alg.transpose(inputSet), outputSet, 2);
|
||||
// alg.printVector(MNB.modelSetTest(alg.transpose(inputSet)));
|
||||
|
||||
// BernoulliNB BNB(alg.transpose(inputSet), outputSet);
|
||||
// alg.printVector(BNB.modelSetTest(alg.transpose(inputSet)));
|
||||
|
||||
// GaussianNB GNB(alg.transpose(inputSet), outputSet, 2);
|
||||
// alg.printVector(GNB.modelSetTest(alg.transpose(inputSet)));
|
||||
|
||||
// // KMeans
|
||||
// std::vector<std::vector<double>> inputSet = {{32, 0, 7}, {2, 28, 17}, {0, 9, 23}};
|
||||
// KMeans kmeans(inputSet, 3, "KMeans++");
|
||||
// kmeans.train(3, 1);
|
||||
// std::cout << std::endl;
|
||||
// alg.printMatrix(kmeans.modelSetTest(inputSet)); // Returns the assigned centroids to each of the respective training examples
|
||||
// std::cout << std::endl;
|
||||
// alg.printVector(kmeans.silhouette_scores());
|
||||
|
||||
// // kNN
|
||||
// std::vector<std::vector<double>> inputSet = {{1,2,3,4,5,6,7,8}, {0,0,0,0,1,1,1,1}};
|
||||
// std::vector<double> outputSet = {0,0,0,0,1,1,1,1};
|
||||
// kNN knn(alg.transpose(inputSet), outputSet, 8);
|
||||
// alg.printVector(knn.modelSetTest(alg.transpose(inputSet)));
|
||||
// std::cout << "ACCURACY: " << 100 * knn.score() << "%" << std::endl;
|
||||
|
||||
|
||||
// //CONVOLUTION, POOLING, ETC..
|
||||
// std::vector<std::vector<double>> input = {
|
||||
// {1,1,1,1,0,0,0,0},
|
||||
// {1,1,1,1,0,0,0,0},
|
||||
// {1,1,1,1,0,0,0,0},
|
||||
// {1,1,1,1,0,0,0,0},
|
||||
// {1,1,1,1,0,0,0,0},
|
||||
// {1,1,1,1,0,0,0,0},
|
||||
// {1,1,1,1,0,0,0,0},
|
||||
// {1,1,1,1,0,0,0,0}
|
||||
// };
|
||||
|
||||
// alg.printMatrix(conv.convolve(input, conv.getPrewittVertical(), 1)); // Can use padding
|
||||
// alg.printMatrix(conv.pool(input, 4, 4, "Max")); // Can use Max, Min, or Average pooling.
|
||||
|
||||
// std::vector<std::vector<std::vector<double>>> tensorSet;
|
||||
// tensorSet.push_back(input);
|
||||
// tensorSet.push_back(input);
|
||||
// alg.printVector(conv.globalPool(tensorSet, "Average")); // Can use Max, Min, or Average global pooling.
|
||||
|
||||
// // PCA, SVD, eigenvalues & eigenvectors
|
||||
// std::vector<std::vector<double>> inputSet = {{1,1}, {1,1}};
|
||||
// auto [Eigenvectors, Eigenvalues] = alg.eig(inputSet);
|
||||
// std::cout << "Eigenvectors:" << std::endl;
|
||||
// alg.printMatrix(Eigenvectors);
|
||||
// std::cout << std::endl;
|
||||
// std::cout << "Eigenvalues:" << std::endl;
|
||||
// alg.printMatrix(Eigenvalues);
|
||||
|
||||
// auto [U, S, Vt] = alg.SVD(inputSet);
|
||||
|
||||
// // PCA done using Jacobi's method to approximate eigenvalues.
|
||||
// PCA dr(inputSet, 1); // 1 dimensional representation.
|
||||
// std::cout << std::endl;
|
||||
// std::cout << "Dimensionally reduced representation:" << std::endl;
|
||||
// alg.printMatrix(dr.principalComponents());
|
||||
// std::cout << "SCORE: " << dr.score() << std::endl;
|
||||
|
||||
|
||||
// // NLP/DATA
|
||||
// std::string verbText = "I am appearing and thinking, as well as conducting.";
|
||||
// std::cout << "Stemming Example:" << std::endl;
|
||||
// std::cout << data.stemming(verbText) << std::endl;
|
||||
// std::cout << std::endl;
|
||||
|
||||
// std::vector<std::string> sentences = {"He is a good boy", "She is a good girl", "The boy and girl are good"};
|
||||
// std::cout << "Bag of Words Example:" << std::endl;
|
||||
// alg.printMatrix(data.BOW(sentences, "Default"));
|
||||
// std::cout << std::endl;
|
||||
// std::cout << "TFIDF Example:" << std::endl;
|
||||
// alg.printMatrix(data.TFIDF(sentences));
|
||||
// std::cout << std::endl;
|
||||
|
||||
// std::cout << "Tokenization:" << std::endl;
|
||||
// alg.printVector(data.tokenize(verbText));
|
||||
// std::cout << std::endl;
|
||||
|
||||
// std::cout << "Word2Vec:" << std::endl;
|
||||
// std::string textArchive = {"He is a good boy. She is a good girl. The boy and girl are good."};
|
||||
// std::vector<std::string> corpus = data.splitSentences(textArchive);
|
||||
// auto [wordEmbeddings, wordList] = data.word2Vec(corpus, "CBOW", 2, 2, 0.1, 10000); // Can use either CBOW or Skip-n-gram.
|
||||
// alg.printMatrix(wordEmbeddings);
|
||||
// std::cout << std::endl;
|
||||
|
||||
// std::vector<std::vector<double>> inputSet = {{1,2},{2,3},{3,4},{4,5},{5,6}};
|
||||
// std::cout << "Feature Scaling Example:" << std::endl;
|
||||
// alg.printMatrix(data.featureScaling(inputSet));
|
||||
// std::cout << std::endl;
|
||||
|
||||
// std::cout << "Mean Centering Example:" << std::endl;
|
||||
// alg.printMatrix(data.meanCentering(inputSet));
|
||||
// std::cout << std::endl;
|
||||
|
||||
// std::cout << "Mean Normalization Example:" << std::endl;
|
||||
// alg.printMatrix(data.meanNormalization(inputSet));
|
||||
// std::cout << std::endl;
|
||||
|
||||
// // Outlier Finder
|
||||
// std::vector<double> inputSet = {1,2,3,4,5,6,7,8,9,23554332523523};
|
||||
// OutlierFinder outlierFinder(2); // Any datapoint outside of 2 stds from the mean is marked as an outlier.
|
||||
// alg.printVector(outlierFinder.modelTest(inputSet));
|
||||
|
||||
// // Testing for new Functions
|
||||
// alg.printMatrix(alg.pinverse({{1,2}, {3,4}}));
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user