Захотелось мне поделиться своей наработкой из области машинного обучения - ANFIS. Реализаций этого дела существует достаточно много, да и вещь, в общем-то, довольно стандартная. Тем не менее, мне не доводилось встречать подобных решений на C#. Более того, классическая схема реализации ANFIS имеет весьма существенные недостатки при решении задач высокой размерности - растет база правил и падает производительность системы в целом. Чтобы нивелировать этот аспект, я при реализации ANFIS использую схему с одним нечетким высказыванием и многомерные функции принадлежности.
Сразу приведу ссылку на github.
Для тех, кто не в теме, на хабре есть замечательная статья, которая объясняет основные принципы нечетких систем вывода. Тут я опишу лишь особенности своей реализации.
Как известно, нечеткий вывод представляет собой систему правил вида
Главной особенностью данной реализации является процедура вычисления значения функции принадлежности μi(х)=μi, на вход которой подается весь входной вектор x. К примеру, гауссовская функция принадлежности в такой схеме имеет вид:
Адаптивность вышеприведенной системы проявляется в том, что возможна корректировка заключений ki0 и параметров функций принадлежности (ci и ai в примере выше) с помощью метода обратного распространения ошибки.
Для того, чтобы все заработало нужно
Сразу приведу ссылку на github.
Для тех, кто не в теме, на хабре есть замечательная статья, которая объясняет основные принципы нечетких систем вывода. Тут я опишу лишь особенности своей реализации.
Как известно, нечеткий вывод представляет собой систему правил вида
if x is Ai then y is Bi, (μi),где x - это входное значение (скаляр или вектор), Ai - нечеткое множество, на принадлежность к которому проверяется х, y - выходное значение системы, Bi это следствие для i-ого правила, а μi это весовой коэффициент, обозначающий степень уверенности в заключении i-ого правила. Я использую вывод Такаги-Сугено нулевого порядка, поэтому выражение для Bi имеет вид
Bi=ki0Чуть позже планирую перейти на вывод Такаги-Сугено первого порядка, однако сути это особо не поменяет.
Главной особенностью данной реализации является процедура вычисления значения функции принадлежности μi(х)=μi, на вход которой подается весь входной вектор x. К примеру, гауссовская функция принадлежности в такой схеме имеет вид:
μi(х)=e-||x-ci||ai-2,где ci - центроид, вектор той же размерности, что и входной вектор х, a ai это масштабирующий параметр. Определение нечетких переменных таким образом означает, что пространство входных векторов x разбивается на кластеры, положение которых зависит от центроидов и параметров соответствующих функций принадлежности.
Адаптивность вышеприведенной системы проявляется в том, что возможна корректировка заключений ki0 и параметров функций принадлежности (ci и ai в примере выше) с помощью метода обратного распространения ошибки.
Для того, чтобы все заработало нужно
- Определить обучающую выборку из пар входных и выходных значений.
- Проинициализировать нечеткие правила системы с помощью обычной кластеризации.
- Откорректировать нечеткие правила с помощью метода обратного распространения ошибки.
Проще всего показать как это работает на примере предсказаний следующего шага логистического отображения по предыдущим двум:
///Зададим размер обучающей выборки int trainingSamples = 2000; double[][] x = new double[trainingSamples][];///входные значения double[][] y = new double[trainingSamples][];///выходные значения double px = 0.1; double r = 3.8; double lx = r * px * (1 - px); ///Генерируем обучающую выборку for (int i = 0; i < trainingSamples; i++) { x[i] = new double[] { px, lx }; px = lx; lx = r * lx * (1 - lx); y[i] = new double[] { lx }; } ///Инициализируем алгоритм обучения Backprop bprop = new Backprop(1e-2); ///Создаем кластеризатор для инициализации нечетких правил KMEANSExtractorIO extractor = new KMEANSExtractorIO(10); ///Собираем все вместе для получения готовой к употреблению ANFIS ANFIS fis = ANFISFActory<gaussianrule>.Build(x, y, extractor, bprop, 1000); ///[Backprop - GaussianRule] Error 0,0006908 Elapsed 00:00:31 RuleBase 10Все, теперь мы можем пользоваться обученной ANFIS следующим образом
double[] y = fis.Inference(x);