Giter VIP home page Giter VIP logo

minidnn's Introduction

MiniDNN

MiniDNN is a C++ library that implements a number of popular deep neural network (DNN) models. It has a mini codebase but is fully functional to construct different types of feed-forward neural networks. MiniDNN is built on top of Eigen.

MiniDNN is a header-only library implemented purely in C++98, whose only dependency, Eigen, is also header-only. These features make it easy to embed MiniDNN into larger projects with a broad range of compiler support.

This project was largely inspired by the tiny-dnn library, a header-only C++14 implementation of deep learning models. What makes MiniDNN different is that MiniDNN is based on the high-performance Eigen library for numerical computing, and it has better compiler support.

MiniDNN is still quite experimental for now. Originally I wrote it with the aim of studying deep learning and practicing model implementation, but I also find it useful in my own statistical and machine learning research projects.

Features

  • Able to build feed-forward neural networks with a few lines of code
  • Header-only, highly portable
  • Fast on CPU
  • Modularized and extensible
  • Provides detailed documentation that is a resource for learning
  • Helps understanding how DNN works
  • A wonderful opportunity to learn and practice both the nice and dirty parts of DNN

Quick Start

The self-explanatory code below is a minimal example to fit a DNN model:

#include <MiniDNN.h>

using namespace MiniDNN;

typedef Eigen::MatrixXd Matrix;
typedef Eigen::VectorXd Vector;

int main()
{
    // Set random seed and generate some data
    std::srand(123);
    // Predictors -- each column is an observation
    Matrix x = Matrix::Random(400, 100);
    // Response variables -- each column is an observation
    Matrix y = Matrix::Random(2, 100);

    // Construct a network object
    Network net;

    // Create three layers
    // Layer 1 -- convolutional, input size 20x20x1, 3 output channels, filter size 5x5
    Layer* layer1 = new Convolutional<ReLU>(20, 20, 1, 3, 5, 5);
    // Layer 2 -- max pooling, input size 16x16x3, pooling window size 3x3
    Layer* layer2 = new MaxPooling<ReLU>(16, 16, 3, 3, 3);
    // Layer 3 -- fully connected, input size 5x5x3, output size 2
    Layer* layer3 = new FullyConnected<Identity>(5 * 5 * 3, 2);

    // Add layers to the network object
    net.add_layer(layer1);
    net.add_layer(layer2);
    net.add_layer(layer3);

    // Set output layer
    net.set_output(new RegressionMSE());

    // Create optimizer object
    RMSProp opt;
    opt.m_lrate = 0.001;

    // (Optional) set callback function object
    VerboseCallback callback;
    net.set_callback(callback);

    // Initialize parameters with N(0, 0.01^2) using random seed 123
    net.init(0, 0.01, 123);

    // Fit the model with a batch size of 100, running 10 epochs with random seed 123
    net.fit(opt, x, y, 100, 10, 123);

    // Obtain prediction -- each column is an observation
    Matrix pred = net.predict(x);

    // Layer objects will be freed by the network object,
    // so do not manually delete them

    return 0;
}

To compile and run this example, simply download the source code of MiniDNN and Eigen, and let the compiler know about their paths. For example:

g++ -O2 -I/path/to/eigen -I/path/to/MiniDNN/include example.cpp

Documentation

The API reference page contains the documentation of MiniDNN generated by Doxygen, including all the class APIs.

License

MiniDNN is an open source project licensed under MPL2.

minidnn's People

Contributors

debruss avatar giovastabile avatar yixuan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

minidnn's Issues

padding constructor

Hi! I'm trying to use MiniDNN to build CNN under C++. It seems there's no padding constructor in the configuration of convolutional layer. I was wondering if I want to add that feature, what do you recommand to do?

Feature Request: Add Mish activation

Mish is a new novel activation function proposed in this paper.
It has shown promising results so far and has been adopted in several packages including:

All benchmarks, analysis and links to official package implementations can be found in this repository

It would be nice to have Mish as an option within the activation function group.

This is the comparison of Mish with other conventional activation functions in a SEResNet-50 for CIFAR-10: (Better accuracy and faster than GELU)
se50_1

The quick-start example doesn't compile on Debian10 64 bit (run is WLS Windows-10 from VisualStudioCode)

on any g++ v8.3 compiler (g++, c89-gcc, c99-gcc) choosen and any C++ standard (CMAKE_CXX_STANDARD 98 / 11 / 14).

Eigen3 v 3.3.7-1 is installed from within Debian :
apt install libeigen3-dev

The project is really needed for very old (Debian6 which can't be upgraded on the targets) LINUX (where builds well with gcc-4.4.5 but many "Parameter .. not used" warnings issued).
DEBIAN10 WLS in Windows10 is only tried for develepment convinience reasons as long as the Eigen vesion is 3.3.7-1 in both DEBIAN6 and DEBIAN10.

The build log :

[main] Building folder: uzsearch uzsearch
[build] Starting build
[proc] Executing command: /usr/bin/cmake --build /home/pochta/myprojects/uzsearch/build --config Debug --target uzsearch -- -j 6
[build] [ 50%] Building CXX object CMakeFiles/uzsearch.dir/main.cpp.o
[build] In file included from /home/pochta/myprojects/GITROOT/MiniDNN/include/Callback/VerboseCallback.h:8,
[build] from /home/pochta/myprojects/GITROOT/MiniDNN/include/MiniDNN.h:34,
[build] from /home/pochta/myprojects/uzsearch/main.cpp:1:
[build] /home/pochta/myprojects/GITROOT/MiniDNN/include/Callback/../Network.h: In instantiation of ‘bool MiniDNN::Network::fit(MiniDNN::Optimizer&, const Eigen::MatrixBase&, const Eigen::MatrixBase&, int, int, int) [with DerivedX = Eigen::Matrix<double, -1, 2>; DerivedY = Eigen::Matrix<double, -1, 2>]’:
[build] /home/pochta/myprojects/uzsearch/main.cpp:48:36: required from here
[build] /home/pochta/myprojects/GITROOT/MiniDNN/include/Callback/../Network.h:477:21: error: call of overloaded ‘pre_training_batch(MiniDNN::Network*, Eigen::Matrix<double, -1, 2>&, Eigen::Matrix<double, -1, 2>&)’ is ambiguous
[build] m_callback->pre_training_batch(this, x_batches[i], y_batches[i]);
[build] ^~~~~~~~~~
[build] In file included from /home/pochta/myprojects/GITROOT/MiniDNN/include/MiniDNN.h:33,
[build] from /home/pochta/myprojects/uzsearch/main.cpp:1:
[build] /home/pochta/myprojects/GITROOT/MiniDNN/include/Callback.h:49:22: note: candidate: ‘virtual void MiniDNN::Callback::pre_training_batch(const MiniDNN::Network*, const Matrix&, const Matrix&)’
[build] virtual void pre_training_batch(const Network* net, const Matrix& x,
[build] ^~~~~~~~~~~~~~~~~~
[build] /home/pochta/myprojects/GITROOT/MiniDNN/include/Callback.h:51:22: note: candidate: ‘virtual void MiniDNN::Callback::pre_training_batch(const MiniDNN::Network*, const Matrix&, const IntegerVector&)’
[build] virtual void pre_training_batch(const Network* net, const Matrix& x,
[build] ^~~~~~~~~~~~~~~~~~
[build] In file included from /home/pochta/myprojects/GITROOT/MiniDNN/include/Callback/VerboseCallback.h:8,
[build] from /home/pochta/myprojects/GITROOT/MiniDNN/include/MiniDNN.h:34,
[build] from /home/pochta/myprojects/uzsearch/main.cpp:1:
[build] /home/pochta/myprojects/GITROOT/MiniDNN/include/Callback/../Network.h:481:21: error: call of overloaded ‘post_training_batch(MiniDNN::Network*, Eigen::Matrix<double, -1, 2>&, Eigen::Matrix<double, -1, 2>&)’ is ambiguous
[build] m_callback->post_training_batch(this, x_batches[i], y_batches[i]);
[build] ^~~~~~~~~~
[build] In file included from /home/pochta/myprojects/GITROOT/MiniDNN/include/MiniDNN.h:33,
[build] from /home/pochta/myprojects/uzsearch/main.cpp:1:
[build] /home/pochta/myprojects/GITROOT/MiniDNN/include/Callback.h:55:22: note: candidate: ‘virtual void MiniDNN::Callback::post_training_batch(const MiniDNN::Network*, const Matrix&, const Matrix&)’
[build] virtual void post_training_batch(const Network* net, const Matrix& x,
[build] ^~~~~~~~~~~~~~~~~~~
[build] /home/pochta/myprojects/GITROOT/MiniDNN/include/Callback.h:57:22: note: candidate: ‘virtual void MiniDNN::Callback::post_training_batch(const MiniDNN::Network*, const Matrix&, const IntegerVector&)’
[build] virtual void post_training_batch(const Network* net, const Matrix& x,
[build] ^~~~~~~~~~~~~~~~~~~
[build] make[3]: *** [CMakeFiles/uzsearch.dir/build.make:63: CMakeFiles/uzsearch.dir/main.cpp.o] Error 1
[build] make[2]: *** [CMakeFiles/Makefile2:585: CMakeFiles/uzsearch.dir/all] Error 2
[build] make[1]: *** [CMakeFiles/Makefile2:597: CMakeFiles/uzsearch.dir/rule] Error 2
[build] make: *** [Makefile:359: uzsearch] Error 2
[build] Build finished with exit code 2

It also fails in runtime with the only instantiation (all the latter code is commented): Matrix x = Matrix::Random(400, 100);
with the run log :

pochta@Vano-Home:~/myprojects/uzsearch$ /home/pochta/myprojects/uzsearch/build/uzsearch
uzsearch: /usr/include/eigen3/Eigen/src/Core/util/XprHelper.h:110: Eigen::internal::variable_if_dynamic<T, Value>::variable_if_dynamic(T) [with T = long int; int Value = 2]: Assertion `v == T(Value)' failed.
Aborted (core dumped)

sparsepp isn't c++98, therefore MiniDNN is also not c++98 compliant

With -std=c++98 clang-8 complains:

MiniDNN/include/Optimizer/../external/sparsepp/spp_utils.h:147:9: error: no member named 'tr1' in namespace 'std'
        SPP_HASH_CLASS<T> hasher;
        ^~~~~~~~~~~~~~
MiniDNN/include/Optimizer/../external/sparsepp/spp_utils.h:88:36: note: expanded from macro 'SPP_HASH_CLASS'
       #define SPP_HASH_CLASS std::tr1::hash
                              ~~~~~^
MiniDNN/include/Optimizer/../external/sparsepp/spp_utils.h:147:24: error: 'T' does not refer to a value
        SPP_HASH_CLASS<T> hasher;
                       ^
MiniDNN/include/Optimizer/../external/sparsepp/spp_utils.h:142:17: note: declared here
template <class T>
                ^
MiniDNN/include/Optimizer/../external/sparsepp/spp_utils.h:147:27: error: use of undeclared identifier 'hasher'
        SPP_HASH_CLASS<T> hasher;
                          ^

So you might want to update the README with a correct level of C++ standard for MiniDNN.

How to add PReLU activation?

I need to add PReLU activation which has a learn-able parameter? What would be the best way to extend this library in this respect?
thanks.

export_net , read_net ?

Hello and thank you for this gem. I would like to know more about those 2 functions - export_net and read_net. There is no explanation in the doc. I see that export_net creates 2 files: one is net info and the second I assume is weights? How to use read_net? Do i put it after or instead of init? Any info highly appreciated. Thanks!

Classification of the Spiral dataset

Hi there, and thank you very much for this brilliant work with MiniDNN.
I am slowly understanding more and more of the code.

Right now I am testing MiniDNN used to classify the the Spiral dataset:
https://cs231n.github.io/neural-networks-case-study/

It doesnt seem to find the optimum.

Any tips on my code, or what optimizer to use?
Have anyone of you tried a testdata for classification?

I would be happy to put together some testdata and make a another tutorial example..... with some help. :)

Sincerely,
Bernt

// Code to read in data and put it into Matrix is scipped.

Network net;
Layer* layer1 = new FullyConnected<Sigmoid>(2, 20);
Layer* layer2 = new FullyConnected<ReLU>(20, 20);
Layer* layer3 = new FullyConnected<Softmax>(20, 3);
net.add_layer(layer1);
net.add_layer(layer2);
net.add_layer(layer3);

net.set_output(new MultiClassEntropy() );

//Adam opt;
//opt.m_lrate = 0.01;
SGD opt;
    
VerboseCallback callback;
net.set_callback(callback);
net.init(0, 0.01, 000);

int nr_epochs = 3000;
net.fit(opt, Xdata.transpose(), Ydata.transpose(), 60, nr_epochs , 000);

Matrix pred = net.predict(Xtest.transpose() );
Matrix P = pred.transpose();

std::cout << P.rows()  << "  " << P.cols() << std::endl;
for(int r = 0; r < P.rows() ; r++){
    std::cout << P(r,0) << " " << P(r,1) << " " << P(r,2) << "\n";
}

How to copy a network to another?

Hi, i'm trying to copy a network to another
this code gives me error :
cannot be assigned because its copy assignment is implicitly deleted

this->net = this->targetnet;

if its not possible at least i need to copy weights

Compile error with GCC 8.3

With recent GCC I get a compiler warning (which is interpreted as an error in my project due to -Werror):
sparsepp.h:3881:27: error: ‘void* memcpy(void*, const void*, size_t)’ writing to an object of type ‘spp::sparsetable<std::pair<const double* const, Eigen::Array<double, -1, 1> >, spp::libc_allocator_with_realloc<std::pair<const double* const, Eigen::Array<double, -1, 1> > > >::group_type’ {aka ‘class spp::sparsegroup<std::pair<const double* const, Eigen::Array<double, -1, 1> >, spp::libc_allocator_with_realloc<std::pair<const double* const, Eigen::Array<double, -1, 1> > > >’} with no trivial copy-assignment; use copy-initialization instead [-Werror=class-memaccess] memcpy(first, _first_group, sizeof(*first) * (std::min)(sz, old_sz));

Do you have any idea to fix this ? I can compile it by deactivating the specific warning, but there is definitely an issue in the code...

Saving and loading models

Hi @yixuan,
Thank you for sharing such a wonderful project with us.

I wish to contribute to the project by providing model save and load functionalities in MiniDNN. So here is the plan:

  1. Use a standard JSON file format to describe the layers in the model.
  2. Weights of the layers can be saved as a binary file. I found this awesome project which basically facilitates saving Eigen matrices in hdf5.
    https://github.com/garrison/eigen3-hdf5

Unfortunately, I am not familiar with the template and header-only programming. What approach would you use?

Asheesh

Doing inference/prediction only, with weights loaded from a Tensorflow NN

Nice project!
Is it possible to do the following:

  1. Train a CNN with, for example, Tensorflow + Python
  2. Save the model weights into a file
  3. Load this weights file from MiniDNN / C++ code, and do prediction/inference only with MiniDNN (no training done with MiniDNN)

How would it be possible to load weights/coefficients of a model pre-trained with Tensorflow, into MiniDNN?

simple XOR

Hey, I was trying out your library and I was having issues. I was just starting out with XOR. main c++ code is below. Hopefully you can tell me what I'm doing wrong. I noticed that the m_Weight is a 2x2 for the first layer which is correct, but the "prev_layer_data" in the feedforward function is a 2x4 because my input matrix is 2x4. Shouldn't it be splitting the inputs into each "vector" of inputs. it looks like its trying to do all the inputs at the same time.

#include <Eigen/Dense>
#include
#include
#include "MiniDNN.h"

using namespace MiniDNN;

typedef Eigen::MatrixXd Matrix;
typedef Eigen::VectorXd Vector;

int main()
{
std::srand(123);

Matrix inputs(2, 4);
inputs(0, 0) = 0; inputs(1, 0) = 0;
inputs(0, 1) = 0; inputs(1, 1) = 1;
inputs(0, 2) = 1; inputs(1, 2) = 0;
inputs(0, 3) = 1; inputs(1, 3) = 1;
Matrix outputs(1, 4);
outputs(0, 0) = 0;
outputs(0, 1) = 1;
outputs(0, 2) = 1;
outputs(0, 3) = 0;

//std::cout << inputs << std::endl;
//std::cout << outputs << std::endl;

// Construct a network object
Network net;

// Create layers
Layer* layer1 = new FullyConnected<Sigmoid>(2, 2);//2 input, 2 hidden
Layer* layer2 = new FullyConnected<Sigmoid>(2, 1);//1 output

// Add layers to the network object
net.add_layer(layer1);
net.add_layer(layer2);

// Set output layer
net.set_output(new RegressionMSE());

//stocastic gradient descent
//SGD opt;
RMSProp opt;
opt.m_lrate = 0.01;

// Initialize parameters with N(0, 0.01^2) using random seed 123
net.init(0, 0.01, 123);

// Fit the model with a batch size of 4, running 10 epochs with random seed 123
net.fit(opt, inputs, outputs, 4, 10, 123);

Matrix pred = net.predict(inputs);
std::cout << pred << std::endl;


 
std::cin.get();  

}

c++11 instead

Hello yixuan,

I just download your work and compile.
I was able to compile and execute the code successfully.

The only issue is that I have to use the compiling flag "--std=c++11"
g++ -O2 --std=c++11 -I eigen -I MiniDNN/include example.cpp
My system pops up syntax error without the flag (or with "--std=c++98")

Nevertheless, great work!

With regards,
YenHao

Support for Image Input?

I'm trying to adapt the example in the readme markdown to accept a grayscale input image with a resolution of 512x448 in the range 0-1 and an output of 8 values between 0-1. My dimensions seem to be incompatible somewhere along the line, but I can't figure out exactly where.

const int WIDTH = 512;
const int HEIGHT = 448;
const int DEPTH = 100;
const int KEYPAD = 8;

Eigen::MatrixXd screen(WIDTH*HEIGHT,DEPTH);
Eigen::MatrixXd keypad(KEYPAD,DEPTH);
Eigen::MatrixXd pred;

// Construct a network object
MiniDNN::Network net;

// Create three layers
// Layer 1 -- convolutional, input size 512x448x1, 1 output channels, filter size 5x5
MiniDNN::Layer* layer1 = new MiniDNN::Convolutional<MiniDNN::ReLU>(WIDTH, HEIGHT, 1, 1, 5, 5);
// Layer 2 -- max pooling, input size 16x16x1, pooling window size 3x3
MiniDNN::Layer* layer2 = new MiniDNN::MaxPooling<MiniDNN::ReLU>(16, 16, 1, 3, 3);
// Layer 3 -- fully connected, input size 5x5x1, output size 8
MiniDNN::Layer* layer3 = new MiniDNN::FullyConnected<MiniDNN::Identity>(5 * 5 * 1, KEYPAD);

// Add layers to the network object
net.add_layer(layer1);
net.add_layer(layer2);
net.add_layer(layer3);

// Set output layer
net.set_output(new MiniDNN::RegressionMSE());

// Create optimizer object
MiniDNN::RMSProp opt;
opt.m_lrate = 0.001;

// (Optional) set callback function object
MiniDNN::VerboseCallback callback;
net.set_callback(callback);

net.init(0, 0.01, 123);

// Populate observations and responses here...
...
...

net.fit(opt, screen, keypad, 100, 10, 123);

The above code when executed yields to the following error:

terminate called after throwing an instance of 'std::invalid_argument'
what(): Unit sizes do not match
Aborted (core dumped)

Any insight on what I am doing incorrectly @giovastabile or @yixuan?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.