/// <summary> /// Создается единственное состояние /// </summary> /// <param name="var">Лингвистическая переменная к которой привязано условие</param> /// <param name="term">Терм в выражении "Переменная есть терм"</param> /// <param name="not">Содержит ли состояние отрицание</param> /// <returns>Созданное состояние</returns> public FuzzyCondition CreateCondition(FuzzyVariable var, FuzzyTerm term, bool not) { return(new FuzzyCondition(var, term, not)); }
/// <summary> /// Создается единственное состояние /// </summary> /// <param name="var">Лингвистическая переменная к которой привязано условие</param> /// <param name="term">Терм в выражении "Переменная есть терм"</param> /// <param name="not">Содержит ли состояние отрицание</param> /// <param name="type">Модификатор</param> /// <returns>Созданное состояние</returns> public FuzzyCondition CreateCondition(FuzzyVariable var, FuzzyTerm term, bool not, HedgeType type) { return(new FuzzyCondition(var, term, not, type)); }
/// <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()); }