From c4b421e13ad6f511e18611baed0823a37bb17abb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E9=80=B8=E5=87=A1?= <1343619937@qq.com> Date: Thu, 25 Apr 2024 17:06:23 +0800 Subject: [PATCH] 1 --- .travis.yml | 7 + 1.xlsx | Bin 0 -> 99210 bytes LICENSE | 20 +++ Makefile | 35 ++++ README.md | 154 +++++++++++++++++ build.sh | 10 ++ doc/e1.dot | 9 + doc/e1.png | Bin 0 -> 22067 bytes example/iris.data | 150 +++++++++++++++++ example/iris.names | 69 ++++++++ example/xor.ann | 1 + example1.c | 41 +++++ example2.c | 71 ++++++++ example3.c | 39 +++++ example4.c | 119 +++++++++++++ genann.c | 405 +++++++++++++++++++++++++++++++++++++++++++++ genann.h | 108 ++++++++++++ minctest.h | 127 ++++++++++++++ my_test.c | 76 +++++++++ mytest | Bin 0 -> 42112 bytes test.c | 276 ++++++++++++++++++++++++++++++ 21 files changed, 1717 insertions(+) create mode 100644 .travis.yml create mode 100644 1.xlsx create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 build.sh create mode 100644 doc/e1.dot create mode 100644 doc/e1.png create mode 100644 example/iris.data create mode 100644 example/iris.names create mode 100644 example/xor.ann create mode 100644 example1.c create mode 100644 example2.c create mode 100644 example3.c create mode 100644 example4.c create mode 100644 genann.c create mode 100644 genann.h create mode 100644 minctest.h create mode 100644 my_test.c create mode 100644 mytest create mode 100644 test.c diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..d275c1a --- /dev/null +++ b/.travis.yml @@ -0,0 +1,7 @@ +language: c + +compiler: + - clang + - gcc + +script: make diff --git a/1.xlsx b/1.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..417c1218991ef1dea1f07efa18fe1ab67b914204 GIT binary patch literal 99210 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�?*pZS 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

Vd4)h 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 + +# Genann + +Genann is a minimal, well-tested 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 + +- **C99 with no dependencies**. +- Contained in a single source code and header file. +- Simple. +- Fast and thread-safe. +- Easily extendible. +- Implements backpropagation training. +- *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. + +## Building + +Genann is self-contained in two files: `genann.c` and `genann.h`. To use Genann, simply add those two files to your project. + +## Example Code + +Four example programs are included with the source code. + +- [`example1.c`](./example1.c) - Trains an ANN on the XOR function using backpropagation. +- [`example2.c`](./example2.c) - Trains an ANN on the XOR function using random search. +- [`example3.c`](./example3.c) - Loads and runs an ANN from a file. +- [`example4.c`](./example4.c) - Trains an ANN on the [IRIS data-set](https://archive.ics.uci.edu/ml/datasets/Iris) using backpropagation. + +## Quick Example + +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" + +/* Not shown, loading your training and test data. */ +double **training_data_input, **training_data_output, **test_data_input; + +/* 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) { + for (j = 0; j < 100; ++j) + genann_train(ann, training_data_input[j], training_data_output[j], 0.1); +} + +/* Run the network and see what it predicts. */ +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); +``` + +This example is to show API usage, it is not showing good machine learning +techniques. In a real application you would likely want to learn on the test +data in a random order. You would also want to monitor the learning to prevent +over-fitting. + + +## Usage + +### Creating and Freeing ANNs +```C +genann *genann_init(int inputs, int hidden_layers, int hidden, int outputs); +genann *genann_copy(genann const *ann); +void genann_free(genann *ann); +``` + +Creating a new ANN is done with the `genann_init()` function. Its arguments +are the number of inputs, the number of hidden layers, the number of neurons in +each hidden layer, and the number of outputs. It returns a `genann` struct pointer. + +Calling `genann_copy()` will create a deep-copy of an existing `genann` struct. + +Call `genann_free()` when you're finished with an ANN returned by `genann_init()`. + + +### Training ANNs +```C +void genann_train(genann const *ann, double const *inputs, + double const *desired_outputs, double learning_rate); +``` + +`genann_train()` will preform one update using standard backpropogation. It +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. + +A primary design goal of Genann was to store all the network weights in one +contigious block of memory. This makes it easy and efficient to train the +network weights using direct-search numeric optimization algorthims, +such as [Hill Climbing](https://en.wikipedia.org/wiki/Hill_climbing), +[the Genetic Algorithm](https://en.wikipedia.org/wiki/Genetic_algorithm), [Simulated +Annealing](https://en.wikipedia.org/wiki/Simulated_annealing), etc. +These methods can be used by searching on the ANN's weights directly. +Every `genann` struct contains the members `int total_weights;` and +`double *weight;`. `*weight` points to an array of `total_weights` +size which contains all weights used by the ANN. See *example2.c* for +an example of training using random hill climbing search. + +### Saving and Loading ANNs + +```C +genann *genann_read(FILE *in); +void genann_write(genann const *ann, FILE *out); +``` + +Genann provides the `genann_read()` and `genann_write()` functions for loading or saving an ANN in a text-based format. + +### Evaluating + +```C +double const *genann_run(genann const *ann, double const *inputs); +``` + +Call `genann_run()` on a trained ANN to run a feed-forward pass on a given set of inputs. `genann_run()` +will provide a pointer to the array of predicted outputs (of `ann->outputs` length). + + +## Hints + +- All functions start with `genann_`. +- The code is simple. Dig in and change things. + +## Extra Resources + +The [comp.ai.neural-nets +FAQ](http://www.faqs.org/faqs/ai-faq/neural-nets/part1/) is an excellent +resource for an introduction to artificial neural networks. + +If you need an even smaller neural network library, check out the excellent single-hidden-layer library [tinn](https://github.com/glouw/tinn). + +If you're looking for a heavier, more opinionated neural network library in C, +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/build.sh b/build.sh new file mode 100644 index 0000000..11f6dd0 --- /dev/null +++ b/build.sh @@ -0,0 +1,10 @@ +### + # @Author: 陈逸凡 1343619937@qq.com + # @Date: 2024-04-25 16:02:09 + # @LastEditors: 陈逸凡 1343619937@qq.com + # @LastEditTime: 2024-04-25 16:02:21 + # @FilePath: \genann-master\build.sh + # @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE +### +gcc genann.c my_test.c -o mytest -lm +./mytest \ No newline at end of file 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 diff --git a/example/iris.data b/example/iris.data new file mode 100644 index 0000000..a3490e0 --- /dev/null +++ b/example/iris.data @@ -0,0 +1,150 @@ +5.1,3.5,1.4,0.2,Iris-setosa +4.9,3.0,1.4,0.2,Iris-setosa +4.7,3.2,1.3,0.2,Iris-setosa +4.6,3.1,1.5,0.2,Iris-setosa +5.0,3.6,1.4,0.2,Iris-setosa +5.4,3.9,1.7,0.4,Iris-setosa +4.6,3.4,1.4,0.3,Iris-setosa +5.0,3.4,1.5,0.2,Iris-setosa +4.4,2.9,1.4,0.2,Iris-setosa +4.9,3.1,1.5,0.1,Iris-setosa +5.4,3.7,1.5,0.2,Iris-setosa +4.8,3.4,1.6,0.2,Iris-setosa +4.8,3.0,1.4,0.1,Iris-setosa +4.3,3.0,1.1,0.1,Iris-setosa +5.8,4.0,1.2,0.2,Iris-setosa +5.7,4.4,1.5,0.4,Iris-setosa +5.4,3.9,1.3,0.4,Iris-setosa +5.1,3.5,1.4,0.3,Iris-setosa +5.7,3.8,1.7,0.3,Iris-setosa +5.1,3.8,1.5,0.3,Iris-setosa +5.4,3.4,1.7,0.2,Iris-setosa +5.1,3.7,1.5,0.4,Iris-setosa +4.6,3.6,1.0,0.2,Iris-setosa +5.1,3.3,1.7,0.5,Iris-setosa +4.8,3.4,1.9,0.2,Iris-setosa +5.0,3.0,1.6,0.2,Iris-setosa +5.0,3.4,1.6,0.4,Iris-setosa +5.2,3.5,1.5,0.2,Iris-setosa +5.2,3.4,1.4,0.2,Iris-setosa +4.7,3.2,1.6,0.2,Iris-setosa +4.8,3.1,1.6,0.2,Iris-setosa +5.4,3.4,1.5,0.4,Iris-setosa +5.2,4.1,1.5,0.1,Iris-setosa +5.5,4.2,1.4,0.2,Iris-setosa +4.9,3.1,1.5,0.1,Iris-setosa +5.0,3.2,1.2,0.2,Iris-setosa +5.5,3.5,1.3,0.2,Iris-setosa +4.9,3.1,1.5,0.1,Iris-setosa +4.4,3.0,1.3,0.2,Iris-setosa +5.1,3.4,1.5,0.2,Iris-setosa +5.0,3.5,1.3,0.3,Iris-setosa +4.5,2.3,1.3,0.3,Iris-setosa +4.4,3.2,1.3,0.2,Iris-setosa +5.0,3.5,1.6,0.6,Iris-setosa +5.1,3.8,1.9,0.4,Iris-setosa +4.8,3.0,1.4,0.3,Iris-setosa +5.1,3.8,1.6,0.2,Iris-setosa +4.6,3.2,1.4,0.2,Iris-setosa +5.3,3.7,1.5,0.2,Iris-setosa +5.0,3.3,1.4,0.2,Iris-setosa +7.0,3.2,4.7,1.4,Iris-versicolor +6.4,3.2,4.5,1.5,Iris-versicolor +6.9,3.1,4.9,1.5,Iris-versicolor +5.5,2.3,4.0,1.3,Iris-versicolor +6.5,2.8,4.6,1.5,Iris-versicolor +5.7,2.8,4.5,1.3,Iris-versicolor +6.3,3.3,4.7,1.6,Iris-versicolor +4.9,2.4,3.3,1.0,Iris-versicolor +6.6,2.9,4.6,1.3,Iris-versicolor +5.2,2.7,3.9,1.4,Iris-versicolor +5.0,2.0,3.5,1.0,Iris-versicolor +5.9,3.0,4.2,1.5,Iris-versicolor +6.0,2.2,4.0,1.0,Iris-versicolor +6.1,2.9,4.7,1.4,Iris-versicolor +5.6,2.9,3.6,1.3,Iris-versicolor +6.7,3.1,4.4,1.4,Iris-versicolor +5.6,3.0,4.5,1.5,Iris-versicolor +5.8,2.7,4.1,1.0,Iris-versicolor +6.2,2.2,4.5,1.5,Iris-versicolor +5.6,2.5,3.9,1.1,Iris-versicolor +5.9,3.2,4.8,1.8,Iris-versicolor +6.1,2.8,4.0,1.3,Iris-versicolor +6.3,2.5,4.9,1.5,Iris-versicolor +6.1,2.8,4.7,1.2,Iris-versicolor +6.4,2.9,4.3,1.3,Iris-versicolor +6.6,3.0,4.4,1.4,Iris-versicolor +6.8,2.8,4.8,1.4,Iris-versicolor +6.7,3.0,5.0,1.7,Iris-versicolor +6.0,2.9,4.5,1.5,Iris-versicolor +5.7,2.6,3.5,1.0,Iris-versicolor +5.5,2.4,3.8,1.1,Iris-versicolor +5.5,2.4,3.7,1.0,Iris-versicolor +5.8,2.7,3.9,1.2,Iris-versicolor +6.0,2.7,5.1,1.6,Iris-versicolor +5.4,3.0,4.5,1.5,Iris-versicolor +6.0,3.4,4.5,1.6,Iris-versicolor +6.7,3.1,4.7,1.5,Iris-versicolor +6.3,2.3,4.4,1.3,Iris-versicolor +5.6,3.0,4.1,1.3,Iris-versicolor +5.5,2.5,4.0,1.3,Iris-versicolor +5.5,2.6,4.4,1.2,Iris-versicolor +6.1,3.0,4.6,1.4,Iris-versicolor +5.8,2.6,4.0,1.2,Iris-versicolor +5.0,2.3,3.3,1.0,Iris-versicolor +5.6,2.7,4.2,1.3,Iris-versicolor +5.7,3.0,4.2,1.2,Iris-versicolor +5.7,2.9,4.2,1.3,Iris-versicolor +6.2,2.9,4.3,1.3,Iris-versicolor +5.1,2.5,3.0,1.1,Iris-versicolor +5.7,2.8,4.1,1.3,Iris-versicolor +6.3,3.3,6.0,2.5,Iris-virginica +5.8,2.7,5.1,1.9,Iris-virginica +7.1,3.0,5.9,2.1,Iris-virginica +6.3,2.9,5.6,1.8,Iris-virginica +6.5,3.0,5.8,2.2,Iris-virginica +7.6,3.0,6.6,2.1,Iris-virginica +4.9,2.5,4.5,1.7,Iris-virginica +7.3,2.9,6.3,1.8,Iris-virginica +6.7,2.5,5.8,1.8,Iris-virginica +7.2,3.6,6.1,2.5,Iris-virginica +6.5,3.2,5.1,2.0,Iris-virginica +6.4,2.7,5.3,1.9,Iris-virginica +6.8,3.0,5.5,2.1,Iris-virginica +5.7,2.5,5.0,2.0,Iris-virginica +5.8,2.8,5.1,2.4,Iris-virginica +6.4,3.2,5.3,2.3,Iris-virginica +6.5,3.0,5.5,1.8,Iris-virginica +7.7,3.8,6.7,2.2,Iris-virginica +7.7,2.6,6.9,2.3,Iris-virginica +6.0,2.2,5.0,1.5,Iris-virginica +6.9,3.2,5.7,2.3,Iris-virginica +5.6,2.8,4.9,2.0,Iris-virginica +7.7,2.8,6.7,2.0,Iris-virginica +6.3,2.7,4.9,1.8,Iris-virginica +6.7,3.3,5.7,2.1,Iris-virginica +7.2,3.2,6.0,1.8,Iris-virginica +6.2,2.8,4.8,1.8,Iris-virginica +6.1,3.0,4.9,1.8,Iris-virginica +6.4,2.8,5.6,2.1,Iris-virginica +7.2,3.0,5.8,1.6,Iris-virginica +7.4,2.8,6.1,1.9,Iris-virginica +7.9,3.8,6.4,2.0,Iris-virginica +6.4,2.8,5.6,2.2,Iris-virginica +6.3,2.8,5.1,1.5,Iris-virginica +6.1,2.6,5.6,1.4,Iris-virginica +7.7,3.0,6.1,2.3,Iris-virginica +6.3,3.4,5.6,2.4,Iris-virginica +6.4,3.1,5.5,1.8,Iris-virginica +6.0,3.0,4.8,1.8,Iris-virginica +6.9,3.1,5.4,2.1,Iris-virginica +6.7,3.1,5.6,2.4,Iris-virginica +6.9,3.1,5.1,2.3,Iris-virginica +5.8,2.7,5.1,1.9,Iris-virginica +6.8,3.2,5.9,2.3,Iris-virginica +6.7,3.3,5.7,2.5,Iris-virginica +6.7,3.0,5.2,2.3,Iris-virginica +6.3,2.5,5.0,1.9,Iris-virginica +6.5,3.0,5.2,2.0,Iris-virginica +6.2,3.4,5.4,2.3,Iris-virginica +5.9,3.0,5.1,1.8,Iris-virginica diff --git a/example/iris.names b/example/iris.names new file mode 100644 index 0000000..062b486 --- /dev/null +++ b/example/iris.names @@ -0,0 +1,69 @@ +1. Title: Iris Plants Database + Updated Sept 21 by C.Blake - Added discrepency information + +2. Sources: + (a) Creator: R.A. Fisher + (b) Donor: Michael Marshall (MARSHALL%PLU@io.arc.nasa.gov) + (c) Date: July, 1988 + +3. Past Usage: + - Publications: too many to mention!!! Here are a few. + 1. Fisher,R.A. "The use of multiple measurements in taxonomic problems" + Annual Eugenics, 7, Part II, 179-188 (1936); also in "Contributions + to Mathematical Statistics" (John Wiley, NY, 1950). + 2. Duda,R.O., & Hart,P.E. (1973) Pattern Classification and Scene Analysis. + (Q327.D83) John Wiley & Sons. ISBN 0-471-22361-1. See page 218. + 3. Dasarathy, B.V. (1980) "Nosing Around the Neighborhood: A New System + Structure and Classification Rule for Recognition in Partially Exposed + Environments". IEEE Transactions on Pattern Analysis and Machine + Intelligence, Vol. PAMI-2, No. 1, 67-71. + -- Results: + -- very low misclassification rates (0% for the setosa class) + 4. Gates, G.W. (1972) "The Reduced Nearest Neighbor Rule". IEEE + Transactions on Information Theory, May 1972, 431-433. + -- Results: + -- very low misclassification rates again + 5. See also: 1988 MLC Proceedings, 54-64. Cheeseman et al's AUTOCLASS II + conceptual clustering system finds 3 classes in the data. + +4. Relevant Information: + --- This is perhaps the best known database to be found in the pattern + recognition literature. Fisher's paper is a classic in the field + and is referenced frequently to this day. (See Duda & Hart, for + example.) The data set contains 3 classes of 50 instances each, + where each class refers to a type of iris plant. One class is + linearly separable from the other 2; the latter are NOT linearly + separable from each other. + --- Predicted attribute: class of iris plant. + --- This is an exceedingly simple domain. + --- This data differs from the data presented in Fishers article + (identified by Steve Chadwick, spchadwick@espeedaz.net ) + The 35th sample should be: 4.9,3.1,1.5,0.2,"Iris-setosa" + where the error is in the fourth feature. + The 38th sample: 4.9,3.6,1.4,0.1,"Iris-setosa" + where the errors are in the second and third features. + +5. Number of Instances: 150 (50 in each of three classes) + +6. Number of Attributes: 4 numeric, predictive attributes and the class + +7. Attribute Information: + 1. sepal length in cm + 2. sepal width in cm + 3. petal length in cm + 4. petal width in cm + 5. class: + -- Iris Setosa + -- Iris Versicolour + -- Iris Virginica + +8. Missing Attribute Values: None + +Summary Statistics: + Min Max Mean SD Class Correlation + sepal length: 4.3 7.9 5.84 0.83 0.7826 + sepal width: 2.0 4.4 3.05 0.43 -0.4194 + petal length: 1.0 6.9 3.76 1.76 0.9490 (high!) + petal width: 0.1 2.5 1.20 0.76 0.9565 (high!) + +9. Class Distribution: 33.3% for each of 3 classes. diff --git a/example/xor.ann b/example/xor.ann new file mode 100644 index 0000000..c11a968 --- /dev/null +++ b/example/xor.ann @@ -0,0 +1 @@ +2 1 2 1 -1.777 -5.734 -6.029 -4.460 -3.261 -3.172 2.444 -6.581 5.826 diff --git a/example1.c b/example1.c new file mode 100644 index 0000000..b45393c --- /dev/null +++ b/example1.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include "genann.h" + +int main(int argc, char *argv[]) +{ + printf("GENANN example 1.\n"); + printf("Train a small ANN to the XOR function using backpropagation.\n"); + + /* This will make the neural network initialize differently each run. */ + /* If you don't get a good result, try again for a different result. */ + srand(time(0)); + + /* Input and expected out data for the XOR function. */ + const double input[4][2] = {{0, 0}, {0, 1}, {1, 0}, {1, 1}}; + const double output[4] = {0, 1, 1, 0}; + int i; + + /* New network with 2 inputs, + * 1 hidden layer of 2 neurons, + * and 1 output. */ + genann *ann = genann_init(2, 1, 2, 1); + + /* Train on the four labeled data points many times. */ + for (i = 0; i < 500; ++i) { + genann_train(ann, input[0], output + 0, 3); + genann_train(ann, input[1], output + 1, 3); + genann_train(ann, input[2], output + 2, 3); + genann_train(ann, input[3], output + 3, 3); + } + + /* Run the network and see what it predicts. */ + printf("Output for [%1.f, %1.f] is %1.f.\n", input[0][0], input[0][1], *genann_run(ann, input[0])); + printf("Output for [%1.f, %1.f] is %1.f.\n", input[1][0], input[1][1], *genann_run(ann, input[1])); + printf("Output for [%1.f, %1.f] is %1.f.\n", input[2][0], input[2][1], *genann_run(ann, input[2])); + printf("Output for [%1.f, %1.f] is %1.f.\n", input[3][0], input[3][1], *genann_run(ann, input[3])); + + genann_free(ann); + return 0; +} diff --git a/example2.c b/example2.c new file mode 100644 index 0000000..fe63569 --- /dev/null +++ b/example2.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include "genann.h" + +int main(int argc, char *argv[]) +{ + printf("GENANN example 2.\n"); + printf("Train a small ANN to the XOR function using random search.\n"); + + srand(time(0)); + + /* Input and expected out data for the XOR function. */ + const double input[4][2] = {{0, 0}, {0, 1}, {1, 0}, {1, 1}}; + const double output[4] = {0, 1, 1, 0}; + int i; + + /* New network with 2 inputs, + * 1 hidden layer of 2 neurons, + * and 1 output. */ + genann *ann = genann_init(2, 1, 2, 1); + + double err; + double last_err = 1000; + int count = 0; + + do { + ++count; + if (count % 1000 == 0) { + /* We're stuck, start over. */ + genann_randomize(ann); + last_err = 1000; + } + + genann *save = genann_copy(ann); + + /* Take a random guess at the ANN weights. */ + for (i = 0; i < ann->total_weights; ++i) { + ann->weight[i] += ((double)rand())/RAND_MAX-0.5; + } + + /* See how we did. */ + err = 0; + err += pow(*genann_run(ann, input[0]) - output[0], 2.0); + err += pow(*genann_run(ann, input[1]) - output[1], 2.0); + err += pow(*genann_run(ann, input[2]) - output[2], 2.0); + err += pow(*genann_run(ann, input[3]) - output[3], 2.0); + + /* Keep these weights if they're an improvement. */ + if (err < last_err) { + genann_free(save); + last_err = err; + } else { + genann_free(ann); + ann = save; + } + + } while (err > 0.01); + + printf("Finished in %d loops.\n", count); + + /* Run the network and see what it predicts. */ + printf("Output for [%1.f, %1.f] is %1.f.\n", input[0][0], input[0][1], *genann_run(ann, input[0])); + printf("Output for [%1.f, %1.f] is %1.f.\n", input[1][0], input[1][1], *genann_run(ann, input[1])); + printf("Output for [%1.f, %1.f] is %1.f.\n", input[2][0], input[2][1], *genann_run(ann, input[2])); + printf("Output for [%1.f, %1.f] is %1.f.\n", input[3][0], input[3][1], *genann_run(ann, input[3])); + + genann_free(ann); + return 0; +} diff --git a/example3.c b/example3.c new file mode 100644 index 0000000..2ace13b --- /dev/null +++ b/example3.c @@ -0,0 +1,39 @@ +#include +#include +#include "genann.h" + +const char *save_name = "example/xor.ann"; + +int main(int argc, char *argv[]) +{ + printf("GENANN example 3.\n"); + printf("Load a saved ANN to solve the XOR function.\n"); + + + FILE *saved = fopen(save_name, "r"); + if (!saved) { + printf("Couldn't open file: %s\n", save_name); + exit(1); + } + + genann *ann = genann_read(saved); + fclose(saved); + + if (!ann) { + printf("Error loading ANN from file: %s.", save_name); + exit(1); + } + + + /* Input data for the XOR function. */ + const double input[4][2] = {{0, 0}, {0, 1}, {1, 0}, {1, 1}}; + + /* Run the network and see what it predicts. */ + printf("Output for [%1.f, %1.f] is %1.f.\n", input[0][0], input[0][1], *genann_run(ann, input[0])); + printf("Output for [%1.f, %1.f] is %1.f.\n", input[1][0], input[1][1], *genann_run(ann, input[1])); + printf("Output for [%1.f, %1.f] is %1.f.\n", input[2][0], input[2][1], *genann_run(ann, input[2])); + printf("Output for [%1.f, %1.f] is %1.f.\n", input[3][0], input[3][1], *genann_run(ann, input[3])); + + genann_free(ann); + return 0; +} diff --git a/example4.c b/example4.c new file mode 100644 index 0000000..14de783 --- /dev/null +++ b/example4.c @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include +#include "genann.h" + +/* This example is to illustrate how to use GENANN. + * It is NOT an example of good machine learning techniques. + */ + +const char *iris_data = "example/iris.data"; + +double *input, *class; +int samples; +const char *class_names[] = {"Iris-setosa", "Iris-versicolor", "Iris-virginica"}; + +void load_data() { + /* Load the iris data-set. */ + FILE *in = fopen("example/iris.data", "r"); + if (!in) { + printf("Could not open file: %s\n", iris_data); + exit(1); + } + + /* Loop through the data to get a count. */ + char line[1024]; + while (!feof(in) && fgets(line, 1024, in)) { + ++samples; + } + fseek(in, 0, SEEK_SET); + + printf("Loading %d data points from %s\n", samples, iris_data); + + /* Allocate memory for input and output data. */ + input = malloc(sizeof(double) * samples * 4); + class = malloc(sizeof(double) * samples * 3); + + /* Read the file into our arrays. */ + int i, j; + for (i = 0; i < samples; ++i) { + double *p = input + i * 4; + double *c = class + i * 3; + c[0] = c[1] = c[2] = 0.0; + + if (fgets(line, 1024, in) == NULL) { + perror("fgets"); + exit(1); + } + + char *split = strtok(line, ","); + for (j = 0; j < 4; ++j) { + p[j] = atof(split); + split = strtok(0, ","); + } + + split[strlen(split)-1] = 0; + if (strcmp(split, class_names[0]) == 0) {c[0] = 1.0;} + else if (strcmp(split, class_names[1]) == 0) {c[1] = 1.0;} + else if (strcmp(split, class_names[2]) == 0) {c[2] = 1.0;} + else { + printf("Unknown class %s.\n", split); + exit(1); + } + + /* printf("Data point %d is %f %f %f %f -> %f %f %f\n", i, p[0], p[1], p[2], p[3], c[0], c[1], c[2]); */ + } + + fclose(in); +} + + +int main(int argc, char *argv[]) +{ + printf("GENANN example 4.\n"); + printf("Train an ANN on the IRIS dataset using backpropagation.\n"); + + srand(time(0)); + + /* Load the data from file. */ + load_data(); + + /* 4 inputs. + * 1 hidden layer(s) of 4 neurons. + * 3 outputs (1 per class) + */ + genann *ann = genann_init(4, 1, 4, 3); + + int i, j; + int loops = 5000; + + /* Train the network with backpropagation. */ + printf("Training for %d loops over data.\n", loops); + for (i = 0; i < loops; ++i) { + for (j = 0; j < samples; ++j) { + genann_train(ann, input + j*4, class + j*3, .01); + } + /* printf("%1.2f ", xor_score(ann)); */ + } + + int correct = 0; + for (j = 0; j < samples; ++j) { + const double *guess = genann_run(ann, input + j*4); + if (class[j*3+0] == 1.0) {if (guess[0] > guess[1] && guess[0] > guess[2]) ++correct;} + else if (class[j*3+1] == 1.0) {if (guess[1] > guess[0] && guess[1] > guess[2]) ++correct;} + else if (class[j*3+2] == 1.0) {if (guess[2] > guess[0] && guess[2] > guess[1]) ++correct;} + else {printf("Logic error.\n"); exit(1);} + } + + printf("%d/%d correct (%0.1f%%).\n", correct, samples, (double)correct / samples * 100.0); + + + + genann_free(ann); + free(input); + free(class); + + return 0; +} diff --git a/genann.c b/genann.c new file mode 100644 index 0000000..b05fa4f --- /dev/null +++ b/genann.c @@ -0,0 +1,405 @@ +/* + * GENANN - Minimal C Artificial Neural Network + * + * Copyright (c) 2015-2018 Lewis Van Winkle + * + * http://CodePlea.com + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgement in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + */ + +#include "genann.h" + +#include +#include +#include +#include +#include +#include + +#ifndef genann_act +#define genann_act_hidden genann_act_hidden_indirect +#define genann_act_output genann_act_output_indirect +#else +#define genann_act_hidden genann_act +#define genann_act_output genann_act +#endif + +#define LOOKUP_SIZE 4096 + +double genann_act_hidden_indirect(const struct genann *ann, double a) { + return ann->activation_hidden(ann, a); +} + +double genann_act_output_indirect(const struct genann *ann, double a) { + return ann->activation_output(ann, a); +} + +const double sigmoid_dom_min = -15.0; +const double sigmoid_dom_max = 15.0; +double interval; +double lookup[LOOKUP_SIZE]; + +#ifdef __GNUC__ +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#define unused __attribute__((unused)) +#else +#define likely(x) x +#define unlikely(x) x +#define unused +#pragma warning(disable : 4996) /* For fscanf */ +#endif + + +double genann_act_sigmoid(const genann *ann unused, double a) { + if (a < -45.0) return 0; + if (a > 45.0) return 1; + return 1.0 / (1 + exp(-a)); +} + +void genann_init_sigmoid_lookup(const genann *ann) { + const double f = (sigmoid_dom_max - sigmoid_dom_min) / LOOKUP_SIZE; + int i; + + interval = LOOKUP_SIZE / (sigmoid_dom_max - sigmoid_dom_min); + for (i = 0; i < LOOKUP_SIZE; ++i) { + lookup[i] = genann_act_sigmoid(ann, sigmoid_dom_min + f * i); + } +} + +double genann_act_sigmoid_cached(const genann *ann unused, double a) { + assert(!isnan(a)); + + if (a < sigmoid_dom_min) return lookup[0]; + if (a >= sigmoid_dom_max) return lookup[LOOKUP_SIZE - 1]; + + size_t j = (size_t)((a-sigmoid_dom_min)*interval+0.5); + + /* Because floating point... */ + if (unlikely(j >= LOOKUP_SIZE)) return lookup[LOOKUP_SIZE - 1]; + + return lookup[j]; +} + +double genann_act_linear(const struct genann *ann unused, double a) { + return a; +} + +double genann_act_threshold(const struct genann *ann unused, double a) { + return a > 0; +} + +genann *genann_init(int inputs, int hidden_layers, int hidden, int outputs) { + if (hidden_layers < 0) return 0; + if (inputs < 1) return 0; + if (outputs < 1) return 0; + if (hidden_layers > 0 && hidden < 1) return 0; + + + const int hidden_weights = hidden_layers ? (inputs+1) * hidden + (hidden_layers-1) * (hidden+1) * hidden : 0; + const int output_weights = (hidden_layers ? (hidden+1) : (inputs+1)) * outputs; + const int total_weights = (hidden_weights + output_weights); + + const int total_neurons = (inputs + hidden * hidden_layers + outputs); + + /* Allocate extra size for weights, outputs, and deltas. */ + const int size = sizeof(genann) + sizeof(double) * (total_weights + total_neurons + (total_neurons - inputs)); + genann *ret = malloc(size); + if (!ret) return 0; + + ret->inputs = inputs; + ret->hidden_layers = hidden_layers; + ret->hidden = hidden; + ret->outputs = outputs; + + ret->total_weights = total_weights; + ret->total_neurons = total_neurons; + + /* Set pointers. */ + ret->weight = (double*)((char*)ret + sizeof(genann)); + ret->output = ret->weight + ret->total_weights; + ret->delta = ret->output + ret->total_neurons; + + genann_randomize(ret); + + ret->activation_hidden = genann_act_sigmoid_cached; + ret->activation_output = genann_act_sigmoid_cached; + + genann_init_sigmoid_lookup(ret); + + return ret; +} + + +genann *genann_read(FILE *in) { + int inputs, hidden_layers, hidden, outputs; + int rc; + + errno = 0; + rc = fscanf(in, "%d %d %d %d", &inputs, &hidden_layers, &hidden, &outputs); + if (rc < 4 || errno != 0) { + perror("fscanf"); + return NULL; + } + + genann *ann = genann_init(inputs, hidden_layers, hidden, outputs); + + int i; + for (i = 0; i < ann->total_weights; ++i) { + errno = 0; + rc = fscanf(in, " %le", ann->weight + i); + if (rc < 1 || errno != 0) { + perror("fscanf"); + genann_free(ann); + + return NULL; + } + } + + return ann; +} + + +genann *genann_copy(genann const *ann) { + const int size = sizeof(genann) + sizeof(double) * (ann->total_weights + ann->total_neurons + (ann->total_neurons - ann->inputs)); + genann *ret = malloc(size); + if (!ret) return 0; + + memcpy(ret, ann, size); + + /* Set pointers. */ + ret->weight = (double*)((char*)ret + sizeof(genann)); + ret->output = ret->weight + ret->total_weights; + ret->delta = ret->output + ret->total_neurons; + + return ret; +} + + +void genann_randomize(genann *ann) { + int i; + for (i = 0; i < ann->total_weights; ++i) { + double r = GENANN_RANDOM(); + /* Sets weights from -0.5 to 0.5. */ + ann->weight[i] = r - 0.5; + } +} + + +void genann_free(genann *ann) { + /* The weight, output, and delta pointers go to the same buffer. */ + free(ann); +} + + +double const *genann_run(genann const *ann, double const *inputs) { + double const *w = ann->weight; + double *o = ann->output + ann->inputs; + double const *i = ann->output; + + /* Copy the inputs to the scratch area, where we also store each neuron's + * output, for consistency. This way the first layer isn't a special case. */ + memcpy(ann->output, inputs, sizeof(double) * ann->inputs); + + int h, j, k; + + if (!ann->hidden_layers) { + double *ret = o; + for (j = 0; j < ann->outputs; ++j) { + double sum = *w++ * -1.0; + for (k = 0; k < ann->inputs; ++k) { + sum += *w++ * i[k]; + } + *o++ = genann_act_output(ann, sum); + } + + return ret; + } + + /* Figure input layer */ + for (j = 0; j < ann->hidden; ++j) { + double sum = *w++ * -1.0; + for (k = 0; k < ann->inputs; ++k) { + sum += *w++ * i[k]; + } + *o++ = genann_act_hidden(ann, sum); + } + + i += ann->inputs; + + /* Figure hidden layers, if any. */ + for (h = 1; h < ann->hidden_layers; ++h) { + for (j = 0; j < ann->hidden; ++j) { + double sum = *w++ * -1.0; + for (k = 0; k < ann->hidden; ++k) { + sum += *w++ * i[k]; + } + *o++ = genann_act_hidden(ann, sum); + } + + i += ann->hidden; + } + + double const *ret = o; + + /* Figure output layer. */ + for (j = 0; j < ann->outputs; ++j) { + double sum = *w++ * -1.0; + for (k = 0; k < ann->hidden; ++k) { + sum += *w++ * i[k]; + } + *o++ = genann_act_output(ann, sum); + } + + /* Sanity check that we used all weights and wrote all outputs. */ + assert(w - ann->weight == ann->total_weights); + assert(o - ann->output == ann->total_neurons); + + return ret; +} + + +void genann_train(genann const *ann, double const *inputs, double const *desired_outputs, double learning_rate) { + /* To begin with, we must run the network forward. */ + genann_run(ann, inputs); + + int h, j, k; + + /* First set the output layer deltas. */ + { + double const *o = ann->output + ann->inputs + ann->hidden * ann->hidden_layers; /* First output. */ + double *d = ann->delta + ann->hidden * ann->hidden_layers; /* First delta. */ + double const *t = desired_outputs; /* First desired output. */ + + + /* Set output layer deltas. */ + if (genann_act_output == genann_act_linear || + ann->activation_output == genann_act_linear) { + for (j = 0; j < ann->outputs; ++j) { + *d++ = *t++ - *o++; + } + } else { + for (j = 0; j < ann->outputs; ++j) { + *d++ = (*t - *o) * *o * (1.0 - *o); + ++o; ++t; + } + } + } + + + /* Set hidden layer deltas, start on last layer and work backwards. */ + /* Note that loop is skipped in the case of hidden_layers == 0. */ + for (h = ann->hidden_layers - 1; h >= 0; --h) { + + /* Find first output and delta in this layer. */ + double const *o = ann->output + ann->inputs + (h * ann->hidden); + double *d = ann->delta + (h * ann->hidden); + + /* Find first delta in following layer (which may be hidden or output). */ + double const * const dd = ann->delta + ((h+1) * ann->hidden); + + /* Find first weight in following layer (which may be hidden or output). */ + double const * const ww = ann->weight + ((ann->inputs+1) * ann->hidden) + ((ann->hidden+1) * ann->hidden * (h)); + + for (j = 0; j < ann->hidden; ++j) { + + double delta = 0; + + for (k = 0; k < (h == ann->hidden_layers-1 ? ann->outputs : ann->hidden); ++k) { + const double forward_delta = dd[k]; + const int windex = k * (ann->hidden + 1) + (j + 1); + const double forward_weight = ww[windex]; + delta += forward_delta * forward_weight; + } + + *d = *o * (1.0-*o) * delta; + ++d; ++o; + } + } + + + /* Train the outputs. */ + { + /* Find first output delta. */ + double const *d = ann->delta + ann->hidden * ann->hidden_layers; /* First output delta. */ + + /* Find first weight to first output delta. */ + double *w = ann->weight + (ann->hidden_layers + ? ((ann->inputs+1) * ann->hidden + (ann->hidden+1) * ann->hidden * (ann->hidden_layers-1)) + : (0)); + + /* Find first output in previous layer. */ + double const * const i = ann->output + (ann->hidden_layers + ? (ann->inputs + (ann->hidden) * (ann->hidden_layers-1)) + : 0); + + /* Set output layer weights. */ + for (j = 0; j < ann->outputs; ++j) { + *w++ += *d * learning_rate * -1.0; + for (k = 1; k < (ann->hidden_layers ? ann->hidden : ann->inputs) + 1; ++k) { + *w++ += *d * learning_rate * i[k-1]; + } + + ++d; + } + + assert(w - ann->weight == ann->total_weights); + } + + + /* Train the hidden layers. */ + for (h = ann->hidden_layers - 1; h >= 0; --h) { + + /* Find first delta in this layer. */ + double const *d = ann->delta + (h * ann->hidden); + + /* Find first input to this layer. */ + double const *i = ann->output + (h + ? (ann->inputs + ann->hidden * (h-1)) + : 0); + + /* Find first weight to this layer. */ + double *w = ann->weight + (h + ? ((ann->inputs+1) * ann->hidden + (ann->hidden+1) * (ann->hidden) * (h-1)) + : 0); + + + for (j = 0; j < ann->hidden; ++j) { + *w++ += *d * learning_rate * -1.0; + for (k = 1; k < (h == 0 ? ann->inputs : ann->hidden) + 1; ++k) { + *w++ += *d * learning_rate * i[k-1]; + } + ++d; + } + + } + +} + + +void genann_write(genann const *ann, FILE *out) { + fprintf(out, "%d %d %d %d", ann->inputs, ann->hidden_layers, ann->hidden, ann->outputs); + + int i; + for (i = 0; i < ann->total_weights; ++i) { + fprintf(out, " %.20e", ann->weight[i]); + } +} + + diff --git a/genann.h b/genann.h new file mode 100644 index 0000000..e4b7383 --- /dev/null +++ b/genann.h @@ -0,0 +1,108 @@ +/* + * GENANN - Minimal C Artificial Neural Network + * + * Copyright (c) 2015-2018 Lewis Van Winkle + * + * http://CodePlea.com + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgement in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + */ + + +#ifndef GENANN_H +#define GENANN_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef GENANN_RANDOM +/* We use the following for uniform random numbers between 0 and 1. + * If you have a better function, redefine this macro. */ +#define GENANN_RANDOM() (((double)rand())/RAND_MAX) +#endif + +struct genann; + +typedef double (*genann_actfun)(const struct genann *ann, double a); + +typedef struct genann { + /* How many inputs, outputs, and hidden neurons. */ + int inputs, hidden_layers, hidden, outputs; + + /* Which activation function to use for hidden neurons. Default: gennann_act_sigmoid_cached*/ + genann_actfun activation_hidden; + + /* Which activation function to use for output. Default: gennann_act_sigmoid_cached*/ + genann_actfun activation_output; + + /* Total number of weights, and size of weights buffer. */ + int total_weights; + + /* Total number of neurons + inputs and size of output buffer. */ + int total_neurons; + + /* All weights (total_weights long). */ + double *weight; + + /* Stores input array and output of each neuron (total_neurons long). */ + double *output; + + /* Stores delta of each hidden and output neuron (total_neurons - inputs long). */ + double *delta; + +} genann; + +/* Creates and returns a new ann. */ +genann *genann_init(int inputs, int hidden_layers, int hidden, int outputs); + +/* Creates ANN from file saved with genann_write. */ +genann *genann_read(FILE *in); + +/* Sets weights randomly. Called by init. */ +void genann_randomize(genann *ann); + +/* Returns a new copy of ann. */ +genann *genann_copy(genann const *ann); + +/* Frees the memory used by an ann. */ +void genann_free(genann *ann); + +/* Runs the feedforward algorithm to calculate the ann's output. */ +double const *genann_run(genann const *ann, double const *inputs); + +/* Does a single backprop update. */ +void genann_train(genann const *ann, double const *inputs, double const *desired_outputs, double learning_rate); + +/* Saves the ann. */ +void genann_write(genann const *ann, FILE *out); + +void genann_init_sigmoid_lookup(const genann *ann); +double genann_act_sigmoid(const genann *ann, double a); +double genann_act_sigmoid_cached(const genann *ann, double a); +double genann_act_threshold(const genann *ann, double a); +double genann_act_linear(const genann *ann, double a); + + +#ifdef __cplusplus +} +#endif + +#endif /*GENANN_H*/ diff --git a/minctest.h b/minctest.h new file mode 100644 index 0000000..eb3ad41 --- /dev/null +++ b/minctest.h @@ -0,0 +1,127 @@ +/* + * + * MINCTEST - Minimal C Test Library - 0.1 + * + * Copyright (c) 2014, 2015, 2016 Lewis Van Winkle + * + * http://CodePlea.com + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgement in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + */ + + + +/* + * MINCTEST - Minimal testing library for C + * + * + * Example: + * + * void test1() { + * lok('a' == 'a'); + * } + * + * void test2() { + * lequal(5, 6); + * lfequal(5.5, 5.6); + * } + * + * int main() { + * lrun("test1", test1); + * lrun("test2", test2); + * lresults(); + * return lfails != 0; + * } + * + * + * + * Hints: + * All functions/variables start with the letter 'l'. + * + */ + + +#ifndef __MINCTEST_H__ +#define __MINCTEST_H__ + +#include +#include +#include + + +/* How far apart can floats be before we consider them unequal. */ +#define LTEST_FLOAT_TOLERANCE 0.001 + + +/* Track the number of passes, fails. */ +/* NB this is made for all tests to be in one file. */ +static int ltests = 0; +static int lfails = 0; + + +/* Display the test results. */ +#define lresults() do {\ + if (lfails == 0) {\ + printf("ALL TESTS PASSED (%d/%d)\n", ltests, ltests);\ + } else {\ + printf("SOME TESTS FAILED (%d/%d)\n", ltests-lfails, ltests);\ + }\ +} while (0) + + +/* Run a test. Name can be any string to print out, test is the function name to call. */ +#define lrun(name, test) do {\ + const int ts = ltests;\ + const int fs = lfails;\ + const clock_t start = clock();\ + printf("\t%-14s", name);\ + test();\ + printf("pass:%2d fail:%2d %4dms\n",\ + (ltests-ts)-(lfails-fs), lfails-fs,\ + (int)((clock() - start) * 1000 / CLOCKS_PER_SEC));\ +} while (0) + + +/* Assert a true statement. */ +#define lok(test) do {\ + ++ltests;\ + if (!(test)) {\ + ++lfails;\ + printf("%s:%d error \n", __FILE__, __LINE__);\ + }} while (0) + + +/* Assert two integers are equal. */ +#define lequal(a, b) do {\ + ++ltests;\ + if ((a) != (b)) {\ + ++lfails;\ + printf("%s:%d (%d != %d)\n", __FILE__, __LINE__, (a), (b));\ + }} while (0) + + +/* Assert two floats are equal (Within LTEST_FLOAT_TOLERANCE). */ +#define lfequal(a, b) do {\ + ++ltests;\ + if (fabs((double)(a)-(double)(b)) > LTEST_FLOAT_TOLERANCE) {\ + ++lfails;\ + printf("%s:%d (%f != %f)\n", __FILE__, __LINE__, (double)(a), (double)(b));\ + }} while (0) + + +#endif /*__MINCTEST_H__*/ diff --git a/my_test.c b/my_test.c new file mode 100644 index 0000000..7b37362 --- /dev/null +++ b/my_test.c @@ -0,0 +1,76 @@ +/** function comment + * @Author: 陈逸凡 1343619937@qq.com + * @Date: 2024-04-25 15:21:22 + * @LastEditors: 陈逸凡 1343619937@qq.com + * @LastEditTime: 2024-04-25 16:06:42 + * @FilePath: \genann-master\my_test.c + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ + +#include +#include +#include +#include "genann.h" +/* +上面3组是吸到了 +下面3组是没吸到 +*/ +const double input[][300]={ + {2304,2288,2305,2337,2361,2354,2302,2220,2146,2095,2067,2068,2097,2141,2161,2113,1986,1821,1696,1626,1587,1570,1571,1547,1462,1358,1296,1257,1183,1093,1045,1024,1008,1019,1027,949,775,609,508,467,479,525,587,641,652,585,504,490,530,553,573,650,737,765,772,790,742,622,546,555,594,672,774,823,786,731,701,693,703,729,769,842,947,1035,1064,1042,1005,976,966,985,1045,1148,1266,1339,1332,1282,1242,1243,1274,1320,1373,1460,1577,1664,1677,1634,1576,1536,1514,1518,1570,1665,1765,1812,1795,1726,1661,1635,1631,1630,1643,1693,1765,1806,1782,1692,1583,1488,1415,1379,1385,1442,1508,1530,1489,1406,1327,1290,1283,1280,1293,1347,1429,1489,1488,1416,1312,1219,1160,1135,1158,1230,1324,1387,1379,1317,1249,1216,1214,1232,1269,1348,1458,1551,1574,1520,1422,1342,1296,1285,1324,1416,1526,1586,1576,1505,1435,1409,1416,1435,1474,1547,1643,1706,1695,1611,1510,1437,1398,1395,1429,1504,1579,1601,1552,1464,1389,1363,1369,1375,1392,1455,1550,1623,1626,1550,1439,1336,1264,1234,1262,1350,1468,1559,1574,1536,1502,1519,1583,1674,1773,1876,1970,2052,2102,2123,2148,2198,2267,2359,2467,2552,2605,2660,2701,2706,2750,2854,2920,2932,3000,3103,3127,3089,3116,3199,3235,3240,3271,3316,3356,3383,3374,3336,3300,3281,3285,3318,3328,3290,3269,3277,3236,3157,3129,3156,3171,3160,3136,3104,3080,3062,3028,2995,}, + {2317,2296,2305,2343,2379,2390,2361,2286,2196,2123,2084,2082,2114,2162,2191,2169,2063,1909,1775,1695,1657,1629,1613,1608,1571,1470,1360,1293,1248,1172,1096,1067,1066,1061,1063,1037,917,727,564,494,492,538,597,648,684,673,595,518,522,573,600,635,732,823,834,821,815,741,621,575,616,676,767,875,905,848,779,745,737,753,795,850,932,1038,1103,1097,1034,973,941,943,984,1064,1177,1281,1325,1290,1216,1169,1175,1218,1275,1348,1455,1570,1636,1627,1564,1495,1455,1456,1494,1572,1676,1767,1800,1764,1687,1626,1610,1618,1631,1661,1726,1799,1825,1772,1661,1542,1461,1419,1413,1442,1504,1563,1565,1507,1417,1339,1312,1316,1326,1349,1412,1492,1530,1499,1397,1282,1204,1171,1182,1233,1321,1411,1455,1428,1351,1289,1275,1297,1333,1390,1490,1605,1678,1667,1579,1470,1396,1379,1401,1466,1570,1670,1711,1669,1580,1512,1499,1519,1552,1607,1691,1780,1822,1777,1666,1552,1491,1477,1500,1553,1631,1697,1694,1622,1519,1440,1423,1440,1462,1501,1583,1686,1735,1694,1571,1440,1345,1298,1306,1367,1477,1596,1666,1656,1597,1561,1585,1662,1759,1867,1977,2069,2141,2185,2201,2225,2280,2356,2455,2575,2657,2698,2744,2783,2790,2835,2943,3010,3031,3106,3199,3208,3163,3188,3255,3278,3274,3290,3322,3351,3360,3330,3271,3222,3193,3194,3223,3222,3175,3157,3165,3115,3037,3023,3061,3075,3063,3041,3014,2995,2982,2952,2928,}, + {2323,2303,2309,2339,2378,2397,2375,2310,2216,2141,2110,2126,2174,2227,2251,2224,2138,1998,1857,1778,1752,1733,1702,1664,1615,1530,1410,1308,1265,1231,1164,1120,1124,1123,1089,1036,931,757,586,508,530,588,647,681,681,653,590,507,475,531,608,658,730,829,870,813,745,688,596,522,564,670,768,857,909,860,754,682,674,706,764,838,914,999,1061,1047,965,875,843,876,947,1045,1150,1246,1298,1280,1213,1152,1160,1230,1321,1401,1479,1572,1634,1621,1549,1470,1445,1486,1571,1661,1744,1814,1838,1807,1744,1694,1695,1743,1793,1832,1877,1923,1936,1881,1768,1652,1587,1585,1613,1644,1666,1678,1662,1600,1520,1459,1446,1472,1497,1509,1532,1574,1596,1560,1470,1362,1294,1295,1331,1373,1406,1430,1434,1400,1334,1275,1271,1313,1364,1411,1467,1541,1590,1574,1491,1380,1314,1323,1387,1461,1533,1601,1626,1590,1513,1447,1439,1488,1546,1601,1673,1754,1802,1773,1662,1531,1452,1453,1508,1581,1651,1703,1710,1649,1550,1468,1452,1496,1555,1606,1658,1715,1737,1682,1569,1451,1392,1409,1461,1524,1578,1619,1638,1614,1563,1536,1588,1700,1819,1909,1976,2025,2067,2119,2170,2217,2278,2353,2433,2521,2612,2660,2681,2728,2768,2791,2870,2989,3037,3050,3119,3179,3155,3129,3197,3279,3302,3303,3319,3335,3343,3338,3305,3256,3220,3205,3222,3248,3232,3185,3175,3169,3108,3046,3056,3093,3100,3083,3055,3026,3009,2990,2960,2952,}, + {1861,1879,1921,1981,2054,2120,2154,2135,2060,1963,1906,1916,1991,2086,2156,2185,2188,2168,2129,2081,2035,1981,1891,1755,1609,1498,1419,1335,1252,1205,1170,1108,1045,1015,979,862,706,591,525,488,497,532,516,434,356,336,340,340,330,318,324,350,363,370,417,481,501,506,560,616,607,595,643,681,659,667,727,758,772,816,849,858,895,957,977,929,828,719,673,731,826,889,913,924,941,954,958,967,1002,1060,1122,1189,1259,1330,1383,1378,1317,1255,1260,1341,1436,1499,1523,1533,1550,1574,1596,1617,1652,1701,1745,1784,1827,1864,1867,1801,1668,1531,1477,1509,1572,1612,1605,1565,1525,1483,1436,1398,1387,1408,1433,1451,1464,1475,1471,1426,1335,1245,1207,1233,1274,1291,1270,1236,1224,1233,1240,1243,1255,1278,1307,1352,1407,1462,1492,1457,1365,1269,1236,1288,1376,1442,1458,1450,1444,1438,1422,1408,1423,1470,1526,1578,1626,1665,1678,1628,1516,1398,1354,1394,1473,1526,1525,1497,1475,1454,1429,1412,1418,1450,1484,1508,1524,1539,1539,1495,1407,1322,1293,1336,1393,1416,1394,1363,1355,1357,1352,1353,1381,1434,1486,1517,1534,1569,1648,1749,1831,1898,1956,2009,2076,2150,2204,2250,2311,2383,2471,2572,2642,2682,2739,2807,2844,2901,3012,3080,3073,3097,3161,3166,3121,3136,3194,3202,3168,3134,3100,3076,3061,3031,2985,2943,2909,2891,2903,2897,2841,2805,2817,2794,2722,2685,2702,2707,2692,2678,2660,2646,2642,2627,2611,}, + {1817,1797,1827,1894,1993,2101,2179,2199,2139,2026,1922,1873,1900,1980,2075,2155,2222,2274,2297,2276,2209,2121,2027,1926,1801,1659,1537,1460,1403,1337,1290,1288,1287,1227,1112,976,830,677,558,541,586,611,616,603,529,407,313,290,300,312,319,337,388,444,452,412,400,427,439,457,542,627,619,595,635,674,671,703,774,806,821,861,879,852,831,843,855,854,848,832,832,860,876,862,850,874,926,974,989,982,1013,1098,1195,1274,1307,1291,1244,1197,1169,1192,1284,1407,1493,1519,1509,1507,1534,1567,1591,1616,1664,1741,1818,1853,1835,1773,1695,1622,1570,1559,1598,1653,1659,1610,1540,1494,1491,1500,1486,1458,1452,1488,1538,1570,1548,1475,1380,1280,1207,1185,1226,1299,1346,1335,1287,1249,1241,1246,1250,1257,1289,1348,1412,1450,1437,1387,1339,1307,1285,1296,1356,1424,1450,1428,1389,1372,1402,1445,1465,1466,1486,1547,1623,1664,1651,1590,1516,1448,1402,1399,1448,1522,1558,1537,1482,1436,1433,1445,1437,1424,1448,1516,1586,1618,1584,1500,1404,1318,1269,1273,1333,1417,1460,1438,1373,1327,1325,1347,1365,1378,1405,1448,1479,1492,1514,1572,1678,1783,1852,1897,1931,1966,2028,2113,2182,2246,2330,2413,2491,2576,2635,2668,2723,2787,2826,2887,2993,3060,3052,3073,3141,3157,3115,3127,3184,3186,3140,3104,3079,3065,3064,3048,3007,2966,2927,2907,2913,2899,2844,2818,2837,2818,2751,2716,2730,2736,2722,2703,2682,2665,2658,2641,2623,}, + {1822,1808,1846,1923,2033,2137,2203,2202,2125,2003,1893,1839,1841,1865,1873,1863,1855,1842,1794,1714,1632,1565,1477,1348,1230,1146,1064,967,891,881,914,926,917,903,826,668,505,396,318,284,329,422,496,510,472,420,398,396,381,378,437,527,569,586,625,627,554,519,585,649,661,681,701,678,659,690,725,741,770,814,837,826,789,733,693,693,695,681,681,713,763,800,812,817,859,937,1006,1040,1060,1095,1162,1257,1357,1448,1515,1542,1511,1458,1438,1491,1596,1690,1743,1756,1763,1779,1784,1776,1771,1792,1837,1881,1903,1891,1853,1783,1684,1588,1532,1541,1591,1618,1581,1504,1435,1394,1363,1329,1291,1270,1282,1307,1323,1318,1283,1216,1115,1012,955,972,1054,1134,1165,1155,1147,1157,1173,1189,1209,1250,1324,1401,1449,1469,1476,1464,1424,1385,1378,1424,1505,1564,1567,1538,1526,1552,1584,1597,1597,1614,1661,1720,1765,1776,1757,1698,1600,1490,1412,1407,1459,1505,1493,1441,1389,1352,1318,1277,1241,1243,1299,1374,1424,1439,1417,1356,1258,1157,1116,1162,1271,1361,1390,1369,1354,1369,1397,1435,1497,1590,1708,1802,1852,1892,1948,2030,2151,2279,2370,2425,2465,2498,2548,2622,2687,2747,2835,2911,2937,2978,3058,3084,3049,3070,3134,3125,3061,3056,3092,3076,3032,3008,2996,2987,2972,2927,2864,2808,2764,2748,2770,2769,2723,2707,2725,2692,2619,2594,2625,2646,2647,2647,2645,2645,2651,2650,2658,}, + + //{}, +}; +//额外找的没吸到 +const double test[300]={ + 1949,1920,1926,1984,2069,2140,2169,2146,2081,2008,1970,1973,2007,2042,2042,2009,1966,1926,1887,1835,1760,1681,1616,1543,1435,1313,1219,1141,1046,962,944,990,1007,951,860,743,602,492,457,456,437,423,442,453,429,394,368,372,402,418,407,431,490,504,465,466,512,529,539,609,679,663,625,623,614,610,662,713,707,691,726,789,841,850,796,712,649,614,591,591,631,703,771,802,813,835,885,940,979,1011,1075,1187,1308,1380,1389,1362,1352,1368,1400,1452,1530,1621,1680,1692,1668,1658,1687,1726,1746,1761,1801,1879,1949,1952,1872,1758,1654,1578,1538,1529,1550,1588,1596,1548,1467,1398,1370,1364,1353,1341,1349,1386,1418,1394,1310,1216,1160,1139,1139,1155,1181,1209,1213,1177,1123,1095,1117,1162,1196,1209,1241,1319,1405,1436,1401,1330,1276,1251,1245,1263,1311,1382,1433,1441,1413,1392,1400,1415,1413,1401,1419,1496,1575,1586,1510,1401,1309,1250,1225,1226,1266,1333,1375,1357,1303,1259,1258,1284,1310,1333,1379,1459,1528,1526,1451,1358,1297,1270,1266,1284,1322,1372,1398,1375,1327,1307,1349,1426,1497,1542,1587,1651,1722,1777,1828,1893,1973,2072,2167,2220,2246,2271,2297,2334,2408,2491,2550,2610,2677,2715,2748,2833,2907,2910,2927,3004,3041,2994,2970,3014,3042,3019,2991,2974,2959,2943,2907,2850,2794,2756,2739,2752,2767,2740,2710,2722,2712,2644,2596,2611,2628,2618,2599,2577,2559,2552,2537,2521, +}; +//源数据input[0]数据裁剪了一下 +const double test2[300]= {1821,1696,1626,1587,1570,1571,1547,1462,1358,1296,1257,1183,1093,1045,1024,1008,1019,1027,949,775,609,508,467,479,525,587,641,652,585,504,490,530,553,573,650,737,765,772,790,742,622,546,555,594,672,774,823,786,731,701,693,703,729,769,842,947,1035,1064,1042,1005,976,966,985,1045,1148,1266,1339,1332,1282,1242,1243,1274,1320,1373,1460,1577,1664,1677,1634,1576,1536,1514,1518,1570,1665,1765,1812,1795,1726,1661,1635,1631,1630,1643,1693,1765,1806,1782,1692,1583,1488,1415,1379,1385,1442,1508,1530,1489,1406,1327,1290,1283,1280,1293,1347,1429,1489,1488,1416,1312,1219,1160,1135,1158,1230,1324,1387,1379,1317,1249,1216,1214,1232,1269,1348,1458,1551,1574,1520,1422,1342,1296,1285,1324,1416,1526,1586,1576,1505,1435,1409,1416,1435,1474,1547,1643,1706,1695,1611,1510,1437,1398,1395,1429,1504,1579,1601,1552,1464,1389,1363,1369,1375,1392,1455,1550,1623,1626,1550,1439,1336,1264,1234,1262,1350,1468,1559,1574,1536,1502,1519,1583,1674,1773,1876,1970,2052,2102,2123,2148,2198,2267,2359,2467,2552,2605,2660,2701,2706,2750,2854,2920,2932,3000,3103,3127,3089,3116,3199,3235,3240,3271,3316,3356,3383,3374,3336,3300,3281,3285,3318,3328,3290,3269,3277,3236,3157,3129,3156,3171,3160,3136,3104,3080,3062,3028,2995, +}; +//目标结果 +const double output[]={ + 1,1,1, + 0,0,0, +}; +int main(int argc, char *argv[]) +{ + printf("GENANN example 1.\n"); + printf("Train a small ANN to the XOR function using backpropagation.\n"); + + /* This will make the neural network initialize differently each run. */ + /* If you don't get a good result, try again for a different result. */ + // srand(time(0)); + + /* Input and expected out data for the XOR function. */ + // const double input[4][2] = {{0, 0}, {0, 1}, {1, 0}, {1, 1}}; + // const double output[4] = {0, 1, 1, 0}; + int i; + + /* New network with 2 inputs, + * 1 hidden layer of 2 neurons, + * and 1 output. */ + genann *ann = genann_init(300, 1, 20, 1); + + /* Train on the four labeled data points many times. */ + for (i = 0; i < 500; ++i) { + genann_train(ann, input[0], output + 0, 3); + genann_train(ann, input[1], output + 1, 3); + genann_train(ann, input[2], output + 2, 3); + genann_train(ann, input[3], output + 3, 3); + genann_train(ann, input[4], output + 4, 3); + genann_train(ann, input[5], output + 5, 3); + } + + /* Run the network and see what it predicts. */ + printf("%f\n",*genann_run(ann, input[0])); + printf("%f\n",*genann_run(ann, input[4])); + printf("%f\n",*genann_run(ann, test)); + printf("%f\n",*genann_run(ann, test2)); + genann_free(ann); + return 0; +} diff --git a/mytest b/mytest new file mode 100644 index 0000000000000000000000000000000000000000..b6af46132c0b65e6e826547319efb5743f1c563d GIT binary patch literal 42112 zcmeI54^-V(mG6HL(qc=>O(lvo)@w~Ww5CWRR-$RWO}ObzO;V;MN@rp(gg*r(aD_`t zl*HSRv{0bpOd3(6(oD42;VCmO)4@(u5@SPMOc(kx%4n8@eR1BU$y7vC^u_S@`JK=H zak)wAOxLXS)|%nh!uPlL*?XUJ_Sxs0{X4%K?k9trHl(JcIC?E|?r;n>zSMF86bv2Y zMj+r6I7{UBTb=8jD}+vSdA2-YK}zj4mO3BP;V%+2dfDdY61d#59Yt-SL8EuMEAl#9 zqUiW6ZS)qKTj*q5dYzS1)N-%BJX`K0;o2h0S4`A1z6o{N^3WIN<1l{7Znb>XGi;+* zf?f%FiVk{;>QCbn^HYF7lQF5;PO@G#ddXNQHqE7I>M+-RKaWazmT@YvsqtSbsbsca~@H`;{;5FnGD^kQ5mGV$DAJ0^@T#ee=X`~#QamtKbdvlSW!q~jopAWU z9rbnL#%NhXG#s{~mlUjQj)-u1b6L2mrmn2E=Hr#ljYRqMx(cT%(oj?kJD!bRv}v z4fPG8CRkS=mI}(EHT8AEkT#ZoG+bW&QCpFi-C-uvZH}qH-rconxP|0B6I^UW_m?Vmm% z)9Fg*tlXO`Mf86rsO!jnxBLp{H}JA*YL=MUZ?;Y&^G26WbFPLy;>s^_mO(dNS0g)9 zs^b^hT)H3VIy^+M6tUhbKL$U&*H!b@ZKcP)Wcg+-NL(kz6ZmFb(JP+7zgn4slL`FH z1pZ6{KQW#o@UIkEy5wp#C-8MGGzGB)zPk^*(vH)Xz&Cx+t2=>j>d>nvfv-L?WxWY} zQUF(_FM)rR8W9{w;AbT82NU=*z}_{Kz`w@hI?iwcUt`4-k0$U*r4qCjZWlbT;DH4X zEO=nS1OI}=%*&`^k|dlOiirvXtUu@O}tHM>D|9Q zVR~2Sxcw7)YZARVi4G>wwPNHv3qHj#1-;zWxOQM$~(TkJlKXlD+|F0A2RsXiJ z{reAu+FuH_o|!Bv4z3zn^+KrY_HQh6oY`gnOC+bOax>q$SDa$bD{lXta6(;+rwpu_ zi7u1Sc-GuYXuNKAJoBwFBljIp>*-+kP`%@;!Llc8g;ygzhoW>F~R`Ox<-M6<-e zJ`AMKj#s&UR(%scvD=@NVyEdHTSKk4Z#TE0_Mb;HLLIkP2@${l!t89kLI&&k#XE#f z`LO7E^&9<(ho#WmY!y8TW?!g%*UVJr(%@vMBRCW42>C)CTiyGrP-flnQ2WW*@5|lp zAwv$m@SRsv&3+B4Q<=WS`{lv2D)XJe$%n3}%KXL9**_I#a8fvn_ejY@R~ea@+?_3O z3x1Wkd&wiN%7>24H7$O9)=ZJ@Vi{D~}mKm(d%#jMVeb4Zh%?U1kQ>Wvc3{IO-Kl?$`nW@ZMg40&|{>`qL zpUN?vX`gBO_r&RO<5}bA_)nww~0fxd|CQj`J89277J6E_q#*! zTd7RCeasB&ujIb*>ZwrX%ArtuaOUjWO$|SF1;qEt4h@QJbHzfdOlZoF2!|foHDmgp z`I({2XNSy0bK_(1subs}1fU3XWqsFZNeBP>akuelsdHhH;4%$-JleWz%-MOB+n$LMp z=mRc2>d}w7^q8~T*ShPJ$Bn>^zP%%Ox^*Ze^XtJ=?Z-NTV_ikF9l=vB=eS{}44+-> zR@5FmW2%j&+v2lVc#5O#!Fb2kGZK0!a(hn7MRBbCxCo@kuTjID?AR&=lZKvrhww*3 zJ)zd2^kd_T+Jn;_!D%5SVjutg?5sN|t-EHNCOTxiZw8`c>*;n`P0Y<$dr_LbJJnt! z`={ZJwin5=W$w zWH4?jJ{yhi6&tidMk^$~lA%rX!*Hl;$v)Tii(WIrUNanN#+}-X8>AWc(TtOhxD&S*~-Ui{oz-)p_poo26DH;~nl;$7Q6t zGEyzW40*i6x%qfk+EQuu#bNe#(-1TF-7ve-wqu8h!t&8j$7W+!)&|qJc>K3^?EbSO z=;F@kGXH`25vh~4e#oq3%f)|FnGeV=B0Goan;jA}XWY;oH7kzU3zod}1|w|A@p%mjManJo`JKijw zEwLtAgNKcyq(f_hhg<$W)bZhgP}h2?(sXL;kSUTi*>0(u&Cr*VD1r+|x1b>DV9Xso4SM;_$oE zm+GmFL+z29_I0%l!IrX={o+ zAer5MSVlNTp**A%sNBUGo_L$cm_~_ax2GA%mi_+s5_X|AqfLK)a$i&gq&Lpl_ldW< zS-HB+x+8Q9IwrKVOqNx4 z-1~%Hyk8E-r3!cW=c+Wz;8G{l8jPjOukQ5L%T)epuQ_S0@s##`5$WQ@O>Xjo^G#@Y z&X<~LeR}5CU18()VRkBUUJn8iQl8rb39@!e6Tx0jFjUatTIwpA^Nnbj0riGQ!iwgE zao$PCM4bHj8jMW;~ zX-$$9Q+3AKtGxU4_qiIGpIR@qO0@KdWfPPJ-Kcrs8XGls!@OUX`i@{PA=7I@rstxN zNw@Ku+4&=R@@)MdCQ?#bziGh9Z2w1-XL@7g4gIUkxPduwZ%9qL5WPoxF@J#Df0+4o zZ|+|-zN4xXFusxKk+r~$AD(aQqA)mDrx(?3owusG$4+edt5_UO2%urJ(sf9JWGDWh z_*&?#1A_9@dA~e+nMKd$Z#KRp;+(VhCF#gGxjLyb^G8MRNu$^Cq=`rKoPX@4MWL>{ zXGCZ;lwyt)Qbp!Cq2gQ=DdNyf?OY&TV)3jOF^*6gC$9C@;J`(r&MKAJd4s86N7&ta z1{3!Sf-qtG`N`F0;Xn4=N9>l7;gV+iS?%7PjNg6EvnX5i-10MQ6ug?eSi0mgGUN${ z@(9N0&DvjYFazlwPntk&efhGXF*au?M-6>I4gE(V@%SIDYB(WgzHMV>n3$22&yAU( ze@DzD>X?`@I)5}~#x5T-^t$O9uh%A8mMG;0j}4bkJ|YXm&_$u*EfDW8u1;DY-XV)d z(nE^headT>$6)hB*KD5e;~f#{ia^Mm0K_|d@_YQw_TSyl>Rj0aRyNhje&S-;9yulB zk?bQ@_NVu`?YQS+*^w2V>>XD2IV=12i)Ec$Pxe|Xd%(*6)&=dK+ur>5c(VU0sT7Bj zzY>3BKJl^yg>i?ZS+}}l>*jv<{nBt9;ZN5fTqQ&oita?72!)ilaoPT9@QjTL_V-{Etj z{u|}fsP6T!|5m>!+(dsCyDd6k>{FH=12f?Fby7@bjcoz>3c1f zf+6@Z^m}*P@^17(k61bm7NM8^7<|xAdj`Nf_z~LYL%#&h1Y5vnupf*j z*(<=#81^HSAEjLZ+OwQ~b<)qnU>p2yO~%#>Zaxwb)AoRZscp$m#l|%gC69g*c+o?BT4>`A=gj4($Eh; zkE4GCy-i>R*a8lLN0Bc;e;f96-Bo@Ia^v`G2>*w`K`7r+f)wQ@z^6JQ)Hcm_M*HqZwSBXh-17v2ze5xAxW^f3;=4BO(QyS~}5m561-FFL-+XkjH&gVege{~BkD>HGkFos2e{If?3QXAM!=$Yu;81eF{0ve@7XQO<*%v$haKF zeg<}Re2So#V{Zj=I-Z5lr@%qvLbM|b{}$l?3{dkCT^~l#)4c8sbe#G%PO{NI3TA-= z__LRK)eo94Xuh+Y_SB*`%6K+2z9*p5DObHs+8;0i7E-Uq&tCMJ!4m4zcEsq-wttY3g^zp&HxG@OXo`7LH1>{wseU?_Nh9B8u`2(C|4eYXXPt2l2 zKGco;=%bb&Z?~97UQ`VoqFpiS>)m7JG;h;tuPgc8!DL+WPEnonC4)v@43dW(Dam-=d^_)h>=N$S2*gFF1dE^o7jxde~u{#K! zfM0-|o+GKfQtWS{JRA8qID(xOv@-;~7x{kLqvv0Gey4sL#eN_1o3PuX?E-5l*Ym7V z=x*w(#XtJIJJP7N1kBcm}iXdpPYhzfV|{~;8#FBC;C0~7s-Q0z!$++z-ykd_OA!Cz#mW^0dv5sK+UU4 zp#$Jc)T{Z{ap({@Li@+TTi_RfZvcNv`C)JmxDE7!nr}G^*E|nov5s#8(}?G3FoXE* z22X)s1GB+?b2yv$Su zkhmQOJK0bC#I-)RuYm7EPxoIvAJF_q^Ts^t({r3C`_?I)7ohe>-$V7|2Zw%EfV!WK zLua6W9y$c-Jd5JD)A(J_tMvWtO8hy7ToLF8RlXFu7CZ>fC?7k1+I=3>bD1LAd4l#8 zQ?Bn7y?U_|qr46IVXzPE2AjbGQ2nLnLo@Kls9*C8&Cm4xvgW-J#%ln19giH^GYqC_ zIjG~Qd9aSlAoUl6J}?K={^Vh&8yp2Qh!@3e@YTP4_$wdO_k|~Dr=NPX-THoVCFS`l z2d)73gVpHkbIlRzp8++`8^UkJ%%6kIlRoB8_ZRItRl&Ydp!*0|z<#qIyylRV|01}B zJS>~M>o7PCR*`qT0v3>eJp;CBzCnJH3a$qK7CZ`W2lc(2o=c^D)wXMh@)l6@pLA$F zf6{Zcd#PW~-JYXe2f(j^hrrd~%k(D|`V@2__4-$T5vAWlC*d|p9Z=7P_{??Wz~_%1|$0Gxz>8}dH{w_)c5I0X)a>%hN2 zzMp!sv8VgcIp$p&>%=JY^&Io}4C_J;=m(dBD_Orw*`M|ELX+(OIs0t9M;@^lk6A3* zV=d&ziK8g>eYM;IX$Nugg*f4dq@XbaU5FD zwKTu&hF?TIljL0y@~b#F0QQk@Um5$`dV)uwC?MAE~Mv+nqTe3e>wPf6Mjr*K5Aa3^KUP56`-D9wm}~T zS76779nB*&e~8k4%^S}luj8Ht9RTyN6F^Vx6hR-MJOakS{gj^pR8-PL?FivCgLj({2Pi@`Q<8q{{``EwEd>;v_=Li5$r%%@4_&tdkRmFyFP z-~juFe*QOu{iPGkKV;XxAA=8(Z~4g!4uE6e2J(yN!7TEVC&2CGJ8^If)V%9)@+5tq zr|$IQSJ%^TjmiTR^3E)6W917%T-f zAG;n}^U@#SuM^-Qa5w1u7rpfJ00H814Al1(Cy2+tCBL~%;}HBD{7uO1C$5iT=LEO{ zzUE!aq0du345lm1b9;<=ug~LI%r9ME^}SG>{Zv24qvsoAdM*NXvp?%T-3MI&>Uqle zUOUgaKWTBO*`l5^4SkIAsKrw98wdGuFt*E<2PhxMj@lc2*p~N#MdU}#HTSds90-RUrxz%#UKZku?_v8Ge^}3(<$z~rp2(9^r z?hBfSOd?lJJnDPC2WdF2@8`uQl$ zKcs2<3Xdr0?N!;OqI*0D3X78vGzw0BT-TN_!@0Zx7fE9tIDAn*Zr})7|j( z-030uUkL62_5A5;(2CDMD?ST-1l0V=S-4yeM2S}i)N>(+_|?x94id-uxpe(^gZdt? z6nXvk9;dLk4SqZc_54p%O#AbdSXDR|7zx6wTo^>gfcE);9Ae9eaD={eaLwEla?f_+wgaIZzp&zf5;od^2B0pvpDKiOap zb_Sp|uL_a>=sD9k`Bnfq&GWRL<~_Dv#X;)T^RjI8edJgAIkRl)=_5}rWxVu#ZV%%) z!gzPGFYD*?tCKMFzXzElc54i2z?#o70Y**^oHv+a+7`u;9X`8N17V2JqL3+j2R zzK_@W7h}Ezi2r8f$FSQ+yz9PyhISRe_wq03Jn$U-(DzT(^sfk90Zy~;WAwf)=J`aQ<8`0OV}E)D)PLWu=ThGy|I+s(YY*9Z zJPPVL)w#d2{0j1gm%-b}OEizU;VV{7&w-9YYaY~0UZkHBuYk@6^>gDVpbvl#fNR0) z!3#DV4#fVI z4|?xSm|unLfBL@84?m{z?5mpREc{&r>*s#WOIg?SJ?l#Nn&;^IGtCP|$P}-09d?&e}`JUFe;IQz& z|K#j!fzTNTW@k$T?-Fbld{MAR@bjOMzolvDp4r(k!AZdx!CO8%JDZ*AIKTg#=nJkn zDEfj|d_nXDKQ7oK_*ub0!NrGWXHN^h^_kh(^MXTy{zcLNxlB9FmGbd>os?!@%9}H; zOz)OD41c-&m^R;J1PZV88CW4d`SKI^3)?s68sCO%vhU8k`r-7L^Zx7Jd&|34++gI4 z{xE4=%16HT=Dro&MQCRm1ju5e@U~;5h;IE zV#4^>Yk%rTz5bn(@*hk2TNBGaXxrx(UWUZRKTCOST7rJCbmq4f8VsG9A z9r}X3c{8+moHN&T7Mvo=&GVYMwEWi>X6p?-!1=*qL&(+3%@vk(#wgbVl9e>{YRa?0 zWuO9TPRW-n$2=mMs{nm-eqgREEjVuk3uvJ7o4L_;4bzEdn=8M}(Rr!-r{(5S?H_REuXP6UtfbD{=i!gS*ZFoD z{y2PH7p8=NDf^f6+j-YcmQxUuo22VfcI2zZ#XoO!lH>OEuA^S>%ov9xTsOJ$+1~uu zqP4@cY|NbPM7fgR(0O*5t-uNuJ3i;r1ipJ_DfNC&_@=+fC zIk`P2v7g5H>b!eN`2Iu#+@DAOdFIy*@UM}9(ECKSPa40aN_OQ-~yLc%63$SE1Guf*eNOrR9GaV^F+O`^9hHG?hO_f-yhzvb<6tV zjrVK`hjUkp_Ql*)m*nO-J9dVnm5ov9T{yhq-a9u3!@(_u;jj}fynoA`n>Vf(_FY@H zhJztWLxuM`;k!27v+mAK;d?f0xGz{7F1~Z!reIjwUs)NrYtzPc>%*&aSLeRlsi~8% z1QPw)n(gJ`#%NhXG`vGz|9LX+%9p~*hK9QOaBY3L`;yNqGy36;#hb%(J}=(9-gvyY zY`c6*Q8--FSYN(oP1t^Qk*D__{puj|)k4)Z6&00r;=YQShRX7&Bh6{_Bux$aHA7`} z74__G^!vaAieVv`hsr@vTPgXiKBT z3*{dTmsfu@Tvb+6>$N3cRZSftR@T^9Dc+hVW7?~=OKZbBNe0p97dzB32 z#(PAxqNXm~)F|KLWM1#qmwN&U#vg8|iOTR*)_Hz4aUF;2 zt8h%Pu6804HuVkj?1#e=AOvs1*Gt(Enu`H9sB{|73#kO9+M2q`vIc2Xd2^W=y0Tgc zj(N3-?Ss8X4)(7K^u4Oh?Z>^j5b)T);rfy#L2Czk5=YB zSl5(m-g(RD?@VBAZ>p)SxV5GN)}8A%-fEU6SG>BcvD(S4*jXo4Sd2E*iMh%u`!1MTF>`nW@uz4@#AYp2X}wb^-P+iB9HxZIN7@Ao););{X8~%=L>43Om57xi|UWjens;w$>uU`G`HG+eXcj#s8LaUJ)cn2 z^9T`fuVnv!Ot|J*U-k9*UQzQVZNJJX?iPJ>cA&JLA1KD$TIYPM?T77j$&K-;>g#!i z;t+ybzv^rMKZE`{XNlD_84if>m(C+Vx%Zzt*N^OWKe z6$F$0_g(aL{Pj6Oac0we1OEA>`&?-Julo9&t=OL=pIrY>q&!i-ZeQqw%9= ze=axI$Pd%jJJ$%Az?LgnUTMW&icF^bsJ@;@7X3T*{~)?1c2!@`A4ymTg{b-NkieBjO`n;96E=eJYbp9Vym1@oa literal 0 HcmV?d00001 diff --git a/test.c b/test.c new file mode 100644 index 0000000..a7f895e --- /dev/null +++ b/test.c @@ -0,0 +1,276 @@ +/* + * GENANN - Minimal C Artificial Neural Network + * + * Copyright (c) 2015-2018 Lewis Van Winkle + * + * http://CodePlea.com + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgement in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + */ + +#include "genann.h" +#include "minctest.h" +#include +#include +#include + + + +void basic() { + genann *ann = genann_init(1, 0, 0, 1); + + lequal(ann->total_weights, 2); + double a; + + + a = 0; + ann->weight[0] = 0; + ann->weight[1] = 0; + lfequal(0.5, *genann_run(ann, &a)); + + a = 1; + lfequal(0.5, *genann_run(ann, &a)); + + a = 11; + lfequal(0.5, *genann_run(ann, &a)); + + a = 1; + ann->weight[0] = 1; + ann->weight[1] = 1; + lfequal(0.5, *genann_run(ann, &a)); + + a = 10; + ann->weight[0] = 1; + ann->weight[1] = 1; + lfequal(1.0, *genann_run(ann, &a)); + + a = -10; + lfequal(0.0, *genann_run(ann, &a)); + + genann_free(ann); +} + + +void xor() { + genann *ann = genann_init(2, 1, 2, 1); + ann->activation_hidden = genann_act_threshold; + ann->activation_output = genann_act_threshold; + + lequal(ann->total_weights, 9); + + /* First hidden. */ + ann->weight[0] = .5; + ann->weight[1] = 1; + ann->weight[2] = 1; + + /* Second hidden. */ + ann->weight[3] = 1; + ann->weight[4] = 1; + ann->weight[5] = 1; + + /* Output. */ + ann->weight[6] = .5; + ann->weight[7] = 1; + ann->weight[8] = -1; + + + double input[4][2] = {{0, 0}, {0, 1}, {1, 0}, {1, 1}}; + double output[4] = {0, 1, 1, 0}; + + lfequal(output[0], *genann_run(ann, input[0])); + lfequal(output[1], *genann_run(ann, input[1])); + lfequal(output[2], *genann_run(ann, input[2])); + lfequal(output[3], *genann_run(ann, input[3])); + + genann_free(ann); +} + + +void backprop() { + genann *ann = genann_init(1, 0, 0, 1); + + double input, output; + input = .5; + output = 1; + + double first_try = *genann_run(ann, &input); + genann_train(ann, &input, &output, .5); + double second_try = *genann_run(ann, &input); + lok(fabs(first_try - output) > fabs(second_try - output)); + + genann_free(ann); +} + + +void train_and() { + double input[4][2] = {{0, 0}, {0, 1}, {1, 0}, {1, 1}}; + double output[4] = {0, 0, 0, 1}; + + genann *ann = genann_init(2, 0, 0, 1); + + int i, j; + + for (i = 0; i < 50; ++i) { + for (j = 0; j < 4; ++j) { + genann_train(ann, input[j], output + j, .8); + } + } + + ann->activation_output = genann_act_threshold; + lfequal(output[0], *genann_run(ann, input[0])); + lfequal(output[1], *genann_run(ann, input[1])); + lfequal(output[2], *genann_run(ann, input[2])); + lfequal(output[3], *genann_run(ann, input[3])); + + genann_free(ann); +} + + +void train_or() { + double input[4][2] = {{0, 0}, {0, 1}, {1, 0}, {1, 1}}; + double output[4] = {0, 1, 1, 1}; + + genann *ann = genann_init(2, 0, 0, 1); + genann_randomize(ann); + + int i, j; + + for (i = 0; i < 50; ++i) { + for (j = 0; j < 4; ++j) { + genann_train(ann, input[j], output + j, .8); + } + } + + ann->activation_output = genann_act_threshold; + lfequal(output[0], *genann_run(ann, input[0])); + lfequal(output[1], *genann_run(ann, input[1])); + lfequal(output[2], *genann_run(ann, input[2])); + lfequal(output[3], *genann_run(ann, input[3])); + + genann_free(ann); +} + + + +void train_xor() { + double input[4][2] = {{0, 0}, {0, 1}, {1, 0}, {1, 1}}; + double output[4] = {0, 1, 1, 0}; + + genann *ann = genann_init(2, 1, 2, 1); + + int i, j; + + for (i = 0; i < 500; ++i) { + for (j = 0; j < 4; ++j) { + genann_train(ann, input[j], output + j, 3); + } + /* printf("%1.2f ", xor_score(ann)); */ + } + + ann->activation_output = genann_act_threshold; + lfequal(output[0], *genann_run(ann, input[0])); + lfequal(output[1], *genann_run(ann, input[1])); + lfequal(output[2], *genann_run(ann, input[2])); + lfequal(output[3], *genann_run(ann, input[3])); + + genann_free(ann); +} + + + +void persist() { + genann *first = genann_init(1000, 5, 50, 10); + + FILE *out = fopen("persist.txt", "w"); + genann_write(first, out); + fclose(out); + + + FILE *in = fopen("persist.txt", "r"); + genann *second = genann_read(in); + fclose(in); + + lequal(first->inputs, second->inputs); + lequal(first->hidden_layers, second->hidden_layers); + lequal(first->hidden, second->hidden); + lequal(first->outputs, second->outputs); + lequal(first->total_weights, second->total_weights); + + int i; + for (i = 0; i < first->total_weights; ++i) { + lok(first->weight[i] == second->weight[i]); + } + + genann_free(first); + genann_free(second); +} + + +void copy() { + genann *first = genann_init(1000, 5, 50, 10); + + genann *second = genann_copy(first); + + lequal(first->inputs, second->inputs); + lequal(first->hidden_layers, second->hidden_layers); + lequal(first->hidden, second->hidden); + lequal(first->outputs, second->outputs); + lequal(first->total_weights, second->total_weights); + + int i; + for (i = 0; i < first->total_weights; ++i) { + lfequal(first->weight[i], second->weight[i]); + } + + genann_free(first); + genann_free(second); +} + + +void sigmoid() { + double i = -20; + const double max = 20; + const double d = .0001; + + while (i < max) { + lfequal(genann_act_sigmoid(NULL, i), genann_act_sigmoid_cached(NULL, i)); + i += d; + } +} + + +int main(int argc, char *argv[]) +{ + printf("GENANN TEST SUITE\n"); + + srand(100); //Repeatable test results. + + lrun("basic", basic); + lrun("xor", xor); + lrun("backprop", backprop); + lrun("train and", train_and); + lrun("train or", train_or); + lrun("train xor", train_xor); + lrun("persist", persist); + lrun("copy", copy); + lrun("sigmoid", sigmoid); + + lresults(); + + return lfails != 0; +}