Advertisement
hishlishter

Untitled

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