Implement classifier.predict_proba & test
This commit is contained in:
parent
e1c4221c11
commit
443e5cc882
@ -5,7 +5,13 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [Unreleased]
|
## =[Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- predict_proba method in Classifier
|
||||||
|
- predict_proba method in BoostAODE
|
||||||
|
- predict_voting parameter in BoostAODE constructor to use voting or probability to predict (default is voting)
|
||||||
|
|
||||||
## [1.0.2] - 2024-02-20
|
## [1.0.2] - 2024-02-20
|
||||||
|
|
||||||
|
@ -16,12 +16,15 @@ namespace bayesnet {
|
|||||||
virtual ~BaseClassifier() = default;
|
virtual ~BaseClassifier() = default;
|
||||||
torch::Tensor virtual predict(torch::Tensor& X) = 0;
|
torch::Tensor virtual predict(torch::Tensor& X) = 0;
|
||||||
std::vector<int> virtual predict(std::vector<std::vector<int >>& X) = 0;
|
std::vector<int> virtual predict(std::vector<std::vector<int >>& X) = 0;
|
||||||
|
torch::Tensor virtual predict_proba(torch::Tensor& X) = 0;
|
||||||
|
std::vector<std::vector<double>> virtual predict_proba(std::vector<std::vector<int >>& X) = 0;
|
||||||
status_t virtual getStatus() const = 0;
|
status_t virtual getStatus() const = 0;
|
||||||
float virtual score(std::vector<std::vector<int>>& X, std::vector<int>& y) = 0;
|
float virtual score(std::vector<std::vector<int>>& X, std::vector<int>& y) = 0;
|
||||||
float virtual score(torch::Tensor& X, torch::Tensor& y) = 0;
|
float virtual score(torch::Tensor& X, torch::Tensor& y) = 0;
|
||||||
int virtual getNumberOfNodes()const = 0;
|
int virtual getNumberOfNodes()const = 0;
|
||||||
int virtual getNumberOfEdges()const = 0;
|
int virtual getNumberOfEdges()const = 0;
|
||||||
int virtual getNumberOfStates() const = 0;
|
int virtual getNumberOfStates() const = 0;
|
||||||
|
int virtual getClassNumStates() const = 0;
|
||||||
std::vector<std::string> virtual show() const = 0;
|
std::vector<std::string> virtual show() const = 0;
|
||||||
std::vector<std::string> virtual graph(const std::string& title = "") const = 0;
|
std::vector<std::string> virtual graph(const std::string& title = "") const = 0;
|
||||||
virtual std::string getVersion() = 0;
|
virtual std::string getVersion() = 0;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#include "folding.hpp"
|
#include "folding.hpp"
|
||||||
|
|
||||||
namespace bayesnet {
|
namespace bayesnet {
|
||||||
BoostAODE::BoostAODE() : Ensemble()
|
BoostAODE::BoostAODE() : Ensemble(false)
|
||||||
{
|
{
|
||||||
validHyperparameters = { "repeatSparent", "maxModels", "ascending", "convergence", "threshold", "select_features", "tolerance" };
|
validHyperparameters = { "repeatSparent", "maxModels", "ascending", "convergence", "threshold", "select_features", "tolerance" };
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
namespace bayesnet {
|
namespace bayesnet {
|
||||||
Classifier::Classifier(Network model) : model(model), m(0), n(0), metrics(Metrics()), fitted(false) {}
|
Classifier::Classifier(Network model) : model(model), m(0), n(0), metrics(Metrics()), fitted(false) {}
|
||||||
|
const std::string CLASSIFIER_NOT_FITTED = "Classifier has not been fitted";
|
||||||
Classifier& Classifier::build(const std::vector<std::string>& features, const std::string& className, std::map<std::string, std::vector<int>>& states, const torch::Tensor& weights)
|
Classifier& Classifier::build(const std::vector<std::string>& features, const std::string& className, std::map<std::string, std::vector<int>>& states, const torch::Tensor& weights)
|
||||||
{
|
{
|
||||||
this->features = features;
|
this->features = features;
|
||||||
@ -87,14 +88,14 @@ namespace bayesnet {
|
|||||||
torch::Tensor Classifier::predict(torch::Tensor& X)
|
torch::Tensor Classifier::predict(torch::Tensor& X)
|
||||||
{
|
{
|
||||||
if (!fitted) {
|
if (!fitted) {
|
||||||
throw std::logic_error("Classifier has not been fitted");
|
throw std::logic_error(CLASSIFIER_NOT_FITTED);
|
||||||
}
|
}
|
||||||
return model.predict(X);
|
return model.predict(X);
|
||||||
}
|
}
|
||||||
std::vector<int> Classifier::predict(std::vector<std::vector<int>>& X)
|
std::vector<int> Classifier::predict(std::vector<std::vector<int>>& X)
|
||||||
{
|
{
|
||||||
if (!fitted) {
|
if (!fitted) {
|
||||||
throw std::logic_error("Classifier has not been fitted");
|
throw std::logic_error(CLASSIFIER_NOT_FITTED);
|
||||||
}
|
}
|
||||||
auto m_ = X[0].size();
|
auto m_ = X[0].size();
|
||||||
auto n_ = X.size();
|
auto n_ = X.size();
|
||||||
@ -105,10 +106,31 @@ namespace bayesnet {
|
|||||||
auto yp = model.predict(Xd);
|
auto yp = model.predict(Xd);
|
||||||
return yp;
|
return yp;
|
||||||
}
|
}
|
||||||
|
torch::Tensor Classifier::predict_proba(torch::Tensor& X)
|
||||||
|
{
|
||||||
|
if (!fitted) {
|
||||||
|
throw std::logic_error(CLASSIFIER_NOT_FITTED);
|
||||||
|
}
|
||||||
|
return model.predict_proba(X);
|
||||||
|
}
|
||||||
|
std::vector<std::vector<double>> Classifier::predict_proba(std::vector<std::vector<int>>& X)
|
||||||
|
{
|
||||||
|
if (!fitted) {
|
||||||
|
throw std::logic_error(CLASSIFIER_NOT_FITTED);
|
||||||
|
}
|
||||||
|
auto m_ = X[0].size();
|
||||||
|
auto n_ = X.size();
|
||||||
|
std::vector<std::vector<int>> Xd(n_, std::vector<int>(m_, 0));
|
||||||
|
for (auto i = 0; i < n_; i++) {
|
||||||
|
Xd[i] = std::vector<int>(X[i].begin(), X[i].end());
|
||||||
|
}
|
||||||
|
auto yp = model.predict_proba(Xd);
|
||||||
|
return yp;
|
||||||
|
}
|
||||||
float Classifier::score(torch::Tensor& X, torch::Tensor& y)
|
float Classifier::score(torch::Tensor& X, torch::Tensor& y)
|
||||||
{
|
{
|
||||||
if (!fitted) {
|
if (!fitted) {
|
||||||
throw std::logic_error("Classifier has not been fitted");
|
throw std::logic_error(CLASSIFIER_NOT_FITTED);
|
||||||
}
|
}
|
||||||
torch::Tensor y_pred = predict(X);
|
torch::Tensor y_pred = predict(X);
|
||||||
return (y_pred == y).sum().item<float>() / y.size(0);
|
return (y_pred == y).sum().item<float>() / y.size(0);
|
||||||
@ -116,7 +138,7 @@ namespace bayesnet {
|
|||||||
float Classifier::score(std::vector<std::vector<int>>& X, std::vector<int>& y)
|
float Classifier::score(std::vector<std::vector<int>>& X, std::vector<int>& y)
|
||||||
{
|
{
|
||||||
if (!fitted) {
|
if (!fitted) {
|
||||||
throw std::logic_error("Classifier has not been fitted");
|
throw std::logic_error(CLASSIFIER_NOT_FITTED);
|
||||||
}
|
}
|
||||||
return model.score(X, y);
|
return model.score(X, y);
|
||||||
}
|
}
|
||||||
@ -145,6 +167,10 @@ namespace bayesnet {
|
|||||||
{
|
{
|
||||||
return fitted ? model.getStates() : 0;
|
return fitted ? model.getStates() : 0;
|
||||||
}
|
}
|
||||||
|
int Classifier::getClassNumStates() const
|
||||||
|
{
|
||||||
|
return fitted ? model.getClassNumStates() : 0;
|
||||||
|
}
|
||||||
std::vector<std::string> Classifier::topological_order()
|
std::vector<std::string> Classifier::topological_order()
|
||||||
{
|
{
|
||||||
return model.topological_sort();
|
return model.topological_sort();
|
||||||
|
@ -7,8 +7,31 @@
|
|||||||
|
|
||||||
namespace bayesnet {
|
namespace bayesnet {
|
||||||
class Classifier : public BaseClassifier {
|
class Classifier : public BaseClassifier {
|
||||||
private:
|
public:
|
||||||
Classifier& build(const std::vector<std::string>& features, const std::string& className, std::map<std::string, std::vector<int>>& states, const torch::Tensor& weights);
|
Classifier(Network model);
|
||||||
|
virtual ~Classifier() = default;
|
||||||
|
Classifier& fit(std::vector<std::vector<int>>& X, std::vector<int>& y, const std::vector<std::string>& features, const std::string& className, std::map<std::string, std::vector<int>>& states) override;
|
||||||
|
Classifier& 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) override;
|
||||||
|
Classifier& fit(torch::Tensor& dataset, const std::vector<std::string>& features, const std::string& className, std::map<std::string, std::vector<int>>& states) override;
|
||||||
|
Classifier& fit(torch::Tensor& dataset, const std::vector<std::string>& features, const std::string& className, std::map<std::string, std::vector<int>>& states, const torch::Tensor& weights) override;
|
||||||
|
void addNodes();
|
||||||
|
int getNumberOfNodes() const override;
|
||||||
|
int getNumberOfEdges() const override;
|
||||||
|
int getNumberOfStates() const override;
|
||||||
|
int getClassNumStates() const override;
|
||||||
|
torch::Tensor predict(torch::Tensor& X) override;
|
||||||
|
std::vector<int> predict(std::vector<std::vector<int>>& X) override;
|
||||||
|
torch::Tensor predict_proba(torch::Tensor& X) override;
|
||||||
|
std::vector<std::vector<double>> predict_proba(std::vector<std::vector<int>>& X) override;
|
||||||
|
status_t getStatus() const override { return status; }
|
||||||
|
std::string getVersion() override { return { project_version.begin(), project_version.end() }; };
|
||||||
|
float score(torch::Tensor& X, torch::Tensor& y) override;
|
||||||
|
float score(std::vector<std::vector<int>>& X, std::vector<int>& y) override;
|
||||||
|
std::vector<std::string> show() const override;
|
||||||
|
std::vector<std::string> topological_order() override;
|
||||||
|
std::vector<std::string> getNotes() const override { return notes; }
|
||||||
|
void dump_cpt() const override;
|
||||||
|
void setHyperparameters(const nlohmann::json& hyperparameters) override; //For classifiers that don't have hyperparameters
|
||||||
protected:
|
protected:
|
||||||
bool fitted;
|
bool fitted;
|
||||||
int m, n; // m: number of samples, n: number of features
|
int m, n; // m: number of samples, n: number of features
|
||||||
@ -24,28 +47,8 @@ namespace bayesnet {
|
|||||||
virtual void buildModel(const torch::Tensor& weights) = 0;
|
virtual void buildModel(const torch::Tensor& weights) = 0;
|
||||||
void trainModel(const torch::Tensor& weights) override;
|
void trainModel(const torch::Tensor& weights) override;
|
||||||
void buildDataset(torch::Tensor& y);
|
void buildDataset(torch::Tensor& y);
|
||||||
public:
|
private:
|
||||||
Classifier(Network model);
|
Classifier& build(const std::vector<std::string>& features, const std::string& className, std::map<std::string, std::vector<int>>& states, const torch::Tensor& weights);
|
||||||
virtual ~Classifier() = default;
|
|
||||||
Classifier& fit(std::vector<std::vector<int>>& X, std::vector<int>& y, const std::vector<std::string>& features, const std::string& className, std::map<std::string, std::vector<int>>& states) override;
|
|
||||||
Classifier& 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) override;
|
|
||||||
Classifier& fit(torch::Tensor& dataset, const std::vector<std::string>& features, const std::string& className, std::map<std::string, std::vector<int>>& states) override;
|
|
||||||
Classifier& fit(torch::Tensor& dataset, const std::vector<std::string>& features, const std::string& className, std::map<std::string, std::vector<int>>& states, const torch::Tensor& weights) override;
|
|
||||||
void addNodes();
|
|
||||||
int getNumberOfNodes() const override;
|
|
||||||
int getNumberOfEdges() const override;
|
|
||||||
int getNumberOfStates() const override;
|
|
||||||
torch::Tensor predict(torch::Tensor& X) override;
|
|
||||||
status_t getStatus() const override { return status; }
|
|
||||||
std::string getVersion() override { return { project_version.begin(), project_version.end() }; };
|
|
||||||
std::vector<int> predict(std::vector<std::vector<int>>& X) override;
|
|
||||||
float score(torch::Tensor& X, torch::Tensor& y) override;
|
|
||||||
float score(std::vector<std::vector<int>>& X, std::vector<int>& y) override;
|
|
||||||
std::vector<std::string> show() const override;
|
|
||||||
std::vector<std::string> topological_order() override;
|
|
||||||
std::vector<std::string> getNotes() const override { return notes; }
|
|
||||||
void dump_cpt() const override;
|
|
||||||
void setHyperparameters(const nlohmann::json& hyperparameters) override; //For classifiers that don't have hyperparameters
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -2,7 +2,10 @@
|
|||||||
|
|
||||||
namespace bayesnet {
|
namespace bayesnet {
|
||||||
|
|
||||||
Ensemble::Ensemble(bool predict_voting) : Classifier(Network()), n_models(0), predict_voting(predict_voting) {};
|
Ensemble::Ensemble(bool predict_voting) : Classifier(Network()), n_models(0), predict_voting(predict_voting)
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
const std::string ENSEMBLE_NOT_FITTED = "Ensemble has not been fitted";
|
const std::string ENSEMBLE_NOT_FITTED = "Ensemble has not been fitted";
|
||||||
void Ensemble::trainModel(const torch::Tensor& weights)
|
void Ensemble::trainModel(const torch::Tensor& weights)
|
||||||
{
|
{
|
||||||
@ -37,7 +40,7 @@ namespace bayesnet {
|
|||||||
if (!fitted) {
|
if (!fitted) {
|
||||||
throw std::logic_error(ENSEMBLE_NOT_FITTED);
|
throw std::logic_error(ENSEMBLE_NOT_FITTED);
|
||||||
}
|
}
|
||||||
return predict_voting ? do_predict_voting(X) : do_predict_prob(X);
|
return do_predict_voting(X);
|
||||||
|
|
||||||
}
|
}
|
||||||
torch::Tensor Ensemble::predict(torch::Tensor& X)
|
torch::Tensor Ensemble::predict(torch::Tensor& X)
|
||||||
@ -45,27 +48,32 @@ namespace bayesnet {
|
|||||||
if (!fitted) {
|
if (!fitted) {
|
||||||
throw std::logic_error(ENSEMBLE_NOT_FITTED);
|
throw std::logic_error(ENSEMBLE_NOT_FITTED);
|
||||||
}
|
}
|
||||||
return predict_voting ? do_predict_voting(X) : do_predict_prob(X);
|
return do_predict_voting(X);
|
||||||
}
|
}
|
||||||
torch::Tensor Ensemble::do_predict_prob(torch::Tensor& X)
|
torch::Tensor Ensemble::predict_proba(torch::Tensor& X)
|
||||||
{
|
{
|
||||||
torch::Tensor y_pred = torch::zeros({ X.size(1), n_models }, torch::kFloat32);
|
auto n_states = getClassNumStates();
|
||||||
// auto threads{ std::vector<std::thread>() };
|
torch::Tensor y_pred = torch::zeros({ X.size(1), n_states }, torch::kFloat32);
|
||||||
// std::mutex mtx;
|
auto threads{ std::vector<std::thread>() };
|
||||||
// for (auto i = 0; i < n_models; ++i) {
|
std::mutex mtx;
|
||||||
// threads.push_back(std::thread([&, i]() {
|
for (auto i = 0; i < n_models; ++i) {
|
||||||
// auto ypredict = models[i]->predict(X);
|
threads.push_back(std::thread([&, i]() {
|
||||||
// std::lock_guard<std::mutex> lock(mtx);
|
auto ypredict = models[i]->predict_proba(X);
|
||||||
// y_pred.index_put_({ "...", i }, ypredict);
|
ypredict *= significanceModels[i];
|
||||||
// }));
|
std::lock_guard<std::mutex> lock(mtx);
|
||||||
// }
|
y_pred.index_put_({ "...", i }, ypredict);
|
||||||
// for (auto& thread : threads) {
|
}));
|
||||||
// thread.join();
|
}
|
||||||
// }
|
for (auto& thread : threads) {
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
auto sum = std::reduce(significanceModels.begin(), significanceModels.end());
|
||||||
|
y_pred /= sum;
|
||||||
return y_pred;
|
return y_pred;
|
||||||
}
|
}
|
||||||
std::vector<int> Ensemble::do_predict_prob(std::vector<std::vector<int>>& X)
|
std::vector<std::vector<double>> Ensemble::predict_proba(std::vector<std::vector<int>>& X)
|
||||||
{
|
{
|
||||||
|
|
||||||
// long m_ = X[0].size();
|
// long m_ = X[0].size();
|
||||||
// long n_ = X.size();
|
// long n_ = X.size();
|
||||||
// vector<vector<int>> Xd(n_, vector<int>(m_, 0));
|
// vector<vector<int>> Xd(n_, vector<int>(m_, 0));
|
||||||
@ -77,7 +85,7 @@ namespace bayesnet {
|
|||||||
// y_pred.index_put_({ "...", i }, torch::tensor(models[i]->predict(Xd), torch::kInt32));
|
// y_pred.index_put_({ "...", i }, torch::tensor(models[i]->predict(Xd), torch::kInt32));
|
||||||
// }
|
// }
|
||||||
// return voting(y_pred);
|
// return voting(y_pred);
|
||||||
return std::vector<int>();
|
return std::vector<std::vector<double>>();
|
||||||
}
|
}
|
||||||
torch::Tensor Ensemble::do_predict_voting(torch::Tensor& X)
|
torch::Tensor Ensemble::do_predict_voting(torch::Tensor& X)
|
||||||
{
|
{
|
||||||
@ -105,14 +113,23 @@ namespace bayesnet {
|
|||||||
Xd[i] = std::vector<int>(X[i].begin(), X[i].end());
|
Xd[i] = std::vector<int>(X[i].begin(), X[i].end());
|
||||||
}
|
}
|
||||||
torch::Tensor y_pred = torch::zeros({ m_, n_models }, torch::kInt32);
|
torch::Tensor y_pred = torch::zeros({ m_, n_models }, torch::kInt32);
|
||||||
|
auto threads{ std::vector<std::thread>() };
|
||||||
|
std::mutex mtx;
|
||||||
for (auto i = 0; i < n_models; ++i) {
|
for (auto i = 0; i < n_models; ++i) {
|
||||||
y_pred.index_put_({ "...", i }, torch::tensor(models[i]->predict(Xd), torch::kInt32));
|
threads.push_back(std::thread([&, i]() {
|
||||||
|
auto ypredict = models[i]->predict(Xd);
|
||||||
|
std::lock_guard<std::mutex> lock(mtx);
|
||||||
|
y_pred.index_put_({ "...", i }, torch::tensor(ypredict, torch::kInt32));
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
for (auto& thread : threads) {
|
||||||
|
thread.join();
|
||||||
}
|
}
|
||||||
return voting(y_pred);
|
return voting(y_pred);
|
||||||
}
|
}
|
||||||
float Ensemble::score(torch::Tensor& X, torch::Tensor& y)
|
float Ensemble::score(torch::Tensor& X, torch::Tensor& y)
|
||||||
{
|
{
|
||||||
auto y_pred = predict_voting ? do_predict_voting(X) : do_predict_prob(X);
|
auto y_pred = do_predict_voting(X);
|
||||||
int correct = 0;
|
int correct = 0;
|
||||||
for (int i = 0; i < y_pred.size(0); ++i) {
|
for (int i = 0; i < y_pred.size(0); ++i) {
|
||||||
if (y_pred[i].item<int>() == y[i].item<int>()) {
|
if (y_pred[i].item<int>() == y[i].item<int>()) {
|
||||||
@ -123,7 +140,7 @@ namespace bayesnet {
|
|||||||
}
|
}
|
||||||
float Ensemble::score(std::vector<std::vector<int>>& X, std::vector<int>& y)
|
float Ensemble::score(std::vector<std::vector<int>>& X, std::vector<int>& y)
|
||||||
{
|
{
|
||||||
auto y_pred = predict_voting ? do_predict_voting(X) : do_predict_prob(X);
|
auto y_pred = do_predict_voting(X);
|
||||||
int correct = 0;
|
int correct = 0;
|
||||||
for (int i = 0; i < y_pred.size(); ++i) {
|
for (int i = 0; i < y_pred.size(); ++i) {
|
||||||
if (y_pred[i] == y[i]) {
|
if (y_pred[i] == y[i]) {
|
||||||
|
@ -12,10 +12,10 @@ namespace bayesnet {
|
|||||||
virtual ~Ensemble() = default;
|
virtual ~Ensemble() = default;
|
||||||
torch::Tensor predict(torch::Tensor& X) override;
|
torch::Tensor predict(torch::Tensor& X) override;
|
||||||
std::vector<int> predict(std::vector<std::vector<int>>& X) override;
|
std::vector<int> predict(std::vector<std::vector<int>>& X) override;
|
||||||
|
torch::Tensor predict_proba(torch::Tensor& X) override;
|
||||||
|
std::vector<std::vector<double>> predict_proba(std::vector<std::vector<int>>& X) override;
|
||||||
torch::Tensor do_predict_voting(torch::Tensor& X);
|
torch::Tensor do_predict_voting(torch::Tensor& X);
|
||||||
std::vector<int> do_predict_voting(std::vector<std::vector<int>>& X);
|
std::vector<int> do_predict_voting(std::vector<std::vector<int>>& X);
|
||||||
torch::Tensor do_predict_prob(torch::Tensor& X);
|
|
||||||
std::vector<int> do_predict_prob(std::vector<std::vector<int>>& X);
|
|
||||||
float score(torch::Tensor& X, torch::Tensor& y) override;
|
float score(torch::Tensor& X, torch::Tensor& y) override;
|
||||||
float score(std::vector<std::vector<int>>& X, std::vector<int>& y) override;
|
float score(std::vector<std::vector<int>>& X, std::vector<int>& y) override;
|
||||||
int getNumberOfNodes() const override;
|
int getNumberOfNodes() const override;
|
||||||
|
@ -7,23 +7,6 @@
|
|||||||
|
|
||||||
namespace bayesnet {
|
namespace bayesnet {
|
||||||
class Network {
|
class Network {
|
||||||
private:
|
|
||||||
std::map<std::string, std::unique_ptr<Node>> nodes;
|
|
||||||
bool fitted;
|
|
||||||
float maxThreads = 0.95;
|
|
||||||
int classNumStates;
|
|
||||||
std::vector<std::string> features; // Including classname
|
|
||||||
std::string className;
|
|
||||||
double laplaceSmoothing;
|
|
||||||
torch::Tensor samples; // nxm tensor used to fit the model
|
|
||||||
bool isCyclic(const std::string&, std::unordered_set<std::string>&, std::unordered_set<std::string>&);
|
|
||||||
std::vector<double> predict_sample(const std::vector<int>&);
|
|
||||||
std::vector<double> predict_sample(const torch::Tensor&);
|
|
||||||
std::vector<double> exactInference(std::map<std::string, int>&);
|
|
||||||
double computeFactor(std::map<std::string, int>&);
|
|
||||||
void completeFit(const std::map<std::string, std::vector<int>>& states, const torch::Tensor& weights);
|
|
||||||
void checkFitData(int n_features, int n_samples, int n_samples_y, const std::vector<std::string>& featureNames, const std::string& className, const std::map<std::string, std::vector<int>>& states, const torch::Tensor& weights);
|
|
||||||
void setStates(const std::map<std::string, std::vector<int>>&);
|
|
||||||
public:
|
public:
|
||||||
Network();
|
Network();
|
||||||
explicit Network(float);
|
explicit Network(float);
|
||||||
@ -58,6 +41,23 @@ namespace bayesnet {
|
|||||||
void initialize();
|
void initialize();
|
||||||
void dump_cpt() const;
|
void dump_cpt() const;
|
||||||
inline std::string version() { return { project_version.begin(), project_version.end() }; }
|
inline std::string version() { return { project_version.begin(), project_version.end() }; }
|
||||||
|
private:
|
||||||
|
std::map<std::string, std::unique_ptr<Node>> nodes;
|
||||||
|
bool fitted;
|
||||||
|
float maxThreads = 0.95;
|
||||||
|
int classNumStates;
|
||||||
|
std::vector<std::string> features; // Including classname
|
||||||
|
std::string className;
|
||||||
|
double laplaceSmoothing;
|
||||||
|
torch::Tensor samples; // nxm tensor used to fit the model
|
||||||
|
bool isCyclic(const std::string&, std::unordered_set<std::string>&, std::unordered_set<std::string>&);
|
||||||
|
std::vector<double> predict_sample(const std::vector<int>&);
|
||||||
|
std::vector<double> predict_sample(const torch::Tensor&);
|
||||||
|
std::vector<double> exactInference(std::map<std::string, int>&);
|
||||||
|
double computeFactor(std::map<std::string, int>&);
|
||||||
|
void completeFit(const std::map<std::string, std::vector<int>>& states, const torch::Tensor& weights);
|
||||||
|
void checkFitData(int n_features, int n_samples, int n_samples_y, const std::vector<std::string>& featureNames, const std::string& className, const std::map<std::string, std::vector<int>>& states, const torch::Tensor& weights);
|
||||||
|
void setStates(const std::map<std::string, std::vector<int>>&);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
@ -165,7 +165,6 @@ TEST_CASE("BoostAODE test used features in train note", "[BayesNet]")
|
|||||||
{"convergence", true},
|
{"convergence", true},
|
||||||
{"repeatSparent",true},
|
{"repeatSparent",true},
|
||||||
{"select_features","CFS"},
|
{"select_features","CFS"},
|
||||||
{"tolerance", 3}
|
|
||||||
});
|
});
|
||||||
clf.fit(raw.Xv, raw.yv, raw.featuresv, raw.classNamev, raw.statesv);
|
clf.fit(raw.Xv, raw.yv, raw.featuresv, raw.classNamev, raw.statesv);
|
||||||
REQUIRE(clf.getNumberOfNodes() == 72);
|
REQUIRE(clf.getNumberOfNodes() == 72);
|
||||||
@ -175,3 +174,42 @@ TEST_CASE("BoostAODE test used features in train note", "[BayesNet]")
|
|||||||
REQUIRE(clf.getNotes()[1] == "Used features in train: 7 of 8");
|
REQUIRE(clf.getNotes()[1] == "Used features in train: 7 of 8");
|
||||||
REQUIRE(clf.getNotes()[2] == "Number of models: 8");
|
REQUIRE(clf.getNotes()[2] == "Number of models: 8");
|
||||||
}
|
}
|
||||||
|
TEST_CASE("TAN predict_proba", "[BayesNet]")
|
||||||
|
{
|
||||||
|
auto raw = RawDatasets("iris", true);
|
||||||
|
auto clf = bayesnet::TAN();
|
||||||
|
clf.fit(raw.Xv, raw.yv, raw.featuresv, raw.classNamev, raw.statesv);
|
||||||
|
auto y_pred_proba = clf.predict_proba(raw.Xv);
|
||||||
|
auto y_pred = clf.predict(raw.Xv);
|
||||||
|
auto yt_pred_proba = clf.predict_proba(raw.Xt);
|
||||||
|
REQUIRE(y_pred.size() == y_pred_proba.size());
|
||||||
|
REQUIRE(y_pred.size() == yt_pred_proba.size(0));
|
||||||
|
REQUIRE(y_pred.size() == raw.yv.size());
|
||||||
|
REQUIRE(y_pred_proba[0].size() == 3);
|
||||||
|
REQUIRE(yt_pred_proba.size(1) == y_pred_proba[0].size());
|
||||||
|
for (int i = 0; i < y_pred_proba.size(); ++i) {
|
||||||
|
auto maxElem = max_element(y_pred_proba[i].begin(), y_pred_proba[i].end());
|
||||||
|
int predictedClass = distance(y_pred_proba[i].begin(), maxElem);
|
||||||
|
REQUIRE(predictedClass == y_pred[i]);
|
||||||
|
REQUIRE(yt_pred_proba[i].argmax().item<int>() == y_pred[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST_CASE("BoostAODE predict_proba", "[BayesNet]")
|
||||||
|
// {
|
||||||
|
// auto raw = RawDatasets("iris", true);
|
||||||
|
// auto clf = bayesnet::BoostAODE();
|
||||||
|
// clf.fit(raw.Xv, raw.yv, raw.featuresv, raw.classNamev, raw.statesv);
|
||||||
|
// auto y_pred = clf.predict_proba(raw.Xv);
|
||||||
|
// REQUIRE(y_pred.size(0) == raw.yv.size(0));
|
||||||
|
// REQUIRE(y_pred.size(1) == 3);
|
||||||
|
// auto y_pred2 = clf.predict_proba(raw.Xv);
|
||||||
|
// REQUIRE(y_pred2.size(0) == raw.yv.size(0));
|
||||||
|
// REQUIRE(y_pred2.size(1) == 3);
|
||||||
|
// REQUIRE(y_pred.equal(y_pred2));
|
||||||
|
// for (int i = 0; i < y_pred.size(0); ++i) {
|
||||||
|
// for (int j = 0; j < y_pred.size(1); ++j) {
|
||||||
|
// REQUIRE(y_pred[i][j].item<float>() == y_pred2[i][j].item<float>());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
Loading…
Reference in New Issue
Block a user