From d9da5edab47c7ff9aaf2a98b2e4fe2d1574651d4 Mon Sep 17 00:00:00 2001 From: Lewis Van Winkle Date: Mon, 14 Mar 2016 12:23:10 -0500 Subject: [PATCH] Added to documentation. --- README.md | 35 +++++++++++++++++++++-------------- doc/e1.dot | 9 +++++++++ doc/e1.png | Bin 0 -> 22067 bytes 3 files changed, 30 insertions(+), 14 deletions(-) create mode 100644 doc/e1.dot create mode 100644 doc/e1.png diff --git a/README.md b/README.md index b32b10c..c461379 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,10 @@ #Genann -Genann is a very minimal library for training and using feedforward artificial neural -networks (ANN) in C. Its primary focus is on being simple, fast, and hackable. It achieves -this by providing only the necessary functions and little extra. +Genann is a minimal, but well tested and documented, library for training and +using feedforward artificial neural networks (ANN) in C. Its primary focus is +on being simple, fast, reliable, and hackable. It achieves this by providing only the +necessary functions and little extra. ##Features @@ -14,13 +15,13 @@ this by providing only the necessary functions and little extra. - Fast and thread-safe. - Easily extendible. - Implements backpropagation training. -- Compatible with training by alternative methods (classic optimization, genetic algorithms, etc) +- *Compatible with alternative training methods* (classic optimization, genetic algorithms, etc) - Includes examples and test suite. - Released under the zlib license - free for nearly any use. ##Example Code -Four example programs are included. +Four example programs are included with the source code. - `example1.c` - Trains an ANN on the XOR function using backpropagation. - `example2.c` - Trains an ANN on the XOR function using random search. @@ -29,8 +30,13 @@ Four example programs are included. ##Quick Example -Here we create an ANN, train it on a set of labeled data using backpropagation, -ask it to predict on a test data point, and then free it: +We create an ANN taking 2 inputs, having 1 layer of 3 hidden neurons, and +providing 2 outputs. It has the following structure: + +![NN Example Structure](./doc/e1.png) + +We then train it on a set of labeled data using backpropagation and ask it to +predict on a test data point: ```C #include "genann.h" @@ -38,10 +44,10 @@ ask it to predict on a test data point, and then free it: /* Not shown, loading your training and test data. */ double **training_data_input, **training_data_output, **test_data_input; -/* New network with 5 inputs, - * 2 hidden layer of 10 neurons each, - * and 1 output. */ -genann *ann = genann_init(5, 2, 10, 1); +/* New network with 2 inputs, + * 1 hidden layer of 3 neurons each, + * and 2 outputs. */ +genann *ann = genann_init(2, 1, 3, 2); /* Learn on the training set. */ for (i = 0; i < 300; ++i) { @@ -50,7 +56,8 @@ for (i = 0; i < 300; ++i) { } /* Run the network and see what it predicts. */ -printf("Output for the first test data point is: %f\n", *genann_run(ann, test_data_input[0])); +double const *prediction = genann_run(ann, test_data_input[0]); +printf("Output for the first test data point is: %f, %f\n", prediction[0], prediction[1]); genann_free(ann); ``` @@ -86,7 +93,7 @@ void genann_train(genann const *ann, double const *inputs, ``` `genann_train()` will preform one update using standard backpropogation. It -should be called by passing in an array of inputs, an array of expected output, +should be called by passing in an array of inputs, an array of expected outputs, and a learning rate. See *example1.c* for an example of learning with backpropogation. @@ -133,7 +140,7 @@ FAQ](http://www.faqs.org/faqs/ai-faq/neural-nets/part1/) is an excellent resource for an introduction to artificial neural networks. If you're looking for a heavier, more opinionated neural network library in C, -I highly recommend the [FANN library](http://leenissen.dk/fann/wp/). Another +I recommend the [FANN library](http://leenissen.dk/fann/wp/). Another good library is Peter van Rossum's [Lightweight Neural Network](http://lwneuralnet.sourceforge.net/), which despite its name, is heavier and has more features than Genann. diff --git a/doc/e1.dot b/doc/e1.dot new file mode 100644 index 0000000..9e498c2 --- /dev/null +++ b/doc/e1.dot @@ -0,0 +1,9 @@ +digraph G { + rankdir=LR; + + {i1 i2} -> {h1 h2 h3} -> {o1 o2}; + i1, i2, h1, h2, h3, o1, o2 [shape=circle; label="";]; + + input -> hidden -> output [style=invis;]; + input, hidden, output [shape=plaintext;]; +} diff --git a/doc/e1.png b/doc/e1.png new file mode 100644 index 0000000000000000000000000000000000000000..4a6cb9de7d606843b9d537fd8e3de9a8747fbc26 GIT binary patch literal 22067 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 Ir1b9pe~Bra{{R30 literal 0 HcmV?d00001