Advertisement
hishlishter

Untitled

Mar 15th, 2025
349
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 15.36 KB | Source Code | 0 0
  1. using System;
  2.  
  3. namespace Org.Example
  4. {
  5.     public class Program
  6.     {
  7.         // Константы: число нейронов, скорость обучения и число обучающих примеров
  8.         const int INPUT_NEURONS = 4;    // Параметры: давление, сахар, пульс, температура
  9.         const int HIDDEN_NEURONS = 3;
  10.         const int OUTPUT_NEURONS = 4;   // 4 класса здоровья
  11.         const double LEARN_RATE = 0.2;
  12.         const int MAX_SAMPLES = 16;
  13.  
  14.         // Jagged-массивы для весов (с дополнительной строкой для смещения)
  15.         double[][] wih; // Веса между входным и скрытым слоями (размер: INPUT_NEURONS+1 x HIDDEN_NEURONS)
  16.         double[][] who; // Веса между скрытым и выходным слоями (размер: HIDDEN_NEURONS+1 x OUTPUT_NEURONS)
  17.  
  18.         // Массивы для хранения значений нейронов
  19.         double[] inputs;  // Входной слой
  20.         double[] hidden;  // Скрытый слой
  21.         double[] target;  // Целевой вектор (one-hot кодировка)
  22.         double[] actual;  // Фактический выход сети
  23.  
  24.         // Массивы для ошибок нейронов
  25.         double[] erro;    // Ошибки на выходном слое
  26.         double[] errh;    // Ошибки на скрытом слое
  27.  
  28.         // Массив с названиями классов здоровья
  29.         string[] conditions = { "Здоров", "Предболен", "Болен", "Критическое состояние" };
  30.  
  31.         // Класс, представляющий обучающий пример
  32.         public class Sample
  33.         {
  34.             public double bloodPressure; // Артериальное давление (мм рт. ст.)
  35.             public double bloodSugar;    // Уровень сахара (мг/дл)
  36.             public double heartRate;     // Пульс (уд/мин)
  37.             public double temperature;   // Температура тела (°C)
  38.             public double[] Out;         // One-hot представление класса
  39.  
  40.             public Sample(double bloodPressure, double bloodSugar, double heartRate, double temperature, double[] output)
  41.             {
  42.                 this.bloodPressure = bloodPressure;
  43.                 this.bloodSugar = bloodSugar;
  44.                 this.heartRate = heartRate;
  45.                 this.temperature = temperature;
  46.                 this.Out = output;
  47.             }
  48.         }
  49.  
  50.         // Обучающий набор: 16 примеров (по 4 для каждого класса)
  51.         Sample[] samples = new Sample[]
  52.         {
  53.             // "Здоров": нормальные показатели
  54.             new Sample(120, 100, 75, 36.8, new double[] {1.0, 0.0, 0.0, 0.0}),
  55.             new Sample(118, 98, 73, 36.7, new double[] {1.0, 0.0, 0.0, 0.0}),
  56.             new Sample(121, 101, 76, 36.9, new double[] {1.0, 0.0, 0.0, 0.0}),
  57.             new Sample(119, 99, 74, 36.8, new double[] {1.0, 0.0, 0.0, 0.0}),
  58.  
  59.             // "Предболен": небольшие отклонения
  60.             new Sample(130, 110, 80, 37.2, new double[] {0.0, 1.0, 0.0, 0.0}),
  61.             new Sample(128, 108, 79, 37.1, new double[] {0.0, 1.0, 0.0, 0.0}),
  62.             new Sample(131, 112, 81, 37.3, new double[] {0.0, 1.0, 0.0, 0.0}),
  63.             new Sample(129, 109, 80, 37.2, new double[] {0.0, 1.0, 0.0, 0.0}),
  64.  
  65.             // "Болен": выраженные отклонения
  66.             new Sample(150, 140, 90, 38.0, new double[] {0.0, 0.0, 1.0, 0.0}),
  67.             new Sample(148, 138, 89, 37.9, new double[] {0.0, 0.0, 1.0, 0.0}),
  68.             new Sample(151, 142, 91, 38.1, new double[] {0.0, 0.0, 1.0, 0.0}),
  69.             new Sample(149, 139, 90, 38.0, new double[] {0.0, 0.0, 1.0, 0.0}),
  70.  
  71.             // "Критическое состояние": очень сильные отклонения
  72.             new Sample(170, 180, 120, 39.0, new double[] {0.0, 0.0, 0.0, 1.0}),
  73.             new Sample(168, 178, 118, 38.9, new double[] {0.0, 0.0, 0.0, 1.0}),
  74.             new Sample(171, 182, 121, 39.1, new double[] {0.0, 0.0, 0.0, 1.0}),
  75.             new Sample(169, 179, 119, 39.0, new double[] {0.0, 0.0, 0.0, 1.0})
  76.         };
  77.  
  78.         // Диапазоны для нормализации входных данных
  79.         const double BP_MIN = 80;      // мм рт. ст.
  80.         const double BP_MAX = 180;
  81.         const double SUGAR_MIN = 70;   // мг/дл
  82.         const double SUGAR_MAX = 200;
  83.         const double HR_MIN = 50;      // уд/мин
  84.         const double HR_MAX = 150;
  85.         const double TEMP_MIN = 35;    // °C
  86.         const double TEMP_MAX = 41;
  87.  
  88.         // Статический экземпляр Random для генерации случайных чисел
  89.         static Random rand = new Random();
  90.  
  91.         // Конструктор: инициализация массивов
  92.         public Program()
  93.         {
  94.             // Инициализация массивов для весов
  95.             wih = new double[INPUT_NEURONS + 1][];
  96.             for (int i = 0; i < INPUT_NEURONS + 1; i++)
  97.             {
  98.                 wih[i] = new double[HIDDEN_NEURONS];
  99.             }
  100.             who = new double[HIDDEN_NEURONS + 1][];
  101.             for (int i = 0; i < HIDDEN_NEURONS + 1; i++)
  102.             {
  103.                 who[i] = new double[OUTPUT_NEURONS];
  104.             }
  105.             // Инициализация массивов для нейронов и ошибок
  106.             inputs = new double[INPUT_NEURONS];
  107.             hidden = new double[HIDDEN_NEURONS];
  108.             target = new double[OUTPUT_NEURONS];
  109.             actual = new double[OUTPUT_NEURONS];
  110.             erro = new double[OUTPUT_NEURONS];
  111.             errh = new double[HIDDEN_NEURONS];
  112.         }
  113.  
  114.         // Инициализация весов случайными значениями в диапазоне [-0.5, 0.5]
  115.         void AssignRandomWeights()
  116.         {
  117.             for (int inp = 0; inp < INPUT_NEURONS + 1; inp++)
  118.             {
  119.                 for (int hid = 0; hid < HIDDEN_NEURONS; hid++)
  120.                 {
  121.                     wih[inp][hid] = rand.NextDouble() - 0.5;
  122.                 }
  123.             }
  124.             for (int hid = 0; hid < HIDDEN_NEURONS + 1; hid++)
  125.             {
  126.                 for (int out = 0; out < OUTPUT_NEURONS; out++)
  127.                 {
  128.                     who[hid][out] = rand.NextDouble() - 0.5;
  129.                 }
  130.             }
  131.         }
  132.  
  133.         // Функция активации (сигмоида) и её производная
  134.         double Sigmoid(double val)
  135.         {
  136.             return 1.0 / (1.0 + Math.Exp(-val));
  137.         }
  138.  
  139.         double SigmoidDerivative(double val)
  140.         {
  141.             return val * (1.0 - val);
  142.         }
  143.  
  144.         // Нормализация входных данных (без добавления шума)
  145.         void NormalizeInputs()
  146.         {
  147.             // Приведение к диапазону [0, 1] по формуле: (value - min) / (max - min)
  148.             inputs[0] = (inputs[0] - BP_MIN) / (BP_MAX - BP_MIN);
  149.             inputs[1] = (inputs[1] - SUGAR_MIN) / (SUGAR_MAX - SUGAR_MIN);
  150.             inputs[2] = (inputs[2] - HR_MIN) / (HR_MAX - HR_MIN);
  151.             inputs[3] = (inputs[3] - TEMP_MIN) / (TEMP_MAX - TEMP_MIN);
  152.         }
  153.  
  154.         // Прямое распространение сигнала по сети
  155.         void FeedForward()
  156.         {
  157.             // Вычисление выхода скрытого слоя
  158.             for (int hid = 0; hid < HIDDEN_NEURONS; hid++)
  159.             {
  160.                 double sum = 0.0;
  161.                 for (int inp = 0; inp < INPUT_NEURONS; inp++)
  162.                 {
  163.                     sum += inputs[inp] * wih[inp][hid];
  164.                 }
  165.                 // Смещение: последний элемент в массиве wih для данного скрытого нейрона
  166.                 sum += wih[INPUT_NEURONS][hid];
  167.                 hidden[hid] = Sigmoid(sum);
  168.             }
  169.             // Вычисление выхода выходного слоя
  170.             for (int out = 0; out < OUTPUT_NEURONS; out++)
  171.             {
  172.                 double sum = 0.0;
  173.                 for (int hid = 0; hid < HIDDEN_NEURONS; hid++)
  174.                 {
  175.                     sum += hidden[hid] * who[hid][out];
  176.                 }
  177.                 // Смещение: последний элемент в массиве who для данного выходного нейрона
  178.                 sum += who[HIDDEN_NEURONS][out];
  179.                 actual[out] = Sigmoid(sum);
  180.             }
  181.         }
  182.  
  183.         // Алгоритм обратного распространения ошибки
  184.         void BackPropagate()
  185.         {
  186.             // Вычисление ошибки на выходном слое
  187.             for (int out = 0; out < OUTPUT_NEURONS; out++)
  188.             {
  189.                 erro[out] = (target[out] - actual[out]) * SigmoidDerivative(actual[out]);
  190.             }
  191.             // Вычисление ошибки на скрытом слое
  192.             for (int hid = 0; hid < HIDDEN_NEURONS; hid++)
  193.             {
  194.                 errh[hid] = 0.0;
  195.                 for (int out = 0; out < OUTPUT_NEURONS; out++)
  196.                 {
  197.                     errh[hid] += erro[out] * who[hid][out];
  198.                 }
  199.                 errh[hid] *= SigmoidDerivative(hidden[hid]);
  200.             }
  201.             // Обновление весов между скрытым и выходным слоями
  202.             for (int out = 0; out < OUTPUT_NEURONS; out++)
  203.             {
  204.                 for (int hid = 0; hid < HIDDEN_NEURONS; hid++)
  205.                 {
  206.                     who[hid][out] += LEARN_RATE * erro[out] * hidden[hid];
  207.                 }
  208.                 // Обновление смещения
  209.                 who[HIDDEN_NEURONS][out] += LEARN_RATE * erro[out];
  210.             }
  211.             // Обновление весов между входным и скрытым слоями
  212.             for (int hid = 0; hid < HIDDEN_NEURONS; hid++)
  213.             {
  214.                 for (int inp = 0; inp < INPUT_NEURONS; inp++)
  215.                 {
  216.                     wih[inp][hid] += LEARN_RATE * errh[hid] * inputs[inp];
  217.                 }
  218.                 // Обновление смещения
  219.                 wih[INPUT_NEURONS][hid] += LEARN_RATE * errh[hid];
  220.             }
  221.         }
  222.  
  223.         // Функция, возвращающая индекс элемента с наибольшим значением (определяет класс)
  224.         int Action(double[] vector)
  225.         {
  226.             int sel = 0;
  227.             double max = vector[0];
  228.             for (int i = 1; i < OUTPUT_NEURONS; i++)
  229.             {
  230.                 if (vector[i] > max)
  231.                 {
  232.                     max = vector[i];
  233.                     sel = i;
  234.                 }
  235.             }
  236.             return sel;
  237.         }
  238.  
  239.         public static void Main(string[] args)
  240.         {
  241.             Program wc = new Program();
  242.             wc.AssignRandomWeights();
  243.  
  244.             int sampleIndex = 0;
  245.             double err;
  246.             // Обучение сети (10000 итераций)
  247.             for (int step = 0; step < 10000; step++)
  248.             {
  249.                 sampleIndex = (sampleIndex + 1) % MAX_SAMPLES;
  250.                 Sample s = wc.samples[sampleIndex];
  251.                 // Заполняем входной вектор данными из обучающего примера
  252.                 // Порядок: давление, сахар, пульс, температура
  253.                 wc.inputs[0] = s.bloodPressure;
  254.                 wc.inputs[1] = s.bloodSugar;
  255.                 wc.inputs[2] = s.heartRate;
  256.                 wc.inputs[3] = s.temperature;
  257.                 // Нормализуем входные данные (без шума)
  258.                 wc.NormalizeInputs();
  259.                 // Копируем целевой вектор
  260.                 for (int i = 0; i < OUTPUT_NEURONS; i++)
  261.                 {
  262.                     wc.target[i] = s.Out[i];
  263.                 }
  264.                 wc.FeedForward();
  265.                 err = 0.0;
  266.                 for (int i = 0; i < OUTPUT_NEURONS; i++)
  267.                 {
  268.                     double diff = s.Out[i] - wc.actual[i];
  269.                     err += diff * diff;
  270.                 }
  271.                 err = 0.5 * err;
  272.                 if (step % 1000 == 0)
  273.                 {
  274.                     Console.WriteLine("step = " + step + " mse = " + err);
  275.                 }
  276.                 wc.BackPropagate();
  277.             }
  278.  
  279.             Console.WriteLine();
  280.             int correct = 0;
  281.             // Проверка сети на обучающих примерах
  282.             for (int i = 0; i < MAX_SAMPLES; i++)
  283.             {
  284.                 Sample s = wc.samples[i];
  285.                 wc.inputs[0] = s.bloodPressure;
  286.                 wc.inputs[1] = s.bloodSugar;
  287.                 wc.inputs[2] = s.heartRate;
  288.                 wc.inputs[3] = s.temperature;
  289.                 wc.NormalizeInputs();
  290.                 for (int j = 0; j < OUTPUT_NEURONS; j++)
  291.                 {
  292.                     wc.target[j] = s.Out[j];
  293.                 }
  294.                 wc.FeedForward();
  295.                 int predicted = wc.Action(wc.actual);
  296.                 int expected = wc.Action(wc.target);
  297.                 if (predicted != expected)
  298.                 {
  299.                     Console.WriteLine("Input: " + s.bloodPressure + " " + s.bloodSugar + " "
  300.                         + s.heartRate + " " + s.temperature +
  301.                         " predicted: " + wc.conditions[predicted] +
  302.                         " expected: " + wc.conditions[expected]);
  303.                 }
  304.                 else
  305.                 {
  306.                     correct++;
  307.                 }
  308.             }
  309.             Console.WriteLine("Network is " + ((float)correct / MAX_SAMPLES * 100.0) + "% correct\n");
  310.  
  311.             // Дополнительное тестирование с новыми входными данными
  312.             // Задаем тестовые значения, ожидаемые для каждого класса:
  313.             double[][] testInputs = new double[][]
  314.             {
  315.                 new double[] {120, 100, 75, 36.8},   // ожидается "Здоров"
  316.                 new double[] {130, 110, 80, 37.2},   // ожидается "Предболен"
  317.                 new double[] {150, 140, 90, 38.0},   // ожидается "Болен"
  318.                 new double[] {170, 180, 120, 39.0}   // ожидается "Критическое состояние"
  319.             };
  320.             foreach (double[] test in testInputs)
  321.             {
  322.                 wc.inputs[0] = test[0];
  323.                 wc.inputs[1] = test[1];
  324.                 wc.inputs[2] = test[2];
  325.                 wc.inputs[3] = test[3];
  326.                 wc.NormalizeInputs();
  327.                 wc.FeedForward();
  328.                 int index = wc.Action(wc.actual);
  329.                 Console.WriteLine("Input: [" + test[0] + ", " + test[1] + ", " + test[2] + ", " + test[3]
  330.                     + "] -> " + wc.conditions[index]);
  331.             }
  332.         }
  333.     }
  334. }
  335.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement