Оценка массива уравнений работает очень медленно

Я работал над проектом по моделированию биологически вдохновленных нейронных сетей с использованием arrayfire. Я подошел к моменту проведения некоторых временных тестов и был разочарован результатами, которые я получил. Я решил попробовать одну из самых быстрых и простых в использовании моделей для временного теста - модель Ижикевича. Когда я запустил новый тест с этой моделью, результаты были хуже. Код, который я использую ниже. Он не делает ничего особенного. Это просто стандартная матричная алгебра. Тем не менее, это займет более 5 секунд, чтобы сделать единственную оценку уравнения только для 10 нейронов! Каждая остановка после этого занимает примерно столько же времени.

Код:

unsigned int neuron_count = 10;

array a = af::constant(0.02, neuron_count);
array b = af::constant(0.2, neuron_count);
array c = af::constant(-65.0, neuron_count);
array d = af::constant(6, neuron_count);

array v = af::constant(-70.0, neuron_count);
array u = af::constant(-20.0, neuron_count);
array i = af::constant(14, neuron_count);

double tau = 0.2;

void StepIzhikevich()
{
    v = v + tau*(0.04*pow(v, 2) + 5 * v + 140 - u + i);
    //af_print(v);
    u = u + tau*a*(b*v - u);
    //Leaving off spike threshold checks for now
}

void TestIzhikevich()
{
    StepIzhikevich();

    timer::start();

    StepIzhikevich();

    printf("elapsed seconds: %g\n", timer::stop());
}

Вот результаты синхронизации для различного числа нейронов.

Результаты:

neurons   seconds
10        5.18275
100       5.27969
1000      5.20637
10000     4.86609

Увеличение количества нейронов, похоже, не имеет огромного эффекта. Время идет немного. Я что-то здесь не так делаю? Есть ли лучший способ оптимизировать вещи с помощью arrayfire, чтобы получить лучшие результаты?

Когда я переключил уравнение v на использование v*v вместо pow(v, 2), время, необходимое для шага, уменьшилось до 3.75762. Это все еще очень медленно, поэтому происходит нечто странное.

[РЕДАКТИРОВАТЬ] Я попытался разделить обработку на куски и нашел что-то новое. Вот код, который я использую сейчас.

Код:

unsigned int neuron_count = 10;

array a = af::constant(0.02, neuron_count);
array b = af::constant(0.2, neuron_count);
array c = af::constant(-65.0, neuron_count);
array d = af::constant(6, neuron_count);

array v = af::constant(-70.0, neuron_count);
array u = af::constant(-20.0, neuron_count);
array i = af::constant(14, neuron_count);

array g = af::constant(0.0, neuron_count);

double tau = 0.2;

void StepIzhikevich()
{
    array j = tau*(0.04*pow(v, 2));
    //af_print(j);

    array k = 5 * v + 140 - u + i;
    //af_print(k);

    array l = v + j + k;
    //af_print(l);

    v = l;  //If this line is here time is long on second loop
    //g = l; //If this is here then time is short.

    //u = u + tau*a*(b*v - u);
    //Leaving off spike threshold checks for now
}

void TestIzhikevich()
{
    timer::start();

    StepIzhikevich();

    printf("elapsed seconds: %g\n", timer::stop());

    timer::start();

    StepIzhikevich();

    printf("elapsed seconds: %g\n", timer::stop());
}

Когда я запускаю его, не переназначая его обратно на v или не назначая его новой переменной g, тогда время для шага как в первом, так и во втором запуске мало

Результаты:

истекших секунд: 0,0036143

истекшие секунды: 0,00340621

Однако, когда я ставлю v = l; обратно, затем в первый раз он работает быстро, но с тех пор он медленно.

Результаты:

прошедшие секунды: 0,0034497

истекших секунд: 2.98624

Любые идеи о том, что вызывает это?

[РЕДАКТИРОВАТЬ 2]

Я до сих пор не знаю, почему это происходит, но я нашел обходной путь, скопировав массив v, прежде чем использовать его снова.

Код:

unsigned int neuron_count = 100000;

array v = af::constant(-70.0, neuron_count);
array u = af::constant(-20.0, neuron_count);
array i = af::constant(14, neuron_count);

double tau = 0.2;

void StepIzhikevich()
{
    //array vp = v;
    array vp = v.copy();
    //af_print(vp);

    array j = tau*(0.04*pow(vp, 2));
    //af_print(j);

    array k = 5 * vp + 140 - u + i;
    //af_print(k);

    array l = vp + j + k;
    //af_print(l);

    v = l;  //If this line is here time is long on second loop
}

void TestIzhikevich()
{
    for (int i = 0; i < 10; i++)
    {
        timer::start();

        StepIzhikevich();

        printf("loop: %d  ", i);
        printf("elapsed seconds: %g\n", timer::stop());

        timer::start();
    }
}

Вот результаты сейчас. Во второй раз он работает немного медленно, но теперь быстро. Огромное улучшение по сравнению с ранее.

Результаты: цикл: 0 истекших секунд: 0.657355

цикл: 1 прошедших секунд: 0,981287

цикл: 2 прошедших секунды: 0.000416182

цикл: 3 прошедших секунды: 0.000415045

цикл: 4 прошедших секунды: 0,000421014

цикл: 5 прошедших секунд: 0.000413339

цикл: 6 прошедших секунд: 0.00041675

цикл: 7 прошедших секунд: 0,000412202

цикл: 8 прошедших секунд: 0.000473321

цикл: 9 прошедших секунд: 0,000677432

0 ответов

Другие вопросы по тегам