Занятие 12. Символьная регрессия и автоматическое дифференцирование • • • • • Краткое содержание Понятие символьной регрессии Синтаксические деревья и обратная польская запись Понятие генетического алгоритма Символьная регрессия: практический пример Дуальные числа и автоматическое дифференцирование Часть 1. Символьная регрессия Символьная регрессия - метод построения регрессионных моделей путём перебора суперпозиций заранее заданного набора функций Достоинства: 1. Возможно использовать в том случае, когда неизвестен вид модели Недостатки: 1. Ресурсоёмкость 2. Нередко полученные модели избыточно сложны Для поиска оптимальной модели применяют так называемые генетические алгоритмы. Привычная для нас запись формул сложна и неудобна для использования в генетических алгоритмах (из-за разного приоритета операций, скобок и т.п.) Синтаксическое дерево 𝒚= • Обычно получают в ходе синтаксического анализа формул • Не требуется задание приоритета операций в самом дереве • Расчёт с помощью рекурсии (т.е. спуск по поддеревьям) 𝒙𝟐 − 𝟑𝒙 + 𝟐 + − 𝟐 ^ 𝒙 ∗ 𝟐 𝟑 𝒙 Обратная польская запись Обратная польская (постфиксная) запись 3 5 + 2 * 6 7 + 8 9 - / - Традиционная (инфиксная) запись 2*(3+5) – (6+7)/(8-9) Вычисление выражения Вычисление выражения Вход Стек 3 5 + 2 * 6 7 + 8 9 - / 3 5 Вход Стек + 2 * 6 7 + 8 9 - / 8 2 Вход Стек * 6 7 + 8 9 - / 16 6 7 Вход Стек + 8 9 - / 16 13 8 9 Вход Стек - / 16 13 -1 Вход Стек / 16 -13 Вход Стек 29 3+5 = 8; 8*2 = 16 6+7 = 13; 8-9 = -1 13/-1 = -13; 16 – (-13) = 29 Особенности обратной польской записи: • У операций отсутствует приоритет • Не нужны скобки • Все операции записываются единообразно Особенности работы со стеком 1. Новые значения добавляются на его вершину 2. Операции берут значения с вершины стека и помещают результат на вершину Генетические алгоритмы Генетические алгоритмы – алгоритмы нелинейной оптимизации. Ключевые характеристики: • Работа с большим количеством потенциальных решений («популяцией») • Использование целевой функции для отбора членов популяции • Получение новых членов популяции операциями «скрещивания» (комбинированием) и «мутациями» (случайные изменения) Ср. с процессом эволюции в живой природе (идея генетического алгоритма была взята именно из биологии) Генерация исходной (случайной) популяции Отбор части популяции с использованием целевой функции ДА Желаемый результат достигнут? НЕТ Вернуть результат Получение недостающей части популяции скрещиванием и мутациями Пример символьной регрессии Базовые операции Скрещивание Поместить в стек x Поместить в стек число Сложение и вычитание Умножение и деление (в виде 𝑥/(𝑦 + 𝛿)) 5. Возведение в степень (в виде 𝑥 𝑦) 6. Унарный минус Шаг 1. Взять два случайных члена популяции Шаг 2. Разделить каждое выражение на две части и поменять их местами Внимание! Они должны возвращать корректный результат при любых входных данных! Шаг 3. Внести случайные изменения («мутации» в коэффициенты и операции) 1. 2. 3. 4. Члены популяции Выражения в обратной польской записи A B + C D C D / B A Результат A B + C / C D D + * + * => (A+B)*(C+D) ^ + => (C/D)+B^A B A ^ + => (A+B)/C+B^A => C*(D+D) Функция приспособленности 𝑅𝑆𝑆 = 𝑦𝑖 − 𝑦𝑖 𝑖 2 Пример символьной регрессии 𝑦 = 𝑥 2 − 2𝑥 + 3 Результат регрессии X [-1.0409] + U- [2.0115] ^ [3.8315] [0.3417] ^ [0.6995] / [0.6995] ^ + Упрощенный результат регрессии (X – 1.0409)^2.0115 + (3.8315^0.3417/0.6995)^0.6995 = = (X – 1.0409)^2.0115 + 1.7701 Часть 2. Автоматическое дифференцирование Дифференцирование функции Численное 𝑓 ′ (𝑥) ≈ 𝑓 𝑥 + Δ𝑥 − 𝑓(𝑥) Δ𝑥 Преимущества: • Нет ограничений на вид функции (напр., допустимы методы МонтеКарло, бисекции и т.п.) • Простота Недостатки: • Высокая погрешность Символьное Преобразование выражений Преимущества: • Низкая погрешность Недостатки: • Сложность • Функция должна быть одним выражением Автоматическое Использование дуальных чисел и особой арифметики Преимущества: • Низкая погрешность • Относительная простота • Допустимы циклы и ветвления в функции Недостатки: • Некоторые ограничения на вид функции Дуальные числа Пусть 𝜀 ≠ 0 такое, что 𝜀 2 = 0, а 𝑎 и 𝑏 – действительные числа. Тогда 𝑐 = 𝑎 + 𝑏𝜀 – дуальное число (англ. dual number) Арифметические действия над дуальными числами • • 𝑎 + 𝑏𝜀 + 𝑐 + 𝑑𝜀 = 𝑎 + 𝑐 + 𝑏 + 𝑑 𝜀 𝑎 + 𝑏𝜀 𝑐 + 𝑑𝜀 = 𝑎𝑐 + 𝑎𝑑𝜀 + 𝑏𝑐𝜀 + 𝑏𝑑𝜀 2 = 𝑎𝑐 + 𝑏𝑐 + 𝑎𝑑 𝜀 (𝑎+𝑏𝜀)(𝑐−𝑑𝜀) 𝑎𝑐−𝑎𝑑𝜀+𝑏𝑐𝜀−𝑏𝑑𝜀2 = = 2 (𝑐+𝑑𝜀)(𝑐−𝑑𝜀) 𝑐 −𝑐𝑑𝜀+𝑐𝑑𝜀−𝑑 2 𝜀 2 + 𝑏𝜀 𝑛 = exp 𝑛 ln 𝑎 + 𝑏𝜀 = exp • 𝑎+𝑏𝜀 𝑐+𝑑𝜀 • 𝑎 𝑎𝑐+ 𝑏𝑐−𝑎𝑑 𝜀 𝑎 𝑏𝑐−𝑎𝑑 = + 𝜀 𝑐2 𝑐 𝑐2 𝑛𝑏 𝑛 ln 𝑎 + 𝜀 = 𝑎𝑛 + 𝑏𝑎𝑛−1 𝜀 𝑎 = Функция от дуального числа 𝑓 𝑎 + 𝑏𝜀 = 𝑓 𝑎 + 𝑏𝑓 ′ 𝑎 ⋅ 𝜀 Доказательство: через ряд Тейлора 𝑓′ 𝑎 𝑓 ′′ 𝑎 𝑓 𝑎 + 𝑏𝜀 = 𝑓 𝑎 + 𝑏𝜀 + 1! 2! =0 𝑏𝜀 2 + ⋯ = 𝑓 𝑎 + 𝑏𝑓 ′ 𝑎 ⋅ 𝜀 Автоматическое дифференцирование Автоматическое дифференцирование сводится к арифметике дуальных чисел. Алгоритм нахождения частной производной: • Константы и параметры остаются действительными числами • Переменная, по которой ведется дифференцирование, заменяется 𝜕𝑥 дуальным числом: 𝑥 = 𝑥 (0) + 𝜀 (т.к. = 1). 𝜕𝑥 • Результат – дуальное число. Действительная часть – значение функции, мнимая (т.е. с 𝜀) – значение производной в точке 𝑥 (0) Пример 𝑓 𝑥 = 6 5𝑥 + 2 2 ; 𝑥 (0) = 2 Способ 1. Аналитический расчёт производной 𝑓 ′ 𝑥 = 60 5𝑥 + 2 = 300𝑥 + 120; 𝑓 ′ 𝑥 0 = 720 Способ 2. Автоматическое дифференцирование 6 5 2 + 𝜀 + 2 2 = 6 12 + 5𝜀 2 = 6 144 + 120𝜀 + 25𝜀 2 = 864 + 720 𝜀 =0 𝑓(2) 𝑓′(2) Автоматическое дифференцирование Программная реализация Преобразователи исходных текстов функций Преимущества: • Высокое быстродействие кода • Применимо к любому языку программирования Недостатки: • Автоматическая генерация кода • Низкая наглядность Введение дуальных чисел как типа данных Преимущества: • Простота и наглядность • Функции легко переделать вручную Недостатки: • Язык должен поддерживать ООП и перегрузку операторов (C++, MATLAB, Python, Ruby, Fortran-90 и др.) • Снижение скорости за счет пользовательского типа данных Понятие о классе в программировании Класс – тип данных, состоящий из полей (переменных) и методов (функций) classdef DualNumber % Имя класса properties % Поля класса a b end methods % Методы (функции) класса function obj = DualNumber(a, b) % Конструктор obj.a = a; obj.b = b; end function r = log(o1) % Метод; o1 – экземпляр класса r = DualNumber(builtin('log', o1.a), o1.b./o1.a); end function r = times(o1, o2) % Перегруженный оператор .* r = DualNumber(o1.a.*o2.a, o1.b.*o2.a + o1.a.*o2.b); end % … КОД ПРОПУЩЕН … end end Класс для автоматического дифференцирования Создание переменной >> x=DualNumber.CreateXValue(2) x = 1 x 1 DualNumber matrix (@ means epsilon) 2.0000+1.0000@ >> x.a 2 >> x.b 3 Нахождение производной >> 0.5.*(2.*x + 3).^4 1 x 1 DualNumber matrix (@ means epsilon) 1.00e+03 * 1.2005+1.3720@ >> 4*(2*2+3)^3 1372 Работа с матрицами >> x=DualNumber.CreateXValue([0.5 1; 1.5 2]) x = 2 x 2 DualNumber matrix (@ means epsilon) 0.5000+1.0000@ 1.0000+1.0000@ 1.5000+1.0000@ 2.0000+1.0000@ >> (2.*x+3).^(3.*x-1) ans = 2 x 2 DualNumber matrix (@ means epsilon) 1.00e+05 * 0.0000+0.0001@ 0.0003+0.0014@ 0.0053+0.0346@ 0.1681+1.2212@ Внимание! Требуется Octave 4.0 или выше или MATLAB 7.6 и выше (для classdef) Класс для автоматического дифференцирования xv = DualNumber.CreateXValue(-3:0.01:3); f = xv.^3; close all; plot(xv.a, f.b, 'k-', 'LineWidth', 2); hold on; plot(xv.a, f.a, 'r-', 'LineWidth', 2); hold off; legend('f''(x)', 'f(x)');