blob: 8f74d47a0a74419f73464f0bcceeeaba5551559d [file] [log] [blame]
/* ----------------------------------------------------------------------- *//**
*
* @file model.hpp
*
* This file contians classes of coefficients (or model), which usually has
* fields that maps to transition states for user-defined aggregates.
* The necessity of these wrappers is to allow classes in algo/ and task/ to
* have a type that they can template over.
*
*//* ----------------------------------------------------------------------- */
#ifndef MADLIB_MODULES_CONVEX_TYPE_MODEL_HPP_
#define MADLIB_MODULES_CONVEX_TYPE_MODEL_HPP_
#include <modules/shared/HandleTraits.hpp>
namespace madlib {
namespace modules {
namespace convex {
template <class Handle>
struct LMFModel {
typename HandleTraits<Handle>::MatrixTransparentHandleMap matrixU;
typename HandleTraits<Handle>::MatrixTransparentHandleMap matrixV;
/**
* @brief Space needed.
*
* Extra information besides the values in the matrix, like dimension is
* necessary for a matrix, so that it can perform operations. These are
* stored in the HandleMap.
*/
static inline uint32_t arraySize(const int32_t inRowDim,
const int32_t inColDim, const int32_t inMaxRank) {
return (inRowDim + inColDim) * inMaxRank;
}
/**
* @brief Initialize the model randomly with a user-provided scale factor
*/
void initialize(const double &inScaleFactor) {
// using madlib::dbconnector::$database::NativeRandomNumberGenerator
NativeRandomNumberGenerator rng;
int i, j, rr;
double base = rng.min();
double span = rng.max() - base;
for (rr = 0; rr < matrixU.cols(); rr ++) {
for (i = 0; i < matrixU.rows(); i ++) {
matrixU(i, rr) = inScaleFactor * (rng() - base) / span;
}
}
for (rr = 0; rr < matrixV.cols(); rr ++) {
for (j = 0; j < matrixV.rows(); j ++) {
matrixV(j, rr) = inScaleFactor * (rng() - base) / span;
}
}
}
/*
* Some operator wrappers for two matrices.
*/
LMFModel &operator*=(const double &c) {
matrixU *= c;
matrixV *= c;
return *this;
}
template<class OtherHandle>
LMFModel &operator-=(const LMFModel<OtherHandle> &inOtherModel) {
matrixU -= inOtherModel.matrixU;
matrixV -= inOtherModel.matrixV;
return *this;
}
template<class OtherHandle>
LMFModel &operator+=(const LMFModel<OtherHandle> &inOtherModel) {
matrixU += inOtherModel.matrixU;
matrixV += inOtherModel.matrixV;
return *this;
}
template<class OtherHandle>
LMFModel &operator=(const LMFModel<OtherHandle> &inOtherModel) {
matrixU = inOtherModel.matrixU;
matrixV = inOtherModel.matrixV;
return *this;
}
};
typedef HandleTraits<MutableArrayHandle<double> >::ColumnVectorTransparentHandleMap
GLMModel;
typedef HandleTraits<MutableArrayHandle<double> >::ColumnVectorTransparentHandleMap
SVMModel;
// The necessity of this wrapper is to allow classes in algo/ and task/ to
// have a type that they can template over
template <class Handle>
struct MLPModel {
typename HandleTraits<Handle>::ReferenceToDouble is_classification;
typename HandleTraits<Handle>::ReferenceToDouble activation;
typename HandleTraits<Handle>::ReferenceToDouble momentum;
typename HandleTraits<Handle>::ReferenceToDouble is_nesterov;
uint16_t num_layers;
// std::vector<Eigen::Map<Matrix > > u;
std::vector<MutableMappedMatrix> u;
std::vector<MutableMappedMatrix> velocity;
/**
* @brief Space needed for the whole model
*
*/
static inline uint32_t arraySize(const uint16_t &inNumberOfStages,
const double *inNumbersOfUnits) {
// inNumberOfStages == 0 is not an expected value, but
// it won't cause exception -- returning 0
uint32_t size = 0;
size_t N = inNumberOfStages;
const double *n = inNumbersOfUnits;
size_t k;
for (k = 0; k < N; k ++) {
size += static_cast<uint32_t>((n[k] + 1) * (n[k+1]));
}
//TODO conditionally assign size based on momentum
return size * 2; // position (u) + velocity
}
/**
* @brief Space needed for the coefficients
*
*/
static inline uint32_t coeffArraySize(const uint16_t &inNumberOfStages,
const double *inNumbersOfUnits) {
// inNumberOfStages == 0 is not an expected value, but
// it won't cause exception -- returning 0
uint32_t size = 0;
size_t N = inNumberOfStages;
const double *n = inNumbersOfUnits;
size_t k;
for (k = 0; k < N; k ++) {
size += (n[k] + 1) * (n[k+1]);
}
return size; // weights (u)
}
size_t rebind(const double *is_classification_in,
const double *activation_in,
const double *momentum_in,
const double *is_nesterov_in,
const double *data,
const uint16_t &inNumberOfStages,
const double *inNumbersOfUnits) {
const double *n = inNumbersOfUnits;
size_t k;
is_classification.rebind(is_classification_in);
activation.rebind(activation_in);
momentum.rebind(momentum_in);
is_nesterov.rebind(is_nesterov_in);
num_layers = inNumberOfStages;
size_t sizeOfU = 0;
u.clear();
for (k = 0; k < num_layers; k ++) {
u.push_back(MutableMappedMatrix());
u[k].rebind(const_cast<double *>(data + sizeOfU),
static_cast<Index>(n[k] + 1),
static_cast<Index>(n[k+1]));
sizeOfU += static_cast<size_t>((n[k] + 1) * (n[k+1]));
}
for (k = 0; k < num_layers; k ++) {
velocity.push_back(MutableMappedMatrix());
velocity[k].rebind(const_cast<double *>(data + sizeOfU),
n[k] + 1, n[k+1]);
sizeOfU += (n[k] + 1) * (n[k+1]);
}
return sizeOfU;
}
void initialize(const uint16_t &inNumberOfStages,
const double *inNumbersOfUnits) {
num_layers = inNumberOfStages;
for (size_t k =0; k < num_layers; ++k){
// Initalize according to Glorot and Bengio (2010)
// See design doc for more info
double span = 0.5 * sqrt(6.0 / (inNumbersOfUnits[k] + inNumbersOfUnits[k+1]));
u[k] << span * Matrix::Random(u[k].rows(), u[k].cols());
velocity[k].setZero();
}
}
double norm() const {
double norm = 0.;
size_t k;
for (k = 0; k < u.size(); k ++) {
norm += u[k].bottomRows(u[k].rows()-1).squaredNorm();
}
return std::sqrt(norm);
}
void setZero(){
size_t k;
for (k = 0; k < u.size(); k ++) {
u[k].setZero();
velocity[k].setZero();
}
}
/*
* Some operator wrappers for u.
*/
MLPModel& operator*=(const double &c) {
// Note that when scaling the model, don't update the bias.
size_t k;
for (k = 0; k < u.size(); k ++) {
u[k] *= c;
}
return *this;
}
template<class OtherHandle>
MLPModel& operator-=(const MLPModel<OtherHandle> &inOtherModel) {
size_t k;
for (k = 0; k < u.size() && k < inOtherModel.u.size(); k ++) {
u[k] -= inOtherModel.u[k];
}
return *this;
}
template<class OtherHandle>
MLPModel& operator+=(const MLPModel<OtherHandle> &inOtherModel) {
size_t k;
for (k = 0; k < u.size() && k < inOtherModel.u.size(); k ++) {
u[k] += inOtherModel.u[k];
}
return *this;
}
template<class OtherHandle>
MLPModel& operator=(const MLPModel<OtherHandle> &inOtherModel) {
size_t k;
for (k = 0; k < u.size() && k < inOtherModel.u.size(); k ++) {
u[k] = inOtherModel.u[k];
velocity[k] = inOtherModel.velocity[k];
}
num_layers = inOtherModel.num_layers;
is_classification = inOtherModel.is_classification;
activation = inOtherModel.activation;
momentum = inOtherModel.momentum;
is_nesterov = inOtherModel.is_nesterov;
return *this;
}
};
} // namespace convex
} // namespace modules
} // namespace madlib
#endif