Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- public class Program
- {
- // Константы: число нейронов, коэффициент обучения, число обучающих примеров
- const int INPUT_NEURONS = 4; // Параметры: давление, сахар, пульс, температура
- const int HIDDEN_NEURONS = 3;
- const int OUTPUT_NEURONS = 4; // 4 класса здоровья
- const double LEARN_RATE = 0.2;
- const int MAX_SAMPLES = 16;
- // Jagged-массивы для весов (с дополнительной строкой для смещения)
- double[][] wih; // Веса между входным и скрытым слоями (размер: INPUT_NEURONS+1 x HIDDEN_NEURONS)
- double[][] who; // Веса между скрытым и выходным слоями (размер: HIDDEN_NEURONS+1 x OUTPUT_NEURONS)
- // Массивы для хранения значений нейронов
- double[] inputs; // Входной слой
- double[] hidden; // Скрытый слой
- double[] target; // Целевой вектор (one-hot кодировка)
- double[] actual; // Фактический выход сети
- // Массивы для ошибок нейронов
- double[] erro; // Ошибки на выходном слое
- double[] errh; // Ошибки на скрытом слое
- // Массив с названиями классов здоровья
- string[] conditions = { "Здоров", "Предболен", "Болен", "Критическое состояние" };
- // Класс, представляющий обучающий пример
- public class Sample
- {
- public double bloodPressure; // Артериальное давление (мм рт. ст.)
- public double bloodSugar; // Уровень сахара (мг/дл)
- public double heartRate; // Пульс (уд/мин)
- public double temperature; // Температура тела (°C)
- public double[] Out; // One-hot представление класса
- public Sample(double bloodPressure, double bloodSugar, double heartRate, double temperature, double[] output)
- {
- this.bloodPressure = bloodPressure;
- this.bloodSugar = bloodSugar;
- this.heartRate = heartRate;
- this.temperature = temperature;
- this.Out = output;
- }
- }
- // Обучающий набор: 16 примеров (по 4 для каждого класса)
- Sample[] samples = new Sample[]
- {
- // "Здоров": нормальные показатели
- new Sample(120, 100, 75, 36.8, new double[]{1.0, 0.0, 0.0, 0.0}),
- new Sample(118, 98, 73, 36.7, new double[]{1.0, 0.0, 0.0, 0.0}),
- new Sample(121, 101, 76, 36.9, new double[]{1.0, 0.0, 0.0, 0.0}),
- new Sample(119, 99, 74, 36.8, new double[]{1.0, 0.0, 0.0, 0.0}),
- // "Предболен": небольшие отклонения
- new Sample(130, 110, 80, 37.2, new double[]{0.0, 1.0, 0.0, 0.0}),
- new Sample(128, 108, 79, 37.1, new double[]{0.0, 1.0, 0.0, 0.0}),
- new Sample(131, 112, 81, 37.3, new double[]{0.0, 1.0, 0.0, 0.0}),
- new Sample(129, 109, 80, 37.2, new double[]{0.0, 1.0, 0.0, 0.0}),
- // "Болен": выраженные отклонения
- new Sample(150, 140, 90, 38.0, new double[]{0.0, 0.0, 1.0, 0.0}),
- new Sample(148, 138, 89, 37.9, new double[]{0.0, 0.0, 1.0, 0.0}),
- new Sample(151, 142, 91, 38.1, new double[]{0.0, 0.0, 1.0, 0.0}),
- new Sample(149, 139, 90, 38.0, new double[]{0.0, 0.0, 1.0, 0.0}),
- // "Критическое состояние": очень сильные отклонения
- new Sample(170, 180, 120, 39.0, new double[]{0.0, 0.0, 0.0, 1.0}),
- new Sample(168, 178, 118, 38.9, new double[]{0.0, 0.0, 0.0, 1.0}),
- new Sample(171, 182, 121, 39.1, new double[]{0.0, 0.0, 0.0, 1.0}),
- new Sample(169, 179, 119, 39.0, new double[]{0.0, 0.0, 0.0, 1.0})
- };
- // Минимальные и максимальные значения для нормализации входных данных
- const double BP_MIN = 80; // мм рт. ст.
- const double BP_MAX = 180;
- const double SUGAR_MIN = 70; // мг/дл
- const double SUGAR_MAX = 200;
- const double HR_MIN = 50; // уд/мин
- const double HR_MAX = 150;
- const double TEMP_MIN = 35; // °C
- const double TEMP_MAX = 41;
- static Random rand = new Random();
- // Конструктор: выделение памяти для массивов весов и нейронов
- public Program()
- {
- wih = new double[INPUT_NEURONS + 1][];
- for (int i = 0; i < INPUT_NEURONS + 1; i++)
- {
- wih[i] = new double[HIDDEN_NEURONS];
- }
- who = new double[HIDDEN_NEURONS + 1][];
- for (int i = 0; i < HIDDEN_NEURONS + 1; i++)
- {
- who[i] = new double[OUTPUT_NEURONS];
- }
- inputs = new double[INPUT_NEURONS];
- hidden = new double[HIDDEN_NEURONS];
- target = new double[OUTPUT_NEURONS];
- actual = new double[OUTPUT_NEURONS];
- erro = new double[OUTPUT_NEURONS];
- errh = new double[HIDDEN_NEURONS];
- }
- // Инициализация весов случайными значениями в диапазоне [-0.5, 0.5]
- void AssignRandomWeights()
- {
- for (int inp = 0; inp < INPUT_NEURONS + 1; inp++)
- {
- for (int hid = 0; hid < HIDDEN_NEURONS; hid++)
- {
- wih[inp][hid] = rand.NextDouble() - 0.5;
- }
- }
- for (int hid = 0; hid < HIDDEN_NEURONS + 1; hid++)
- {
- for (int out = 0; out < OUTPUT_NEURONS; out++)
- {
- who[hid][out] = rand.NextDouble() - 0.5;
- }
- }
- }
- // Функция активации (сигмоида) и её производная
- double Sigmoid(double val)
- {
- return 1.0 / (1.0 + Math.Exp(-val));
- }
- double SigmoidDerivative(double val)
- {
- return val * (1.0 - val);
- }
- // Нормализация входных данных (без добавления шума)
- void NormalizeInputs()
- {
- inputs[0] = (inputs[0] - BP_MIN) / (BP_MAX - BP_MIN);
- inputs[1] = (inputs[1] - SUGAR_MIN) / (SUGAR_MAX - SUGAR_MIN);
- inputs[2] = (inputs[2] - HR_MIN) / (HR_MAX - HR_MIN);
- inputs[3] = (inputs[3] - TEMP_MIN) / (TEMP_MAX - TEMP_MIN);
- }
- // Прямое распространение сигнала по сети
- void FeedForward()
- {
- // Вычисление выхода скрытого слоя
- for (int hid = 0; hid < HIDDEN_NEURONS; hid++)
- {
- double sum = 0.0;
- for (int inp = 0; inp < INPUT_NEURONS; inp++)
- {
- sum += inputs[inp] * wih[inp][hid];
- }
- // Добавляем смещение (последний элемент в wih)
- sum += wih[INPUT_NEURONS][hid];
- hidden[hid] = Sigmoid(sum);
- }
- // Вычисление выхода выходного слоя
- for (int out = 0; out < OUTPUT_NEURONS; out++)
- {
- double sum = 0.0;
- for (int hid = 0; hid < HIDDEN_NEURONS; hid++)
- {
- sum += hidden[hid] * who[hid][out];
- }
- // Добавляем смещение (последний элемент в who)
- sum += who[HIDDEN_NEURONS][out];
- actual[out] = Sigmoid(sum);
- }
- }
- // Алгоритм обратного распространения ошибки
- void BackPropagate()
- {
- // Вычисление ошибки на выходном слое
- for (int out = 0; out < OUTPUT_NEURONS; out++)
- {
- erro[out] = (target[out] - actual[out]) * SigmoidDerivative(actual[out]);
- }
- // Вычисление ошибки на скрытом слое
- for (int hid = 0; hid < HIDDEN_NEURONS; hid++)
- {
- errh[hid] = 0.0;
- for (int out = 0; out < OUTPUT_NEURONS; out++)
- {
- errh[hid] += erro[out] * who[hid][out];
- }
- errh[hid] *= SigmoidDerivative(hidden[hid]);
- }
- // Обновление весов между скрытым и выходным слоями
- for (int out = 0; out < OUTPUT_NEURONS; out++)
- {
- for (int hid = 0; hid < HIDDEN_NEURONS; hid++)
- {
- who[hid][out] += LEARN_RATE * erro[out] * hidden[hid];
- }
- // Обновление смещения
- who[HIDDEN_NEURONS][out] += LEARN_RATE * erro[out];
- }
- // Обновление весов между входным и скрытым слоями
- for (int hid = 0; hid < HIDDEN_NEURONS; hid++)
- {
- for (int inp = 0; inp < INPUT_NEURONS; inp++)
- {
- wih[inp][hid] += LEARN_RATE * errh[hid] * inputs[inp];
- }
- // Обновление смещения
- wih[INPUT_NEURONS][hid] += LEARN_RATE * errh[hid];
- }
- }
- // Функция, возвращающая индекс элемента с наибольшим значением (определяет класс)
- int Action(double[] vector)
- {
- int sel = 0;
- double max = vector[0];
- for (int i = 1; i < OUTPUT_NEURONS; i++)
- {
- if (vector[i] > max)
- {
- max = vector[i];
- sel = i;
- }
- }
- return sel;
- }
- public static void Main(string[] args)
- {
- Program eq = new Program();
- eq.AssignRandomWeights();
- int sampleIndex = 0;
- double err;
- // Обучение сети (10000 итераций)
- for (int step = 0; step < 10000; step++)
- {
- sampleIndex = (sampleIndex + 1) % MAX_SAMPLES;
- Sample s = eq.samples[sampleIndex];
- // Заполняем входной вектор данными из обучающего примера
- // Порядок: давление, сахар, пульс, температура
- eq.inputs[0] = s.bloodPressure;
- eq.inputs[1] = s.bloodSugar;
- eq.inputs[2] = s.heartRate;
- eq.inputs[3] = s.temperature;
- // Нормализуем входные данные (без шума)
- eq.NormalizeInputs();
- // Копируем целевой вектор
- for (int i = 0; i < OUTPUT_NEURONS; i++)
- {
- eq.target[i] = s.Out[i];
- }
- eq.FeedForward();
- err = 0.0;
- for (int i = 0; i < OUTPUT_NEURONS; i++)
- {
- double diff = s.Out[i] - eq.actual[i];
- err += diff * diff;
- }
- err = 0.5 * err;
- if (step % 1000 == 0)
- {
- Console.WriteLine("step = " + step + " mse = " + err);
- }
- eq.BackPropagate();
- }
- Console.WriteLine();
- int correct = 0;
- // Проверка сети на обучающих примерах
- for (int i = 0; i < MAX_SAMPLES; i++)
- {
- Sample s = eq.samples[i];
- eq.inputs[0] = s.bloodPressure;
- eq.inputs[1] = s.bloodSugar;
- eq.inputs[2] = s.heartRate;
- eq.inputs[3] = s.temperature;
- eq.NormalizeInputs();
- for (int j = 0; j < OUTPUT_NEURONS; j++)
- {
- eq.target[j] = s.Out[j];
- }
- eq.FeedForward();
- int predicted = eq.Action(eq.actual);
- int expected = eq.Action(eq.target);
- if (predicted != expected)
- {
- Console.WriteLine("Input: " + s.bloodPressure + " " + s.bloodSugar + " "
- + s.heartRate + " " + s.temperature +
- " predicted: " + eq.conditions[predicted] +
- " expected: " + eq.conditions[expected]);
- }
- else
- {
- correct++;
- }
- }
- Console.WriteLine("Network is " + ((float)correct / MAX_SAMPLES * 100.0) + "% correct\n");
- // Дополнительное тестирование с новыми входными данными:
- // Порядок входов: давление, сахар, пульс, температура.
- double[][] testInputs = new double[][]
- {
- new double[] {120, 100, 75, 36.8}, // ожидается "Здоров"
- new double[] {130, 110, 80, 37.2}, // ожидается "Предболен"
- new double[] {150, 140, 90, 38.0}, // ожидается "Болен"
- new double[] {170, 180, 120, 39.0} // ожидается "Критическое состояние"
- };
- foreach (double[] test in testInputs)
- {
- eq.inputs[0] = test[0];
- eq.inputs[1] = test[1];
- eq.inputs[2] = test[2];
- eq.inputs[3] = test[3];
- eq.NormalizeInputs();
- eq.FeedForward();
- int index = eq.Action(eq.actual);
- Console.WriteLine("Input: [" + test[0] + ", " + test[1] + ", " + test[2] + ", " + test[3]
- + "] -> " + eq.conditions[index]);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement