English 中文 Español Deutsch 日本語 Português
preview
Алгоритм атомарного орбитального поиска — Atomic Orbital Search (AOS): Модификация

Алгоритм атомарного орбитального поиска — Atomic Orbital Search (AOS): Модификация

MetaTrader 5Тестер |
688 5
Andrey Dik
Andrey Dik

Содержание

  1. Введение
  2. Реализация алгоритма
  3. Пример использования алгоритмов класса C_AO
  4. Результаты тестов


Введение

В первой части статьи мы подробно рассмотрели алгоритм AOS (Atomic Orbital Search), его основы, вдохновленные атомной орбитальной моделью, и механизмы, лежащие в его основе. Мы обсудили, как алгоритм использует вероятностные распределения и динамику взаимодействий для поиска оптимальных решений в сложных задачах оптимизации.

Во второй части статьи мы сосредоточимся на модификации алгоритма AOS, поскольку не можем пройти мимо такой выдающейся идеи, не стремясь её улучшить. Мы проанализируем концепцию улучшения алгоритма, уделяя особое внимание специфическим операторам, которые присущи этому методу и могут повысить его эффективность и адаптивность.

Работа над алгоритмом AOS открыла передо мной множество интересных аспектов, связанных с его методами поиска в пространстве решений. В процессе исследования я также пришел к ряду идей о том, как можно улучшить этот интересный алгоритм. В частности, я сосредоточился на переработке имеющихся методов, которые могут повысить производительность работы алгоритма, улучшая его способность к исследованию сложных пространств решений. Мы рассмотрим, как эти улучшения могут быть интегрированы в существующую структуру алгоритма AOS, чтобы сделать его еще более мощным инструментом для решения задач оптимизации. Таким образом, наша цель — не только проанализировать существующие механизмы, но и предложить иные подходы, которые могут значительно расширить возможности алгоритма AOS.


Реализация алгоритма

В предыдущей статье мы подробно рассмотрели ключевые компоненты алгоритма AOS. Напомним, что в этом алгоритме популяция рассматривается как молекула, а допустимая область координат, в которой осуществляется поиск оптимальных решений, представлена в виде атома. Каждый атом состоит из различных слоев, которые помогают организовать и направлять поиск.

Конкретные значения по координате, которые мы получаем в процессе оптимизации, можно интерпретировать как электроны. Эти электроны, находясь в пределах атома, представляют собой возможные решения одного из параметров задачи, которую мы оптимизируем. Таким образом, каждая молекула (популяция) стремится к нахождению оптимальных значений (электронов) в пределах заданной области (атома).

В оригинальной версии алгоритма AOS энергия слоя BEk определяется как среднее арифметическое энергии электронов в слое, а связь BSk — как среднее арифметическое их координат. Энергия BEk используется для сравнения с энергией электронов с целью определения способа их последующего перемещения. Связь BSk служит для вычисления приращения к положению электронов, как разницы между наилучшим положением электронов LEk в слое и связью BSk по следующей формуле: Xki[t+1] = Xkit + αi × (βi × LEk − γi × BSk).

Предлагаю отказаться от усредненного положения электронов BSk в пользу персонального лучшего положения электрона. Таким образом, электрон будет двигаться в сторону наилучшего решения в своем слое, основываясь на индивидуальном достижении, а не на усредненном решении по слою. Кроме того, два случайных компонента βi и γi представляются излишними, поскольку уже имеется внешний случайный компонент αi. Это позволит сократить время на генерацию случайных чисел в данной формуле в три раза, не теряя при этом физического смысла.

Теперь давайте рассмотрим структуру, описывающую слой в атоме. Красным цветом выделены элементы, которые будут удалены из кода:

//——————————————————————————————————————————————————————————————————————————————
struct S_Layer
{
    int    pc;  // счетчик частиц
    double BSk; // состояние связи
    double BEk; // энергия связи
    double LEk; // минимальная энергия

    void Init ()
    {
      pc  = 0;
      BSk = 0.0;
      BEk = 0.0;
      LEk = 0.0;
    }
};
//——————————————————————————————————————————————————————————————————————————————

Рассмотрим код метода "CalcLayerParams", который выполняет расчет характеристик слоев, таких как энергия и связь. Строки, выделенные красным, будут удалены, так как они больше не понадобятся. Напомним, что этот метод играет ключевую роль в стратегии поиска AOS, направленной на предотвращение застревания алгоритма в локальных ловушках. Поскольку уровень энергии в слоях не зависит от их расположения (энергия уменьшается от центра к внешним слоям атома), а определяется наличием значимых локальных экстремумов (внешний слой может иметь энергию, превышающую внутренние), слои служат для корректировки движения электронов в пространстве поиска.

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

AOS layers

Рисунок 1. Разница направления и размера смещения электрона e в зависимости от количества слоев в атоме

Рисунок 1 иллюстрирует различия в поведении электронов в атомах с разным количеством слоев в алгоритме AOS. Верхняя часть показывает атом с тремя слоями, где электрон находится в слое L1 со значением целевой функции B1 и движется в сторону локального лучшего значения LEk1. Нижняя часть рисунка иллюстрирует атом с двумя слоями, где электрон находится так же в слое L1 и движется в сторону локального лучшего значения LEk1 со значением целевой функции B1 (в случае с тремя слоями это была бы точка LEk2).

Ключевые элементы на рисунке:

  • B0, B1, B2 — обозначения локальных значений целевой функции для соответствующих слоев,
  • LEk0, LEk1, LEk2 — лучшие решения в соответствующих слоях,
  • L0, L1, L2 — слои в атоме,
  • e — электрон,
  • MIN, MAX — границы внешних слоев атомов (граничные условия по оптимизируемым параметрам задачи).
//——————————————————————————————————————————————————————————————————————————————
// Расчет параметров для каждого слоя
void C_AO_AOS::CalcLayerParams ()
{
  double energy;

  // Обработка каждой координаты (атома)
  for (int c = 0; c < coords; c++)
  {
    atoms [c].Init (maxLayers);

    // Обработка каждого слоя
    for (int L = 0; L < currentLayers [c]; L++)
    {
      energy = -DBL_MAX;

      // Обработка каждого электрона
      for (int e = 0; e < popSize; e++)
      {
        if (electrons [e].layerID [c] == L)
        {
          atoms [c].layers [L].pc++;
          atoms [c].layers [L].BEk += a [e].f;
          atoms [c].layers [L].BSk += a [e].c [c];

          if (a [e].f > energy)
          {
            energy = a [e].f;
            atoms [c].layers [L].LEk = a [e].c [c];
          }
        }
      }

      // Расчет средних значений для слоя
      if (atoms [c].layers [L].pc != 0)
      {
        atoms [c].layers [L].BEk /= atoms [c].layers [L].pc;
        atoms [c].layers [L].BSk /= atoms [c].layers [L].pc;
      }
    }
  }

  // Расчет общего состояния связей
  ArrayInitialize (BS, 0);

  for (int c = 0; c < coords; c++)
  {
    for (int e = 0; e < popSize; e++)
    {
      BS [c] += a [e].c [c];
    }

    BS [c] /= popSize;
  }
}
//——————————————————————————————————————————————————————————————————————————————

Для обновления наилучших индивидуальных решений добавим код в метод "Revision" в класс модифицированной версии "C_AO_AOSm".

//——————————————————————————————————————————————————————————————————————————————
// Метод пересмотра лучших решений
void C_AO_AOSm::Revision ()
{
  int bestIndex = -1;

  // Поиск лучшего решения в текущей итерации
  for (int i = 0; i < popSize; i++)
  {
    // Обновление глобального лучшего решения
    if (a [i].f > fB)
    {
      fB = a [i].f;
      bestIndex = i;
    }

    // Обновление персонального лучшего решения
    if (a [i].f > a [i].fB)
    {
      a [i].fB = a [i].f;
      ArrayCopy (a [i].cB, a [i].c, 0, 0, WHOLE_ARRAY);
    }
  }

  // Обновление лучших координат если найдено лучшее решение
  if (bestIndex != -1) ArrayCopy (cB, a [bestIndex].c, 0, 0, WHOLE_ARRAY);
}
//——————————————————————————————————————————————————————————————————————————————

В методе "UpdateElectrons" удалим переменные "β" и "γ", так как они не нужны для генерации соответствующих случайных чисел. Кроме того, исключим деление приращения электрона на количество слоев в случае перемещения в сторону глобального решения. Честно говоря, решение авторов выглядит спорным, и физический смысл этого подхода не совсем ясен. Возможно, авторы стремились сделать степень перемещения электронов в направлении глобального решения вариативной, изменяя её в зависимости от количества слоев: чем меньше слоев, тем интенсивнее должно быть перемещение (хотя мои эксперименты показали, что это ничего не дает).

//——————————————————————————————————————————————————————————————————————————————
// Обновление положения электронов
void C_AO_AOS::UpdateElectrons ()
{
  double α;      // коэффициент скорости
  double β;      // коэффициент веса лучшего решения
  double γ;      // коэффициент веса среднего состояния
  double φ;      // вероятность перехода
  double newPos; // новая позиция
  double LE;     // лучшая энергия
  double BSk;    // состояние связи
  int    lID;    // идентификатор слоя

  // Обработка каждой частицы
  for (int p = 0; p < popSize; p++)
  {
    for (int c = 0; c < coords; c++)
    {
      φ = u.RNDprobab ();

      if (φ < PR)
      {
        // Случайное рассеивание
        newPos = u.RNDfromCI (rangeMin [c], rangeMax [c]);
      }
      else
      {
        lID = electrons [p].layerID [c];

        α = u.RNDfromCI (-1.0, 1.0);
        β = u.RNDprobab ();
        γ = u.RNDprobab ();

        // Если текущая энергия частицы меньше средней энергии слоя
        if (a [p].f < atoms [c].layers [lID].BEk)
        {
          // Движение в сторону глобального оптимума----------------------------
          LE = cB [c];

          newPos = a [p].c [c]+ α * (β * LE - γ * BS [c]) / currentLayers [c];
        }
        else
        {
          // Движение в сторону локального оптимума слоя------------------------
          LE  = atoms [c].layers [lID].LEk;
          BSk = atoms [c].layers [lID].BSk;

          newPos = a [p].c [c] + α * (β * LE - γ * BSk);
        }
      }

      // Ограничение новой позиции в пределах диапазона поиска с учетом шага
      a [p].c [c] = u.SeInDiSp (newPos, rangeMin [c], rangeMax [c], rangeStep [c]);
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

Дополнительно в методе "UpdateElectrons" в классе "C_AO_AOSm" вместо случайного рассеивания электрона по пространству поиска реализуем перемещение электрона в центр ядра с некоторой вероятностью. По сути, это означает замену значения по какой-то координате на значение глобального решения, что должно повысить комбинаторные свойства алгоритма. А случайное рассеивание было призвано обеспечивать разнообразие в популяции решений, но это свойство обеспечивало распространение электронов по логнормальному распределению, где была ненулевая вероятность попадания электрона в любую точку пространства при перемещении.

Зеленым показаны изменения в формулах перемещения электронов, теперь приращение считается как разница между локальным лучшим решением слоя и индивидуальным лучшим решением электрона.

//——————————————————————————————————————————————————————————————————————————————
// Обновление положения электронов
void C_AO_AOSm::UpdateElectrons ()
{
  double α;      // коэффициент скорости
  double φ;      // вероятность перехода
  double newPos; // новая позиция
  double LE;     // лучшая энергия
  double BSk;    // состояние связи
  int    lID;    // идентификатор слоя

  // Обработка каждой частицы
  for (int p = 0; p < popSize; p++)
  {
    for (int c = 0; c < coords; c++)
    {
      φ = u.RNDprobab ();

      if (φ < PR)
      {
        // Случайный переход к центру
        newPos = cB [c];
      }
      else
      {
        lID = electrons [p].layerID [c];

        α = u.RNDfromCI (-1.0, 1.0);

        // Если текущая энергия частицы меньше средней энергии слоя
        if (a [p].f < atoms [c].layers [lID].BEk)
        {
          // Движение в сторону глобального оптимума----------------------------
          LE     = cB [c];

          newPos = a [p].cB [c]+ α * (LE - a [p].cB [c]);
        }
        else
        {
          // Движение в сторону локального оптимума слоя------------------------
          LE     = atoms [c].layers [lID].LEk;

          newPos = a [p].cB [c]+ α * (LE - a [p].cB [c]);
        }
      }

      // Ограничение новой позиции в пределах диапазона поиска с учетом шага
      a [p].c [c] = u.SeInDiSp (newPos, rangeMin [c], rangeMax [c], rangeStep [c]);
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

Метод "DistributeParticles" распределяет электроны в пространстве поиска, используя логнормальное распределение для каждой координаты. Для каждой частицы и каждой координаты вызывается функция, которая генерирует позицию с учетом заданных параметров (среднее, минимальное и максимальное значения, пик), а затем применяется дополнительная функция для корректировки позиции в заданном диапазоне.

//——————————————————————————————————————————————————————————————————————————————
// Распределение частиц в пространстве поиска
void C_AO_AOS::DistributeParticles ()
{
  for (int i = 0; i < popSize; i++)
  {
    for (int c = 0; c < coords; c++)
    {
      // Используем логнормальное распределение для позиционирования частиц
      a [i].c [c] = u.LognormalDistribution (cB [c], rangeMin [c], rangeMax [c], peakPosition);
      a [i].c [c] = u.SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

Мы изменим распределение электронов на нормальное. В этом распределении используется среднеквадратичное отклонение, равное 8. Хотя этот параметр можно было бы сделать внешним для алгоритма, я решил не делать этого. Меньшие значения способствуют более широкому исследованию пространства поиска, тогда как более высокие значения повышают точность сходимости при уточнении глобального решения.

//——————————————————————————————————————————————————————————————————————————————
// Распределение частиц в пространстве поиска
void C_AO_AOSm::DistributeParticles ()
{
  for (int i = 0; i < popSize; i++)
  {
    for (int c = 0; c < coords; c++)
    {
      // Используем гауссово распределение для позиционирования частиц
      a [i].c [c] = u.GaussDistribution (cB [c], rangeMin [c], rangeMax [c], 8);
      a [i].c [c] = u.SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

Были проанализированы все изменения, внесенные в оригинальную версию алгоритма AOS, с целью повышения его эффективности. Поскольку в логику поисковой стратегии были внесены значительные изменения, модифицированную версию алгоритма можно обозначить буквой "m". В дальнейшем в рейтинговой таблице будет представлена только одна модифицированная версия — AOSm.


Пример использования алгоритмов класса C_AO

Поскольку все популяционные алгоритмы оптимизации, рассмотренные ранее, унаследованы от общего класса C_AO, это позволяет использовать их единообразно и с минимальными усилиями для решения различных задач, требующих подбора оптимальных параметров. В приведенном ниже примере представлен скрипт, в котором осуществляется оптимизация целевой функции:

1. В начале скрипта вы можете выбрать, какой алгоритм оптимизации использовать. Если ничего не выбрано, скрипт сообщит об ошибке и остановится.
2. Настройка параметров. Скрипт определяет, сколько раз будет запускаться функция, сколько параметров нужно оптимизировать, размер группы решений и сколько итераций будет выполнено.
3. Границы значений. Для каждого параметра устанавливаются минимальные и максимальные значения (в данном примере от -10 до 10).
4. Скрипт начинает процесс оптимизации:

  • Он генерирует решения (наборы параметров) и проверяет, насколько они хороши, используя специальную функцию (целевую функцию).
  • На каждой итерации алгоритм обновляет свои решения, основываясь на том, какие из них показали лучшие результаты.

5. Результаты. После завершения оптимизации, скрипт выводит информацию о том, какой алгоритм использовался, какое лучшее значение было найдено, и сколько раз функция была запущена.
6. Целевая функция — это абстрактная задача оптимизации (в данном примере используется решение задачи поиска глобального максимума перевернутой параболы), которая принимает параметры и возвращает оценку их качества.

#property script_show_inputs                           // Указывает, что скрипт будет показывать входные параметры в окне свойств

#include <Math\AOs\PopulationAO\#C_AO_enum.mqh>        // Подключение библиотеки для работы с алгоритмами оптимизации

input E_AO AOexactly = NONE_AO;                        // Параметр для выбора алгоритма оптимизации, по умолчанию - NONE_AO

//——————————————————————————————————————————————————————————————————————————————
void OnStart()
{
  //----------------------------------------------------------------------------
  int numbTestFuncRuns = 10000;                        // Общее количество запусков тестовой функции
  int params           = 1000;                         // Количество параметров для оптимизации
  int popSize          = 50;                           // Размер популяции для алгоритма оптимизации
  int epochCount       = numbTestFuncRuns / popSize;   // Общее количество эпох (итераций) для оптимизации
  
  
  double rangeMin [], rangeMax [], rangeStep [];       // Массивы для хранения границ и шагов параметров
  
  ArrayResize (rangeMin,  params);                     // Изменение размера массива min границ
  ArrayResize (rangeMax,  params);                     // Изменение размера массива max границ
  ArrayResize (rangeStep, params);                     // Изменение размера массива шагов
  
  // Инициализация границ и шагов для каждого параметра
  for (int i = 0; i < params; i++)
  {
    rangeMin  [i] = -10;                               // Минимальное значение параметра
    rangeMax  [i] =  10;                               // Максимальное значение параметра
    rangeStep [i] =  DBL_EPSILON;                      // Шаг для параметра
  }
  
  //----------------------------------------------------------------------------
  C_AO *ao = SelectAO (AOexactly);                     // Выбор алгоритма оптимизации
  if (ao == NULL)                                      // Проверка, был ли выбран алгоритм
  {
    Print ("AO не выбран...");                         // Сообщение об ошибке, если алгоритм не выбран
    return;
  }
  
  ao.params [0].val = popSize;                         // Назначение размера популяции....
  ao.SetParams ();                                     //... (необязательно, тогда будет использован размер популяции по умолчанию)
  
  
  ao.Init (rangeMin, rangeMax, rangeStep, epochCount); // Инициализация алгоритма с заданными границами и количеством эпох
  
  // Основной цикл по количеству эпох
  for (int epochCNT = 1; epochCNT <= epochCount; epochCNT++)
  {
    ao.Moving ();                                      // Выполнение одной эпохи алгоритма оптимизации

    // Вычисление значения целевой функции для каждого решения в популяции
    for (int set = 0; set < ArraySize (ao.a); set++)
    {
      ao.a [set].f = ObjectiveFunction (ao.a [set].c); // Применение целевой функции к каждому решению
    }

    ao.Revision ();                                    // Обновление популяции на основе результатов целевой функции
  }
  
  //----------------------------------------------------------------------------
  // Вывод имени алгоритма, лучшего результата и количества запусков функции
  Print (ao.GetName (), ", best result: ", ao.fB, ", number of function launches: ", numbTestFuncRuns);
  
  delete ao;                                           // Освобождение памяти, занятой объектом алгоритма
}
//——————————————————————————————————————————————————————————————————————————————

//——————————————————————————————————————————————————————————————————————————————
// Определение целевой функции пользователя, в данном случае как пример - параболоид, F(Xn) ∈ [0.0; 1.0], X ∈ [-10.0; 10.0], максимизация
double ObjectiveFunction (double &x [])
{
  double sum = 0.0;  // Переменная для накопления результата

  // Цикл по всем параметрам
  for (int i = 0; i < ArraySize (x); i++)
  {
    // Проверка, находится ли параметр в допустимом диапазоне
    if (x [i] < -10.0 || x [i] > 10.0) return 0.0;  // Если параметр вне диапазона, возвращаем 0
    sum += (-x [i] * x [i] + 100.0) * 0.01;         // Вычисление значения целевой функции
  }
  
  return sum /= ArraySize (x);
}
//——————————————————————————————————————————————————————————————————————————————


Результаты тестов

Перейдем к тестированию модифицированной версии алгоритма.

AOS|Atomic Orbital Search|50.0|10.0|20.0|0.1|
=============================
5 Hilly's; Func runs: 10000; result: 0.8023218355650774
25 Hilly's; Func runs: 10000; result: 0.7044908398821188
500 Hilly's; Func runs: 10000; result: 0.3102116882841442
=============================
5 Forest's; Func runs: 10000; result: 0.8565993699987462
25 Forest's; Func runs: 10000; result: 0.6945107796904211
500 Forest's; Func runs: 10000; result: 0.21996085558228406
=============================
5 Megacity's; Func runs: 10000; result: 0.7461538461538461
25 Megacity's; Func runs: 10000; result: 0.5286153846153846
500 Megacity's; Func runs: 10000; result: 0.1435846153846167
=============================
All score: 5.00645 (55.63%)

Как можно заметить, результаты модифицированной версии значительно улучшились по сравнению с предыдущими показателями оригинальной версии, где общий балл составил 3.00488 (33.39%). Это улучшение становится очевидным при анализе визуализации, которая демонстрирует не только улучшение сходимости, но и более детальную проработку значимых экстремумов.

Одним из ключевых аспектов, который стоит отметить, является эффект "кучкования" решений по отдельным координатам. Этот феномен наблюдается как в оригинальной версии, так и в модифицированной, что подчеркивает характерную особенность алгоритмов AOS. "Кучкование" решений может свидетельствовать о том, что алгоритм эффективно находит области, где расположены потенциальные оптимальные решения.

Hilly

AOSm на тестовой функции Hilly

Forest

AOSm на тестовой функции Forest

Megacity

  AOSm на тестовой функции Megacity

Модифицированная версия алгоритма Atomic Orbital Search (AOS) значительно улучшила свои показатели по сравнению с оригинальной версией и теперь достигает более 55% от максимально возможного. Это действительно впечатляющий результат! В рейтинговой таблице алгоритм занимает 12-е место, в ее верхней части, что говорит о весьма достойных результатах.

AO Description Hilly Hilly final Forest Forest final Megacity (discrete) Megacity final Final result % of MAX
10 p (5 F)50 p (25 F)1000 p (500 F)10 p (5 F)50 p (25 F)1000 p (500 F)10 p (5 F)50 p (25 F)1000 p (500 F)
1ANSacross neighbourhood search0,949480,847760,438572,235811,000000,923340,399882,323230,709230,634770,230911,574916,13468,15
2CLAcode lock algorithm (joo)0,953450,871070,375902,200420,989420,917090,316422,222940,796920,693850,193031,683806,10767,86
3AMOmanimal migration ptimization M0,903580,843170,462842,209590,990010,924360,465982,380340,567690,591320,237731,396755,98766,52
4(P+O)ES(P+O) evolution strategies0,922560,881010,400212,203790,977500,874900,319452,171850,673850,629850,186341,490035,86665,17
5CTAcomet tail algorithm (joo)0,953460,863190,277702,094350,997940,857400,339492,194840,887690,564310,105121,557125,84664,96
6SDSmstochastic diffusion search M0,930660,854450,394762,179880,999830,892440,196192,088460,723330,611000,106701,441035,70963,44
7AAmarchery algorithm M0,917440,708760,421602,047800,925270,758020,353282,036570,673850,552000,237381,463235,54861,64
8ESGevolution of social groups (joo)0,999060,796540,350562,146161,000000,828630,131021,959650,823330,553000,047251,423585,52961,44
9SIAsimulated isotropic annealing (joo)0,957840,842640,414652,215130,982390,795860,205071,983320,686670,493000,090531,270205,46960,76
10ACSartificial cooperative search0,755470,747440,304071,806981,000000,888610,224132,112740,690770,481850,133221,305835,22658,06
11ASOanarchy society optimization0,848720,746460,314651,909830,961480,791500,238031,991010,570770,540620,166141,277525,17857,54
12AOSmatomic orbital search M0,802320,704490,310211,817020,856600,694510,219961,771070,746150,528620,143581,418355,00655,63
13TSEAturtle shell evolution algorithm (joo)0,967980,644800,296721,909490,994490,619810,227081,841390,690770,426460,135981,253225,00455,60
14DEdifferential evolution0,950440,616740,303081,870260,953170,788960,166521,908650,786670,360330,029531,176534,95555,06
15CROchemical reaction optimisation0,946290,661120,298531,905930,879060,584220,211461,674730,758460,426460,126861,311784,89254,36
16BSAbird swarm algorithm0,893060,649000,262501,804550,924200,711210,249391,884790,693850,326150,100121,120124,80953,44
17HSharmony search0,865090,687820,325271,878180,999990,680020,095901,775920,620000,422670,054581,097254,75152,79
18SSGsaplings sowing and growing0,778390,649250,395431,823080,859730,624670,174291,658690,646670,441330,105981,193984,67651,95
19BCOmbacterial chemotaxis optimization M0,759530,622680,314831,697040,893780,613390,225421,732590,653850,420920,144351,219124,64951,65
20ABOafrican buffalo optimization0,833370,622470,299641,755480,921700,586180,197231,705110,610000,431540,132251,173784,63451,49
21(PO)ES(PO) evolution strategies0,790250,626470,429351,846060,876160,609430,195911,681510,590000,379330,113221,082554,61051,22
22TSmtabu search M0,877950,614310,291041,783300,928850,518440,190541,637830,610770,382150,121571,114494,53650,40
23BSObrain storm optimization0,937360,576160,296881,810410,931310,558660,235371,725340,552310,290770,119140,962224,49849,98
24WOAmwale optimization algorithm M0,845210,562980,262631,670810,931000,522780,163651,617430,663080,411380,113571,188034,47649,74
25AEFAartificial electric field algorithm0,877000,617530,252351,746880,927290,726980,180641,834900,666150,116310,095080,877544,45949,55
26AEOartificial ecosystem-based optimization algorithm0,913800,467130,264701,645630,902230,437050,214001,553270,661540,308000,285631,255174,45449,49
27ACOmant colony optimization M0,881900,661270,303771,846930,858730,586800,150511,596040,596670,373330,024720,994724,43849,31
28BFO-GAbacterial foraging optimization - ga0,891500,551110,315291,757900,969820,396120,063051,428990,726670,275000,035251,036924,22446,93
29ABHAartificial bee hive algorithm0,841310,542270,263041,646630,878580,477790,171811,528180,509230,338770,103970,951974,12745,85
30ACMOatmospheric cloud model optimization0,903210,485460,304031,692700,802680,378570,191781,373030,623080,244000,107950,975034,04144,90
31ASHAartificial showering algorithm0,896860,404330,256171,557370,803600,355260,191601,350460,476920,181230,097740,755893,66440,71
32ASBOadaptive social behavior optimization0,763310,492530,326191,582020,795460,400350,260971,456770,264620,171690,182000,618313,65740,63
33MECmind evolutionary computation0,695330,533760,326611,555690,724640,330360,071981,126980,525000,220000,041980,786983,47038,55
34IWOinvasive weed optimization0,726790,522560,331231,580580,707560,339550,074841,121960,423330,230670,046170,700173,40337,81
35Micro-AISmicro artificial immune system0,795470,519220,308611,623300,729560,368790,093981,192330,376670,158670,028020,563353,37937,54
36COAmcuckoo optimization algorithm M0,758200,486520,313691,558410,740540,280510,055991,077040,505000,174670,033800,713473,34937,21
37SDOmspiral dynamics optimization M0,746010,446230,296871,489120,702040,346780,109441,158260,428330,167670,036630,632633,28036,44
38NMmNelder-Mead method M0,738070,505980,313421,557470,636740,283020,082211,001970,446670,186670,040280,673623,23335,92
39FAmfirefly algorithm M0,586340,472280,322761,381380,684670,374390,109081,168140,286670,164670,047220,498553,04833,87
40GSAgravitational search algorithm0,647570,491970,300621,440160,539620,363530,099451,002600,326670,122000,019170,467832,91132,34
41BFObacterial foraging optimization0,611710,432700,313181,357590,544100,215110,056760,815970,421670,138000,031950,591622,76530,72
42ABCartificial bee colony0,633770,424020,308921,366710,551030,218740,056230,826000,340000,142000,031020,513022,70630,06
43BAbat algorithm0,597610,459110,352421,409150,403210,193130,071750,668100,210000,101000,035170,346172,42326,93
44AAAalgae adaptive algorithm0,500070,320400,255251,075720,370210,222840,167850,760890,278460,148000,097550,524022,36126,23
45SAsimulated annealing0,557870,421770,315491,295130,349980,152590,050230,552800,311670,100330,028830,440832,28925,43


Выводы

В данной статье была представлена модифицированная версия алгоритма атомарного орбитального поиска (AOSm), в которой я отказался от усредненного положения электронов BSk в слоях атома в пользу индивидуального лучшего положения каждого электрона. Это позволило электронам более эффективно двигаться в сторону наилучшего решения в своем слое, основываясь на личном достижении, а не на усредненном значении. Кроме того, были исключены два случайных компонента βi и γi, что сократило время на генерацию случайных чисел в три раза, не теряя при этом физического смысла алгоритма.

В методе "UpdateElectrons" были удалены теперь ненужные переменные и исключены деления приращения электрона на количество слоев при перемещении к глобальному решению. Хотя авторы оригинальной версии, возможно, стремились сделать степень перемещения вариативной, мои эксперименты показали, что это не приносит значительных преимуществ.

Также были внедрены изменения в метод "UpdateElectrons" в классе "C_AO_AOSm", заменив случайное рассеивание электрона на перемещение к центру ядра с определенной вероятностью. Это повысило комбинаторные свойства алгоритма, позволяя электронам более точно нацеливаться на глобальное решение. Было также заменено логнормальное распределение на нормальное, что увеличило точность сходимости при уточнении глобального решения.

Результаты модифицированной версии AOSm показали значительное улучшение, с общим баллом, превышающим 55% от максимально возможного, что подтверждает высокую эффективность и конкурентоспособность алгоритма. В рейтинговой таблице AOSm занимает 12-е место, что свидетельствует о его значительных достижениях среди других методов оптимизации.

Одним из наиболее заметных аспектов AOSm является улучшение сходимости, которое стало очевидным при визуализации результатов. Алгоритм более детально прорабатывает значимые экстремумы и демонстрирует способность к эффективному поиску оптимальных решений в сложных многомерных пространствах. Эффект "кучкования" решений, наблюдаемый как в оригинальной, так и в модифицированной версиях, подчеркивает способность алгоритма находить и сосредотачиваться на областях с потенциальными оптимумами, что особенно полезно в задачах с высокой размерностью и сложной структурой.

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

Tab

Рисунок 2. Цветовая градация алгоритмов по соответствующим тестам. Белым цветом подсвечены результаты больше или равные 0.99

chart

Рисунок 3. Гистограмма результатов тестирования алгоритмов (по шкале от 0 до 100, чем больше, тем лучше,

где 100 - максимально возможный теоретический результат, в архиве скрипт для расчета рейтинговой таблицы)


Плюсы и минусы алгоритма AOSm:

Плюсы:

  1. Хорошая результативность на различных задачах.
  2. Малое количество внешних параметров.
  3. Хорошая масштабируемость.
  4. Сбалансированный поиск и по локальным экстремумам и глобального.

Минусы:

  1. Достаточно сложная реализация.
  2. Средняя по отношению к другим алгоритмам точность сходимости на гладких функциях.

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

Программы, используемые в статье

#ИмяТипОписание
1#C_AO.mqh
Включаемый файл
Родительский класс популяционных алгоритмов оптимизации
2#C_AO_enum.mqh
Включаемый файл
Перечисление популяционных алгоритмов оптимизации
3TestFunctions.mqh
Включаемый файл
Библиотека тестовых функций
4
TestStandFunctions.mqh
Включаемый файл
Библиотека функций тестового стенда
5
Utilities.mqh
Включаемый файл
Библиотека вспомогательных функций
6
CalculationTestResults.mqh
Включаемый файл
Скрипт для расчета результатов в сравнительную таблицу
7
Testing AOs.mq5
СкриптЕдиный испытательный стенд для всех популяционных алгоритмов оптимизации
8
Simple use of population optimization algorithms.mq5
Скрипт
Простой пример использования популяционных алгоритмов оптимизации без визуализации
9
AO_AOSm_AtomicOrbitalSearch.mqh
Включаемый файлКласс алгоритма AOSm
10
Test_AO_AOSm.mq5
Скрипт
Испытательный стенд для AOSm
Прикрепленные файлы |
AOSm.ZIP (137.09 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (5)
Evgeniy Chernish
Evgeniy Chernish | 15 нояб. 2024 в 11:51

Благодарю за статью!

Посидел я немного вчера и сегодня над функцией Hilly и алглибовскими  методами. И вот какие мысли.

Для того что бы найти максимум данной функции, особенно когда количество параметров от 10 и больше бессмысленно применять градиентные методы, это задача комбинаторных методов оптимизации. Градиентные просто мгновенно застревают в локальном экстремуме. И не имеет значение сколько раз делать рестарт из новой точки пространства параметров, шанс попасть в нужную область пространства из которой градиентный метод мгновенно находит решение стремится к нулю с ростом количества параметров. 

Например, точка пространства из которой lbfgs или CG за 2(две) итерации находят максимум для любого количества параметров следующая  {x = -1,2 , y = 0.5}


lbfgs

Но шанс попасть в эту область как я уже сказал просто нулевой. Это нужно наверно лет сто случайные числа генерировать.

Поэтому нужно каким-то образом скомбинировать генетические алгоритмы представленные в статье (что бы они провели разведку, сократили пространство поиска)  с градиентными методами, которые бы уже далее быстро находили экстремум из более выгодной точки.

Andrey Dik
Andrey Dik | 15 нояб. 2024 в 16:25
Evgeniy Chernish #:

Благодарю за статью!

Спасибо за отзыв.

Для того что бы найти максимум данной функции, особенно когда количество параметров от 10 и больше бессмысленно применять градиентные методы

Да, верно.

это задача комбинаторных методов оптимизации.

Комбинаторные, такие как классический "муравьиный", предназначены для проблем типа "задачи коммивояжера" и "задачи о рюкзаке", т.е, предназначены для дискретных задач с фиксированным шагом (ребро графа). Для многомерных "непрерывных" задач эти алгоритмы не предназначены совсем, например, для таких задач, как обучение нейронных сетей. Да, комбинаторные свойства очень полезны для стохастических эвристических методов, но не являются единственным и достаточным свойством для успешного решения подобных, приближенных к реальным, тестовым задачам. Важны ещё и сами поисковые стратегии в алго.

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

Да, так.

Но шанс попасть в эту область как я уже сказал просто нулевой. Это нужно наверно лет сто случайные числа генерировать.

Да, так. В маломерных пространствах (1-2) попасть в окрестности глобала очень просто, для этого даже могут сгодится простые рандомные генераторы. Но всё совершенно меняется, когда размерность задачи растет, здесь начинают играть важную роль именно поисковые свойства алгоритмов, а не Госпожа Удача.

Поэтому нужно каким-то образом скомбинировать генетические алгоритмы представленные в статье (что бы они провели разведку, сократили пространство поиска)  с градиентными методами, которые бы уже далее быстро находили экстремум из более выгодной точки.

"генетические" - наверное имеете ввиду "эвристические". А зачем "рыбке зонтик" и "а зачем нам кузнец? кузнец нам не нужен".))) Есть эффективные способы решения сложных многомерных в непрерывном пространстве задач, которые описаны в статьях о популяционных методах. А для классических градиентных есть свои задачи - одномерные аналитически определимые задачи (в этом им равных нет, там будет быстрая и точная сходимость).

И, вопрос, какие у Вас впечатления от скорости работы эвристики?

ЗЫ:

О сколько нам открытий чудных

Готовят просвещенья дух

И опыт, сын ошибок трудных,

И гений, парадоксов друг,

И случай, бог изобретатель.


ЗЗЫ. Один момент. В неизвестном пространстве поиска никогда невозможно знать в любой момент времени или шаге итерации, что это на самом деле действительно перспективное направление в сторону глобала. Поэтому невозможно сначала разведать, а потом уточнять. Могут работать только цельные стратегии поиска, они либо работают хорошо, либо плохо. Степень "хорошести" и "пригодности для задачи" каждый выбирает сам, для этого ведется рейтинговая таблица, чтобы выбирать алгоритм по специфике задачи.

Evgeniy Chernish
Evgeniy Chernish | 15 нояб. 2024 в 16:53
Andrey Dik #:
Да, так. В маломерных пространствах (1-2) попасть в окрестности глобала очень просто, для этого даже могут сгодится простые рандомные генераторы. Но всё совершенно меняется, когда размерность задачи растет, здесь начинают играть важную роль именно поисковые свойства алгоритмов, а не Госпожа Удача.

Так они же не справляются

Andrey Dik #:
И, вопрос, какие у Вас впечатления от скорости работы эвристики?

несмотря на то что работают быстро. Результат для 1000 параметров что-то около 0,4.

Вот поэтому я чисто интуитивно подумал, что есть смысл комбинировать ГА и градиентные методы, что бы добраться до максимума. Иначе по отдельности они вашу функцию не разгадают. На практике не проверял.


P.S. Все-таки считаю что данная функция слишком сгущает краски, в реальных задача(обучение нейросетей например) таких проблем нет, хотя там тоже поверхность ошибок вся в локальных минимумах. 

Andrey Dik
Andrey Dik | 15 нояб. 2024 в 18:47
Evgeniy Chernish #:

1. Так они же не справляются

2. несмотря на то что работают быстро. Результат для 1000 параметров что-то около 0,4.

3. Вот поэтому я чисто интуитивно подумал, что есть смысл комбинировать ГА и градиентные методы, что бы добраться до максимума. Иначе по отдельности они вашу функцию не разгадают. На практике не проверял.

4. P.S. Все-таки считаю что данная функция слишком сгущает краски, в реальных задача(обучение нейросетей например) таких проблем нет, хотя там тоже поверхность ошибок вся в локальных минимумах. 

1. Что значит "не справляются"? Есть ограничение на число обращений к целевой функции, кто показал лучше результат - того и тапки.)) Увеличивать количество разрешенных обращений? Ну тогда все равно придут к финишу более проворные и приспособленные к сложным функциям. Попробуйте увеличивать обращения, картина не изменится.

2. Да. А у кого-то 0.3, а у других 0.2, а у третьих 0.001. Лучше те, кто показал 0.4.

3. Не поможет, интуитивно было пробовано и перепробовано сотни комбинаций и вариаций. Лучше тот, кто показывает лучше результат за заданное количество эпох (итераций). Увеличивайте количество обращений к целевой, увидите кто из них достигнет финиша первым.

4. Если на сложных задачах есть лидеры, то считаете, что на легких задачах лидеры покажут результаты хуже чем аутсайдеры? Это не так, мягко говоря. Работаю над более "простой" но реалистичной задачей по обучению сеток. Результатами буду делится, как всегда. Будет интересно.


Просто экспериментируйте, пробуйте разные алгоритмы, разные задачи, не зацикливайтесь на чем-то одном. Весь инструментарий я постарался предоставить для этого.

Evgeniy Chernish
Evgeniy Chernish | 15 нояб. 2024 в 19:18
Andrey Dik #:

1. Что значит "не справляются"? Есть ограничение на число обращений к целевой функции, кто показал лучше результат - того и тапки.)) Увеличивать количество разрешенных обращений? Ну тогда все равно придут к финишу более проворные и приспособленные к сложным функциям. Попробуйте увеличивать обращения, картина не изменится.

2. Да. А у кого-то 0.3, а у других 0.2, а у третьих 0.001. Лучше те, кто показал 0.4.

3. Не поможет, интуитивно было пробовано и перепробовано сотни комбинаций и вариаций. Лучше тот, кто показывает лучше результат за заданное количество эпох (итераций). Увеличивайте количество обращений к целевой, увидите кто из них достигнет финиша первым.

4. Если на сложных задачах есть лидеры, то считаете, что на легких задачах лидеры покажут результаты хуже чем аутсайдеры? Это не так, мягко говоря. Работаю над более "простой" но реалистичной задачей по обучению сеток. Результатами буду делится, как всегда. Будет интересно.


Просто экспериментируйте, пробуйте разные алгоритмы, разные задачи, не зацикливайтесь на чем-то одном. Весь инструментарий я постарался предоставить для этого.

да вот экспериментирую, 

ANS

Про реалистичную задачу это правильно, проверить алгоритмы на задачах приближенных к боевым.

Вдвойне интересно посмотреть как сети на генетике будут обучаться.

Нейросети в трейдинге: Повышение эффективности Transformer путем снижения резкости (SAMformer) Нейросети в трейдинге: Повышение эффективности Transformer путем снижения резкости (SAMformer)
Обучение моделей Transformer требует больших объемов данных и часто затруднено из-за слабой способности моделей к обобщению на малых выборках. Фреймворк SAMformer помогает решить эту проблему, избегая плохих локальных минимумов. И повышает эффективность моделей даже на ограниченных обучающих выборках.
Объемный нейросетевой анализ как ключ к будущим трендам Объемный нейросетевой анализ как ключ к будущим трендам
Статья исследует возможность улучшения прогнозирования цен на основе анализа объема торгов, интегрируя принципы технического анализа с архитектурой LSTM нейронных сетей. Особое внимание уделяется выявлению и интерпретации аномальных объемов, использованию кластеризации и созданию признаков на основе объемов и их определения в контексте машинного обучения.
Изучение MQL5 — от новичка до профи (Часть VI):  Основы написания советников Изучение MQL5 — от новичка до профи (Часть VI): Основы написания советников
Статья продолжает цикл для начинающих. Здесь будут рассмотрены основные принципы построения советников. Мы создадим два советника: первый будет торговать без индикаторов, отложенными ордерами, второй — на основе стандартного индикатора MA, торгующий с помощью сделок по текущей цене. Здесь я предполагаю, что вы уже не совсем новичок и владеете материалом предыдущих статей относительно свободно.
Нейросети в трейдинге: Оптимизация Transformer для прогнозирования временных рядов (LSEAttention) Нейросети в трейдинге: Оптимизация Transformer для прогнозирования временных рядов (LSEAttention)
Фреймворк LSEAttention предлагает пути совершенствования архитектуры Transformer, и был разработан специально для долгосрочного прогнозирования многомерных временных рядов. Предложенные авторами метода подходы позволяют решить проблемы энтропийного коллапса и нестабильности обучения, характерные для ванильного Transformer.