From 14ea51648a1d14748d68a2da470cee53093bd5e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Montan=CC=83ana?= Date: Sun, 6 Aug 2023 11:31:44 +0200 Subject: [PATCH] Complete AODELd --- .vscode/launch.json | 4 ++-- Makefile | 5 +++++ src/BayesNet/AODELd.cc | 34 ++++++++++++++++++++++++++++++++++ src/BayesNet/AODELd.h | 20 ++++++++++++++++++++ src/BayesNet/CMakeLists.txt | 2 +- src/BayesNet/Ensemble.cc | 34 +++++++++++++++++++--------------- src/BayesNet/Ensemble.h | 8 ++++---- src/BayesNet/bayesnetUtils.cc | 1 + src/Platform/Models.h | 1 + src/Platform/modelRegister.h | 8 +++++--- 10 files changed, 92 insertions(+), 25 deletions(-) create mode 100644 src/BayesNet/AODELd.cc create mode 100644 src/BayesNet/AODELd.h diff --git a/.vscode/launch.json b/.vscode/launch.json index 567f55a..7241ae2 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -25,14 +25,14 @@ "program": "${workspaceFolder}/build/src/Platform/main", "args": [ "-m", - "TANNew", + "AODELd", "-p", "/Users/rmontanana/Code/discretizbench/datasets", "--stratified", "-d", "iris" ], - "cwd": "${workspaceFolder}/build/src/Platform", + "cwd": "/Users/rmontanana/Code/discretizbench", }, { "name": "Build & debug active file", diff --git a/Makefile b/Makefile index 1307544..9806dc3 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,11 @@ dependency: ## Create a dependency graph diagram of the project (build/dependenc build: ## Build the main and BayesNetSample cmake --build build -t main -t BayesNetSample -j 32 +clean: ## Clean the debug info + @echo ">>> Cleaning Debug BayesNet ..."; + find . -name "*.gcda" -print0 | xargs -0 rm + @echo ">>> Done"; + debug: ## Build a debug version of the project @echo ">>> Building Debug BayesNet ..."; @if [ -d ./build ]; then rm -rf ./build; fi diff --git a/src/BayesNet/AODELd.cc b/src/BayesNet/AODELd.cc new file mode 100644 index 0000000..861aa71 --- /dev/null +++ b/src/BayesNet/AODELd.cc @@ -0,0 +1,34 @@ +#include "AODELd.h" + +namespace bayesnet { + using namespace std; + AODELd::AODELd() : Ensemble(), Proposal(Ensemble::Xv, Ensemble::yv, features, className) {} + AODELd& AODELd::fit(torch::Tensor& X_, torch::Tensor& y_, vector& features_, string className_, map>& states_) + { + features = features_; + className = className_; + states = states_; + train(); + for (const auto& model : models) { + model->fit(X_, y_, features_, className_, states_); + } + n_models = models.size(); + fitted = true; + return *this; + } + void AODELd::train() + { + models.clear(); + for (int i = 0; i < features.size(); ++i) { + models.push_back(std::make_unique(i)); + } + } + Tensor AODELd::predict(Tensor& X) + { + return Ensemble::predict(X); + } + vector AODELd::graph(const string& name) + { + return Ensemble::graph(name); + } +} \ No newline at end of file diff --git a/src/BayesNet/AODELd.h b/src/BayesNet/AODELd.h new file mode 100644 index 0000000..33a0dff --- /dev/null +++ b/src/BayesNet/AODELd.h @@ -0,0 +1,20 @@ +#ifndef AODELD_H +#define AODELD_H +#include "Ensemble.h" +#include "Proposal.h" +#include "SPODELd.h" + +namespace bayesnet { + using namespace std; + class AODELd : public Ensemble, public Proposal { + public: + AODELd(); + virtual ~AODELd() = default; + AODELd& fit(torch::Tensor& X, torch::Tensor& y, vector& features, string className, map>& states) override; + vector graph(const string& name = "AODE") override; + Tensor predict(Tensor& X) override; + void train() override; + static inline string version() { return "0.0.1"; }; + }; +} +#endif // !AODELD_H \ No newline at end of file diff --git a/src/BayesNet/CMakeLists.txt b/src/BayesNet/CMakeLists.txt index d1416ad..5df47d5 100644 --- a/src/BayesNet/CMakeLists.txt +++ b/src/BayesNet/CMakeLists.txt @@ -1,5 +1,5 @@ include_directories(${BayesNet_SOURCE_DIR}/lib/mdlp) include_directories(${BayesNet_SOURCE_DIR}/lib/Files) add_library(BayesNet bayesnetUtils.cc Network.cc Node.cc BayesMetrics.cc Classifier.cc - KDB.cc TAN.cc SPODE.cc Ensemble.cc AODE.cc TANLd.cc KDBLd.cc SPODELd.cc Mst.cc Proposal.cc) + KDB.cc TAN.cc SPODE.cc Ensemble.cc AODE.cc TANLd.cc KDBLd.cc SPODELd.cc AODELd.cc Mst.cc Proposal.cc) target_link_libraries(BayesNet mdlp ArffFiles "${TORCH_LIBRARIES}") \ No newline at end of file diff --git a/src/BayesNet/Ensemble.cc b/src/BayesNet/Ensemble.cc index ca64798..8cbd17c 100644 --- a/src/BayesNet/Ensemble.cc +++ b/src/BayesNet/Ensemble.cc @@ -3,24 +3,24 @@ namespace bayesnet { using namespace torch; - Ensemble::Ensemble() : m(0), n(0), n_models(0), metrics(Metrics()), fitted(false) {} + Ensemble::Ensemble() : n_models(0), metrics(Metrics()), fitted(false) {} Ensemble& Ensemble::build(vector& features, string className, map>& states) { - dataset = cat({ X, y.view({y.size(0), 1}) }, 1); + Tensor ytmp = torch::transpose(y.view({ y.size(0), 1 }), 0, 1); + samples = torch::cat({ X, ytmp }, 0); this->features = features; this->className = className; this->states = states; auto n_classes = states[className].size(); - metrics = Metrics(dataset, features, className, n_classes); + metrics = Metrics(samples, features, className, n_classes); // Build models train(); // Train models n_models = models.size(); - auto Xt = torch::transpose(X, 0, 1); for (auto i = 0; i < n_models; ++i) { - if (Xv == vector>()) { + if (Xv.empty()) { // fit with tensors - models[i]->fit(Xt, y, features, className, states); + models[i]->fit(X, y, features, className, states); } else { // fit with vectors models[i]->fit(Xv, yv, features, className, states); @@ -29,9 +29,16 @@ namespace bayesnet { fitted = true; return *this; } + void Ensemble::generateTensorXFromVector() + { + X = torch::zeros({ static_cast(Xv.size()), static_cast(Xv[0].size()) }, kInt32); + for (int i = 0; i < Xv.size(); ++i) { + X.index_put_({ i, "..." }, torch::tensor(Xv[i], kInt32)); + } + } Ensemble& Ensemble::fit(torch::Tensor& X, torch::Tensor& y, vector& features, string className, map>& states) { - this->X = torch::transpose(X, 0, 1); + this->X = X; this->y = y; Xv = vector>(); yv = vector(y.data_ptr(), y.data_ptr() + y.size(0)); @@ -39,11 +46,8 @@ namespace bayesnet { } Ensemble& Ensemble::fit(vector>& X, vector& y, vector& features, string className, map>& states) { - this->X = torch::zeros({ static_cast(X[0].size()), static_cast(X.size()) }, kInt32); Xv = X; - for (int i = 0; i < X.size(); ++i) { - this->X.index_put_({ "...", i }, torch::tensor(X[i], kInt32)); - } + generateTensorXFromVector(); this->y = torch::tensor(y, kInt32); yv = y; return build(features, className, states); @@ -53,10 +57,11 @@ namespace bayesnet { auto y_pred_ = y_pred.accessor(); vector y_pred_final; for (int i = 0; i < y_pred.size(0); ++i) { - vector votes(states[className].size(), 0); + vector votes(y_pred.size(1), 0); for (int j = 0; j < y_pred.size(1); ++j) { votes[y_pred_[i][j]] += 1; } + // argsort in descending order auto indices = argsort(votes); y_pred_final.push_back(indices[0]); } @@ -70,13 +75,12 @@ namespace bayesnet { Tensor y_pred = torch::zeros({ X.size(1), n_models }, kInt32); //Create a threadpool auto threads{ vector() }; - auto lock = mutex(); + mutex mtx; for (auto i = 0; i < n_models; ++i) { threads.push_back(thread([&, i]() { auto ypredict = models[i]->predict(X); - lock.lock(); + lock_guard lock(mtx); y_pred.index_put_({ "...", i }, ypredict); - lock.unlock(); })); } for (auto& thread : threads) { diff --git a/src/BayesNet/Ensemble.h b/src/BayesNet/Ensemble.h index ef9d7f1..322032e 100644 --- a/src/BayesNet/Ensemble.h +++ b/src/BayesNet/Ensemble.h @@ -10,23 +10,23 @@ using namespace torch; namespace bayesnet { class Ensemble : public BaseClassifier { private: - bool fitted; - long n_models; Ensemble& build(vector& features, string className, map>& states); protected: + unsigned n_models; + bool fitted; vector> models; - int m, n; // m: number of samples, n: number of features Tensor X; vector> Xv; Tensor y; vector yv; - Tensor dataset; + Tensor samples; Metrics metrics; vector features; string className; map> states; void virtual train() = 0; vector voting(Tensor& y_pred); + void generateTensorXFromVector(); public: Ensemble(); virtual ~Ensemble() = default; diff --git a/src/BayesNet/bayesnetUtils.cc b/src/BayesNet/bayesnetUtils.cc index 356b4ea..8b69006 100644 --- a/src/BayesNet/bayesnetUtils.cc +++ b/src/BayesNet/bayesnetUtils.cc @@ -3,6 +3,7 @@ namespace bayesnet { using namespace std; using namespace torch; + // Return the indices in descending order vector argsort(vector& nums) { int n = nums.size(); diff --git a/src/Platform/Models.h b/src/Platform/Models.h index 82b5917..0e3184b 100644 --- a/src/Platform/Models.h +++ b/src/Platform/Models.h @@ -9,6 +9,7 @@ #include "TANLd.h" #include "KDBLd.h" #include "SPODELd.h" +#include "AODELd.h" namespace platform { class Models { private: diff --git a/src/Platform/modelRegister.h b/src/Platform/modelRegister.h index d906216..6ae9af3 100644 --- a/src/Platform/modelRegister.h +++ b/src/Platform/modelRegister.h @@ -2,16 +2,18 @@ #define MODEL_REGISTER_H static platform::Registrar registrarT("TAN", [](void) -> bayesnet::BaseClassifier* { return new bayesnet::TAN();}); -static platform::Registrar registrarTN("TANLd", +static platform::Registrar registrarTLD("TANLd", [](void) -> bayesnet::BaseClassifier* { return new bayesnet::TANLd();}); static platform::Registrar registrarS("SPODE", [](void) -> bayesnet::BaseClassifier* { return new bayesnet::SPODE(2);}); -static platform::Registrar registrarSN("SPODELd", +static platform::Registrar registrarSLD("SPODELd", [](void) -> bayesnet::BaseClassifier* { return new bayesnet::SPODELd(2);}); static platform::Registrar registrarK("KDB", [](void) -> bayesnet::BaseClassifier* { return new bayesnet::KDB(2);}); -static platform::Registrar registrarKN("KDBLd", +static platform::Registrar registrarKLD("KDBLd", [](void) -> bayesnet::BaseClassifier* { return new bayesnet::KDBLd(2);}); static platform::Registrar registrarA("AODE", [](void) -> bayesnet::BaseClassifier* { return new bayesnet::AODE();}); +static platform::Registrar registrarALD("AODELd", + [](void) -> bayesnet::BaseClassifier* { return new bayesnet::AODELd();}); #endif \ No newline at end of file