From 55286168cb35f208e5907258b38ccfd448d7ae89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Montan=CC=83ana?= Date: Fri, 10 Nov 2023 11:11:10 +0100 Subject: [PATCH] Add id to classifier --- src/PyClassifier.cc | 20 +++++++++++--------- src/PyClassifier.h | 3 ++- src/PyWrap.cc | 43 ++++++++++++++++++++++--------------------- src/PyWrap.h | 21 +++++++++++---------- src/TypeId.h | 4 ++++ src/main.cc | 11 ++++++----- 6 files changed, 56 insertions(+), 46 deletions(-) create mode 100644 src/TypeId.h diff --git a/src/PyClassifier.cc b/src/PyClassifier.cc index 19dc5d6..9106454 100644 --- a/src/PyClassifier.cc +++ b/src/PyClassifier.cc @@ -5,13 +5,15 @@ namespace pywrap { namespace np = boost::python::numpy; PyClassifier::PyClassifier(const std::string& module, const std::string& className) : module(module), className(className), fitted(false) { - id = 0;//reinterpret_cast(&this); + // This id allows to have more than one instance of the same module/class + id = reinterpret_cast(this); + std::cout << "PyClassifier: Creating instance of " << module << " and class " << className << " id " << id << std::endl; pyWrap = PyWrap::GetInstance(); - pyWrap->importClass(module, className); + pyWrap->importClass(id, module, className); } PyClassifier::~PyClassifier() { - pyWrap->clean(module, className); + pyWrap->clean(id); } np::ndarray tensor2numpy(torch::Tensor& X) { @@ -29,22 +31,22 @@ namespace pywrap { } std::string PyClassifier::version() { - return pyWrap->version(module, className); + return pyWrap->version(id); } std::string PyClassifier::callMethodString(const std::string& method) { - return pyWrap->callMethodString(module, className, method); + return pyWrap->callMethodString(id, method); } PyClassifier& PyClassifier::fit(torch::Tensor& X, torch::Tensor& y, const std::vector& features, const std::string& className, std::map>& states) { if (!fitted && hyperparameters.size() > 0) { std::cout << "PyClassifier: Setting hyperparameters" << std::endl; - pyWrap->setHyperparameters(module, this->className, hyperparameters); + pyWrap->setHyperparameters(id, hyperparameters); } auto [Xn, yn] = tensors2numpy(X, y); CPyObject Xp = bp::incref(bp::object(Xn).ptr()); CPyObject yp = bp::incref(bp::object(yn).ptr()); - pyWrap->fit(module, this->className, Xp, yp); + pyWrap->fit(id, Xp, yp); fitted = true; return *this; } @@ -53,7 +55,7 @@ namespace pywrap { int dimension = X.size(1); auto Xn = tensor2numpy(X); CPyObject Xp = bp::incref(bp::object(Xn).ptr()); - PyObject* incoming = pyWrap->predict(module, className, Xp); + PyObject* incoming = pyWrap->predict(id, Xp); bp::handle<> handle(incoming); bp::object object(handle); np::ndarray prediction = np::from_object(object); @@ -72,7 +74,7 @@ namespace pywrap { auto [Xn, yn] = tensors2numpy(X, y); CPyObject Xp = bp::incref(bp::object(Xn).ptr()); CPyObject yp = bp::incref(bp::object(yn).ptr()); - auto result = pyWrap->score(module, className, Xp, yp); + auto result = pyWrap->score(id, Xp, yp); return result; } void PyClassifier::setHyperparameters(const nlohmann::json& hyperparameters) diff --git a/src/PyClassifier.h b/src/PyClassifier.h index 358d4e7..8072e59 100644 --- a/src/PyClassifier.h +++ b/src/PyClassifier.h @@ -10,6 +10,7 @@ #include #include "PyWrap.h" #include "Classifier.h" +#include "TypeId.h" namespace pywrap { class PyClassifier : public Classifier { @@ -29,7 +30,7 @@ namespace pywrap { PyWrap* pyWrap; std::string module; std::string className; - uint32_t id; + clfId_t id; bool fitted; }; } /* namespace pywrap */ diff --git a/src/PyWrap.cc b/src/PyWrap.cc index c6f8ce9..483894f 100644 --- a/src/PyWrap.cc +++ b/src/PyWrap.cc @@ -36,9 +36,9 @@ namespace pywrap { wrapper = nullptr; } } - void PyWrap::importClass(const std::string& moduleName, const std::string& className) + void PyWrap::importClass(const clfId_t id, const std::string& moduleName, const std::string& className) { - auto result = moduleClassMap.find({ moduleName, className }); + auto result = moduleClassMap.find(id); if (result != moduleClassMap.end()) { return; } @@ -58,12 +58,13 @@ namespace pywrap { module.AddRef(); classObject.AddRef(); instance.AddRef(); - moduleClassMap.insert({ { moduleName, className }, { module.getObject(), classObject.getObject(), instance.getObject() } }); + moduleClassMap.insert({ id, { module.getObject(), classObject.getObject(), instance.getObject() } }); } - void PyWrap::clean(const std::string& moduleName, const std::string& className) + void PyWrap::clean(const clfId_t id) { + // Remove Python interpreter if no more modules imported left std::lock_guard lock(mutex); - auto result = moduleClassMap.find({ moduleName, className }); + auto result = moduleClassMap.find(id); if (result == moduleClassMap.end()) { return; } @@ -73,7 +74,7 @@ namespace pywrap { moduleClassMap.erase(result); if (PyErr_Occurred()) { PyErr_Print(); - errorAbort("Error cleaning module " + moduleName + " and class " + className); + errorAbort("Error cleaning module "); } if (moduleClassMap.empty()) { RemoveInstance(); @@ -86,17 +87,17 @@ namespace pywrap { RemoveInstance(); exit(1); } - PyObject* PyWrap::getClass(const std::string& moduleName, const std::string& className) + PyObject* PyWrap::getClass(const clfId_t id) { - auto item = moduleClassMap.find({ moduleName, className }); + auto item = moduleClassMap.find(id); if (item == moduleClassMap.end()) { - errorAbort("Module " + moduleName + " and class " + className + " not found"); + errorAbort("Module not found"); } return std::get<2>(item->second); } - std::string PyWrap::callMethodString(const std::string& moduleName, const std::string& className, const std::string& method) + std::string PyWrap::callMethodString(const clfId_t id, const std::string& method) { - PyObject* instance = getClass(moduleName, className); + PyObject* instance = getClass(id); PyObject* result; try { if (!(result = PyObject_CallMethod(instance, method.c_str(), NULL))) @@ -109,16 +110,16 @@ namespace pywrap { Py_XDECREF(result); return value; } - std::string PyWrap::version(const std::string& moduleName, const std::string& className) + std::string PyWrap::version(const clfId_t id) { - return callMethodString(moduleName, className, "version"); + return callMethodString(id, "version"); } - void PyWrap::setHyperparameters(const std::string& moduleName, const std::string& className, const json& hyperparameters) + void PyWrap::setHyperparameters(const clfId_t id, const json& hyperparameters) { // Set hyperparameters as attributes of the class std::cout << "Building dictionary of arguments" << std::endl; PyObject* pValue; - PyObject* instance = getClass(moduleName, className); + PyObject* instance = getClass(id); for (const auto& [key, value] : hyperparameters.items()) { std::stringstream oss; oss << value.type_name(); @@ -139,9 +140,9 @@ namespace pywrap { Py_XDECREF(pValue); } } - void PyWrap::fit(const std::string& moduleName, const std::string& className, CPyObject& X, CPyObject& y) + void PyWrap::fit(const clfId_t id, CPyObject& X, CPyObject& y) { - PyObject* instance = getClass(moduleName, className); + PyObject* instance = getClass(id); CPyObject result; std::string method = "fit"; try { @@ -154,9 +155,9 @@ namespace pywrap { // Py_XDECREF(result); } - PyObject* PyWrap::predict(const std::string& moduleName, const std::string& className, CPyObject& X) + PyObject* PyWrap::predict(const clfId_t id, CPyObject& X) { - PyObject* instance = getClass(moduleName, className); + PyObject* instance = getClass(id); PyObject* result; std::string method = "predict"; try { @@ -169,9 +170,9 @@ namespace pywrap { Py_INCREF(result); return result; // Caller must free this object } - double PyWrap::score(const std::string& moduleName, const std::string& className, CPyObject& X, CPyObject& y) + double PyWrap::score(const clfId_t id, CPyObject& X, CPyObject& y) { - PyObject* instance = getClass(moduleName, className); + PyObject* instance = getClass(id); CPyObject result; std::string method = "score"; try { diff --git a/src/PyWrap.h b/src/PyWrap.h index f122837..13002d6 100644 --- a/src/PyWrap.h +++ b/src/PyWrap.h @@ -7,6 +7,7 @@ #include #include #include "PyHelper.hpp" +#include "TypeId.h" #pragma once @@ -22,21 +23,21 @@ namespace pywrap { static PyWrap* GetInstance(); void operator=(const PyWrap&) = delete; ~PyWrap() = default; - std::string callMethodString(const std::string& moduleName, const std::string& className, const std::string& method); - std::string version(const std::string& moduleName, const std::string& className); - void setHyperparameters(const std::string& moduleName, const std::string& className, const json& hyperparameters); - void fit(const std::string& moduleName, const std::string& className, CPyObject& X, CPyObject& y); - PyObject* predict(const std::string& moduleName, const std::string& className, CPyObject& X); - double score(const std::string& moduleName, const std::string& className, CPyObject& X, CPyObject& y); - void clean(const std::string& moduleName, const std::string& className); - void importClass(const std::string& moduleName, const std::string& className); - PyObject* getClass(const std::string& moduleName, const std::string& className); + std::string callMethodString(const clfId_t id, const std::string& method); + std::string version(const clfId_t id); + void setHyperparameters(const clfId_t id, const json& hyperparameters); + void fit(const clfId_t id, CPyObject& X, CPyObject& y); + PyObject* predict(const clfId_t id, CPyObject& X); + double score(const clfId_t id, CPyObject& X, CPyObject& y); + void clean(const clfId_t id); + void importClass(const clfId_t id, const std::string& moduleName, const std::string& className); + PyObject* getClass(const clfId_t id); private: // Only call RemoveInstance from clean method static void RemoveInstance(); void errorAbort(const std::string& message); // No need to use static map here, since this class is a singleton - std::map, std::tuple> moduleClassMap; + std::map> moduleClassMap; static CPyInstance* pyInstance; static PyWrap* wrapper; static std::mutex mutex; diff --git a/src/TypeId.h b/src/TypeId.h new file mode 100644 index 0000000..54b08a4 --- /dev/null +++ b/src/TypeId.h @@ -0,0 +1,4 @@ +#ifndef TYPEDEF_H +#define TYPEDEF_H +typedef uint64_t clfId_t; +#endif /* TYPEDEF_H */ \ No newline at end of file diff --git a/src/main.cc b/src/main.cc index bee7d06..f5983cc 100644 --- a/src/main.cc +++ b/src/main.cc @@ -8,6 +8,7 @@ #include "STree.h" #include "SVC.h" #include "RandomForest.h" +#include "XGBoost.h" using namespace std; using namespace torch; @@ -53,16 +54,16 @@ int main(int argc, char* argv[]) cout << "X: " << X.sizes() << endl; cout << "y: " << y.sizes() << endl; auto clf = pywrap::STree(); - // auto stree = pywrap::STree(); + auto stree = pywrap::STree(); auto hyperparameters = json::parse("{\"C\": 0.7, \"max_iter\": 10000, \"kernel\": \"rbf\", \"random_state\": 17}"); - // stree.setHyperparameters(hyperparameters); + stree.setHyperparameters(hyperparameters); cout << "STree Version: " << clf.version() << endl; auto svc = pywrap::SVC(); cout << "SVC with hyperparameters" << endl; svc.fit(X, y, features, className, states); cout << "Graph: " << endl << clf.graph() << endl; clf.fit(X, y, features, className, states); - // stree.fit(X, y, features, className, states); + stree.fit(X, y, features, className, states); auto prediction = clf.predict(X); cout << "Prediction: " << endl << "{"; for (int i = 0; i < prediction.size(0); ++i) { @@ -71,10 +72,10 @@ int main(int argc, char* argv[]) cout << "}" << endl; auto rf = pywrap::RandomForest(); rf.fit(X, y, features, className, states); - auto xg = pywrap::RandomForest(); + auto xg = pywrap::XGBoost(); xg.fit(X, y, features, className, states); cout << "STree Score ......: " << clf.score(X, y) << endl; - // cout << "STree hyper score : " << stree.score(X, y) << endl; + cout << "STree hyper score : " << stree.score(X, y) << endl; cout << "RandomForest Score: " << rf.score(X, y) << endl; cout << "SVC Score ........: " << svc.score(X, y) << endl; cout << "XGBoost Score ....: " << xg.score(X, y) << endl;