Skip to content

Commit

Permalink
Inherit AveragePerceptron from IterativeMachine
Browse files Browse the repository at this point in the history
  • Loading branch information
vinx13 committed Jan 7, 2019
1 parent c0add2c commit 7caeb67
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 81 deletions.
125 changes: 55 additions & 70 deletions src/shogun/classifier/AveragedPerceptron.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,23 @@

#include <shogun/base/progress.h>
#include <shogun/classifier/AveragedPerceptron.h>
#include <shogun/features/iterators/DotIterator.h>
#include <shogun/labels/BinaryLabels.h>
#include <shogun/labels/Labels.h>
#include <shogun/lib/Signal.h>
#include <shogun/mathematics/Math.h>
#include <shogun/mathematics/linalg/LinalgNamespace.h>

using namespace shogun;

CAveragedPerceptron::CAveragedPerceptron()
: CLinearMachine()
: CIterativeMachine<CLinearMachine>()
{
init();

}

CAveragedPerceptron::CAveragedPerceptron(CDotFeatures* traindat, CLabels* trainlab)
: CLinearMachine()
: CIterativeMachine<CLinearMachine>()
{
set_features(traindat);
set_labels(trainlab);
Expand All @@ -35,84 +36,68 @@ CAveragedPerceptron::~CAveragedPerceptron()

void CAveragedPerceptron::init()
{
max_iter = 1000;
learn_rate = 0.1;
SG_ADD(&max_iter, "max_iter", "Maximum number of iterations.", ParameterProperties::HYPER);
SG_ADD(&learn_rate, "learn_rate", "Learning rate.", ParameterProperties::HYPER);
}

bool CAveragedPerceptron::train_machine(CFeatures* data)
void CAveragedPerceptron::init_model(CFeatures* features, CLabels* labels)
{
ASSERT(m_labels)
set_labels(labels);

ASSERT(features);
if (!features->has_property(FP_DOT))
SG_ERROR("Specified features are not of type CDotFeatures\n")
set_features((CDotFeatures*) features);

SG_REF(features);
SG_UNREF(m_continue_features);
m_continue_features = features->as<CDotFeatures>();
int32_t num_feat =
m_continue_features->as<CDotFeatures>()->get_dim_feature_space();
cur_w = SGVector<float64_t>(num_feat);
linalg::set_const(cur_w, 1.0 / num_feat);
cur_bias = 0.0;
}

if (data)
{
if (!data->has_property(FP_DOT))
SG_ERROR("Specified features are not of type CDotFeatures\n")
set_features((CDotFeatures*) data);
}
ASSERT(features)
bool converged=false;
int32_t iter=0;
SGVector<int32_t> train_labels = binary_labels(m_labels)->get_int_labels();
int32_t num_feat=features->get_dim_feature_space();
int32_t num_vec=features->get_num_vectors();

ASSERT(num_vec==train_labels.vlen)
SGVector<float64_t> w(num_feat);
float64_t* tmp_w=SG_MALLOC(float64_t, num_feat);
memset(tmp_w, 0, sizeof(float64_t)*num_feat);
float64_t* output=SG_MALLOC(float64_t, num_vec);

//start with uniform w, bias=0, tmp_bias=0
bias=0;
float64_t tmp_bias=0;
for (int32_t i=0; i<num_feat; i++)
w[i]=1.0/num_feat;

auto pb = SG_PROGRESS(range(max_iter));
// loop till we either get everything classified right or reach max_iter
while (!converged && iter < max_iter)
void CAveragedPerceptron::iteration()
{
bool converged = true;

auto labels = binary_labels(m_labels)->get_int_labels();
auto iter_train_labels = labels.begin();

auto dot_features = m_continue_features->as<CDotFeatures>();
int32_t num_vec = dot_features->get_num_vectors();
int32_t num_feat = dot_features->get_dim_feature_space();

SGVector<float64_t> sum_w(num_feat);
float64_t sum_bias = 0;

for (const auto& v : DotIterator(dot_features))
{
COMPUTATION_CONTROLLERS
converged=true;
SG_INFO("Iteration Number : %d of max %d\n", iter, max_iter);
const auto true_label = *(iter_train_labels++);
auto predicted_label = v.dot(cur_w) + cur_bias;

for (int32_t i=0; i<num_vec; i++)
if (CMath::sign<float64_t>(predicted_label) != true_label)
{
output[i] = features->dense_dot(i, w.vector, w.vlen) + bias;

if (CMath::sign<float64_t>(output[i]) != train_labels.vector[i])
{
converged=false;
bias+=learn_rate*train_labels.vector[i];
features->add_to_dense_vec(learn_rate*train_labels.vector[i], i, w.vector, w.vlen);
}

// Add current w to tmp_w, and current bias to tmp_bias
// To calculate the sum of each iteration's w, bias
for (int32_t j=0; j<num_feat; j++)
tmp_w[j]+=w[j];
tmp_bias+=bias;
converged = false;
const auto gradient = learn_rate * true_label;
cur_bias += gradient;
v.add(gradient, cur_w);
}
iter++;
pb.print_progress();
// Add current w to w, and current bias to bias
// To calculate the sum of each iteration's w, bias
linalg::add(sum_w, cur_w, sum_w);
sum_bias += cur_bias;
}
pb.complete();
if (converged)
SG_INFO("Averaged Perceptron algorithm converged after %d iterations.\n", iter)
else
SG_WARNING("Averaged Perceptron algorithm did not converge after %d iterations.\n", max_iter)

// calculate and set the average paramter of w, bias
for (int32_t i=0; i<num_feat; i++)
w[i]=tmp_w[i]/(num_vec*iter);
bias=tmp_bias/(num_vec*iter);

SG_FREE(output);
SG_FREE(tmp_w);
// Calculate moving average of w and bias
sum_bias /= num_vec;
bias = (bias * m_current_iteration + sum_bias) / (m_current_iteration + 1);

auto w = get_w();
linalg::add(
w, sum_w, w, m_current_iteration / (m_current_iteration + 1.0),
1.0 / (num_vec * (m_current_iteration + 1)));
set_w(w);

return converged;
}
}
18 changes: 8 additions & 10 deletions src/shogun/classifier/AveragedPerceptron.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include <shogun/lib/common.h>
#include <shogun/features/DotFeatures.h>
#include <shogun/machine/IterativeMachine.h>
#include <shogun/machine/LinearMachine.h>

namespace shogun
Expand All @@ -26,7 +27,7 @@ namespace shogun
*
* \sa CLinearMachine
*/
class CAveragedPerceptron : public CLinearMachine
class CAveragedPerceptron : public CIterativeMachine<CLinearMachine>
{
public:
/** problem type */
Expand Down Expand Up @@ -68,21 +69,18 @@ class CAveragedPerceptron : public CLinearMachine
/** registers and initializes parameters */
void init();

/** train classifier
*
* @param data training data (parameter can be avoided if distance or
* kernel-based classifiers are used and distance/kernels are
* initialized with training data)
*
* @return whether training was successful
*/
virtual bool train_machine(CFeatures* data=NULL);
virtual void init_model(CFeatures* features, CLabels* labels);

virtual void iteration();

protected:
/** learning rate */
float64_t learn_rate;
/** maximum number of iterations */
int32_t max_iter;

SGVector<float64_t> cur_w;
float64_t cur_bias;
};
}
#endif
5 changes: 4 additions & 1 deletion src/shogun/machine/IterativeMachine.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,10 @@ namespace shogun

/** To be overloaded in subclasses to initialize the model for training
*/
virtual void init_model(CFeatures* data = NULL) = 0;
virtual void init_model(CFeatures* data = NULL)
{
SG_SNOTIMPLEMENTED
}

// FIXME: this is a temporary implementation during refactor
virtual void init_model(CFeatures* features, CLabels* labels)
Expand Down

0 comments on commit 7caeb67

Please sign in to comment.