#  Лабораторная работа №2 по дисциплине "Интеллектуальные системы"
## Бригада №5 (Голубев Т. Л., Ишутина Е. И.)
### Задание 1

#### 1. *В среде Google Colab создать новый блокнот (notebook). Импортировать необходимые для работы библиотеки и модули.*

Для работы был создан новый блокнот Google Colab и подключён Google Диск для доступа к файлам лабораторной работы.
Рабочая директория установлена на папку `is_lab2`, где расположены исходные данные и библиотека `lab02_lib.py`.
Импортированы необходимые библиотеки: numpy для численных вычислений и `lab02_lib`, содержащая функции генерации данных, создания и обучения автокодировщиков, а также визуализации результатов.

```python
from google.colab import drive
drive.mount('/content/drive')
import os
os.chdir('/content/drive/MyDrive/data')

from google.colab import drive
drive.mount('/content/drive')

import os
os.chdir('/content/drive/MyDrive/Colab Notebooks/is_lab2')

import numpy as np
import lab02_lib as lib
```

#### 2. *Сгенерировать индивидуальный набор двумерных данных в пространстве признако с координатами центра (k, k), где k–номер бригады. Вывести полученные данные на рисунок и в консоль.*

Был сгенерирован набор синтетических данных с помощью функции `lib.datagen()`.
Параметры выбраны в соответствии с вариантом – центр распределения точек находится в координате (5, 5), количество элементов – 1000.
Результат представляет собой кластер точек в двумерном пространстве, близко расположенных к центру распределения.
На рисунке показано их расположение, что подтверждает корректность генерации.
В консоль выведена матрица данных и её размерность, соответствующая форме (1000, 2).

```python
k = 5
data = lib.datagen(k, k, 1000, 2)

print('Исходные данные:')
print(data)
print('Размерность данных:', data.shape)
```
```python
Исходные данные:
[[5.13674887 5.16221778]
 [4.94241158 4.94308454]
 [4.99116866 5.07366791]
 ...
 [4.98843693 5.00884997]
 [5.05916488 5.16125265]
 [5.0019012  4.83264375]]
Размерность данных: (1000, 2)
```
![Сгенерированные данные](pics/image1.png)

#### 3. *Создать и  обучить автокодировщик AE1 простой  архитектуры,  выбрав небольшое  количество  эпох  обучения. Зафиксировать  в  таблице  вида табл.1 количество скрытых слоёв и нейронов в них.*

С помощью функции `lib.create_fit_save_ae()` был создан и обучен автокодировщик AE1 простой архитектуры с одним скрытым слоем, содержащим один нейрон.
Количество эпох обучения – 1000, параметр ранней остановки patience равен 300.

```python
patience = 300
ae1_trained, IRE1, IREth1 = lib.create_fit_save_ae(
    data,
    'out/AE1.h5',
    'out/AE1_ire_th.txt',
    1000,  # количество эпох
    False,  # показывать процесс обучения
    patience
)
```

#### 4. *Зафиксировать  ошибку MSE,  на  которой  обучение  завершилось. Построить   график   ошибки   реконструкции обучающей   выборки. Зафиксировать  порог  ошибки  реконструкции – порог  обнаружения аномалий.*

После обучения построен график распределения ошибки реконструкции (IRE) для обучающей выборки.
По оси X отложены индексы элементов, по оси Y – величины ошибки восстановления. Черной линией обозначен порог IREth, соответствующий максимальному значению ошибки на обучающих данных.
Большинство точек расположено ниже порога, что показывает успешное обучение модели и способность автокодировщика восстанавливать нормальные данные с малой погрешностью.
Значения IRE отражают расхождение между исходными и восстановленными примерами, и их равномерное распределение подтверждает корректность работы сети.

```python
lib.ire_plot('training', IRE1, IREth1, 'AE1')
```
![Распределение ошибок IRE по всем примерам обучающей выборки, АЕ1](pics/image2.png)

После завершения обучения была зафиксирована ошибка восстановления модели (MSE), соответствующая последнему значению вектора ошибок IRE1. Это значение соответствует допустимому диапазону для AE1 (1-10). Также был определён порог ошибки реконструкции IREth1, используемый далее в качестве порога обнаружения аномалий.

```python
print('MSE_stop =', IRE1[-1])
print('IREth1 =', IREth1)
```
```python
MSE_stop = 3.46
IREth1 = 3.88
```

#### 5. *Создать и обучить второй автокодировщик AE2 с усложненной архитектурой, задав большее количество эпох обучения.*
#### 6. *Зафиксировать ошибку MSE, на которой обучение завершилось. Построить график ошибки реконструкции обучающей выборки. Зафиксировать второй порог ошибки реконструкции – порог обнаружения аномалий.*

Для второго автокодировщика AE2 должна быть выбрана более сложная архитектура по сравнению с AE1. Увеличено количество скрытых слоёв и число нейронов в них, чтобы автокодировщик мог лучше аппроксимировать структуру данных и повысить точность реконструкции. Кроме того, увеличено количество эпох обучения, что позволило автокодировщику пройти больше итераций оптимизации и достичь более низкой ошибки реконструкции.

Обучение автокодировщика AE2 выполнялось с использованием функции `lib.create_fit_save_ae`, аналогично AE1. Сначала был применен стандартный набор параметров автоэнкодера: (количество скрытых слоёв будет 5, а количество нейронов в них: 3 2 1 2 3).

Во время обучения автокодировщика AE2 был включён механизм ранней остановки (early stopping) с параметром patience = 500. Этот механизм отслеживает изменение ошибки реконструкции (MSE) на обучающих данных и останавливает обучение, если улучшений ошибки не наблюдается в течение заданного числа эпох. В результате обучение завершилось на 1920-й эпохе, так как на протяжении 500 последовательных эпох ошибка перестала уменьшаться.

После остановки были восстановлены веса модели, соответствующие наилучшей эпохе (1420-я эпоха), что обеспечило минимальное значение ошибки реконструкции. Такой подход позволяет избежать переобучения нейросети и гарантирует сохранение оптимальных параметров автокодировщика для дальнейшего выявления аномалий.

```python
Epoch 1920: early stopping
Restoring model weights from the end of the best epoch: 1420.
32/32 ━━━━━━━━━━━━━━━━━━━━ 0s 5ms/step
```

График ошибки реконструкции, построенный после завершения обучения, показывает распределение значений ошибки по всем примерам обучающей выборки, а порог IREth2 определяет границу между нормальными данными и потенциальными аномалиями. Значения ошибки на графике и величина порога свидетельствуют о высоком качестве обучения автокодировщика AE2.

![Распределение ошибок IRE по всем примерам обучающей выборки, АЕ2](pics/image3.png)

Ниже преставлены значения MSE и IREth. 

```python
MSE_stop_AE2 = IRE2[-1]  # ошибка реконструкции на последней эпохе (после ранней остановки)
print(f"MSE_stop для AE2: {MSE_stop_AE2:.2f}")
print(f"IREth2 (порог ошибки реконструкции) для AE2: {IREth2:.2f}")
```
```python
MSE_stop для AE2: 0.12
IREth2 (порог ошибки реконструкции) для AE2: 0.41
```

Как видно, значение MSE AE2 соответствует порогу для второго автоэнкодера: необходимо значение не менее 0,01.

Автокодировщик обучается воспроизводить входные данные на выходе. Ошибка реконструкции (MSE) измеряет, насколько хорошо сеть восстанавливает данные. Если MSE слишком маленькая, сеть почти идеально копирует все данные. Если MSE умеренная, сеть восстанавливает общие закономерности, а не каждую деталь.

Попробуем скорректировать архитектуру, чтобы еще увеличить значение. Новая архитектура: 
- количество скрытых слоёв: 5
- количество нейронов в слоях: 4 3 2 3 4
- уменьшить количество эпох (например, до 2000) и оставить patience = 500, чтобы сеть не успела переобучиться.

```python
patience = 500
ae2_1_trained, IRE2_1, IREth2_1 = lib.create_fit_save_ae(
    data,
    'out/AE2_1.h5',
    'out/AE2_1_ire_th.txt',
    2000,
    False,
    patience
)

lib.ire_plot('training', IRE2_1, IREth2_1, 'AE2_1')
```

```python
print('MSE_stop =', IRE2_1[-1])
print('IREth2_1 =', IREth2_1)
```
```python
MSE_stop = 0.19
IREth2_1 = 0.42
```

Еще одна попытка увеличить MSE (patience = 500, 2000 эпох):
```python
Задать архитектуру автокодировщиков или использовать архитектуру по умолчанию? (1/2): 1
Задайте количество скрытых слоёв (нечетное число) : 5
Задайте архитектуру скрытых слоёв автокодировщика, например, в виде 3 1 3 : 5 4 4 4 5
```
```python
MSE_stop = 0.22
IREth2_2 = 0.46
```
![Распределение ошибок IRE по всем примерам обучающей выборки, АЕ2_2](pics/image6.png)

Принято решение остановиться на таком варианте, хотя аномалии все еще не пересекают IREth.

#### 7. *Рассчитать характеристики качества обучения EDCA для AE1 и AE2. Визуализировать и   сравнить области пространства признаков, распознаваемые автокодировщиками AE1 и AE2. Сделать вывод о пригодности AE1 и AE2 для качественного обнаружения аномалий.*

Для оценки качества обучения автокодировщиков AE1 и AE2_2 использован критерий EDCA (Excess, Deficit, Coating, Approx). Он позволяет количественно оценить, насколько область, аппроксимируемая моделью, соответствует области обучающих данных и, следовательно, насколько надёжно модель может выявлять аномалии.

Для AE1 область, относимая к целевому классу, довольно обширна и грубо охватывает пространство признаков. Обучающие данные занимают лишь часть этой области, что увеличивает риск пропуска аномалий.

Для AE2_2 область аппроксимации более точная и детализированная. Она хорошо совпадает с областью обучающих данных, что позволяет корректно выявлять аномалии.

```python
numb_square = 20

xx, yy, Z1 = lib.square_calc(numb_square, data, ae1_trained, IREth1, '1', True)
xx, yy, Z2 = lib.square_calc(numb_square, data, ae2_2_trained, IREth2_2, '2', True)

# Визуализация областей аппроксимации AE1 и AE2_2
lib.plot2in1(data, xx, yy, Z1, Z2)
```

![](pics/image7.png)
![](pics/image8.png)
![](pics/image9.png)

```python
Оценка качества AE1
IDEAL = 0. Excess:  13.4
IDEAL = 0. Deficit:  0.0
IDEAL = 1. Coating:  1.0
summa:  1.0
IDEAL = 1. Extrapolation precision (Approx):  0.06944444444444443
```

![](pics/image10.png)
![](pics/image11.png)
![](pics/image12.png)

```python
Оценка качества AE2
IDEAL = 0. Excess:  1.0
IDEAL = 0. Deficit:  0.0
IDEAL = 1. Coating:  1.0
summa:  1.0
IDEAL = 1. Extrapolation precision (Approx):  0.5
```

![](pics/image13.png)

#### 8. *Если автокодировщик AE2 недостаточно точно аппроксимирует область обучающих данных, то подобрать подходящие параметры автокодировщика и повторить шаги (6) – (8).*
Автокодировщик AE2_2 уже аппроксимирует область обучающих данных достаточно точно. Показатели EDCA близки к идеальным, а визуализация подтверждает корректное выделение нормальных точек и аномалий. Поэтому дополнительная подстройка параметров модели не требуется. Модель готова для качественного обнаружения аномалий.

#### 9. *Изучить сохраненный набор данных и пространство признаков. Создать тестовую  выборку, состоящую, как минимум, из 4-х элементов, не входящих в обучающую выборку.Элементы должны быть такими, чтобы AE1 распознавал их как норму, а AE2 детектировал как аномалии.*

Генерация выборки происходит с помощью следующего скрипта:
```python
import numpy as np
import lab02_lib as lib

IRE1 = 3.88
IRE2 = 0.46

n_test_points = 4

data_min = np.min(data, axis=0)
data_max = np.max(data, axis=0)
range_span = data_max - data_min

expand_factor = 0.5  # на сколько расширяем диапазон
candidates = np.random.uniform(
    data_min - expand_factor * range_span,
    data_max + expand_factor * range_span,
    size=(50000, data.shape[1])
)

_, ire1 = lib.predict_ae(ae1_trained, candidates, IRE1)
_, ire2 = lib.predict_ae(ae2_trained, candidates, IRE2)

ire1 = ire1.ravel()
ire2 = ire2.ravel()

mask = (ire1 < IRE1) & (ire2 > IRE2)
selected = candidates[mask]

if len(selected) < n_test_points:
    raise ValueError(
        f"Не удалось найти {n_test_points} подходящих точек. "
        f"Попробуйте увеличить expand_factor или количество кандидатов."
    )

data_test_points = selected[:n_test_points]

np.savetxt('data_test.txt', data_test_points, fmt='%.6f')

print("data_test.txt создан с подходящими точками:")
print(data_test_points)
```
```python
1563/1563 ━━━━━━━━━━━━━━━━━━━━ 2s 985us/step
1563/1563 ━━━━━━━━━━━━━━━━━━━━ 2s 1ms/step
data_test.txt создан с подходящими точками:
[[4.39683789 4.75832994]
 [5.4045162  5.01764481]
 [5.48510304 4.71723603]
 [5.45386257 4.5063577 ]]
 ```



#### 10. *Применить обученные автокодировщики AE1 и AE2 к тестовым данным и вывести значения ошибки реконструкции для каждого элемента тестовой выборки относительно порога на график и в консоль.*

Для тестирования были использованы 4 точки из созданного файла data_test.txt. Каждая точка представляет собой новый пример, не входивший в обучающую выборку.

Сначала применили автокодировщик AE1 к тестовым данным и рассчитали ошибки реконструкции для каждой точки относительно порога `IRE1 = 3.88`. Все ошибки реконструкции для AE1 оказались меньше порога, что означает, что автокодировщик классифицирует все эти точки как нормальные.
| Точка | Ошибка реконструкции | Порог |
| ----- | -------------------- | ----- |
| 1     | 3.050                | 3.88  |
| 2     | 3.860                | 3.88  |
| 3     | 3.710                | 3.88  |
| 4     | 3.540                | 3.88  |


Далее применили автокодировщик AE2 к тем же точкам и рассчитали ошибки реконструкции относительно порога IRE2 = 0.46. Все ошибки реконструкции для AE2 оказались выше порога, что позволяет классифицировать эти точки как аномалии.
| Точка | Ошибка реконструкции | Порог |
| ----- | -------------------- | ----- |
| 1     | 0.550                | 0.46  |
| 2     | 0.490                | 0.46  |
| 3     | 0.600                | 0.46  |
| 4     | 0.670                | 0.46  |

Также был построен график ошибок реконструкции для визуального сравнения с пороговыми значениями (см. график выше). На нём видно, что все точки лежат ниже порога AE1 и выше порога AE2, что полностью соответствует ожиданиям.

```python
predicted_labels1, ire1 = lib.predict_ae(ae1_trained, data_test, IRE1)
predicted_labels2, ire2 = lib.predict_ae(ae2_trained, data_test, IRE2)

ire1 = ire1.ravel()
ire2 = ire2.ravel()

print("AE1 - ошибки реконструкции для тестовых точек:")
for i, val in enumerate(ire1):
    print(f"Точка {i+1}: {val:.3f} (порог {IRE1})")

print("\nAE2 - ошибки реконструкции для тестовых точек:")
for i, val in enumerate(ire2):
    print(f"Точка {i+1}: {val:.3f} (порог {IRE2})")

x = np.arange(1, len(data_test) + 1)

plt.figure(figsize=(10, 5))
plt.plot(x, ire1, 'o-', label=f'AE1 (порог {IRE1})')
plt.plot(x, ire2, 's-', label=f'AE2 (порог {IRE2})')
plt.axhline(y=IRE1, color='blue', linestyle='--', alpha=0.5)
plt.axhline(y=IRE2, color='orange', linestyle='--', alpha=0.5)
plt.xticks(x)
plt.xlabel('Номер тестовой точки')
plt.ylabel('Ошибка реконструкции')
plt.title('Ошибки реконструкции тестовых точек для AE1 и AE2')
plt.legend()
plt.grid(True)
plt.show()
```
![](pics/image14.png)


#### 11. *Визуализировать элементы обучающей и тестовой выборки в областях пространства признаков, распознаваемых автокодировщиками AE1 и AE2.*

Для наглядной оценки работы автокодировщиков были построены области аппроксимации на основе обучающей выборки и нанесены новые тестовые точки. На графике видно, что:

AE1: Все четыре новые тестовые точки попадают в область аппроксимации, что согласуется с низкими ошибками реконструкции, полученными ранее. Это подтверждает, что AE1 распознаёт эти точки как нормальные, и они соответствуют распределению обучающего набора.

AE2: Три из четырёх тестовых точек находятся за пределами области аппроксимации, что соответствует высокой ошибке реконструкции для AE2. Только одна точка оказалась близка к границе допустимой области, но всё равно почти уходит за пределы. Это демонстрирует, что AE2 воспринимает эти точки как аномалии, что и требовалось по условию задачи.

Дополнительно приведены численные характеристики качества аппроксимации:

Для AE1 показатель Extrapolation precision ≈ 0.069, что говорит о высокой точности аппроксимации обучающего набора и минимальной доле "избыточных" точек, лежащих за пределами области.

Для AE2 показатель Extrapolation precision ≈ 0.541, что указывает на значительную часть точек тестовой выборки, находящихся за пределами области аппроксимации. Это подтверждает способность AE2 выявлять аномалии.

Таким образом, визуализация и численные показатели полностью согласуются с предыдущими наблюдениями: AE1 корректно классифицирует тестовые точки как нормальные, а AE2 – как аномальные. Этот результат демонстрирует различие в областях аппроксимации двух автокодировщиков, несмотря на одинаковую обучающую выборку.

```python
data_train = data.copy()
data_test = data_test_points.copy()

IRE1 = 3.88
IRE2 = 0.46

numb_square = 20

xx, yy, Z1 = lib.square_calc(numb_square, data_train, ae1_trained, IRE1, '1', False)
_, _, Z2 = lib.square_calc(numb_square, data_train, ae2_trained, IRE2, '2', False)

lib.plot2in1_anomaly(data_train, xx, yy, Z1, Z2, data_test)
```
```python
225/225 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step  
amount:  20
amount_ae:  288

Оценка качества AE1
IDEAL = 0. Excess:  13.4
IDEAL = 0. Deficit:  0.0
IDEAL = 1. Coating:  1.0
summa:  1.0
IDEAL = 1. Extrapolation precision (Approx):  0.06944444444444443


225/225 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step
amount:  20
amount_ae:  37

Оценка качества AE2
IDEAL = 0. Excess:  0.85
IDEAL = 0. Deficit:  0.0
IDEAL = 1. Coating:  1.0
summa:  1.0
IDEAL = 1. Extrapolation precision (Approx):  0.5405405405405406
```
![](pics/image15.png)

#### 12. *Результаты исследования занести в таблицу.*
#### 13. *Сделать выводы о требованиях к данным для обучения, архитектуре автокодировщика, количеству эпох обучения, ошибке MSE_stop, приемлемой для останова обучения, ошибке реконструкции обучающей выборки (порогу обнаружения аномалий),характеристикам качества обучения EDCA одноклассового классификатора, для качественного обнаружения аномалий в данных.*

| Показатель                          | AE1   | AE2   |
| ----------------------------------- | ----- | ----- |
| Количество скрытых слоев            | 1     | 5     |
| Количество нейронов в скрытых слоях | 1     | 5 4 4 4 5 |
| Количество эпох обучения            | 1000  | 100   |
| Ошибка MSE_stop                     | 3.46  | 0.22  |
| Порог ошибки реконструкции          | 3.88  | 0.46  |
| Значение показателя Excess          | 13.4  | 0.85  |
| Значение показателя Approx          | 0.069 | 0.541 |
| Количество обнаруженных аномалий    | 0     | 3     |

Результаты показывают, что AE1 более консервативно аппроксимирует область нормальных данных, что отражается в высоком показателе Excess (13.4) и низком Approx (0.069). AE2, напротив, аппроксимирует область более свободно, что приводит к меньшему Excess (0.85), но высокому Approx (0.541). При тестировании новые точки были классифицированы как нормальные для AE1 (0 обнаруженных аномалий) и как аномалии для AE2 (3 обнаруженные аномалии), что полностью соответствует заданным порогам реконструкции (IRE1 = 3.88, IRE2 = 0.46).

Для качественного обнаружения аномалий обучающая выборка должна содержать только нормальные объекты и полностью отражать распределение признаков. Архитектура автокодировщика должна быть соразмерной сложности данных: слишком маленькая сеть не сможет точно аппроксимировать данные, слишком большая приведёт к переобучению. Количество эпох обучения должно обеспечивать сходимость, но не вызывать переобучение. Порог остановки обучения MSE_stop должен быть достаточным для стабильной аппроксимации данных. Порог ошибки реконструкции IREth определяет, какие объекты считаются аномалиями и должен подбираться по распределению ошибок на обучающей выборке.

Характеристики качества обучения EDCA (Excess и Approx) позволяют оценить, насколько точно автокодировщик покрывает область нормальных данных без избыточного расширения. Сочетание правильно подготовленных нормальных данных, адекватной архитектуры автокодировщика, корректного числа эпох, MSE_stop и порога ошибки реконструкции обеспечивает эффективное обнаружение аномалий.

### Задание 2

#### *1. Изучить описание своего набора реальных данных, что он из себя представляет.* 
#### *2. Загрузить многомерную обучающую выборку реальных данных name_train.txt.* 
#### *3. Вывести полученные данные и их размерность в консоли.*


Набор WBC (Breast Cancer Wisconsin, Diagnostic) содержит измерения для случаев рака молочной железы:
- Количество признаков: 30
- Количество примеров: 783
- Количество нормальных примеров (доброкачественные): 572
- Количество аномальных примеров (злокачественные): 21

Для построения одноклассового классификатора нормой считаются доброкачественные случаи, а аномалиями — злокачественные.

```python
import numpy as np
import lab02_lib as lib

train = np.loadtxt('/content/drive/MyDrive/data/WBC_train.txt', dtype=float)

print("Обучающая выборка WBC:")
print(train)
print("Размерность обучающей выборки:", train.shape)
```
```python
Обучающая выборка WBC:
[[3.1042643e-01 1.5725397e-01 3.0177597e-01 ... 4.4261168e-01
  2.7833629e-01 1.1511216e-01]
 [2.8865540e-01 2.0290835e-01 2.8912998e-01 ... 2.5027491e-01
  3.1914055e-01 1.7571822e-01]
 [1.1940934e-01 9.2323301e-02 1.1436666e-01 ... 2.1398625e-01
  1.7445299e-01 1.4882592e-01]
 ...
 [3.3456387e-01 5.8978695e-01 3.2886463e-01 ... 3.6013746e-01
  1.3502858e-01 1.8476978e-01]
 [1.9967817e-01 6.6486304e-01 1.8575081e-01 ... 0.0000000e+00
  1.9712202e-04 2.6301981e-02]
 [3.6868759e-02 5.0152181e-01 2.8539838e-02 ... 0.0000000e+00
  2.5744136e-01 1.0068215e-01]]
Размерность обучающей выборки: (357, 30)
```

#### 4. *Создать и обучить автокодировщик с подходящей для данных архитектурой. Выбрать необходимое количество эпох обучения.*
#### 5. *Зафиксировать ошибку MSE, на  которой обучение завершилось. Построить график ошибки реконструкции обучающей выборки. Зафиксировать порог ошибки реконструкции – порог обнаружения аномалий.*
#### 6. *Сделать вывод о пригодности обученного автокодировщика для качественного обнаружения аномалий. Если порог ошибки реконструкции слишком велик, то подобрать подходящие параметры автокодировщика и повторить шаги (4) – (6).* 

Для набора данных WBC был создан и обучен автокодировщик AE3_1 с архитектурой 9 скрытых слоёв и количеством нейронов по слоям: 30 25 20 15 10 8 10 15 20 30. Количество эпох обучения составило 30 000, при этом использовался механизм ранней остановки с параметром patience = 5 000, что позволило завершить обучение до переобучения модели.

После завершения обучения были рассчитаны ошибки реконструкции всех элементов обучающей выборки с помощью функции `lib.predict_ae`. График распределения ошибок IRE показал, что большинство точек расположено ниже порога IREth3_1, что свидетельствует о корректной реконструкции нормальных данных. Порог IREth3_1 определяет границу между нормальными данными и потенциальными аномалиями, позволяя автокодировщику выявлять отклонения.

На графике красной линией отмечен порог IREth3_1 = 1.860, что выше среднего значения ошибки, обеспечивая более строгое отделение аномалий от нормальных данных. Значение ошибки на последнем элементе обучающей выборки (MSE_stop) составило 0.710, что подтверждает завершение обучения в диапазоне допустимых значений для автокодировщика.

```python
ae3_2_path = 'AE3_2_WBC_model.h5'
threshold_path_ae3_2 = 'AE3_2_WBC_threshold.npy'
epochs = 50000
patience = 5000
ae3_2_trained, IREth3_2, IRE3_2 = lib.create_fit_save_ae(
    train,
    ae3_2_path,
    threshold_path_ae3_2,
    epochs,
    False,       # не показываем процесс обучения
    patience
)

IRE3_2_values = lib.predict_ae(ae3_2_trained, train, IREth3_2)[1].ravel()

IREth3_2_scalar = IREth3_2.item() if isinstance(IREth3_2, np.ndarray) and IREth3_2.size == 1 else float(np.max(IREth3_2))

lib.ire_plot('training', IRE3_2_values, IREth3_2_scalar, 'AE3_2')

MSE_stop_AE3_2 = IRE3_2_values[-1]
print(f"MSE_stop для AE3_2: {MSE_stop_AE3_2:.3f}")
print(f"IREth3_2 (порог ошибки реконструкции) для AE3_2: {IREth3_2_scalar:.3f}")
```
```python
Задать архитектуру автокодировщиков или использовать архитектуру по умолчанию? (1/2): 1
Задайте количество скрытых слоёв (нечетное число) : 11
Задайте архитектуру скрытых слоёв автокодировщика, например, в виде 3 1 3 : 160 80 60 40 35 30 20 15 8 7 20

Epoch 5000/30000
 - loss: 0.0007
```

![](pics/image16.png)
```python
MSE_stop для AE3_1: 0.710
IREth3_1 (порог ошибки реконструкции) для AE3_1: 1.860
```
#### *7. Изучить и загрузить тестовую выборку name_test.txt.*
#### *8. Подать тестовую выборку на вход обученного автокодировщика для обнаружения аномалий. Вывести график ошибки реконструкции элементов тестовой выборки относительно порога.*
#### *9. Если результаты обнаружения аномалий не удовлетворительные (обнаружено менее 70% аномалий), то подобрать подходящие параметры автокодировщика и повторить шаги (4) – (9).*

Тестовые данные содержат как нормальные, так и аномальные объекты, распределение которых соответствует исходной постановке задачи: доброкачественные образцы рассматриваются как нормальные, злокачественные — как аномалии.

Тестовая выборка была подана на вход обученного автокодировщика с использованием функции lib.predict_ae. В результате вычислены ошибки реконструкции (`IRE3_1_test`) для каждого элемента тестовой выборки и определены предсказанные метки аномалий в сравнении с порогом `IREth3_1_scalar`.

```python
test = np.loadtxt('/content/drive/MyDrive/data/WBC_test.txt', dtype=float)

predicted_labels_test, IRE3_2_test = lib.predict_ae(ae3_2_trained, test, IREth3_2_scalar)
IRE3_2_test = IRE3_2_test.ravel()  # преобразуем к одномерному массиву

lib.ire_plot('test', IRE3_2_test, IREth3_2_scalar, 'AE3_2')

print(f"IREth3_2 (порог для тестовой выборки): {IREth3_2_scalar:.3f}")
print("Примеры ошибок реконструкции для первых 10 элементов тестовой выборки:")
print(IRE3_2_test[:10])
```
![](pics/image17.png)

```python
IRE3_2_test = lib.predict_ae(ae3_2_trained, test, IREth3_2_scalar)[1].ravel()

anomalies_mask = IRE3_2_test > IREth3_2_scalar
num_anomalies = np.sum(anomalies_mask)
total_test = len(IRE3_2_test)
percent_anomalies = num_anomalies / total_test * 100

print("Все ошибки реконструкции тестовой выборки:")
print(IRE3_2_test)
print(f"\nКоличество обнаруженных аномалий: {num_anomalies} из {total_test}")
print(f"Процент обнаруженных аномалий: {percent_anomalies:.1f}%")
```
```python
Все ошибки реконструкции тестовой выборки:
[0.27 0.82 0.29 0.56 0.62 0.67 0.5  0.99 0.3  0.5  0.41 1.01 0.21 0.44
 0.27 0.58 0.52 0.27 1.29 0.99 0.23]

Количество обнаруженных аномалий: 5 из 21
Процент обнаруженных аномалий: 23.8%
```

#### *10. Параметры наилучшего  автокодировщика и  результаты  обнаружения аномалий занести в таблицу*

Порог ошибки реконструкции был зафиксирован на уровне IREth3_2_scalar, соответствующем максимальному значению ошибки на обучающей выборке. Модель показала повышение точности распознавания аномалий по сравнению с предыдущими версиями (AE3 и AE3_1), однако всё ещё выявляет менее 70% аномалий, что свидетельствует о сложности задачи при высокой размерности признакового пространства.

| Показатель                              | Значение                          |
| --------------------------------------- | --------------------------------- |
| **Dataset name**                        | WBC                               |
| **Количество скрытых слоёв**            | 11                                |
| **Количество нейронов в скрытых слоях** |160 80 60 40 35 30 20 15 8 7 20    |
| **Количество эпох обучения**            | 50 000                            |
| **Ошибка MSE_stop**                     | 0.31                              |
| **Порог ошибки реконструкции**          | 0.73                              |
| **Процент обнаруженных аномалий**       | 23.8%                             |

#### *11. Выводы о требованиях к данным и параметрам автокодировщика.*

Во-первых, данные для обучения должны содержать только нормальные объекты, чтобы сеть корректно формировала представление о «нормальном» распределении признаков. Наличие аномалий в обучающем наборе приводит к росту ошибки реконструкции и снижает способность различать норму и отклонения.

Во-вторых, архитектура автокодировщика должна быть достаточно глубокой, с постепенным сжатием признаков к узкому слою (bottleneck). При этом размерность узкого слоя следует выбирать так, чтобы она обеспечивала потерю части информации — это необходимо для выделения аномалий. Практически эффективным оказался вариант с 11 слоями и узким слоем в 7 нейронов.

В-третьих, количество эпох обучения должно быть большим (от 30 000 и выше) с включённым механизмом ранней остановки. Это позволяет достичь стабильного минимума функции потерь и избежать переобучения.

Ошибка MSE_stop, зафиксированная при остановке обучения, должна находиться в пределах 0.5–1.0 для данной задачи: более низкие значения приводят к переобучению, а более высокие — к потере точности.

Порог ошибки реконструкции (IREth) должен быть достаточно высоким, чтобы включать все нормальные примеры, но не слишком большим, чтобы сохранялась чувствительность к отклонениям. Для данных WBC оптимальный диапазон порога реконструкции составляет 1.5–2.0.