Skip to content
This repository has been archived by the owner on Jul 24, 2024. It is now read-only.

Commit

Permalink
Reactor replace internal optimizer with public shared optimizer (#45)
Browse files Browse the repository at this point in the history
* refactor out the internal class from public API

* remove todo -- it was incomplete type defintions

* refactored internal optimizers

 while encapulating eigen

* fix spelling

* switch optimizers to shared ptr

* missing CRTP

* fix copy PASTE MISTAKE
  • Loading branch information
prince-chrismc authored Oct 17, 2023
1 parent 3288265 commit 4376e0e
Show file tree
Hide file tree
Showing 11 changed files with 75 additions and 149 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ set(SOURCES
${SOURCE_DIR}/internals/functions/internal_function_logsoftmax.cpp
${SOURCE_DIR}/internals/functions/internal_function_relu.cpp
${SOURCE_DIR}/internals/criterions/internal_criterion_nllloss.cpp
${SOURCE_DIR}/internals/optimizers/internal_optimizer_sgd.cpp)
)

find_package(Eigen3 REQUIRED CONFIG)

Expand Down
14 changes: 7 additions & 7 deletions examples/layers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ cmake --build . --target cabernet-examples-layers
struct Autoencoder : public net::Model<Autoencoder> {

Autoencoder() {
encoder.configure_optimizer(encoder_optimizer);
decoder.configure_optimizer(decoder_optimizer);
encoder.configure_optimizer(std::dynamic_pointer_cast<net::base::Optimizer>(encoder_optimizer));
decoder.configure_optimizer(std::dynamic_pointer_cast<net::base::Optimizer>(decoder_optimizer));
}

net::layer::Sequence encoder {
Expand All @@ -38,16 +38,16 @@ struct Autoencoder : public net::Model<Autoencoder> {
}

void step() {
encoder_optimizer.step();
decoder_optimizer.step();
encoder_optimizer->step();
decoder_optimizer->step();
}
/* you can add diferent optimizers to different layers
/* you can add different optimizers to different layers
or the same, doesn't matter, the optimizer has a shared pointer
to it's implementation so you can pass instances of it with value
semantics without making deep copies */

net::optimizer::SGD encoder_optimizer {/*learning rate*/ 0.1};
net::optimizer::SGD decoder_optimizer {/*learning rate*/ 0.2};
std::shared_ptr<net::optimizer::SGD> encoder_optimizer = std::make_shared<net::optimizer::SGD>(/*learning rate*/ 0.1);
std::shared_ptr<net::optimizer::SGD> decoder_optimizer = std::make_shared<net::optimizer::SGD>(/*learning rate*/ 0.2);
};

int main() {
Expand Down
12 changes: 5 additions & 7 deletions examples/model.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#include <CaberNet.h>

struct Network : public net::Model<Network> {
Network() {
layers.configure_optimizer(optimizer);
}
Network() : net::Model<Network>(
std::make_shared<net::optimizer::SGD>(/*learning rate*/ 0.1)
) {}

net::layer::Sequence layers {
net::layer::Linear(784, 128),
Expand All @@ -15,8 +15,6 @@ struct Network : public net::Model<Network> {
net::Tensor<float> forward(net::Tensor<float> x) {
return layers(x);
}

net::optimizer::SGD optimizer {/*learning rate*/ 0.1};
};

int main() {
Expand All @@ -39,7 +37,7 @@ int main() {

std::cout << "Epoch: " << epoch + 1 << std::endl;

for(int batch = 0; batch < dataset.lenght(); ++batch) {
for(int batch = 0; batch < dataset.length(); ++batch) {
input.copy(dataset.features()[batch].internal()); // I will fix this in the future so it will be prettier and without copies.
targets.copy(dataset.targets()[batch].internal());

Expand All @@ -49,4 +47,4 @@ int main() {
}

}
}
}
2 changes: 1 addition & 1 deletion include/CaberNet/dataset.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class Dataset {
targets_.clear();
}

std::size_t lenght() {
std::size_t length() {
return features_.size();
}

Expand Down
12 changes: 5 additions & 7 deletions include/CaberNet/layers.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

namespace internal {
class Tensor;
class Optimizer;
};

namespace net::layer {
Expand All @@ -23,7 +22,7 @@ class Linear : public Model<Linear> {
initializer distribution = initializer::He );

Tensor<float> forward(Tensor<float> x);
void set_optimizer(internal::Optimizer* optimizer);
void set_optimizer(std::shared_ptr<net::base::Optimizer> optimizer);

private:
Tensor<float> weight_;
Expand All @@ -33,21 +32,21 @@ class Linear : public Model<Linear> {
struct ReLU : public Model<ReLU> {
ReLU() = default;
Tensor<float> forward(Tensor<float> input);
void set_optimizer(internal::Optimizer* optimizer) { return; }
void set_optimizer(std::shared_ptr<net::base::Optimizer> optimizer) { return; }
};

struct Softmax : public Model<Softmax> {
int axis;
Softmax(int axis);
Tensor<float> forward(Tensor<float> input);
void set_optimizer(internal::Optimizer* optimizer) { return; }
void set_optimizer(std::shared_ptr<net::base::Optimizer> optimizer) { return; }
};

struct LogSoftmax : public Model<LogSoftmax> {
int axis;
LogSoftmax(int axis);
Tensor<float> forward(Tensor<float> input);
void set_optimizer(internal::Optimizer* optimizer) { return; }
void set_optimizer(std::shared_ptr<net::base::Optimizer> optimizer) { return; }
};

class Sequence : public Model<Sequence> {
Expand All @@ -71,8 +70,7 @@ class Sequence : public Model<Sequence> {
}
return input;
}

void set_optimizer(internal::Optimizer* optimizer) {
void set_optimizer(std::shared_ptr<net::base::Optimizer> optimizer) {
for (auto& layer : layers_) {
std::cout << "visited" << std::endl;
std::visit([optimizer](auto&& argument) { argument.set_optimizer(optimizer); }, layer);
Expand Down
29 changes: 8 additions & 21 deletions include/CaberNet/model.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,10 @@
#include "tensor.h"
#include "optimizers.h"

namespace internal {
class Optimizer;
}

namespace net {

template<class Derived>
class Model {
using optimizer_variant = std::variant<
optimizer::SGD
>;

public:
using size_type = std::size_t;
using shape_type = std::vector<size_t>;
Expand All @@ -26,24 +18,19 @@ class Model {
return static_cast<Derived*>(this)->forward(input);
}

void configure_optimizer(optimizer_variant instance) {
optimizer_ = std::visit([](auto&& argument) { return argument.get(); }, instance);
static_cast<Derived*>(this)->set_optimizer(optimizer_);
}

void set_optimizer(internal::Optimizer* optimizer) {
void configure_optimizer(std::shared_ptr<net::base::Optimizer> optimizer) {
static_cast<Derived*>(this)->set_optimizer(optimizer);
optimizer_ = optimizer;
}

internal::Optimizer* optimizer() const {
return optimizer_;
}
private:
std::shared_ptr<net::base::Optimizer> optimizer_ = std::make_shared<net::optimizer::NoOptimization>();

protected:
Model() = default;

private:
internal::Optimizer* optimizer_;

Model(std::shared_ptr<net::base::Optimizer> optimizer) : optimizer_(optimizer) {
static_cast<Derived*>(this)->set_optimizer(optimizer);
}
};

} // namespace net
57 changes: 37 additions & 20 deletions include/CaberNet/optimizers.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,56 @@
#include <vector>
#include <memory>

#include "tensor.h"

namespace internal {

class Tensor;
class Optimizer;

} // namespace internal
namespace internal { class Tensor; }

namespace net::base {

class Optimizer {
struct Optimizer {
virtual ~Optimizer() = default;
virtual void add_parameter(internal::Tensor* parameter) = 0;
virtual void step() = 0;
};

template<class Derived>
class Optimize : public Optimizer {
public:
~Optimizer();
void add_parameter(internal::Tensor* parameter);
void step();
~Optimize() override = default;

internal::Optimizer* get() const;
void add_parameter(internal::Tensor* parameter) override final {
parameters_.push_back(parameter);
}

protected:
Optimizer() = default;
std::shared_ptr<internal::Optimizer> optimizer_ = nullptr;
void step() override final {
for(internal::Tensor* parameter : parameters_) {
static_cast<Derived*>(this)->update(parameter);
}
}

private:
std::vector<internal::Tensor*> parameters_;
};

}

namespace net::optimizer {

class SGD : public base::Optimizer {
public:
SGD() = default;
~SGD();
SGD(float learning_rate);
class NoOptimization : public base::Optimize<NoOptimization> {
public:
~NoOptimization() = default;
void update(internal::Tensor* parameter) {return;}
};


class SGD : public base::Optimize<SGD> {
public:
SGD(float learning_rate): learning_rate_{learning_rate} {}
~SGD() = default;

void update(internal::Tensor* parameter);

protected:
const float learning_rate_;
};

} // namespace net::optimizer
24 changes: 0 additions & 24 deletions src/internals/optimizers/internal_optimizer_sgd.cpp

This file was deleted.

38 changes: 0 additions & 38 deletions src/internals/optimizers/internal_optimizers.hpp

This file was deleted.

3 changes: 1 addition & 2 deletions src/layers.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#include "CaberNet/tensor.h"
#include "CaberNet/layers.h"

#include "internals/optimizers/internal_optimizers.hpp"
#include "internals/functions/internal_functions.hpp"


Expand All @@ -23,7 +22,7 @@ LogSoftmax::LogSoftmax(int axis) : axis(axis) {}

/// settings

void Linear::set_optimizer(internal::Optimizer* optimizer) {
void Linear::set_optimizer(std::shared_ptr<net::base::Optimizer> optimizer) {
optimizer->add_parameter(weight_.internal());
optimizer->add_parameter(bias_.internal());
}
Expand Down
31 changes: 10 additions & 21 deletions src/optimizers.cpp
Original file line number Diff line number Diff line change
@@ -1,31 +1,20 @@
#include "CaberNet/optimizers.h"
#include "internals/optimizers/internal_optimizers.hpp"

namespace net::base {
#include "internals/config.h"
#include "internals/internal_tensor.hpp"

Optimizer::~Optimizer() {}

internal::Optimizer* Optimizer::get() const {
return optimizer_.get();
}

void Optimizer::add_parameter(internal::Tensor* parameter) {
optimizer_->add_parameter(parameter);
std::cout << "Parameter added" << std::endl;
}

void Optimizer::step() {
if(optimizer_) optimizer_->step();
}

}
#if defined(USE_EIGEN_BACKEND)

namespace net::optimizer {

SGD::~SGD() {}

SGD::SGD(float learning_rate) {
optimizer_ = std::make_shared<internal::SGD>(learning_rate);
void SGD::update(internal::Tensor* parameter) {
Eigen::Map<Eigen::Array<internal::Tensor::scalar_type, 1, -1>> parameter_map(parameter->data(), parameter->size());
Eigen::Map<Eigen::Array<internal::Tensor::scalar_type, 1, -1>> parameter_gradient_map(parameter->gradient()->data(), parameter->size());
parameter_map -= learning_rate_ * parameter_gradient_map;
parameter_gradient_map = 0;
}

}

#endif

0 comments on commit 4376e0e

Please sign in to comment.