jacobian

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit bd4cc67f67316aeab18ab7770fbc6d3ad9e53f99
parent a933982a1e0c88e5adc55251552ec1ffeb012c7d
Author: David Freifeld <freifeld.david@gmail.com>
Date:   Thu, 25 Jun 2020 19:22:39 -0700

Nicely working python lib

Diffstat:
Mbpnn.cpp | 47++++++++++++++++++++++++-----------------------
Mbpnn.hpp | 2+-
Mexample.cpp | 7++-----
Aexample.py | 21+++++++++++++++++++++
Mkerasdemo.py | 11++++++++---
Mmr_bpnn_2.cpp | 210++++++++++++++++++++++++++++++++++++++-----------------------------------------
6 files changed, 158 insertions(+), 140 deletions(-)

diff --git a/bpnn.cpp b/bpnn.cpp @@ -45,45 +45,46 @@ Network::Network(char* path, int batch_sz, float learn_rate, float bias_rate) batches = 0; } -void Network::add_layer(int nodes, char* activation) +void Network::add_layer(int nodes, char* name) { length++; layers.emplace_back(batch_size, nodes); - set_activation(length-1, activation); -} - -void Network::initialize() -{ - labels = new Eigen::MatrixXd (batch_size,layers[length-1].contents->cols()); - for (int i = 0; i < length-1; i++) { - layers[i].init_weights(layers[i+1]); - } -} - -void Network::set_activation(int index, char* name) -{ if (strcmp(name, "sigmoid") == 0) { - layers[index].activation = sigmoid; - layers[index].activation_deriv = sigmoid_deriv; + layers[length-1].activation = sigmoid; + layers[length-1].activation_deriv = sigmoid_deriv; } else if (strcmp(name, "linear") == 0) { - layers[index].activation = linear; - layers[index].activation_deriv = linear_deriv; + layers[length-1].activation = linear; + layers[length-1].activation_deriv = linear_deriv; } else if (strcmp(name, "relu") == 0) { - layers[index].activation = rectifier(linear); - layers[index].activation_deriv = rectifier(linear_deriv); + layers[length-1].activation = rectifier(linear); + layers[length-1].activation_deriv = rectifier(linear_deriv); } else if (strcmp(name, "resig") == 0) { - layers[index].activation = rectifier(sigmoid); - layers[index].activation_deriv = rectifier(sigmoid_deriv); + layers[length-1].activation = rectifier(sigmoid); + layers[length-1].activation_deriv = rectifier(sigmoid_deriv); } else { - std::cout << "Warning! Incorrect activation specified. Exiting...\n"; + std::cout << "Warning! Incorrect activation specified. Exiting...\n\nIf this is coming up and you don't know why, try defining your own activation function.\n"; exit(1); } } +void Network::initialize() +{ + labels = new Eigen::MatrixXd (batch_size,layers[length-1].contents->cols()); + for (int i = 0; i < length-1; i++) { + layers[i].init_weights(layers[i+1]); + } +} + +void Network::set_activation(int index, std::function<double(double)> custom, std::function<double(double)> custom_deriv) +{ + layers[index].activation = custom; + layers[index].activation_deriv = custom_deriv; +} + void Network::feedforward() { for (int j = 0; j < layers[0].contents->rows(); j++) { diff --git a/bpnn.hpp b/bpnn.hpp @@ -48,7 +48,7 @@ public: void add_layer(int nodes, char* activation); void initialize(); void update_layer(float* vals, int datalen, int index); - void set_activation(int index, char* activation); + void set_activation(int index, std::function<double(double)> custom, std::function<double(double)> custom_deriv); Eigen::MatrixXd init_ones(Eigen::MatrixXd matrix); void feedforward(); diff --git a/example.cpp b/example.cpp @@ -8,21 +8,18 @@ double lecun_tanh(double x) double lecun_tanh_deriv(double x) { - return 1.14393 * pow(sech(2.0/3 * x),2); + return 1.14393 * pow(1.0/cosh(2.0/3 * x),2); } int main() { Network net ("./data_banknote_authentication.txt", 10, 0.01, 0.001); net.add_layer(4, "linear"); - //net.add_layer(3, "resig"); net.add_layer(5, "sigmoid"); + net.set_activation(1, lecun_tanh, lecun_tanh_deriv); net.add_layer(1, "resig"); net.initialize(); net.list_net(); net.train(50); // net.list_net(); - //char line[1024]; - //net.stream->getline(line, 1024); - //std::cout << line << "\n"; } diff --git a/example.py b/example.py @@ -0,0 +1,21 @@ +import mrbpnn +import numpy +import time + +def lecun_tanh(x): + return 1.7159 * numpy.tanh((2.0/3) * x) + +def lecun_tanh_deriv(x): + return 1.14393 * (1.0/numpy.cosh(2.0/3 * x))**2 + +init = time.time() +net = mrbpnn.Network("./data_banknote_authentication.txt", 10, 0.01, 0.001); +net.add_layer(4, "linear"); +net.add_layer(5, "sigmoid"); +net.set_activation(1, lecun_tanh, lecun_tanh_deriv); +net.add_layer(1, "sigmoid"); +net.initialize(); +net.train(50); +end = time.time() +print(end-init) + diff --git a/kerasdemo.py b/kerasdemo.py @@ -10,11 +10,17 @@ #+-----------------------------------------------------------------------------+ import time +import numpy # import tensorflow from numpy import loadtxt import keras +from keras import backend as K from keras.models import Sequential +from keras.layers import Activation from keras.layers import Dense +def lecun_tanh(x): + return 1.7159 * K.tanh((2.0/3) * x) + init = time.time() # load the dataset dataset = loadtxt('extra.txt', delimiter=',') @@ -24,11 +30,10 @@ y = dataset[:,4] # define the keras model model = Sequential() model.add(Dense(4, input_dim=4, activation='linear')) -model.add(Dense(5, activation='sigmoid')) -model.add(Dense(5, activation='sigmoid')) +model.add(Dense(5, activation=lecun_tanh)) model.add(Dense(1, activation='sigmoid')) # compile the keras model -opt = keras.optimizers.SGD(lr=1) +opt = keras.optimizers.SGD(lr=0.01) model.compile(loss='mse', optimizer=opt, metrics=['accuracy']) # fit the keras model on the dataset model.fit(X, y, epochs=50, batch_size=10) diff --git a/mr_bpnn_2.cpp b/mr_bpnn_2.cpp @@ -1,122 +1,116 @@ #include <pybind11/pybind11.h> +#include <pybind11/functional.h> #include "bpnn.hpp" namespace py = pybind11; -struct pair* map (struct pair input_pair) -{ - char* path = new char[100]; - strcpy(path, (char*)input_pair.key); - strcat(path, "_shuf"); - printf("%s and %s\n", path, (char*)input_pair.key); - int linecount = prep_file((char*)input_pair.key, path); - Network* net = new Network (path, 4, 2, 1, 5, 10, 2); - auto begin = std::chrono::high_resolution_clock::now(); - // std::cout << "\n\n\n"; - float epoch_cost = 1000; - float epoch_accuracy = -1; - int epochs = 0; - int total_epochs = 50; - net->batches= 0; - // net.feedforward(); - // net.backpropagate(); - // std::cout << net.cost() << "\n"; +// struct pair* map (struct pair input_pair) +// { +// char* path = new char[100]; +// strcpy(path, (char*)input_pair.key); +// strcat(path, "_shuf"); +// printf("%s and %s\n", path, (char*)input_pair.key); +// int linecount = prep_file((char*)input_pair.key, path); +// Network* net = new Network (path, 4, 2, 1, 5, 10, 2); +// auto begin = std::chrono::high_resolution_clock::now(); +// // std::cout << "\n\n\n"; +// float epoch_cost = 1000; +// float epoch_accuracy = -1; +// int epochs = 0; +// int total_epochs = 50; +// net->batches= 0; +// // net.feedforward(); +// // net.backpropagate(); +// // std::cout << net.cost() << "\n"; - printf("Beginning train on %i instances for %i epochs...\n", linecount, 50); - while (epochs < total_epochs) { - auto ep_begin = std::chrono::high_resolution_clock::now(); - // int linecount = prep_file("./data_banknote_authentication.txt"); - float cost_sum = 0; - float acc_sum = 0; - double times[5] = {0}; - for (int i = 0; i <= linecount-net->batch_size; i+=net->batch_size) { - // auto feed_begin = std::chrono::high_resolution_clock::now(); - net->feedforward(); - // auto back_begin = std::chrono::high_resolution_clock::now(); - net->backpropagate(); - // auto cost_begin = std::chrono::high_resolution_clock::now(); - cost_sum += net->cost(); - // std::cout << acc_sum << " "<< net.accuracy() << " " << net.batch_size << "\n"; - // auto acc_begin = std::chrono::high_resolution_clock::now(); - acc_sum += net->accuracy(); - // std::cout << net.cost() << " as it is " << net.labels[0] << " vs " << *net.layers[net.length-1].contents << "\n"; - // auto batch_begin = std::chrono::high_resolution_clock::now(); +// printf("Beginning train on %i instances for %i epochs...\n", linecount, 50); +// while (epochs < total_epochs) { +// auto ep_begin = std::chrono::high_resolution_clock::now(); +// // int linecount = prep_file("./data_banknote_authentication.txt"); +// float cost_sum = 0; +// float acc_sum = 0; +// double times[5] = {0}; +// for (int i = 0; i <= linecount-net->batch_size; i+=net->batch_size) { +// // auto feed_begin = std::chrono::high_resolution_clock::now(); +// net->feedforward(); +// // auto back_begin = std::chrono::high_resolution_clock::now(); +// net->backpropagate(); +// // auto cost_begin = std::chrono::high_resolution_clock::now(); +// cost_sum += net->cost(); +// // std::cout << acc_sum << " "<< net.accuracy() << " " << net.batch_size << "\n"; +// // auto acc_begin = std::chrono::high_resolution_clock::now(); +// acc_sum += net->accuracy(); +// // std::cout << net.cost() << " as it is " << net.labels[0] << " vs " << *net.layers[net.length-1].contents << "\n"; +// // auto batch_begin = std::chrono::high_resolution_clock::now(); - if (i != linecount-net->batch_size) { // Don't try to advance batch on final batch. - net->next_batch(); - } - net->batches++; - // auto loop_end = std::chrono::high_resolution_clock::now(); - // times[0] += std::chrono::duration_cast<std::chrono::nanoseconds>(back_begin -feed_begin).count() / pow(10,9); - // times[1] += std::chrono::duration_cast<std::chrono::nanoseconds>(cost_begin - back_begin).count() / pow(10,9); - // times[2] += std::chrono::duration_cast<std::chrono::nanoseconds>(acc_begin - cost_begin).count() / pow(10,9); - // times[3] += std::chrono::duration_cast<std::chrono::nanoseconds>(batch_begin - acc_begin).count() / pow(10,9); - // times[4] += std::chrono::duration_cast<std::chrono::nanoseconds>(loop_end - batch_begin).count() / pow(10,9); - } - epoch_accuracy = 1.0/((float) linecount/net->batch_size) * acc_sum; - epoch_cost = 1.0/((float) linecount/net->batch_size) * cost_sum; - auto ep_end = std::chrono::high_resolution_clock::now(); - double epochtime = (double) std::chrono::duration_cast<std::chrono::nanoseconds>(ep_end-ep_begin).count() / pow(10,9); - printf("Epoch %i/%i - time %f - cost %f - acc %f\n", epochs+1, total_epochs, epochtime, epoch_cost, epoch_accuracy); - // printf("Avg time spent across %i batches: %lf on feedforward, %lf on backprop, %lf on cost, %lf on acc, %lf on next batch.\n", net.batches, times[0]/net.batches, times[1]/net.batches, times[2]/net.batches, times[3]/net.batches, times[4]/net.batches); - // printf("Time spent across epoch: %lf on feedforward, %lf on backprop, %lf on cost, %lf on acc, %lf on next batch, %lf other.\n", times[0], times[1], times[2], times[3], times[4], epochtime-times[0]-times[1]-times[2]-times[3]-times[4]); - net->batches=1; - epochs++; - } - struct pair* output = new struct pair; - char* key = new char[100]; - strcpy(key, path); - output[0].key = key; - output[0].value = net; - return output; -} - -struct pair* reduce (struct pair* input_pairs) -{ - struct pair* output = new struct pair[6]; - for (int i = 0; input_pairs[i].key != 0x0; i++) { - float* acc = new float; - *acc = ((Network*)input_pairs[i].value)->test("./test.txt"); - output[i].key = input_pairs[i].key; - output[i].value = acc; - } - return output; -} +// if (i != linecount-net->batch_size) { // Don't try to advance batch on final batch. +// net->next_batch(); +// } +// net->batches++; +// // auto loop_end = std::chrono::high_resolution_clock::now(); +// // times[0] += std::chrono::duration_cast<std::chrono::nanoseconds>(back_begin -feed_begin).count() / pow(10,9); +// // times[1] += std::chrono::duration_cast<std::chrono::nanoseconds>(cost_begin - back_begin).count() / pow(10,9); +// // times[2] += std::chrono::duration_cast<std::chrono::nanoseconds>(acc_begin - cost_begin).count() / pow(10,9); +// // times[3] += std::chrono::duration_cast<std::chrono::nanoseconds>(batch_begin - acc_begin).count() / pow(10,9); +// // times[4] += std::chrono::duration_cast<std::chrono::nanoseconds>(loop_end - batch_begin).count() / pow(10,9); +// } +// epoch_accuracy = 1.0/((float) linecount/net->batch_size) * acc_sum; +// epoch_cost = 1.0/((float) linecount/net->batch_size) * cost_sum; +// auto ep_end = std::chrono::high_resolution_clock::now(); +// double epochtime = (double) std::chrono::duration_cast<std::chrono::nanoseconds>(ep_end-ep_begin).count() / pow(10,9); +// printf("Epoch %i/%i - time %f - cost %f - acc %f\n", epochs+1, total_epochs, epochtime, epoch_cost, epoch_accuracy); +// // printf("Avg time spent across %i batches: %lf on feedforward, %lf on backprop, %lf on cost, %lf on acc, %lf on next batch.\n", net.batches, times[0]/net.batches, times[1]/net.batches, times[2]/net.batches, times[3]/net.batches, times[4]/net.batches); +// // printf("Time spent across epoch: %lf on feedforward, %lf on backprop, %lf on cost, %lf on acc, %lf on next batch, %lf other.\n", times[0], times[1], times[2], times[3], times[4], epochtime-times[0]-times[1]-times[2]-times[3]-times[4]); +// net->batches=1; +// epochs++; +// } +// struct pair* output = new struct pair; +// char* key = new char[100]; +// strcpy(key, path); +// output[0].key = key; +// output[0].value = net; +// return output; +// } -void translate(char* path) -{ - FILE* rptr = fopen(path, "r"); - FILE* wptr = fopen("./translated", "w"); - char* line = new char[MAXLINE]; - char* newline = new char[MAXLINE]; - while (fgets(line, MAXLINE, rptr) != NULL) { - void* addr1; - void* addr2; - sscanf(line, "%p %p", &addr1, &addr2); - sprintf(newline, "%s %f", (char*)addr1, *(float*)addr2); - int batch_num = strtol((char*)addr1, NULL, 10); - fprintf(wptr, "%s %f\n",(char*)addr1, *(float*)addr2); - } - fclose(rptr); - fclose(wptr); - free(newline); - free(line); -} - -double benchmark(int epochs) -{ - auto prog_begin = std::chrono::high_resolution_clock::now(); - demo(epochs); - auto prog_end = std::chrono::high_resolution_clock::now(); - return std::chrono::duration_cast<std::chrono::nanoseconds>(prog_end-prog_begin).count(); -} +// struct pair* reduce (struct pair* input_pairs) +// { +// struct pair* output = new struct pair[6]; +// for (int i = 0; input_pairs[i].key != 0x0; i++) { +// float* acc = new float; +// *acc = ((Network*)input_pairs[i].value)->test("./test.txt"); +// output[i].key = input_pairs[i].key; +// output[i].value = acc; +// } +// return output; +// } +// void translate(char* path) +// { +// FILE* rptr = fopen(path, "r"); +// FILE* wptr = fopen("./translated", "w"); +// char* line = new char[MAXLINE]; +// char* newline = new char[MAXLINE]; +// while (fgets(line, MAXLINE, rptr) != NULL) { +// void* addr1; +// void* addr2; +// sscanf(line, "%p %p", &addr1, &addr2); +// sprintf(newline, "%s %f", (char*)addr1, *(float*)addr2); +// int batch_num = strtol((char*)addr1, NULL, 10); +// fprintf(wptr, "%s %f\n",(char*)addr1, *(float*)addr2); +// } +// fclose(rptr); +// fclose(wptr); +// free(newline); +// free(line); +// } PYBIND11_MODULE(mrbpnn, m) { - m.doc() = "pybind11 example plugin"; // optional module docstring - - m.def("benchmark", &benchmark, "A function which times the BPNN", py::arg("epochs")); + m.doc() = "Fast machine learning in C++"; // optional module docstring + py::class_<Network>(m, "Network") - .def(py::init<char*, int, int, int, int, int, float>()) + .def(py::init<char*, int, float, float>()) + .def("add_layer", &Network::add_layer, py::arg("nodes"), py::arg("activation")) + .def("initialize", &Network::initialize) + .def("set_activation", &Network::set_activation) .def("feedforward", &Network::feedforward) .def("backpropagate", &Network::backpropagate) .def("list_net", &Network::list_net)