Skip to content

Commit

Permalink
Computational graph uses two contiguous arrays of flyweight objects 1…
Browse files Browse the repository at this point in the history
…2 bytes in total (FunctionObject), which serve as state machines and contain edges to previous operands.
  • Loading branch information
alejandroarmas committed May 15, 2022
1 parent 153059d commit 6d7ed4a
Show file tree
Hide file tree
Showing 13 changed files with 1,476 additions and 138 deletions.
85 changes: 85 additions & 0 deletions computational_graph_map.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#include "tensor.h"
#include "computational_graph_map.h"
#include "m_algorithms_register.h"

#include <assert.h>

namespace NeuralNetwork {

namespace Computation {


namespace Graph {


FunctionObject ComputationalGraphMap::_get_operation(TensorID my_tensor_id) noexcept {
// u_int16_t my_tensor_id = _t->get_tensor_id();

assert(my_tensor_id > TensorID(0) && "Must be an op_id greater than 0.");
assert(my_tensor_id <= tensor_id && "OP registry not this large");
// if (my_tensor_id >= tensor_id) throw std::invalid_argument("OP registry not this large.");
return op_registry.at(my_tensor_id.get());
}

std::shared_ptr<Tensor> ComputationalGraphMap::_get_tensor(TensorID my_tensor_id) noexcept {

std::cout << "Get Tensor ID: " << my_tensor_id.get() << std::endl;

assert(my_tensor_id > TensorID(0) && "Must be an op_id greater than 0.");
assert(my_tensor_id <= tensor_id && "OP registry not this large");

return tensor_registry.at(my_tensor_id.get());
}





void ComputationalGraphMap::_recover_tensor_id(TensorID my_tensor_id) noexcept {

recovered_tensor_id.push(my_tensor_id);
tensor_registry.at(my_tensor_id.get()) = nullptr;
}



TensorID ComputationalGraphMap::_obtain_tensor_id() noexcept {
// Matrix::Operations::Utility::Stringify stringify;

TensorID next_tensor_id = TensorID(0);

if (!recovered_tensor_id.empty()){
next_tensor_id = recovered_tensor_id.top();
recovered_tensor_id.pop();
// auto fn = Matrix::Operations::Utility::Function::from(_get_operation(next_tensor_id).get_code());
// std::cout << "Recovered Registry: O[" << next_tensor_id << "]" << std::visit(stringify, fn) << std::endl;
std::cout << "Recovered Registry: OP[" << next_tensor_id.get() << "]" << std::endl;
} else {
next_tensor_id = ++tensor_id;
}
return next_tensor_id;
}


TensorID ComputationalGraphMap::_register_operation(std::shared_ptr<Tensor> _t, FunctionObject& _node) noexcept {

TensorID my_tensor_id = _t->get_tensor_id();

assert(my_tensor_id <= tensor_id && "OP registry not this large");

op_registry.at(my_tensor_id.get()) = _node;
tensor_registry.at(my_tensor_id.get()) = _t;


std::cout << "Updated Operation: OP[" << my_tensor_id.get() << "]" << std::endl;
return my_tensor_id;
}




}

}

}
190 changes: 190 additions & 0 deletions function_object_factory.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
#include "function_object_factory.h"
#include "function_object.h"
#include "computational_graph_map.h"
#include "tensor.h"

#include <optional>



namespace NeuralNetwork {

namespace Computation {

namespace Graph {


// std::optional<FunctionObject> DereferenceRegistry::from(RegisteredOperation _op) {
// if (_op.get_tensor_id() == TensorID(0)) return {};

// ComputationalGraphMap& map = ComputationalGraphMap::get();
// return map._get_tensor(_op.get_tensor_id());

// }


// void OperationFactory::create(
// const Matrix::Operations::Code _typ, T _res,
// TensorID _op, TensorID _op2) {



// ComputationalGraphMap& map = ComputationalGraphMap::get();

// auto op = RegisteredOperation(
// _typ,
// _res->get_tensor_id(),
// _op,
// _op2
// );

// TensorID tensor_id = map._register_operation(_res, op);
// op.result = tensor_id;
// }


/*
Creates a Function Object signifying NOP expression.
*/
FunctionObject FunctionObjectFactory::create(T _res) {

ComputationalGraphMap& map = ComputationalGraphMap::get();

auto tensor_identification = _res->get_tensor_id();

auto fn_object = FunctionObject(
RegisteredTensor(tensor_identification)
);

map._register_operation(_res, fn_object);

return fn_object;
}



/*
1) access _res NOP
2) create Instantiate based on operation
3) fill step 2 with TensorID of operands
4)
*/

template <Matrix::Operations::BinaryMatrixOperatable RegisteryType>
FunctionObject FunctionObjectFactory::create(
RegisteryType operation, T _res,
TensorID _operand_id, TensorID _operand_id_two) {

ComputationalGraphMap& map = ComputationalGraphMap::get();

auto res_tensor_id = _res->get_tensor_id();

auto fn_object = FunctionObject();

auto binaryRegistry = States::BinaryRegistered(
RegisteredBinaryOperation(res_tensor_id,
_operand_id, _operand_id_two)
);

auto instantiate_event = Events::Instantiate(operation, binaryRegistry);


fn_object.process_event(instantiate_event);
fn_object.stringify_type();

// transition _res default NOP state to unary-state
// update computational graph OP state


map._register_operation(_res, fn_object);

return fn_object;
}


template <Matrix::Operations::UnaryMatrixOperatable RegisteryType>
FunctionObject FunctionObjectFactory::create(
RegisteryType operation, T _res, TensorID _operand_id) {

ComputationalGraphMap& map = ComputationalGraphMap::get();

auto res_tensor_id = _res->get_tensor_id();

auto fn_object = FunctionObject();

auto unaryRegistry = States::UnaryRegistered(
RegisteredUnaryOperation(res_tensor_id, _operand_id)
);

auto instantiate_event = Events::Instantiate(operation, unaryRegistry);

fn_object.process_event(instantiate_event);
fn_object.stringify_type();

// transition _res default NOP state to unary-state
// update computational ~graph OP state

map._register_operation(_res, fn_object);


return fn_object;
}


template FunctionObject FunctionObjectFactory::create<Matrix::Operations::Unary::ReLU>(
Matrix::Operations::Unary::ReLU operation,
T _res,
TensorID _operand_id);

template FunctionObject FunctionObjectFactory::create<Matrix::Operations::Unary::SoftMax>(
Matrix::Operations::Unary::SoftMax operation,
T _res,
TensorID _operand_id);

template FunctionObject FunctionObjectFactory::create<Matrix::Operations::Binary::HadamardProduct::Std>(
Matrix::Operations::Binary::HadamardProduct::Std operation,
T _res,
TensorID _operand_id,
TensorID _operand_id_two);

template FunctionObject FunctionObjectFactory::create<Matrix::Operations::Binary::Multiplication::ParallelDNC>(
Matrix::Operations::Binary::Multiplication::ParallelDNC operation,
T _res,
TensorID _operand_id,
TensorID _operand_id_two);

template FunctionObject FunctionObjectFactory::create<Matrix::Operations::Binary::Multiplication::Naive>(
Matrix::Operations::Binary::Multiplication::Naive operation,
T _res,
TensorID _operand_id,
TensorID _operand_id_two);

template FunctionObject FunctionObjectFactory::create<Matrix::Operations::Binary::Multiplication::Square>(
Matrix::Operations::Binary::Multiplication::Square operation,
T _res,
TensorID _operand_id,
TensorID _operand_id_two);

template FunctionObject FunctionObjectFactory::create<Matrix::Operations::Binary::Addition::Std>(
Matrix::Operations::Binary::Addition::Std operation,
T _res,
TensorID _operand_id,
TensorID _operand_id_two);

template FunctionObject FunctionObjectFactory::create<Matrix::Operations::Binary::OuterProduct::Naive>(
Matrix::Operations::Binary::OuterProduct::Naive operation,
T _res,
TensorID _operand_id,
TensorID _operand_id_two);

template FunctionObject FunctionObjectFactory::create<Matrix::Operations::Metric::CrossEntropy>(
Matrix::Operations::Metric::CrossEntropy operation,
T _res,
TensorID _operand_id,
TensorID _operand_id_two);


}
}
}
76 changes: 76 additions & 0 deletions include/computational_graph_map.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#ifndef COMPUTATIONAL_GRAPH_MAP_H
#define COMPUTATIONAL_GRAPH_MAP_H

#include <memory>
#include <stack>

#include "strong_types.h"
#include "m_algorithms_register.h"
#include "function_object.h"


namespace NeuralNetwork {

namespace Computation {


namespace Graph {

class Tensor;

/*
DESCRIPTION:
Singleton Mediator that holds the edges between Tensors
and their registered operations.
Organised as contiguous data structure, to avoid pointer
chasing during runtime and help CPU's memory prefetcher
load data before it's used.
*/
class ComputationalGraphMap {

public:
static ComputationalGraphMap& get(){
static ComputationalGraphMap map;
return map;
}
ComputationalGraphMap(ComputationalGraphMap const&) = delete;
ComputationalGraphMap(ComputationalGraphMap&&) = delete;
ComputationalGraphMap& operator=(ComputationalGraphMap const&) = delete;
ComputationalGraphMap& operator=(ComputationalGraphMap &&) = delete;

void _recover_tensor_id(TensorID my_tensor_id) noexcept;
std::shared_ptr<Tensor> _get_tensor(TensorID my_tensor_id) noexcept;
FunctionObject _get_operation(TensorID my_tensor_id) noexcept;
TensorID _obtain_tensor_id() noexcept;
TensorID _register_operation(std::shared_ptr<Tensor> _t, FunctionObject& _node) noexcept;


protected:
ComputationalGraphMap() :
op_registry(2000),
tensor_registry(2000),
recovered_tensor_id(),
tensor_id(0) {}


private:
std::vector<FunctionObject> op_registry;
std::vector<std::shared_ptr<Tensor>> tensor_registry;
std::stack<TensorID> recovered_tensor_id;
TensorID tensor_id;


};



}

}

}


#endif // COMPUTATIONAL_GRAPH_MAP_H
Loading

0 comments on commit 6d7ed4a

Please sign in to comment.