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:
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)