Xshinnosuke_cpp is the cpp version of xshinnosuke.
As xshinnosuke_cpp choose Eigen as matrix backend and Eigen only supports for Array and Matrix, in other words, the data in Eigen is less than 3 dimensions, so xshinnosuke_cpp just supports operations for 2-dimension datas, such as Linear(Linear in Pytorch or Dense in Keras), relu, sigmoid, batch normalization, etc.
For more functional or Layers details, such as Conv2D, max_pool2d, embedding, lstm, etc. Please refer to xshinnosuke.
Here are some features of XShinnosuke:
-
Based on Eigen and native to C++.
-
Without any other 3rd-party deep learning library.
-
Keras and Pytorch style API, easy to start.
-
Sequential in Keras and Pytorch, Model in Keras and Module in Pytorch, all of them are supported in xshinnosuke_cpp.
-
Training and inference supports for both dynamic graph and static graph.
-
Autograd is supported .
#pragma once
#include<iostream>
#include "../layers/linear.h"
#include "../models.h"
#include "../nn/functional.h"
#include "../utils/data.h"
#include<ctime>
#include<vector>
using namespace std;
// define the network
class myNet : public Module {
// your diy network must be inherited from Module
public:
// declare layers
myNet(int n_classes) {
this->fc1 = new Linear(10);
this->relu1 = new ReLU();
this->fc2 = new Linear(5);
this->relu2 = new ReLU();
this->fc3 = new Linear(n_classes);
};
// free the pointers
~myNet() {
delete this->fc1;
delete this->relu1;
delete this->fc2;
delete this->relu2;
delete this->fc3;
this->fc1 = NULL;
this->relu1 = NULL;
this->fc2 = NULL;
this->relu2 = NULL;
this->fc3 = NULL;
}
// design forward flow
Variable* forward(Variable* x) {
Variable* out;
out = (*(this->fc1))(x);
out = (*(this->relu1))(out);
out = (*(this->fc2))(out);
out = (*(this->relu2))(out);
out = (*(this->fc3))(out);
// use funcational -> sigmoid
out = sigmoid(out);
return out;
}
Layer* fc1;
Layer* relu1;
Layer* fc2;
Layer* relu2;
Layer* fc3;
};
void run_dynamic() {
// random generate training datas
// generate training input datas
Eigen::MatrixXf x = Eigen::MatrixXf::Random(100, 10);
Eigen::MatrixXf y = Eigen::MatrixXf::Zero(100, 1);
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 1; ++j) {
float n = (rand() % 10) / 10;
if (n >= 0.5) {
y(i, j) = 1;
}
}
}
// batch_size
int BATCH_SIZE = 20;
// xshinnosuke_cpp provides DataLoader for batch training/inference
Dataset train_set = Dataset(x, y);
DataLoader train_loader = DataLoader(train_set, BATCH_SIZE);
// instantiate your diy network
myNet net = myNet(1);
// declare criterion
Objective* criterion = new BinaryCrossEntropy();
// declare optimizer, notice pass network's parameters to optimizer
Optimizer* optimizer = new SGD(net.parameters());
clock_t startTime, endTime;
startTime = clock();
int EPOCH = 10;
// define training flow
for (int epoch = 0; epoch < EPOCH; ++epoch) {
for (auto it = train_loader.begin(); it != train_loader.end(); ++it) {
Variable *inputs = (*it).first, *target = (*it).second;
// at every epoch zero_grad's optimizer's trainable_variables' grad.
optimizer->zero_grad();
// forward
Variable* out = net(inputs);
// calculate loss
Variable* loss = (*criterion)(out, target);
float acc = criterion->calc_acc(out, target);
cout << "iter: " << epoch << " loss: " << loss->item() << " acc: " <<
acc << endl;
// backward
loss->backward();
// update parameters
optimizer->step();
}
}
endTime = clock();
cout << "The run time is: " <<
(double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
#pragma once
#include "../layers/base.h"
#include "../layers/linear.h"
#include "../layers/activators.h"
#include "../models.h"
#include "../utils/shape.h"
#include<ctime>
void run_static() {
int n_classes = 1;
Eigen::MatrixXf x = Eigen::MatrixXf::Random(100, 10);
Eigen::MatrixXf y = Eigen::MatrixXf::Zero(100, 1);
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 1; ++j) {
float n = (rand() % 10) / 10;
if (n >= 0.5) {
y(i, j) = 1;
}
}
}
Sequential model = Sequential();
// The first layer in Sequential must be specify input_shape(no need specify batch_size).
model.add(new Linear(10, "null", false, "random", "zeros", Shape({ 10 })));
model.add(new ReLU());
model.add(new Linear(5));
model.add(new ReLU());
model.add(new Linear(n_classes));
model.add(new Sigmoid());
model.compile("sgd", "bce");
clock_t startTime, endTime;
startTime = clock();
int BATCH_SIZE = 20;
int EPOCH = 10;
model.fit(&x, &y, BATCH_SIZE, EPOCH);
endTime = clock();
cout << "The run time is: " <<
(double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
}
-
First download Eigen.
-
git clone https://github.com/eLeVeNnN/xshinnosuke_cpp.git
-
Include
Eigen
to xshinnosuke_cpp projects
run demo.cpp