commit dca5b3e70a6964c668ca1d59b2de7ce8773959d8
parent 7e832f190fc0352ef10cae204227579a30e6e458
Author: David Freifeld <freifeld.david@gmail.com>
Date: Mon, 22 Jun 2020 17:59:24 -0700
Merge python-bindings
Diffstat:
5 files changed, 75 insertions(+), 12 deletions(-)
diff --git a/Makefile b/Makefile
@@ -0,0 +1,6 @@
+
+all: mr_bpnn_2.cpp bpnn.cpp mapreduce.a
+ g++ -w -O2 -Wall -shared -std=c++11 -undefined dynamic_lookup `python3 -m pybind11 --includes` mr_bpnn_2.cpp bpnn.cpp mapreduce.a -o mrbpnn`python3-config --extension-suffix`
+
+clean:
+ $(RM) mrbpnn
diff --git a/bpnn.cpp b/bpnn.cpp
@@ -41,7 +41,8 @@ void Layer::initWeights(Layer next)
Network::Network(char* path, int inputs, int hidden, int outputs, int neurons, int batch_sz, float rate)
{
learning_rate = rate;
- fpath = path;
+ instances = prep_file(path, "./shuffled.txt");
+ fpath = "./shuffled.txt";
length = hidden + 2;
batch_size = batch_sz;
FILE* fptr = fopen(fpath, "r");
@@ -252,6 +253,35 @@ float Network::test(char* path)
return acc_sum/chunks;
}
+void Network::train(int total_epochs)
+{
+ float epoch_cost = 1000;
+ float epoch_accuracy = -1;
+ int epochs = 0;
+ printf("Beginning train on %i instances for %i epochs...\n", instances, total_epochs);
+ while (epochs < total_epochs) {
+ auto ep_begin = std::chrono::high_resolution_clock::now();
+ float cost_sum = 0;
+ float acc_sum = 0;
+ for (int i = 0; i <= instances-batch_size; i+=batch_size) {
+ feedforward();
+ backpropagate();
+ cost_sum += cost();
+ acc_sum += accuracy();
+ if (i != instances-batch_size) { // Don't try to advance batch on final batch.
+ next_batch(fpath);
+ } batches++;
+ }
+ epoch_accuracy = 1.0/((float) instances/batch_size) * acc_sum;
+ epoch_cost = 1.0/((float) instances/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);
+ batches=1;
+ epochs++;
+ }
+}
+
void demo(int total_epochs)
{
int linecount = prep_file("./extra.txt", "./shuffled.txt");
diff --git a/bpnn.hpp b/bpnn.hpp
@@ -28,6 +28,7 @@ public:
class Network {
public:
char* fpath;
+ int instances;
std::vector<Layer> layers;
int length;
@@ -51,6 +52,7 @@ public:
void backpropagate();
int next_batch(char* path);
float test(char* path);
+ void train(int total_epochs);
};
void demo(int total_epochs);
diff --git a/mr_bpnn_2.cpp b/mr_bpnn_2.cpp
@@ -1,4 +1,6 @@
+#include <pybind11/pybind11.h>
#include "bpnn.hpp"
+namespace py = pybind11;
struct pair* map (struct pair input_pair)
{
@@ -101,13 +103,27 @@ void translate(char* path)
free(line);
}
-
-
-int main(int argc, char** argv)
+double benchmark(int epochs)
{
auto prog_begin = std::chrono::high_resolution_clock::now();
- prep_file(argv[2], "./shuffled");
- begin("./shuffled", map, reduce, translate, strtol(argv[1], NULL, 10), 1, argv[3], strtol(argv[4], NULL, 10));
+ demo(epochs);
auto prog_end = std::chrono::high_resolution_clock::now();
- std::cout << "Time: " << std::chrono::duration_cast<std::chrono::nanoseconds>(prog_end-prog_begin).count() / pow(10,9) << "\n";
+ return std::chrono::duration_cast<std::chrono::nanoseconds>(prog_end-prog_begin).count();
+}
+
+
+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"));
+ py::class_<Network>(m, "Network")
+ .def(py::init<char*, int, int, int, int, int, float>())
+ .def("feedforward", &Network::feedforward)
+ .def("backpropagate", &Network::backpropagate)
+ .def("list_net", &Network::list_net)
+ .def("cost", &Network::cost)
+ .def("accuracy", &Network::accuracy)
+ .def("update_layer", &Network::update_layer, py::arg("vals"), py::arg("len"), py::arg("index"))
+ .def("next_batch", &Network::next_batch, py::arg("path"))
+ .def("train", &Network::train, py::arg("epochs"));
}
diff --git a/readme.md b/readme.md
@@ -1,4 +1,3 @@
-
# ML in Parallel
## About
@@ -28,7 +27,17 @@ g++ mr_bpnn_2.cpp bpnn.cpp mapreduce.a -O2 -o bpnn -std=c++11 -w
Compare these demonstrations with a sample Keras demo by running `python kerasdemo.py`
## Usage
-As of now "ML in Parallel" is not fit for usage inside code.
-However:
-- Initial prototype code is being cleaned up so as to make it more usable.
-- Python bindings with `pybind11` are in development for improved usage.
+As of now "ML in Parallel" is not fully fit for usage inside code.
+
+### Python Bindings
+This feature is largely experimental but is the preferred way to demo as of now.
+
+1. Install both the C++ end of pybind11 and the python end.
+2. Build with `make` or the much uglier alternative:
+```
+c++ -w -O2 -Wall -shared -std=c++11 -undefined dynamic_lookup `python3 -m pybind11 --includes` mr_bpnn_2.cpp bpnn.cpp mapreduce.a -o mrbpnn`python3-config --extension-suffix`
+```
+3. Copy the `mrbpnn.cpython-37m-darwin.so` file into your personal project directory.
+4. Import `mrbpnn` from your Python code and use it.
+5. Profit.
+