Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Relaxed Tree #679

Merged
merged 41 commits into from Aug 7, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
784e98a
Added helper utility for Relaxed Tree
pluskid Jul 12, 2012
77e9276
estimate confusion matrix for relaxed-tree.
pluskid Jul 12, 2012
f46eb29
skeleton for RelaxedTree Machine.
pluskid Jul 12, 2012
bc41584
skeleton for relaxed tree
pluskid Jul 13, 2012
c726de7
estimate confusion matrix of Relaxed Tree
pluskid Jul 13, 2012
eea0de0
added an (currently empty) RelaxedTree libshogun example.
pluskid Jul 13, 2012
e06995c
bottom up initialization of relaxed tree.
pluskid Jul 13, 2012
3eb3a6e
the svm train step in relaxed tree.
pluskid Jul 15, 2012
f5db5e2
alternating optimization of RelaxedTree
pluskid Jul 15, 2012
9592235
initialize label space coloring of Relaxed Tree
pluskid Jul 19, 2012
1037b98
apply libsvm for binary classification.
pluskid Jul 19, 2012
877117b
Added find utility for SGVector.
pluskid Jul 20, 2012
407df54
added find_if to SGVector
pluskid Jul 20, 2012
dbf4671
Added sorted_index to SGVector.
pluskid Jul 20, 2012
dab1256
relaxed tree: enforce constraints upper.
pluskid Jul 20, 2012
911f456
relaxedtree: enforce lower constraints
pluskid Jul 20, 2012
da3eaa8
ported the function color_label_space.
pluskid Jul 20, 2012
62b53f4
Relaxed Tree: compute score of models.
pluskid Jul 24, 2012
eb8ae6b
move node_t definition to TreeMachine.
pluskid Jul 24, 2012
1d28ec7
hierarchical training of relaxed tree.
pluskid Jul 24, 2012
aa6410d
classification for relaxed tree.
pluskid Jul 25, 2012
a9f1d2b
test training on relaxed tree.
pluskid Jul 25, 2012
055bac5
fix a bug in Relaxed Tree
pluskid Jul 26, 2012
ab2fad0
better way to obtain # support vectors
pluskid Jul 27, 2012
d1ce23f
use KernelFactory to make a new kernel for each submachine.
pluskid Jul 29, 2012
714da66
better handling of single class
pluskid Jul 29, 2012
8a30ff6
remove debug code.
pluskid Jul 29, 2012
322685e
Added python modular for Relaxed Tree
pluskid Jul 30, 2012
84dcea2
remove pthread flag in libshogun makefile.
pluskid Aug 1, 2012
c69baaf
use shogun evaluation for eval.
pluskid Aug 1, 2012
11389ec
remove unnecessary SG_REF/UNREF for unused local variable
pluskid Aug 1, 2012
1d74145
fix some typos
pluskid Aug 1, 2012
66ff8a1
fix compile error in Relaxed Tree.
pluskid Aug 4, 2012
c22eed2
shalow_copy for GaussianKernel
pluskid Aug 6, 2012
9dfcfb0
ensure shalow_copy of CGaussianKernel not be called in any child.
pluskid Aug 6, 2012
706e86e
use kernel->shalow_copy instead of a kernel factory.
pluskid Aug 6, 2012
e998b74
use CSVM instead of CLibSVM.
pluskid Aug 6, 2012
daf2a13
remove kernel factory.
pluskid Aug 7, 2012
5993b24
several readability improvements.
pluskid Aug 7, 2012
8041148
use multiclassAccuracy::get_confusion_matrix
pluskid Aug 7, 2012
3c40d1e
Added some description of the parameters.
pluskid Aug 7, 2012
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -23,6 +23,7 @@ configure.log
*.swo
*.mex*
*.oct
.localvimrc

# /doc/
/doc/html
Expand Down
100 changes: 100 additions & 0 deletions examples/undocumented/libshogun/classifier_multiclass_relaxedtree.cpp
@@ -0,0 +1,100 @@
#include <algorithm>

#include <shogun/labels/MulticlassLabels.h>
#include <shogun/io/streaming/StreamingAsciiFile.h>
#include <shogun/io/SGIO.h>
#include <shogun/features/streaming/StreamingDenseFeatures.h>
#include <shogun/features/DenseFeatures.h>
#include <shogun/features/DenseSubsetFeatures.h>
#include <shogun/base/init.h>
#include <shogun/multiclass/tree/RelaxedTree.h>
#include <shogun/multiclass/MulticlassLibLinear.h>
#include <shogun/evaluation/MulticlassAccuracy.h>
#include <shogun/kernel/GaussianKernel.h>

#define EPSILON 1e-5

using namespace shogun;

int main(int argc, char** argv)
{
int32_t num_vectors = 0;
int32_t num_feats = 0;

init_shogun_with_defaults();

const char*fname_train = "../data/7class_example4_train.dense";
CStreamingAsciiFile *train_file = new CStreamingAsciiFile(fname_train);
SG_REF(train_file);

CStreamingDenseFeatures<float64_t> *stream_features = new CStreamingDenseFeatures<float64_t>(train_file, true, 1024);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you use streaming features if you in the end only work with a dense feature matrix?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the label for the dataset is embedded in the feature file. I'm using the streaming features to extract the labels.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we need to provide another load routine in dense features - but later.

SG_REF(stream_features);

SGMatrix<float64_t> mat;
SGVector<float64_t> labvec(1000);

stream_features->start_parser();
SGVector< float64_t > vec;
int32_t num_vec=0;
while (stream_features->get_next_example())
{
vec = stream_features->get_vector();
if (num_feats == 0)
{
num_feats = vec.vlen;
mat = SGMatrix<float64_t>(num_feats, 1000);
}
std::copy(vec.vector, vec.vector+vec.vlen, mat.get_column_vector(num_vectors));
labvec[num_vectors] = stream_features->get_label();
num_vectors++;
stream_features->release_example();
num_vec++;

if (num_vec > 20000)
break;
}
stream_features->end_parser();
mat.num_cols = num_vectors;
labvec.vlen = num_vectors;

CMulticlassLabels* labels = new CMulticlassLabels(labvec);
SG_REF(labels);

// Create features with the useful values from mat
CDenseFeatures< float64_t >* features = new CDenseFeatures<float64_t>(mat);
SG_REF(features);

// Create RelaxedTree Machine
CRelaxedTree *machine = new CRelaxedTree();
SG_REF(machine);
machine->set_labels(labels);
CKernel *kernel = new CGaussianKernel();
SG_REF(kernel);
machine->set_kernel(kernel);

CMulticlassLibLinear *svm = new CMulticlassLibLinear();

machine->set_machine_for_confusion_matrix(svm);
machine->train(features);


CMulticlassLabels* output = CMulticlassLabels::obtain_from_generic(machine->apply());

CMulticlassAccuracy *evaluator = new CMulticlassAccuracy();
SG_SPRINT("Accuracy = %.4f\n", evaluator->evaluate(output, labels));

// Free resources
SG_UNREF(machine);
SG_UNREF(output);
SG_UNREF(features);
SG_UNREF(labels);
SG_UNREF(train_file);
SG_UNREF(stream_features);
SG_UNREF(evaluator);
SG_UNREF(kernel);

exit_shogun();

return 0;
}

@@ -0,0 +1,39 @@
import classifier_multiclass_shared

[traindat, label_traindat, testdat, label_testdat] = classifier_multiclass_shared.prepare_data(True)

parameter_list = [[traindat,testdat,label_traindat,label_testdat,2.1,1,1e-5],[traindat,testdat,label_traindat,label_testdat,2.2,1,1e-5]]

def classifier_multiclass_relaxedtree (fm_train_real=traindat,fm_test_real=testdat,label_train_multiclass=label_traindat,label_test_multiclass=label_testdat,lawidth=2.1,C=1,epsilon=1e-5):
from shogun.Features import RealFeatures, MulticlassLabels
from shogun.Classifier import RelaxedTree, MulticlassLibLinear
from shogun.Kernel import GaussianKernel

print('Working on a problem of %d features and %d samples' % fm_train_real.shape)

feats_train = RealFeatures(fm_train_real)

labels = MulticlassLabels(label_train_multiclass)

machine = RelaxedTree()
machine.set_machine_for_confusion_matrix(MulticlassLibLinear())
machine.set_kernel(GaussianKernel())
machine.set_labels(labels)
machine.train(feats_train)

label_pred = machine.apply_multiclass(RealFeatures(fm_test_real))
out = label_pred.get_labels()

if label_test_multiclass is not None:
from shogun.Evaluation import MulticlassAccuracy
labels_test = MulticlassLabels(label_test_multiclass)
evaluator = MulticlassAccuracy()
acc = evaluator.evaluate(label_pred, labels_test)
print('Accuracy = %.4f' % acc)

return out

if __name__=='__main__':
print('MulticlassMachine')
classifier_multiclass_relaxedtree(*parameter_list[0])

3 changes: 2 additions & 1 deletion src/interfaces/modular/Multiclass.i
Expand Up @@ -54,6 +54,7 @@
%rename(QDA) CQDA;

%rename(ShareBoost) CShareBoost;
%rename(RelaxedTree) CRelaxedTree;

/* Include Class Headers to make them visible from within the target language */
%include <shogun/multiclass/RejectionStrategy.h>
Expand Down Expand Up @@ -96,4 +97,4 @@
%include <shogun/multiclass/GaussianNaiveBayes.h>
%include <shogun/multiclass/QDA.h>
%include <shogun/multiclass/ShareBoost.h>

%include <shogun/multiclass/tree/RelaxedTree.h>
1 change: 1 addition & 0 deletions src/interfaces/modular/Multiclass_includes.i
Expand Up @@ -39,4 +39,5 @@
#include <shogun/multiclass/GaussianNaiveBayes.h>
#include <shogun/multiclass/QDA.h>
#include <shogun/multiclass/ShareBoost.h>
#include <shogun/multiclass/tree/RelaxedTree.h>
%}
18 changes: 18 additions & 0 deletions src/shogun/base/SGObject.h
Expand Up @@ -116,6 +116,24 @@ class CSGObject
int32_t unref();
#endif //USE_REFERENCE_COUNTING

/** A shallow copy.
* All the SGObject instance variables will be simply assigned and SG_REF-ed.
*/
virtual CSGObject *shallow_copy() const
{
SG_NOTIMPLEMENTED;
return NULL;
}

/** A deep copy.
* All the instance variables will also be copied.
*/
virtual CSGObject *deep_copy() const
{
SG_NOTIMPLEMENTED;
return NULL;
}

/** Returns the name of the SGSerializable instance. It MUST BE
* the CLASS NAME without the prefixed `C'.
*
Expand Down
2 changes: 1 addition & 1 deletion src/shogun/evaluation/MulticlassAccuracy.h
Expand Up @@ -57,7 +57,7 @@ class CMulticlassAccuracy: public CEvaluation
* @param ground_truth labels assumed to be correct
* @return confusion matrix
*/
SGMatrix<int32_t> get_confusion_matrix(CLabels* predicted, CLabels* ground_truth);
static SGMatrix<int32_t> get_confusion_matrix(CLabels* predicted, CLabels* ground_truth);

inline EEvaluationDirection get_evaluation_direction()
{
Expand Down
15 changes: 15 additions & 0 deletions src/shogun/kernel/GaussianKernel.cpp
Expand Up @@ -46,6 +46,21 @@ CGaussianKernel::~CGaussianKernel()
cleanup();
}

#include <typeinfo>
CSGObject *CGaussianKernel::shallow_copy() const
{
// TODO: remove this after all the classes get shallow_copy properly implemented
// this assert is to avoid any subclass of CGaussianKernel accidentally called
// with the implement here
ASSERT(typeid(*this) == typeid(CGaussianKernel));
CGaussianKernel *kernel = new CGaussianKernel(width, cache_size);
if (lhs)
{
kernel->init(lhs, rhs);
}
return kernel;
}

void CGaussianKernel::cleanup()
{
if (sq_lhs != sq_rhs)
Expand Down
3 changes: 3 additions & 0 deletions src/shogun/kernel/GaussianKernel.h
Expand Up @@ -68,6 +68,9 @@ class CGaussianKernel: public CDotKernel

virtual ~CGaussianKernel();

/** Make a shallow copy of the kernel */
virtual CSGObject *shallow_copy() const;

/** initialize kernel
*
* @param l features of left-hand side
Expand Down
12 changes: 12 additions & 0 deletions src/shogun/lib/SGVector.cpp
Expand Up @@ -623,6 +623,18 @@ int32_t SGVector<T>::unique(T* output, int32_t size)
return j;
}

template <class T>
SGVector<index_t> SGVector<T>::find(T elem)
{
SGVector<index_t> idx(vlen);
index_t k=0;

for (index_t i=0; i < vlen; ++i)
if (vector[i] == elem)
idx[k++] = i;
idx.vlen = k;
return idx;
}

template class SGVector<bool>;
template class SGVector<char>;
Expand Down
53 changes: 53 additions & 0 deletions src/shogun/lib/SGVector.h
Expand Up @@ -12,6 +12,8 @@
#ifndef __SGVECTOR_H__
#define __SGVECTOR_H__

#include <algorithm>

#include <shogun/io/SGIO.h>
#include <shogun/lib/DataType.h>
#include <shogun/lib/SGReferencedData.h>
Expand Down Expand Up @@ -471,6 +473,57 @@ template<class T> class SGVector : public SGReferencedData
const SGVector<T>, const char* name="vector",
const char* prefix="");

/** find index for occurance of an element
* @param elem the element to find
*/
SGVector<index_t> find(T elem);

/** find index for elements where the predicate returns true
* @param p the predicate, it should accept the value of the element and return a bool
*/
template <typename Predicate>
SGVector<index_t> find_if(Predicate p)
{
SGVector<index_t> idx(vlen);
index_t k=0;

for (index_t i=0; i < vlen; ++i)
if (p(vector[i]))
idx[k++] = i;

idx.vlen = k;
return idx;
}

/** Helper functor for the function sorted_index */
struct IndexSorter
{
IndexSorter(const SGVector<T> *vec) { data = vec->vector; }

bool operator() (index_t i, index_t j) const
{
return data[i] < data[j];
}

const T* data;
};
/** get sorted index.
*
* idx = v.sorted_index() is similar to Matlab [~, idx] = sort(v)
*
* @return sorted index for this vector
*/
SGVector<index_t> sorted_index()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use the CMath::qsort_index function here (at least inside this function)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, I tried to modify this. But I failed because this will introduce circular dependency for CMath and SGVector. Any suggestion for how to fix this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't

class CMath;

and then code depending on it work w/o any math include work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm afraid this won't work. Forward class declaration only tells the compiler there is a class named this, so that you can use some limited things like the pointer type (CMath *). But you cannot do things that depends on the content of the class definition. For example, calling CMath's method isn't allowed here because the compiler doesn't know what method CMath has now (by merely seeing a statement "class CMath").

{
IndexSorter cmp(this);
SGVector<index_t> idx(vlen);
for (index_t i=0; i < vlen; ++i)
idx[i] = i;

std::sort(idx.vector, idx.vector+vlen, cmp);

return idx;
}

protected:
/** needs to be overridden to copy data */
Expand Down
2 changes: 0 additions & 2 deletions src/shogun/multiclass/tree/ConditionalProbabilityTree.h
Expand Up @@ -43,8 +43,6 @@ struct ConditionalProbabilityTreeNodeData
class CConditionalProbabilityTree: public CTreeMachine<ConditionalProbabilityTreeNodeData>
{
public:
typedef CTreeMachineNode<ConditionalProbabilityTreeNodeData> node_t;

/** constructor */
CConditionalProbabilityTree(int32_t num_passes=1)
:m_num_passes(num_passes), m_feats(NULL)
Expand Down