Commit 39e27d80 authored by Thomas Purcell's avatar Thomas Purcell
Browse files

The Classification bug should now be fixed

Test in the docker now
parent 6b1f9b3c
......@@ -32,7 +32,7 @@ ConvexHull1D::ConvexHull1D() :
_n_class(0)
{}
ConvexHull1D::ConvexHull1D(const std::vector<int> sizes, const double* prop) :
ConvexHull1D::ConvexHull1D(std::vector<int> sizes, const double* prop) :
_sorted_value(std::accumulate(sizes.begin(), sizes.end(), 0), 0.0),
_cls_max(),
_cls_min(),
......@@ -45,66 +45,65 @@ ConvexHull1D::ConvexHull1D(const std::vector<int> sizes, const double* prop) :
initialize_prop(sizes, prop);
}
void ConvexHull1D::initialize_prop(const std::vector<int>& sizes, const double* prop)
void ConvexHull1D::initialize_prop(std::vector<int> sizes, const double* prop)
{
// Set the number of tasks and samples
_n_task = sizes.size();
// Get number of samples and resize the value and index vectors
_task_scores.resize(_n_task, 0.0);
int n_samp = std::accumulate(sizes.begin(), sizes.end(), 0);
// Set number of classes
std::vector<double> unique_prop_vals;
for(int pp = 0; pp < n_samp; ++pp)
{
if(std::find(unique_prop_vals.begin(), unique_prop_vals.end(), prop[pp]) == unique_prop_vals.end())
{
unique_prop_vals.push_back(prop[pp]);
}
}
std::sort(unique_prop_vals.begin(), unique_prop_vals.end());
_n_class = unique_prop_vals.size();
// Set sizes for the _cls helper variables
_cls_max.resize(_n_class * _n_task, 0.0);
_cls_min.resize(_n_class * _n_task, 0.0);
_cls_sz.resize(_n_class * _n_task, 0);
_cls_start.resize(_n_class * _n_task, 0);
// Set the values of the cls vectors and sorted inds
_sorted_value.resize(n_samp, 0.0);
_sorted_prop_inds.resize(n_samp, 0);
std::iota(_sorted_prop_inds.begin(), _sorted_prop_inds.end(), 0);
// Initialize and fill the vectors used for storing information of the number of samples in each class in each task
std::vector<std::vector<int>> cls_sz(sizes.size());
std::vector<std::vector<int>> cls_start(sizes.size());
std::map<double, int> cl_ind;
for(int cc = 0; cc < _n_class; ++cc)
{
cl_ind[unique_prop_vals[cc]] = cc;
}
int start = 0;
for(int tt = 0; tt < sizes.size(); ++tt)
{
int start_original = start;
util_funcs::argsort<double>(
_sorted_prop_inds.data() + start,
_sorted_prop_inds.data() + start + sizes[tt],
prop
);
for(int pp = start + 1; pp < start_original + sizes[tt]; ++pp)
for(int ind = start; ind < start + sizes[tt]; ++ind)
{
if(prop[_sorted_prop_inds[pp]] != prop[_sorted_prop_inds[pp - 1]])
{
if(prop[_sorted_prop_inds[pp - 1]] != -1)
{
cls_start[tt].push_back(start);
cls_sz[tt].push_back(pp - start);
}
start += pp - start;
}
++_cls_sz[tt * _n_class + cl_ind[prop[ind]]];
}
cls_start[tt].push_back(start);
cls_sz[tt].push_back(sizes[tt] + start_original - start);
start = start_original + sizes[tt];
}
_task_scores.resize(_n_task, 0.0);
for(int tt = 0; tt < _n_task; ++tt)
{
_n_class = std::max(_n_class, static_cast<int>((cls_sz[tt].size())));
}
// Setup vectors used in calculating 1D convex hull
_cls_max.resize(_n_class * _n_task);
_cls_min.resize(_n_class * _n_task);
_cls_sz.resize(_n_class * _n_task, 0);
_cls_start.resize(_n_class * _n_task, 0);
for(int tt = 0; tt < _n_task; ++tt)
{
for(int cc = 0 ; cc < cls_sz[tt].size(); ++cc)
for(int cc = 0; cc < _n_class; ++cc)
{
_cls_sz[tt * _n_class + cc] = cls_sz[tt][cc];
_cls_start[tt * _n_class + cc] = cls_start[tt][cc];
_cls_start[tt * _n_class + cc] = start;
start += _cls_sz[tt * _n_class + cc];
}
}
}
......
......@@ -23,9 +23,9 @@
#define CONVEX_UTILS
#include <coin/ClpSimplex.hpp>
#include "classification/prop_sorted_d_mat.hpp"
#include "utils/math_funcs.hpp"
#include "utils/vector_utils.hpp"
// DocString: cls_convex_hull_1d
/**
......@@ -54,7 +54,7 @@ public:
* @param sizes The size of each task
* @param prop The pointer to the property vector
*/
ConvexHull1D(const std::vector<int> sizes, const double* prop);
ConvexHull1D(std::vector<int> sizes, const double* prop);
/**
* @brief Default constructor
......@@ -67,7 +67,7 @@ public:
* @param sizes The size of each task
* @param prop The pointer to the property vector
*/
void initialize_prop(const std::vector<int>& sizes, const double* prop);
void initialize_prop(std::vector<int> sizes, const double* prop);
/**
* @brief Calculate the projection scores of a set of features to a vector via Pearson correlation
......
......@@ -800,13 +800,18 @@ void FeatureSpace::generate_and_project(std::shared_ptr<LossFunction> loss, std:
#pragma omp parallel firstprivate(worst_score, worst_score_ind, scores_sel_all)
{
std::shared_ptr<LossFunction> loss_copy = loss_function_util::copy(loss);
std::vector<node_ptr> phi_sel_private(phi_sel);
std::vector<double> scores_sel_private(scores_sel);
int index_base = _phi.size() + _n_sis_select * (omp_get_thread_num() + _mpi_comm->size());
#ifdef PARAMETERIZE
std::shared_ptr<NLOptimizer> optimizer = nlopt_wrapper::get_optimizer(_project_type, _task_sizes_train, _prop_train, _max_rung, _max_param_depth);
std::shared_ptr<NLOptimizer> optimizer;
std::shared_ptr<NLOptimizer> reparam_optimizer;
if(_allowed_param_ops.size() > 0)
{
optimizer = nlopt_wrapper::get_optimizer(_project_type, _task_sizes_train, _prop_train, _max_rung, _max_param_depth);
}
if(_reparam_residual)
{
std::vector<double> prop_vec(loss_copy->prop_project());
......
......@@ -65,7 +65,7 @@ LossFunction::LossFunction(std::shared_ptr<LossFunction> o) :
_n_samp(o->n_samp()),
_n_samp_test(o->n_samp_test()),
_n_task(o->n_task()),
_n_project_prop(o->prop_project().size() / o->n_samp()),
_n_project_prop(o->prop_project_copy().size() / o->n_samp()),
_n_feat(o->n_feat()),
_n_dim(o->n_dim()),
_fix_intercept(o->fix_intercept())
......
......@@ -50,10 +50,10 @@ protected:
const int _n_samp; //!< Number of samples in the training set
const int _n_samp_test; //!< Number of samples in the test set
const int _n_task; //!< Number of tasks
int _n_project_prop; //!< Number of properties to project over
int _n_feat; //!< Number features in the linear model
int _n_dim; //!< Total number of constants to fit (scale and bias terms)
const int _n_task; //!< Number of tasks
const bool _fix_intercept; //!< If true then the bias term is fixed at 0
public:
......@@ -195,9 +195,9 @@ public:
inline const std::vector<double>& prop_project() const {return _projection_prop;}
/**
* @brief Pointer to the head of the standardized property vector used for projection
* @brief The standardized property vector used for projection
*/
inline const double* prop_project_std_pointer() const {return _projection_prop_std.data();}
inline const std::vector<double>& prop_project_std() const {return _projection_prop_std;}
/**
* @brief Copy of the value of the property to evaluate the loss function against for the training set
......@@ -225,9 +225,9 @@ public:
inline const std::vector<double> prop_project_copy() const {return _projection_prop;}
/**
* @brief The standardized property vector used for projection
* @brief Copy of the standardized property vector used for projection
*/
inline const std::vector<double>& prop_project_std() const {return _projection_prop_std;}
inline const std::vector<double> prop_project_std_copy() const {return _projection_prop_std;}
/**
* @brief Pointer to the head of the value of the property to evaluate the loss function against for the training set
......@@ -255,9 +255,9 @@ public:
inline const double* prop_project_pointer() const {return _projection_prop.data();}
/**
* @brief Copy of the standardized property vector used for projection
* @brief Pointer to the head of the standardized property vector used for projection
*/
inline const std::vector<double> prop_project_std_copy() const {return _projection_prop_std;}
inline const double* prop_project_std_pointer() const {return _projection_prop_std.data();}
/**
* @brief The error vector for the training set
......
......@@ -88,14 +88,14 @@ LossFunctionConvexHull::LossFunctionConvexHull(
std::copy_n(prop_train.begin(), prop_train.size(), _prop_train.begin());
std::copy_n(prop_test.begin(), prop_test.size(), _prop_test.begin());
set_nfeat(_n_feat);
set_nfeat(_n_feat, true);
prepare_project();
}
LossFunctionConvexHull::LossFunctionConvexHull(std::shared_ptr<LossFunction> o) :
LossFunction(o),
_width(1e-5),
_n_class(vector_utils::unique<double>(o->prop_train_copy()).size())
_n_class(o->n_class())
{
set_nfeat(_n_feat);
prepare_project();
......@@ -115,7 +115,7 @@ void LossFunctionConvexHull::prepare_project()
_convex_hull.resize(_n_project_prop);
for(int pp = 0; pp < _n_project_prop; ++pp)
{
_convex_hull[pp] = ConvexHull1D(_task_sizes_train, &_projection_prop[pp * _n_samp]);
_convex_hull[pp].initialize_prop(_task_sizes_train, &_projection_prop[pp * _n_samp]);
int start = 0;
for(int tt = 0; tt < _n_task; ++tt)
......@@ -226,7 +226,7 @@ void LossFunctionConvexHull::setup_lp(bool initialize_sorted_d_mat)
_lp.push_back(lp);
}
if(prop_sorted_d_mat::N_FEATURES == 0)
if(initialize_sorted_d_mat && (prop_sorted_d_mat::N_CLASS == 0))
{
prop_sorted_d_mat::initialize_sorted_d_matrix_arr(0, _n_task, _n_class, n_samp_per_class);
}
......
......@@ -86,14 +86,14 @@ public:
*
* @param o LossFunctionConvexHull to be copied
*/
LossFunctionConvexHull& operator= (const LossFunctionConvexHull& o) = default;
// LossFunctionConvexHull& operator= (const LossFunctionConvexHull& o) = default;
/**
* @brief Move Assignment operator
*
* @param o LossFunctionConvexHull to be moved
*/
LossFunctionConvexHull& operator= (LossFunctionConvexHull&& o) = default;
// LossFunctionConvexHull& operator= (LossFunctionConvexHull&& o) = default;
/**
* @brief Initialize the LPWrappers used for calculating the loss function
......
......@@ -40,7 +40,7 @@ std::vector<T> unique(const std::vector<T> in_vec)
std::vector<T> out_vec;
for(auto& el : in_vec)
{
if(find(out_vec.begin(), out_vec.end(), el) == out_vec.end())
if(std::find(out_vec.begin(), out_vec.end(), el) == out_vec.end())
{
out_vec.push_back(el);
}
......
# # Copyright 2021 Thomas A. R. Purcell
# #
# # Licensed under the Apache License, Version 2.0 (the "License");
# # you may not use this file except in compliance with the License.
# # You may obtain a copy of the License at
# #
# # http://www.apache.org/licenses/LICENSE-2.0
# #
# # Unless required by applicable law or agreed to in writing, software
# # distributed under the License is distributed on an "AS IS" BASIS,
# # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# # See the License for the specific language governing permissions and
# # limitations under the License.
# import shutil
# import numpy as np
# from sissopp import (
# Inputs,
# FeatureNode,
# FeatureSpace,
# Unit,
# initialize_values_arr,
# SISSOClassifier,
# )
# import matplotlib.pyplot as plt
# def test_sisso_classifier():
# task_sizes_train = [80]
# task_sizes_test = [20]
# initialize_values_arr(task_sizes_train, task_sizes_test, 10, 2)
# inputs = Inputs()
# inputs.task_keys = ["task"]
# inputs.sample_ids_train = [str(ii) for ii in range(20, 100)]
# inputs.sample_ids_test = [str(ii) for ii in range(20)]
# train_data = np.random.random((10, task_sizes_train[0])) * 2.0 - 1.0
# test_data = np.random.random((10, task_sizes_test[0])) * 2.0 - 1.0
# train_data[0][:20] = np.random.random(20) * -1.0 - 1.0
# train_data[0][20:40] = np.random.random(20) + 1.0
# train_data[0][40:60] = np.random.random(20) * -1.0 - 1.0
# train_data[0][60:] = np.random.random(20) + 1.0
# train_data[1][:20] = np.random.random(20) * -1.0 - 1.0
# train_data[1][20:60] = np.random.random(40) + 1.0
# train_data[1][60:] = np.random.random(20) * -1.0 - 1.0
# test_data[0][:5] = np.random.random(5) * -1.0 - 1.0
# test_data[0][5:10] = np.random.random(5) + 1.0
# test_data[0][10:15] = np.random.random(5) * -1.0 - 1.0
# test_data[0][15:] = np.random.random(5) + 1.0
# test_data[1][:5] = np.random.random(5) * -1.0 - 1.0
# test_data[1][5:15] = np.random.random(10) + 1.0
# test_data[1][15:] = np.random.random(5) * -1.0 - 1.0
# inputs.prop_train = (np.sign(train_data[1] * train_data[0]) + 1) // 2
# inputs.prop_test = (np.sign(test_data[1] * test_data[0]) + 1) // 2
# train_data[0][0] = 0.01
# train_data[0][20] = -0.01
# train_data[0][40] = 0.01
# train_data[0][60] = -0.01
# train_data[1][0] = -0.01
# train_data[1][20] = 0.01
# train_data[1][40] = 0.01
# train_data[1][60] = -0.01
# train_data[2][0] = 10.0
# train_data[2][20] = -10.0
# train_data[2][40] = 10.0
# train_data[2][60] = -10.0
# train_data[3][0] = 10.0
# train_data[3][20] = -10.0
# train_data[3][40] = -10.0
# train_data[3][60] = 10.0
# test_data[2][0] = 10.0
# test_data[2][5] = -10.0
# test_data[2][10] = 10.0
# test_data[2][15] = -10.0
# test_data[3][0] = 10.0
# test_data[3][5] = -10.0
# test_data[3][10] = -10.0
# test_data[3][15] = 10.0
# inputs.phi_0 = [
# FeatureNode(
# ff,
# f"feat_{ff}",
# train_data[ff],
# test_data[ff],
# Unit(),
# )
# for ff in range(10)
# ]
# inputs.allowed_ops = ["add", "sub", "mult", "sq", "cb", "sqrt", "cbrt"]
# inputs.calc_type = "classification"
# inputs.max_rung = 1
# inputs.n_sis_select = 10
# inputs.n_dim = 2
# inputs.n_residual = 1
# inputs.n_models_store = 1
# inputs.task_names = ["all"]
# inputs.task_sizes_train = task_sizes_train
# inputs.task_sizes_test = task_sizes_test
# inputs.leave_out_inds = list(range(task_sizes_test[0]))
# inputs.prop_label = "Class"
# feat_space = FeatureSpace(inputs)
# sisso = SISSOClassifier(inputs, feat_space)
# sisso.fit()
# shutil.rmtree("models/")
# shutil.rmtree("feature_space/")
# assert sisso.models[0][0].n_convex_overlap_train == 4
# assert sisso.models[1][0].n_convex_overlap_train == 0
# assert sisso.models[0][0].n_convex_overlap_test == 0
# assert sisso.models[1][0].n_convex_overlap_test == 0
# if __name__ == "__main__":
# test_sisso_classifier()
# Copyright 2021 Thomas A. R. Purcell
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import shutil
import numpy as np
from sissopp import (
Inputs,
FeatureNode,
FeatureSpace,
Unit,
initialize_values_arr,
SISSOClassifier,
)
import matplotlib.pyplot as plt
def test_sisso_classifier():
task_sizes_train = [80]
task_sizes_test = [20]
initialize_values_arr(task_sizes_train, task_sizes_test, 10, 2)
inputs = Inputs()
inputs.task_keys = ["task"]
inputs.sample_ids_train = [str(ii) for ii in range(20, 100)]
inputs.sample_ids_test = [str(ii) for ii in range(20)]
train_data = np.random.random((10, task_sizes_train[0])) * 2.0 - 1.0
test_data = np.random.random((10, task_sizes_test[0])) * 2.0 - 1.0
train_data[0][:20] = np.random.random(20) * -1.0 - 1.0
train_data[0][20:40] = np.random.random(20) + 1.0
train_data[0][40:60] = np.random.random(20) * -1.0 - 1.0
train_data[0][60:] = np.random.random(20) + 1.0
train_data[1][:20] = np.random.random(20) * -1.0 - 1.0
train_data[1][20:60] = np.random.random(40) + 1.0
train_data[1][60:] = np.random.random(20) * -1.0 - 1.0
test_data[0][:5] = np.random.random(5) * -1.0 - 1.0
test_data[0][5:10] = np.random.random(5) + 1.0
test_data[0][10:15] = np.random.random(5) * -1.0 - 1.0
test_data[0][15:] = np.random.random(5) + 1.0
test_data[1][:5] = np.random.random(5) * -1.0 - 1.0
test_data[1][5:15] = np.random.random(10) + 1.0
test_data[1][15:] = np.random.random(5) * -1.0 - 1.0
inputs.prop_train = (np.sign(train_data[1] * train_data[0]) + 1) // 2
inputs.prop_test = (np.sign(test_data[1] * test_data[0]) + 1) // 2
train_data[0][0] = 0.01
train_data[0][20] = -0.01
train_data[0][40] = 0.01
train_data[0][60] = -0.01
train_data[1][0] = -0.01
train_data[1][20] = 0.01
train_data[1][40] = 0.01
train_data[1][60] = -0.01
train_data[2][0] = 10.0
train_data[2][20] = -10.0
train_data[2][40] = 10.0
train_data[2][60] = -10.0
train_data[3][0] = 10.0
train_data[3][20] = -10.0
train_data[3][40] = -10.0
train_data[3][60] = 10.0
test_data[2][0] = 10.0
test_data[2][5] = -10.0
test_data[2][10] = 10.0
test_data[2][15] = -10.0
test_data[3][0] = 10.0
test_data[3][5] = -10.0
test_data[3][10] = -10.0
test_data[3][15] = 10.0
inputs.phi_0 = [
FeatureNode(
ff,
f"feat_{ff}",
train_data[ff],
test_data[ff],
Unit(),
)
for ff in range(10)
]
inputs.allowed_ops = ["add", "sub", "mult", "sq", "cb", "sqrt", "cbrt"]
inputs.calc_type = "classification"
inputs.max_rung = 1
inputs.n_sis_select = 10
inputs.n_dim = 2
inputs.n_residual = 1
inputs.n_models_store = 1
inputs.task_names = ["all"]
inputs.task_sizes_train = task_sizes_train
inputs.task_sizes_test = task_sizes_test
inputs.leave_out_inds = list(range(task_sizes_test[0]))
inputs.prop_label = "Class"
feat_space = FeatureSpace(inputs)
sisso = SISSOClassifier(inputs, feat_space)
sisso.fit()
shutil.rmtree("models/")
shutil.rmtree("feature_space/")
assert sisso.models[0][0].n_convex_overlap_train == 4
assert sisso.models[1][0].n_convex_overlap_train == 0
assert sisso.models[0][0].n_convex_overlap_test == 0
assert sisso.models[1][0].n_convex_overlap_test == 0
if __name__ == "__main__":
test_sisso_classifier()
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment