Add id to classifier
This commit is contained in:
@@ -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<uint32_t>(&this);
|
||||
// This id allows to have more than one instance of the same module/class
|
||||
id = reinterpret_cast<clfId_t>(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<std::string>& features, const std::string& className, std::map<std::string, std::vector<int>>& 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)
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include <torch/torch.h>
|
||||
#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 */
|
||||
|
@@ -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<std::mutex> 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 {
|
||||
|
21
src/PyWrap.h
21
src/PyWrap.h
@@ -7,6 +7,7 @@
|
||||
#include <mutex>
|
||||
#include <nlohmann/json.hpp>
|
||||
#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::pair<std::string, std::string>, std::tuple<PyObject*, PyObject*, PyObject*>> moduleClassMap;
|
||||
std::map<clfId_t, std::tuple<PyObject*, PyObject*, PyObject*>> moduleClassMap;
|
||||
static CPyInstance* pyInstance;
|
||||
static PyWrap* wrapper;
|
||||
static std::mutex mutex;
|
||||
|
4
src/TypeId.h
Normal file
4
src/TypeId.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#ifndef TYPEDEF_H
|
||||
#define TYPEDEF_H
|
||||
typedef uint64_t clfId_t;
|
||||
#endif /* TYPEDEF_H */
|
11
src/main.cc
11
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;
|
||||
|
Reference in New Issue
Block a user