Вывод LSTM на C, но вывод не такой, как ожидалось - PullRequest
0 голосов
/ 04 августа 2020

Я пытаюсь вывести обученную модель от keras до C. Мне нужна модель для работы на nrf52832. Результат предсказания C отличается от keras . Я сделал свою модель как можно меньше, чтобы облегчить отладку.

Вот модель:

функция построения модели (в python)

модель

Прогноз в python:

arr = np.loadtxt('model/input.txt')
arr = arr.reshape((-1, 40, 1))
model = load_model('weights/07-26_0.h5')

layer_name = 'lstm'
intermediate_layer_model = Model(
    inputs=model.input, outputs=model.get_layer(layer_name).output)
intermediate_output = intermediate_layer_model.predict(arr)
print(intermediate_output[0][0])

intermediate_output [0] означает вывод каждого временного шага (ht), как указано в статье.

https://machinelearningmastery.com/return-sequences-and-return-states-for-lstms-in-keras/

вывод слоя lstm в python (ht)

Функция Lstm и функции, используемые в Lstm в C (Я публикую только часть кода, потому что он слишком большой)

float *LSTM_Conv(float *input, float *weight, uint8_t input_len, uint8_t output_len, int gate_index)
{
    float *output = (float *)calloc(output_len, sizeof(float));
    if (output == NULL)
    {
        printf("aver memory is not enough\n");
        while (1)
            ;
    }
    // EXAMPLE:
    // Input shape & Weight shape
    // Xt (1,) (in a single time step)
    // in_weight (1, 256)
    // ht_1 (64,)
    // re_weight (64, 256)
    for (uint8_t output_i = 0; output_i < output_len; output_i++)
    {
        for (uint8_t input_i = 0; input_i < input_len; input_i++)
        {
            output[output_i] += input[input_i] * weight[input_i * output_len * 4 + output_i + gate_index];
        }
    }
    return output;
}

void LSTM_bias(float *input, float *bias, uint8_t len, uint8_t gate_index)
{
    for (uint8_t len_i = 0; len_i < len; len_i++)
    {
        input[len_i] += bias[len_i + gate_index];
    }
    return;
}

float *arr_copy(float *reference, uint8_t start, uint8_t len)
{
    float *toBeCopied = (float *)calloc(len, sizeof(float));
    for (uint8_t len_i = 0; len_i < len; len_i++)
    {
        toBeCopied[len_i] = reference[len_i + start];
    }
    return toBeCopied;
}

float *arr_plus(float *input1, float *input2, uint8_t len)
{
    float *output = (float *)calloc(len, sizeof(float));
    for (uint8_t len_i = 0; len_i < len; len_i++)
    {
        output[len_i] = input1[len_i] + input2[len_i];
    }
    free(input1);
    free(input2);
    return output;
}

float *arr_multi(float *input1, float *input2, uint8_t len)
{
    float *output = (float *)calloc(len, sizeof(float));
    for (uint8_t len_i = 0; len_i < len; len_i++)
    {
        output[len_i] = input1[len_i] * input2[len_i];
    }
    free(input1);
    free(input2);
    return output;
}

void sigmoid(float *input, uint8_t input_len)
{
    uint8_t len_i;
    for (len_i = 0; len_i < input_len; len_i++)
    {
        input[len_i] = 1 / (1 + exp(-1 * input[len_i]));
    }
    return;
}

void tanh_func(float *input, uint8_t input_len)
{
    uint8_t len;
    for (len = 0; len < input_len; len++)
    {
        input[len] = (float)tanh((double)input[len]);
    }
    return;
}
float *Lstm(float *input,
            float *in_weight,
            float *re_weight,
            float *bias,
            uint8_t time_step,
            uint8_t input_len,
            uint8_t output_len)
{
    // I / O:
    // current time input Xt
    // current time output ht
    // current time hidden state Ct
    // last time output ht_1
    // last time hidden state Ct_1
    float *Xt = NULL;
    float *ht = NULL;
    float *Ct = NULL;
    float *ht_1 = (float *)calloc(output_len, sizeof(float));
    float *Ct_1 = (float *)calloc(output_len, sizeof(float));

    // 4 Gates:
    //      input gate: it
    //      forget gate: ft
    //      new candidate cell state: Ct_bar
    //      output gate: Ot
    float *it = NULL;
    float *ft = NULL;
    float *Ct_bar = NULL;
    float *Ot = NULL;
    float *temp = NULL;

    for (uint8_t step = 0; step < time_step; step++)
    {
        if (DEBUG)
        {
            printf("++++++++++++++%d iteration+++++++++++++++\n", step);
        }
        Xt = arr_copy(input, input_len * step, input_len);

        // input gate (it)
        it = arr_plus(
            LSTM_Conv(Xt, in_weight, input_len, output_len, 0 ),
            LSTM_Conv(ht_1, re_weight, output_len, output_len, 0),
            output_len);
        LSTM_bias(it, bias, output_len, 0);
        sigmoid(it, output_len);

        if (DEBUG)
        {
            for (int i = 0; i < output_len; i++)
            {
                printf("%f ", it[i]);
            }
            printf("\nit end***************************\n");
        }

        // forget gate (ft)
        ft = arr_plus(
            LSTM_Conv(Xt, in_weight, input_len, output_len, output_len * 1),
            LSTM_Conv(ht_1, re_weight, output_len, output_len, output_len * 1),
            output_len * 1);
        LSTM_bias(ft, bias, output_len, output_len * 1);
        sigmoid(ft, output_len);

        if (DEBUG)
        {
            for (int i = 0; i < output_len; i++)
            {
                printf("%f ", ft[i]);
            }
            printf("\nft end***************************\n");
        }

        // new candidate cell state (Ct_bar)
        Ct_bar = arr_plus(
            LSTM_Conv(Xt, in_weight, input_len, output_len, output_len * 2),
            LSTM_Conv(ht_1, re_weight, output_len, output_len, output_len * 2),
            output_len);
        LSTM_bias(Ct_bar, bias, output_len, output_len * 2);
        tanh_func(Ct_bar, output_len);

        if (DEBUG)
        {
            for (int i = 0; i < output_len; i++)
            {
                printf("%f ", Ct_bar[i]);
            }
            printf("\nCt_bar end***************************\n");
        }

        // output gate (Ot)
        Ot = arr_plus(
            LSTM_Conv(Xt, in_weight, input_len, output_len, output_len * 3),
            LSTM_Conv(ht_1, re_weight, output_len, output_len, output_len * 3),
            output_len);
        LSTM_bias(Ot, bias, output_len, output_len * 3);
        sigmoid(Ot, output_len);

        if (DEBUG)
        {
            for (int i = 0; i < output_len; i++)
            {
                printf("%f ", Ot[i]);
            }
            printf("\nOt end***************************\n");
        }

        //last time to use ht_1
        if (ht_1 != NULL)
            free(ht_1);
        else
            printf("ht_1 NULL\n\n");

        //last time to use Xt
        if (Xt != NULL)
            free(Xt);
        else
            printf("Xt NULL\n\n");

        Ct = arr_plus(
            //it Ct_bar free here
            arr_multi(it, Ct_bar, output_len),
            //Ct_1 ft free here
            arr_multi(ft, Ct_1, output_len),
            output_len);

        temp = arr_copy(Ct, 0, output_len);
        tanh_func(temp, output_len);
        ht = arr_multi(temp, Ot, output_len); //Ot free

        Ct_1 = Ct;
        ht_1 = ht;

        if (1)
        {
            for (int i = 0; i < output_len; i++)
            {
                printf("%f ", ht[i]);
            }
            printf("\nht end***************************\n");
        }
    }
    if (Ct != NULL)
        free(Ct);
    else
        printf("Ct NULL\n\n");

    return ht;
}

Аргумент функции Lstm: time_step = 40, input_len = 1, output_len = 64

output слоя lstm в C (ht)

LSTM вес и смещение

Я проверил вес и смещение. Они в порядке.

Пожалуйста, посмотрите на результат python и C. Они близки с самого начала.

Я не уверен, неправильно ли я понял механизм LSTM или сделал что-то не так.

Не стесняйтесь, дайте мне знать, если вам понадобится дополнительная информация.

Большое спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...