codeplea / genann

simple neural network library in ANSI C
https://codeplea.com/genann
zlib License
2.01k stars 237 forks source link

Change type double to int16_t #57

Open lazy-dude opened 1 year ago

lazy-dude commented 1 year ago

Hi,

I want to change all data types from double to int16_t. In genann.h addition :

typedef int16_t ann_t;

Then change every occurrence of double to ann_t. Now modifying example1.c :

const ann_t input[4][2] = {{0, 0}, {0, 1}, {1, 0}, {1, 1}};
const ann_t output[4] = {0, 1, 1, 0};

I also use %hd for printf.

And then , compiling the file example1.c I get the output:

$ ./example1 GENANN example 1. Train a small ANN to the XOR function using backpropagation. Output for [0, 0] is 0. Output for [0, 1] is 0. Output for [1, 0] is 0. Output for [1, 1] is 0.

What can I do to get the examples provided to work correctly with new type ?

codeplea commented 1 year ago

You're going to need to change the activation function too. You could do that just by scaling everything. I.e. instead of having it expect most values between 0 and 1, change it so your values are normalized between 0 and 10000.

lazy-dude commented 1 year ago

This activation function does not work. Can you help why ?

#define AF_MAX 10000
ann_t genann_act_sigmoid(const genann *ann unused, ann_t a) {
    if (a < -45.0) return 0;
    if (a > 45.0) return AF_MAX;
    double r = 1.0 / (1.0 + exp(-a));
    return r * AF_MAX;
}
codeplea commented 1 year ago

I can't do it for you. You'll have to actually read the code and try to understand. Think what happens with the exp() function. What happens when you pass in a large value?

I know your username is lazy-dude, but come on.

What's the point of what you're trying to do anyway? You didn't even try to remove floats from that code, so why not just use floats?

lazy-dude commented 1 year ago

Hi,

After doing some other jobs I am back. As why I do not use floats in my code, that is because I prefer it to run as fast as possible. Performance is an issue here. Even with a little loss of accuracy. So I have this genann_train function. Still not the right job here though:

part of genann.h

typedef int16_t genann_t;
#define GENANN_MAX 10000

The function for now used with genann_act_linear

void genann_train(genann const *ann, genann_t const *inputs, genann_t const *desired_outputs, float learning_rate) {
    /* To begin with, we must run the network forward. */
    genann_run(ann, inputs);

    float quant_factor = GENANN_MAX;
    int h, j, k;

    /* First set the output layer deltas. */
    {
        genann_t const *o = ann->output + ann->inputs + ann->hidden * ann->hidden_layers; /* First output. */
        genann_t *d = ann->delta + ann->hidden * ann->hidden_layers; /* First delta. */
        genann_t 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++;
                float output = (float)(*o++ * quant_factor); 
                float target = (float)(*t++ * quant_factor); 
                float delta = target - output; 
                *d++ = delta; 
            }
        } else {
            for (j = 0; j < ann->outputs; ++j) {
                float output = (float)(*o++ * quant_factor); 
                float target = (float)(*t++ * quant_factor); 
                float delta = (target - output) * output * (quant_factor - output);
                *d++ = delta;
            }
        }
    }

    /* 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. */
        genann_t const *o = ann->output + ann->inputs + (h * ann->hidden);
        genann_t *d = ann->delta + (h * ann->hidden);

        /* Find first delta in following layer (which may be hidden or output). */
        genann_t const * const dd = ann->delta + ((h+1) * ann->hidden);

        /* Find first weight in following layer (which may be hidden or output). */
        genann_t const * const ww = ann->weight + ((ann->inputs+1) * ann->hidden) + ((ann->hidden+1) * ann->hidden * (h));

        for (j = 0; j < ann->hidden; ++j) {

            float delta = 0;

            for (k = 0; k < (h == ann->hidden_layers-1 ? ann->outputs : ann->hidden); ++k) {
                const float forward_delta = dd[k];
                const int windex = k * (ann->hidden + 1) + (j + 1);
                const float forward_weight = ww[windex];
                delta += forward_delta * forward_weight;
            }

            float output = (float)(*o++ * quant_factor); 
            *d++ = (genann_t)((float)output * (1.0-output) * ((float)delta * (1.0 / quant_factor)));
        }
    }

    /* Train the output layer */

    for (int l = 0; l < ann->outputs; ++l) {
        float delta = ann->delta[ann->hidden * ann->hidden_layers + l]; 

        genann_t *w;
        w = ann->weight + (ann->hidden_layers 
                            ? ((ann->inputs + 1) * ann->hidden + (ann->hidden + 1) * ann->hidden * (ann->hidden_layers - 1)) 
                            : 0) 
                            + l * (ann->hidden + 1); 

        *w += delta * learning_rate * -1.0; 
        for (int m = 0; m < ann->hidden; ++m) {
            int windex = m + (ann->hidden_layers ? (ann->hidden * (ann->hidden_layers - 1)) : 0);
            w[m+1] += delta * learning_rate 
                * ann->output[windex]; 
        }
    }

    /* Train the hidden layers. */
    for (int n = ann->hidden_layers - 1; n >= 0; --n) {

        /* Find first delta in this layer. */
        genann_t const *d = ann->delta + (n * ann->hidden);

        /* Find first input to this layer. */
        genann_t const *i = ann->output + (n ? (ann->inputs + ann->hidden * (n-1)) : 0);

        /* Find first weight to this layer. */
        genann_t *w = ann->weight + (n ? ((ann->inputs+1) * ann->hidden + (ann->hidden+1) * (ann->hidden) * (n-1)) : 0);

        for (int q = 0; q < ann->hidden; ++q) {
            *w += *d * learning_rate * -1.0; 
            ++w;
            for (int r = 1; r < (n == 0 ? ann->inputs : ann->hidden) + 1; ++r) {
                *w += *d * learning_rate * i[r-1]; 
                ++w;
            }
            ++d; 
        }
    }

}