2015-07-10

Система адаптивного нейро-нечеткого вывода на C#

Захотелось мне поделиться своей наработкой из области машинного обучения - ANFIS. Реализаций этого дела существует достаточно много, да и вещь, в общем-то, довольно стандартная. Тем не менее, мне не доводилось встречать подобных решений на C#. Более того, классическая схема реализации ANFIS имеет весьма существенные недостатки при решении задач высокой размерности - растет база правил и падает производительность системы в целом. Чтобы нивелировать этот аспект, я при реализации ANFIS использую схему с одним нечетким высказыванием и многомерные функции принадлежности.

Сразу приведу ссылку на 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 в примере выше) с помощью метода обратного распространения ошибки.

Для того, чтобы все заработало нужно

  1. Определить обучающую выборку из пар входных и выходных значений.
  2. Проинициализировать нечеткие правила системы с помощью обычной кластеризации.
  3. Откорректировать нечеткие правила с помощью метода обратного распространения ошибки.
Проще всего показать как это работает на примере предсказаний следующего шага логистического отображения по предыдущим двум:
///Зададим размер обучающей выборки
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);