Пример #1
0
        /// <summary>
        /// Генерация базы правил на основе субстратной кластеризации
        /// </summary>
        private void Genfis()
        {
            //
            // Подготовка данных для кластеризации
            //
            int len = xin.Length + 1;                       // + 1, т.к. входные данне

            double[][] x = new double[len][];               // Создаем массив данных
            for (int i = 0; i < x.Length - 1; i++)          // Перебираем массивы
            {
                x[i] = xin[i];
            }
            x[x.Length - 1] = xout;

            //
            // Кластеризация данных
            //

            SubtractClustesing subclust = new SubtractClustesing(x, Radii, SqshFactor, AcceptRatio, RejectRatio);

            subclust.SubClust();
            double[][] centers = subclust.Centers;          // Центы кластеров
            double[]   sigmas  = subclust.Sigmas;           // Радиусы кластеров

            //
            // Ращипление центров кластеров
            //

            // Формирование центров кластеров
            double[][] centersIn  = new double[centers.Length - 1][];
            double[]   centersOut = centers[centers.Length - 1];
            for (int i = 0; i < centersIn.Length; i++)
            {
                centersIn[i] = centers[i];
            }
            // Формирование радиусов кластера
            double[] sigmaIn = new double[sigmas.Length - 1];
            for (int i = 0; i < sigmaIn.Length; i++)
            {
                sigmaIn[i] = sigmas[i];
            }
            double sigmaOut = sigmas[sigmas.Length - 1];

            //
            // Формируем входные переменные
            //

            for (int i = 0; i < centersIn.Length; i++)
            {
                // Создаем переменную
                double min, max;
                MinMax(xin[i], out max, out min);
                FuzzyVariable input = new FuzzyVariable(NameInput + (i + 1).ToString(), min, max);
                // Формируем термы / функции принадлежности
                for (int j = 0; j < centersIn[i].Length; j++)
                {
                    input.Terms.Add(
                        new FuzzyTerm(
                            NameMf + (j + 1).ToString(),
                            new NormalMembershipFunction(centersIn[i][j], sigmaIn[i])
                            )
                        );
                }
                // Заносим переменную в список
                Input.Add(input);
            }

            //
            // Формирование выходных переменных
            //

            SugenoVariable output = new SugenoVariable(NameOutput);

            for (int i = 0; i < centersOut.Length; i++)
            {
                Dictionary <FuzzyVariable, double> mf = new Dictionary <FuzzyVariable, double>();
                for (int j = 0; j < centersIn.Length; j++)                      // Перебираем входные переменные
                {
                    mf.Add(InputByName(NameInput + (j + 1).ToString()), 0.0);   // По умолчанию 0,0
                }
                // Константа тоже по умолчанию 0.0
                output.Functions.Add(CreateSugenoFunction(NameMf + (i + 1).ToString(), mf, 0.0));
            }
            Output.Add(output);

            //
            // Формировние базы правил типа
            // if (input1 is mf1) and (input2 is mf1) then (output1 is mf1)
            //
            rulesText = new string[centersOut.Length];          // Текстовое представление правил
            for (int i = 0; i < centersOut.Length; i++)
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("if");
                for (int j = 0; j < centersIn.Length; j++)
                {
                    sb.Append(string.Format(" ({0} is {1}) ", NameInput + (j + 1).ToString(), NameMf + (i + 1).ToString()));
                    if (j != centersIn.Length - 1)
                    {
                        sb.Append("and");
                    }
                }
                sb.Append("then");
                sb.Append(string.Format(" ({0} is {1})", NameOutput, NameMf + (i + 1).ToString()));
                rulesText[i] = sb.ToString();
                Rules.Add(ParseRule(sb.ToString()));                    // Парсим правило
            }
        }
Пример #2
0
        /// <summary>
        /// Обучение Fis
        /// </summary>
        /// <param name="anfisTrain">Функция обучения</param>
        public void Train(anfisTrain anfisTrain = null)
        {
            //
            // Генерация Fis
            //
            Genfis();
            //
            // Обучение Fis
            //
            int    epoch = 1;
            double epochError;

            if (Rules.Count == 0)
            {
                throw new Exception("Должно быть хотя бы одно правило.");
            }

            int k = xout.Length;                            // Количество параметров обучающей выборки
            int l = (xin.Length + 1) * Rules.Count;         // (m+1)n - m - количество входных переменных n - количество правил

            Matrix C = new Matrix(l, 1);                    // Столбец весовых коэффициентов
            Matrix Y = new Matrix(k, 1);                    // Вектор столбец выходных данных

            for (int i = 0; i < k; i++)
            {
                Y[i, 0] = xout[i];
            }

            errorTrain = new double[Epochs];
            while (epoch <= Epochs)
            {
                epochError = 0.0;                           // Ошибка на i эпохе
                //
                // Формирование матрицы коэффициентов
                //
                Matrix W  = new Matrix(k, l);
                Matrix ew = new Matrix(k, Rules.Count);
                for (int i = 0; i < k; i++)
                {
                    Dictionary <FuzzyVariable, double> inputValues = new Dictionary <FuzzyVariable, double>();
                    // По количеству переменных
                    for (int j = 0; j < xin.Length; j++)
                    {
                        inputValues.Add(InputByName(NameInput + (j + 1).ToString()), xin[j][i]);
                    }
                    // Посылки правил
                    Dictionary <FuzzyVariable, Dictionary <FuzzyTerm, double> > fuzzyInput = Fuzzify(inputValues);
                    // Агрегирование подусловий
                    Dictionary <SugenoFuzzyRule, double> rulesWeight = EvaluateConditions(fuzzyInput);
                    // Заключение правил
                    double        Stau = 0.0;
                    List <double> tau  = new List <double>();
                    foreach (double _tau in rulesWeight.Values)
                    {
                        Stau += _tau;
                        tau.Add(_tau);
                    }
                    double[] b = new double[tau.Count];
                    for (int j = 0; j < b.Length; j++)
                    {
                        b[j]     = tau[j] / Stau;
                        ew[i, j] = tau[j];
                    }
                    // Формирование входных переменных
                    double[] x = new double[xin.Length + 1];        // +1, т.к. x0 = 1
                    x[0] = 1;                                       // x0 = 1
                    for (int j = 1; j < x.Length; j++)
                    {
                        x[j] = xin[j - 1][i];                       // заполняем x1, x2,...,x3
                    }
                    int columnW = 0;
                    for (int g = 0; g < b.Length; g++)              // перебираем по заключениям
                    {
                        for (int d = 0; d < x.Length; d++)          // перебираем по входным данным
                        {
                            W[i, columnW] = b[g] * x[d];            // переменожаем коэффициенты на переменные
                            columnW++;                              // увеличиваем строку на 1
                        }
                    }
                }

                Matrix Winverse = W.PInverse();     // W+ псевдоинверстная матрица

                //
                // Если псевдоинверстная матрица не найдена
                //
                bool breakTrain = false;
                for (int i = 0; i < Winverse.N; i++)
                {
                    for (int j = 0; j < Winverse.M; j++)
                    {
                        if (double.IsNaN(Winverse[i, j]))
                        {
                            breakTrain = true;
                            break;
                        }
                    }
                    if (breakTrain)
                    {
                        break;
                    }
                }
                if (breakTrain)
                {
                    break;              // Прерываем обучение
                }
                C = Winverse * Y;       // Находим коэффициенты
                //
                // Нахождение вектора фактического выхода сети
                //
                Matrix Ystrich = W * C;
                //
                // Правим коэффициенты
                //
                for (int i = 0; i < Input.Count; i++)
                {
                    FuzzyVariable fv = Input[i];                // Забираем переменную
                    for (int j = 0; j < fv.Terms.Count; j++)
                    {
                        FuzzyTerm term = fv.Terms[j];               // Выбираем j терм i входной переменной
                        //
                        // Меняем в случае если функция принадлежности колоколообразная
                        //
                        IMembershipFunction mf = term.MembershipFunction;
                        if (mf is NormalMembershipFunction)
                        {
                            NormalMembershipFunction mfterm = (NormalMembershipFunction)mf;  // Приводим тип
                            //
                            // Перебираем все переменные k - количество выходных параметров
                            //

                            for (int g = 0; g < k; g++)
                            {
                                double b     = mfterm.B;
                                double sigma = mfterm.Sigma;
                                double xa    = xin[i][g] - b;             // xin - b

                                double yyStrih = Ystrich[g, 0] - xout[g]; // y' - y
                                double p       = ew[g, j];
                                double sp      = 0.0;
                                for (int q = 0; q < Rules.Count; q++)
                                {
                                    sp += ew[g, q];
                                }
                                double pb = p / (sp / Math.Pow(sigma, 2));   // (t/summt) / sigma^2
                                //
                                // Инициализируем матрицы для нахождения c
                                //
                                Matrix x = new Matrix(1, xin.Length + 1);
                                Matrix c = new Matrix(xin.Length + 1, 1);
                                x[0, 0] = 1;                                 //x0 = 1
                                for (int q = 1; q < x.M; q++)
                                {
                                    x[0, q] = xin[q - 1][g];
                                }
                                // Заполняем коэффициенты
                                int start = j * x.M;
                                for (int q = start; q < start + x.M; q++)
                                {
                                    c[q - start, 0] = C[q, 0];
                                }

                                // Перемножаем матрици
                                double cy = ((x * c)[0] - Ystrich[g, 0]);
                                //
                                // Корректируем B
                                //

                                b -= 2 * Nu * xa * yyStrih * cy * pb;

                                //
                                // Корректируем Sigma
                                //

                                sigma -= 2 * Nu * Math.Pow(xa, 2) * yyStrih * cy * pb;
                                //
                                // Условия переобучения и недопустимости применения условий
                                //

                                if (double.IsNaN(mfterm.Sigma) || double.IsNaN(mfterm.B))
                                {
                                    continue;   // Идем на следующую итерацию
                                }
                                else
                                {
                                    mfterm.B     = b;
                                    mfterm.Sigma = sigma;
                                }
                            }
                            //
                            // Загоняем терм обратно
                            //



                            fv.Terms[j].MembershipFunction = mfterm;
                        }
                        //
                        // TODO: Настройка остальных функций принадлежности не реализовано
                        //
                    }

                    Input[i] = fv;                      // Загоняем переменную обратно
                }
                //
                // Находим ошибку выхода
                //
                epochError = 0.0;
                for (int i = 0; i < Ystrich.N; i++)
                {
                    epochError += 0.5 * Math.Pow(Ystrich[i, 0] - xout[i], 2);
                }
                errorTrain[epoch - 1] = epochError;
                anfisTrain?.Invoke(epoch, Epochs, nu, epochError);
                Nu *= NuStep;
                epoch++;
            }   // Конец эпох обучения

            //
            // Применяем параметры коэффициентов y = c0 + c1 * x1 + c2 * x2 + ... + ci * xi
            //
            SetCoefficient(C);
            //
            // Перезаписываем правила в силу архитектуры сети
            //
            Rules.Clear();
            for (int i = 0; i < rulesText.Length; i++)
            {
                Rules.Add(ParseRule(rulesText[i]));
            }

            Console.WriteLine(Rules[0].ToString());
        }