genann icon indicating copy to clipboard operation
genann copied to clipboard

Change type double to int16_t

Open lazy-dude opened this issue 2 years ago • 4 comments

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 ?

lazy-dude avatar May 10 '23 13:05 lazy-dude

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.

codeplea avatar May 10 '23 13:05 codeplea

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;
}

lazy-dude avatar May 10 '23 15:05 lazy-dude

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?

codeplea avatar May 10 '23 15:05 codeplea

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; 
        }
    }

}

lazy-dude avatar Jun 13 '23 15:06 lazy-dude