|
|
# Лабораторная работа №2: Обнаружение аномалий с помощью автокодировщиков
|
|
|
**Аникеев А.А; Чагин С.А. — А-02-22**
|
|
|
## Вариант 2 (номер бригады k=5) - данные WBC
|
|
|
|
|
|
### Цель работы
|
|
|
|
|
|
Получить практические навыки создания, обучения и применения искусственных нейронных сетей типа автокодировщик.
|
|
|
Исследовать влияние архитектуры автокодировщика и количества эпох обучения на области в пространстве признаков,
|
|
|
распознаваемые автокодировщиком после обучения. Научиться оценивать качество обучения автокодировщика на основе
|
|
|
ошибки реконструкции и новых метрик EDCA. Научиться решать актуальную задачу обнаружения аномалий в данных с
|
|
|
помощью автокодировщика как одноклассового классификатора.
|
|
|
|
|
|
### Определение варианта
|
|
|
|
|
|
- Номер бригады: k = 5
|
|
|
- N = k mod 3 = 5 mod 3 = 2
|
|
|
- Вариант 2 => данные **WBC**
|
|
|
|
|
|
### Подготовка среды
|
|
|
|
|
|
```python
|
|
|
import os
|
|
|
os.chdir('/content/drive/MyDrive/Colab Notebooks')
|
|
|
```
|
|
|
|
|
|
```python
|
|
|
from google.colab import drive
|
|
|
drive.mount('/content/drive')
|
|
|
import os
|
|
|
work_dir = '/content/drive/MyDrive/Colab Notebooks/is_lab2'
|
|
|
os.makedirs(work_dir, exist_ok=True)
|
|
|
os.chdir(work_dir)
|
|
|
os.makedirs('out', exist_ok=True)
|
|
|
dataset_name = 'WBC'
|
|
|
base_url = "http://uit.mpei.ru/git/main/is_dnn/raw/branch/main/labworks/LW2/"
|
|
|
!wget -N {base_url}lab02_lib.py
|
|
|
!wget -N {base_url}data/{dataset_name}_train.txt
|
|
|
!wget -N {base_url}data/{dataset_name}_test.txt
|
|
|
!cp {dataset_name}_train.txt train.txt
|
|
|
!cp {dataset_name}_test.txt test.txt
|
|
|
print("Файлы успешно скачаны!")
|
|
|
print("Содержимое рабочей директории:")
|
|
|
!ls -la
|
|
|
```
|
|
|
|
|
|
---
|
|
|
|
|
|
## ЗАДАНИЕ 1
|
|
|
|
|
|
### Пункт №1. Импорт необходимых для работы библиотек и модулей.
|
|
|
```python
|
|
|
import numpy as np
|
|
|
import matplotlib.pyplot as plt
|
|
|
from sklearn.preprocessing import StandardScaler
|
|
|
from sklearn.datasets import make_blobs
|
|
|
import tensorflow as tf
|
|
|
from tensorflow.keras.models import Sequential
|
|
|
from tensorflow.keras.layers import Dense, Activation
|
|
|
from tensorflow.keras.optimizers import Adam
|
|
|
from tensorflow.keras.callbacks import EarlyStopping
|
|
|
import lab02_lib as lib
|
|
|
|
|
|
# Параметры для варианта 5
|
|
|
k = 5 # номер бригады
|
|
|
center_coords = (k, k) # координаты центра (5, 5)
|
|
|
```
|
|
|
|
|
|
**Описание:** Импортируем необходимые библиотеки, модули, устанавливаются параметры для варианта 2.
|
|
|
|
|
|
### Пункт №2. Генерация индивидуального набора двумерных данных в пространстве признаков.
|
|
|
```python
|
|
|
|
|
|
print("Генерация синтетических данных с центром в (5, 5)...")
|
|
|
|
|
|
data = lib.datagen(k, k, 1000, 2)
|
|
|
|
|
|
print(f"Сгенерировано {len(data)} точек")
|
|
|
print(f"Центр данных: {center_coords}")
|
|
|
print(f"Размерность данных: {data.shape}")
|
|
|
```
|
|
|
|
|
|
**Результат выполнения:**
|
|
|
```
|
|
|
Сгенерировано 1000 точек
|
|
|
Центр данных: (5, 5)
|
|
|
Размерность данных: (1000, 2)
|
|
|
```
|
|
|
|
|
|

|
|
|
|
|
|
### Пункт №3. Создание и обучение автокодировщика AE1 простой архитектуры.
|
|
|
```python
|
|
|
print("="*50)
|
|
|
print("Обучение AE1")
|
|
|
print("="*50)
|
|
|
|
|
|
def create_simple_ae():
|
|
|
model = Sequential()
|
|
|
|
|
|
model.add(Dense(2, input_shape=(2,), activation='tanh'))
|
|
|
|
|
|
model.add(Dense(1, activation='tanh'))
|
|
|
|
|
|
model.add(Dense(2, activation='linear'))
|
|
|
return model
|
|
|
|
|
|
ae1 = create_simple_ae()
|
|
|
ae1.compile(optimizer=Adam(learning_rate=0.001), loss='mse')
|
|
|
|
|
|
print("Архитектура AE1:")
|
|
|
ae1.summary()
|
|
|
|
|
|
print("\nНачало обучения AE1...")
|
|
|
history_ae1 = ae1.fit(data, data,
|
|
|
epochs=1000,
|
|
|
batch_size=32,
|
|
|
validation_split=0.2,
|
|
|
verbose=1,
|
|
|
callbacks=[EarlyStopping(patience=300, restore_best_weights=True)])
|
|
|
|
|
|
ae1.save('out/AE1.h5')
|
|
|
|
|
|
X_pred_ae1 = ae1.predict(data)
|
|
|
reconstruction_errors_ae1 = np.mean(np.square(data - X_pred_ae1), axis=1)
|
|
|
threshold_ae1 = np.max(reconstruction_errors_ae1)
|
|
|
|
|
|
print("\nАнализ результатов AE1")
|
|
|
mse_ae1 = history_ae1.history['loss'][-1]
|
|
|
print(f"Финальная ошибка MSE AE1: {mse_ae1:.6f}")
|
|
|
print(f"Порог ошибки реконструкции AE1: {threshold_ae1:.6f}")
|
|
|
|
|
|
plt.figure(figsize=(15, 4))
|
|
|
|
|
|
plt.subplot(1, 3, 1)
|
|
|
plt.plot(history_ae1.history['loss'], label='Training Loss', color='blue')
|
|
|
plt.plot(history_ae1.history['val_loss'], label='Validation Loss', color='red')
|
|
|
plt.title('AE1: Ошибка обучения (MSE)')
|
|
|
plt.xlabel('Эпоха')
|
|
|
plt.ylabel('MSE')
|
|
|
plt.legend()
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
plt.subplot(1, 3, 2)
|
|
|
plt.plot(reconstruction_errors_ae1, 'b-', alpha=0.7, linewidth=0.8)
|
|
|
plt.axhline(y=threshold_ae1, color='red', linestyle='--', linewidth=2,
|
|
|
label=f'Порог: {threshold_ae1:.2f}')
|
|
|
plt.title('AE1: Ошибки реконструкции')
|
|
|
plt.xlabel('Номер точки')
|
|
|
plt.ylabel('Ошибка реконструкции')
|
|
|
plt.legend()
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
plt.subplot(1, 3, 3)
|
|
|
plt.hist(reconstruction_errors_ae1, bins=20, alpha=0.7, color='blue', edgecolor='black')
|
|
|
plt.axvline(threshold_ae1, color='red', linestyle='--', linewidth=2,
|
|
|
label=f'Порог: {threshold_ae1:.2f}')
|
|
|
plt.title('AE1: Распределение ошибок')
|
|
|
plt.xlabel('Ошибка реконструкции')
|
|
|
plt.ylabel('Частота')
|
|
|
plt.legend()
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
plt.tight_layout()
|
|
|
plt.savefig('out/ae1_detailed_results.png', dpi=300, bbox_inches='tight')
|
|
|
plt.show()
|
|
|
|
|
|
with open('out/AE1_ire_th.txt', 'w') as f:
|
|
|
f.write(str(threshold_ae1))
|
|
|
|
|
|
ae1_trained = ae1
|
|
|
IRE1 = reconstruction_errors_ae1
|
|
|
IREth1 = threshold_ae1
|
|
|
|
|
|
print(f"Обучение AE1 завершено!")
|
|
|
print(f"Минимальная ошибка: {np.min(IRE1):.6f}")
|
|
|
print(f"Максимальная ошибка: {np.max(IRE1):.6f}")
|
|
|
print(f"Средняя ошибка: {np.mean(IRE1):.6f}")
|
|
|
```
|
|
|
|
|
|
**Описание:** Создается автокодировщик AE1 с простой архитектурой, одним скрытым слоем с одним нейроном.
|
|
|
|
|
|
**Результаты обучения AE1:**
|
|
|
|
|
|
Финальная ошибка MSE AE1: 0.009326
|
|
|
|
|
|
Порог ошибки реконструкции AE1: 0.067896
|
|
|
|
|
|
Минимальная ошибка: 0.000035
|
|
|
|
|
|
Максимальная ошибка: 0.067896
|
|
|
|
|
|

|
|
|
|
|
|
### Пункт №4. Создание и обучение второго автокодировщика AE2 усложненной архитектуры.
|
|
|
|
|
|
```python
|
|
|
print("="*50)
|
|
|
print("Обучение AE2")
|
|
|
print("="*50)
|
|
|
|
|
|
print("Используется архитектура по умолчанию: [2-3-2-1-2-3-2]")
|
|
|
print("Количество скрытых слоев: 5")
|
|
|
print("Нейроны в скрытых слоях: 3-2-1-2-3")
|
|
|
|
|
|
def create_ae2_default():
|
|
|
model = Sequential()
|
|
|
|
|
|
model.add(Dense(2, input_shape=(2,), activation='tanh'))
|
|
|
|
|
|
model.add(Dense(3, activation='tanh'))
|
|
|
model.add(Dense(2, activation='tanh'))
|
|
|
model.add(Dense(1, activation='tanh'))
|
|
|
model.add(Dense(2, activation='tanh'))
|
|
|
model.add(Dense(3, activation='tanh'))
|
|
|
|
|
|
model.add(Dense(2, activation='linear'))
|
|
|
|
|
|
return model
|
|
|
|
|
|
ae2 = create_ae2_default()
|
|
|
ae2.compile(optimizer=Adam(learning_rate=0.001), loss='mse')
|
|
|
|
|
|
print("\nАрхитектура AE2:")
|
|
|
ae2.summary()
|
|
|
|
|
|
print(f"\nНачало обучения AE2 (patience=300)...")
|
|
|
history_ae2 = ae2.fit(data, data,
|
|
|
epochs=3000,
|
|
|
batch_size=32,
|
|
|
validation_split=0.2,
|
|
|
verbose=1,
|
|
|
callbacks=[EarlyStopping(patience=300, restore_best_weights=True)])
|
|
|
|
|
|
ae2.save('out/AE2.h5')
|
|
|
|
|
|
X_pred_ae2 = ae2.predict(data)
|
|
|
reconstruction_errors_ae2 = np.mean(np.square(data - X_pred_ae2), axis=1)
|
|
|
threshold_ae2 = np.max(reconstruction_errors_ae2)
|
|
|
|
|
|
print("\n" + "="*50)
|
|
|
print("АНАЛИЗ РЕЗУЛЬТАТОВ AE2")
|
|
|
print("="*50)
|
|
|
mse_ae2 = history_ae2.history['loss'][-1]
|
|
|
print(f"Финальная ошибка MSE AE2: {mse_ae2:.6f}")
|
|
|
print(f"Порог ошибки реконструкции AE2: {threshold_ae2:.6f}")
|
|
|
|
|
|
print("\nПРОВЕРКА РЕКОМЕНДАЦИЙ:")
|
|
|
if mse_ae2 >= 0.01:
|
|
|
print("✓ MSE_stop для AE2 соответствует рекомендации (≥ 0.01)")
|
|
|
else:
|
|
|
print("✗ MSE_stop для AE2 слишком низкая, возможно переобучение")
|
|
|
|
|
|
plt.figure(figsize=(15, 4))
|
|
|
|
|
|
plt.subplot(1, 3, 1)
|
|
|
plt.plot(history_ae2.history['loss'], label='Training Loss', color='green', linewidth=2)
|
|
|
plt.plot(history_ae2.history['val_loss'], label='Validation Loss', color='red', linewidth=2)
|
|
|
plt.title('AE2: Динамика обучения (MSE)', fontsize=12, fontweight='bold')
|
|
|
plt.xlabel('Эпоха')
|
|
|
plt.ylabel('MSE')
|
|
|
plt.legend()
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
plt.subplot(1, 3, 2)
|
|
|
plt.plot(reconstruction_errors_ae2, 'g-', alpha=0.7, linewidth=0.8)
|
|
|
plt.axhline(y=threshold_ae2, color='red', linestyle='--', linewidth=2,
|
|
|
label=f'Порог: {threshold_ae2:.4f}')
|
|
|
plt.title('AE2: Ошибки реконструкции по точкам', fontsize=12, fontweight='bold')
|
|
|
plt.xlabel('Номер точки')
|
|
|
plt.ylabel('Ошибка реконструкции')
|
|
|
plt.legend()
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
plt.subplot(1, 3, 3)
|
|
|
plt.hist(reconstruction_errors_ae2, bins=20, alpha=0.7, color='green', edgecolor='black')
|
|
|
plt.axvline(threshold_ae2, color='red', linestyle='--', linewidth=2,
|
|
|
label=f'Порог: {threshold_ae2:.4f}')
|
|
|
plt.title('AE2: Распределение ошибок', fontsize=12, fontweight='bold')
|
|
|
plt.xlabel('Ошибка реконструкции')
|
|
|
plt.ylabel('Частота')
|
|
|
plt.legend()
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
plt.tight_layout()
|
|
|
plt.savefig('out/ae2_detailed_results.png', dpi=300, bbox_inches='tight')
|
|
|
plt.show()
|
|
|
|
|
|
with open('out/AE2_ire_th.txt', 'w') as f:
|
|
|
f.write(str(threshold_ae2))
|
|
|
|
|
|
ae2_trained = ae2
|
|
|
IRE2 = reconstruction_errors_ae2
|
|
|
IREth2 = threshold_ae2
|
|
|
|
|
|
print("\nДЕТАЛЬНАЯ СТАТИСТИКА AE2:")
|
|
|
print(f"Минимальная ошибка: {np.min(IRE2):.6f}")
|
|
|
print(f"Максимальная ошибка: {np.max(IRE2):.6f}")
|
|
|
print(f"Средняя ошибка: {np.mean(IRE2):.6f}")
|
|
|
print(f"Медианная ошибка: {np.median(IRE2):.6f}")
|
|
|
print(f"Стандартное отклонение: {np.std(IRE2):.6f}")
|
|
|
print(f"Количество точек с ошибкой выше порога: {np.sum(IRE2 > IREth2)}")
|
|
|
print(f"Процент точек выше порога: {np.sum(IRE2 > IREth2) / len(IRE2) * 100:.2f}%")
|
|
|
|
|
|
print(f"\nОбучение AE2 завершено!")
|
|
|
print(f"Архитектура: [2-3-2-1-2-3-2]")
|
|
|
print(f"Количество скрытых слоев: 5")
|
|
|
print(f"Нейроны в скрытых слоях: 3-2-1-2-3")
|
|
|
```
|
|
|
|
|
|
**Описание:** Создается автокодировщик AE2 с усложненной архитектурой, 5 скрытых слоев с нейронами: 3, 2, 1, 2, 3.
|
|
|
|
|
|
**Результаты обучения AE2:**
|
|
|
|
|
|
Финальная ошибка MSE AE2: 0.004915
|
|
|
|
|
|
Порог ошибки реконструкции AE2: 0.044551
|
|
|
|
|
|
Минимальная ошибка: 0.000000
|
|
|
|
|
|
Максимальная ошибка: 0.044551
|
|
|
|
|
|
Средняя ошибка: 0.004790
|
|
|
|
|
|
Медианная ошибка: 0.002186
|
|
|
|
|
|
Стандартное отклонение: 0.006661
|
|
|
|
|
|
Количество точек с ошибкой выше порога: 0
|
|
|
|
|
|
Процент точек выше порога: 0.00%
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
### Пункт №5. Характеристики качества обучения EDCA.
|
|
|
```python
|
|
|
print("="*70)
|
|
|
print("РАСЧЕТ ХАРАКТЕРИСТИК КАЧЕСТВА ОБУЧЕНИЯ EDCA")
|
|
|
print("="*70)
|
|
|
|
|
|
numb_square = 20
|
|
|
|
|
|
print("\n" + "="*30)
|
|
|
print("РАСЧЕТ ДЛЯ AE1")
|
|
|
print("="*30)
|
|
|
xx, yy, Z1 = lib.square_calc(numb_square, data, ae1_trained, IREth1, '1', True)
|
|
|
|
|
|
print("\n" + "="*30)
|
|
|
print("РАСЧЕТ ДЛЯ AE2")
|
|
|
print("="*30)
|
|
|
xx, yy, Z2 = lib.square_calc(numb_square, data, ae2_trained, IREth2, '2', True)
|
|
|
|
|
|
print("\n" + "="*50)
|
|
|
print("СРАВНЕНИЕ ОБЛАСТЕЙ АППРОКСИМАЦИИ AE1 И AE2")
|
|
|
print("="*50)
|
|
|
lib.plot2in1(data, xx, yy, Z1, Z2)
|
|
|
```
|
|
|
|
|
|
**Оценка качества AE1:**
|
|
|
|
|
|
IDEAL = 0. Excess: 0.0
|
|
|
|
|
|
IDEAL = 0. Deficit: 0.7777777777777778
|
|
|
|
|
|
IDEAL = 1. Coating: 0.2222222222222222
|
|
|
|
|
|
summa: 1.0
|
|
|
|
|
|
IDEAL = 1. Extrapolation precision (Approx): 4.5
|
|
|
|
|
|
**Оценка качества AE2:**
|
|
|
|
|
|
IDEAL = 0. Excess: 0.2222222222222222
|
|
|
|
|
|
IDEAL = 0. Deficit: 0.6111111111111112
|
|
|
|
|
|
IDEAL = 1. Coating: 0.3888888888888889
|
|
|
|
|
|
summa: 1.0
|
|
|
|
|
|
IDEAL = 1. Extrapolation precision (Approx): 1.6363636363636365
|
|
|
|
|
|

|
|
|
|
|
|

|
|
|
|
|
|

|
|
|
|
|
|

|
|
|
|
|
|

|
|
|
|
|
|
**ВЫВОД О ПРИГОДНОСТИ AE1 И AE2 ДЛЯ ОБНАРУЖЕНИЯ АНОМАЛИЙ**
|
|
|
|
|
|
На основе анализа характеристик EDCA можно сделать следующие выводы:
|
|
|
AE1 (простая архитектура [2-1-2]):
|
|
|
|
|
|
НЕ ПРИГОДЕН для качественного обнаружения аномалий по следующим причинам:
|
|
|
|
|
|
Deficit = 0.78 - критически высокое значение, что означает, что автокодировщик пропускает 78% обучающих данных и не распознает их как нормальные
|
|
|
|
|
|
Coating = 0.22 - чрезвычайно низкое значение, автокодировщик охватывает только 22% области обучающих данных
|
|
|
|
|
|
Approx = 4.5 - значительно превышает идеальное значение 1, что свидетельствует о очень плохой аппроксимации данных
|
|
|
|
|
|
Положительный аспект: Excess = 0.0 - автокодировщик не распознает лишние области, что является хорошим свойством, но недостаточным для компенсации других недостатков.
|
|
|
AE2 (архитектура [2-3-2-1-2-3-2]):
|
|
|
|
|
|
ТРЕБУЕТ СУЩЕСТВЕННОГО УЛУЧШЕНИЯ и в текущем состоянии не пригоден для качественного обнаружения аномалий:
|
|
|
|
|
|
Excess = 0.22 - автокодировщик распознает 22% лишних областей, что может приводить к пропуску аномалий
|
|
|
|
|
|
Deficit = 0.61 - все еще высокое значение, 61% данных не распознается как нормальные
|
|
|
|
|
|
Coating = 0.39 - низкое покрытие, только 39% обучающих данных охватывается областью распознавания
|
|
|
|
|
|
Approx = 1.64 - лучше чем у AE1, но все еще далеко от идеального значения 1
|
|
|
|
|
|
ОБЩИЙ ВЫВОД:
|
|
|
|
|
|
Оба автокодировщика демонстрируют недостаточное качество аппроксимации обучающих данных. AE1 слишком прост и не способен adequately выучить распределение данных, в то время как AE2, хотя и показывает улучшение, все еще требует значительной доработки архитектуры и параметров обучения для достижения приемлемого качества обнаружения аномалий.
|
|
|
|
|
|
Рекомендация: Необходимо создать улучшенный автокодировщик AE3 с более сложной архитектурой, увеличить количество эпох обучения и оптимизировать гиперпараметры для достижения значений EDCA, близких к идеальным (Excess ≈ 0, Deficit ≈ 0, Coating ≈ 1, Approx ≈ 1).
|
|
|
|
|
|
### Пункт №6. Улучшение автокодировщика АЕ2.
|
|
|
|
|
|
**Анализ проблем текущего AE2:**
|
|
|
|
|
|
• Excess = 0.22 - слишком много лишних областей
|
|
|
|
|
|
• Deficit = 0.61 - пропускает много нормальных данных
|
|
|
|
|
|
• Coating = 0.39 - плохое покрытие обучающих данных
|
|
|
|
|
|
• Approx = 1.64 - требует улучшения аппроксимации
|
|
|
|
|
|
**Стратегия улучшения AE2:**
|
|
|
|
|
|
• Увеличение количества эпох обучения с 3000 до 5000
|
|
|
|
|
|
• Увеличение patience с 300 до 400
|
|
|
|
|
|
• Уменьшение learning rate с 0.001 до 0.0005
|
|
|
|
|
|
• Уменьшение batch size с 32 до 16
|
|
|
|
|
|
```python
|
|
|
print("="*70)
|
|
|
print("УЛУЧШЕНИЕ АВТОКОДИРОВЩИКА AE2 - ПОВТОРНОЕ ОБУЧЕНИЕ")
|
|
|
print("="*70)
|
|
|
|
|
|
def create_ae2_improved():
|
|
|
model = Sequential()
|
|
|
|
|
|
model.add(Dense(2, input_shape=(2,), activation='tanh'))
|
|
|
|
|
|
model.add(Dense(3, activation='tanh'))
|
|
|
model.add(Dense(2, activation='tanh'))
|
|
|
model.add(Dense(1, activation='tanh'))
|
|
|
model.add(Dense(2, activation='tanh'))
|
|
|
model.add(Dense(3, activation='tanh'))
|
|
|
|
|
|
model.add(Dense(2, activation='linear'))
|
|
|
|
|
|
return model
|
|
|
|
|
|
ae2_improved = create_ae2_improved()
|
|
|
ae2_improved.compile(optimizer=Adam(learning_rate=0.0005), loss='mse')
|
|
|
|
|
|
print("\nАрхитектура AE2 (улучшенный): [2-3-2-1-2-3-2]")
|
|
|
print("Количество скрытых слоев: 5")
|
|
|
ae2_improved.summary()
|
|
|
|
|
|
print(f"\nНачало обучения улучшенного AE2 (5000 эпох, patience=400)...")
|
|
|
history_ae2_improved = ae2_improved.fit(data, data,
|
|
|
epochs=5000,
|
|
|
batch_size=16,
|
|
|
validation_split=0.2,
|
|
|
verbose=1,
|
|
|
callbacks=[EarlyStopping(patience=400, restore_best_weights=True)])
|
|
|
|
|
|
ae2_improved.save('out/AE2_improved.h5')
|
|
|
|
|
|
X_pred_ae2_improved = ae2_improved.predict(data)
|
|
|
reconstruction_errors_ae2_improved = np.mean(np.square(data - X_pred_ae2_improved), axis=1)
|
|
|
threshold_ae2_improved = np.max(reconstruction_errors_ae2_improved)
|
|
|
|
|
|
print("\n" + "="*50)
|
|
|
print("АНАЛИЗ РЕЗУЛЬТАТОВ УЛУЧШЕННОГО AE2")
|
|
|
print("="*50)
|
|
|
mse_ae2_improved = history_ae2_improved.history['loss'][-1]
|
|
|
print(f"Финальная ошибка MSE улучшенного AE2: {mse_ae2_improved:.6f}")
|
|
|
print(f"Порог ошибки реконструкции улучшенного AE2: {threshold_ae2_improved:.6f}")
|
|
|
|
|
|
plt.figure(figsize=(15, 4))
|
|
|
|
|
|
plt.subplot(1, 3, 1)
|
|
|
plt.plot(history_ae2_improved.history['loss'], label='Training Loss', color='green', linewidth=2)
|
|
|
plt.plot(history_ae2_improved.history['val_loss'], label='Validation Loss', color='red', linewidth=2)
|
|
|
plt.title('AE2 (улучшенный): Динамика обучения', fontsize=12, fontweight='bold')
|
|
|
plt.xlabel('Эпоха')
|
|
|
plt.ylabel('MSE')
|
|
|
plt.legend()
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
plt.subplot(1, 3, 2)
|
|
|
plt.plot(reconstruction_errors_ae2_improved, 'green', alpha=0.7, linewidth=0.8)
|
|
|
plt.axhline(y=threshold_ae2_improved, color='red', linestyle='--', linewidth=2,
|
|
|
label=f'Порог: {threshold_ae2_improved:.4f}')
|
|
|
plt.title('AE2 (улучшенный): Ошибки реконструкции', fontsize=12, fontweight='bold')
|
|
|
plt.xlabel('Номер точки')
|
|
|
plt.ylabel('Ошибка реконструкции')
|
|
|
plt.legend()
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
plt.subplot(1, 3, 3)
|
|
|
plt.hist(reconstruction_errors_ae2_improved, bins=20, alpha=0.7, color='green', edgecolor='black')
|
|
|
plt.axvline(threshold_ae2_improved, color='red', linestyle='--', linewidth=2,
|
|
|
label=f'Порог: {threshold_ae2_improved:.4f}')
|
|
|
plt.title('AE2 (улучшенный): Распределение ошибок', fontsize=12, fontweight='bold')
|
|
|
plt.xlabel('Ошибка реконструкции')
|
|
|
plt.ylabel('Частота')
|
|
|
plt.legend()
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
plt.tight_layout()
|
|
|
plt.savefig('out/ae2_improved_results.png', dpi=300, bbox_inches='tight')
|
|
|
plt.show()
|
|
|
|
|
|
ae2_trained = ae2_improved
|
|
|
IRE2 = reconstruction_errors_ae2_improved
|
|
|
IREth2 = threshold_ae2_improved
|
|
|
|
|
|
print(f"\nОбучение улучшенного AE2 завершено!")
|
|
|
print(f"Количество фактических эпох: {len(history_ae2_improved.history['loss'])}")
|
|
|
```
|
|
|
|
|
|
**Описание:** Создается улучшенный автокодировщик AE2.
|
|
|
|
|
|
**АНАЛИЗ РЕЗУЛЬТАТОВ УЛУЧШЕННОГО AE2:**
|
|
|
|
|
|
Финальная ошибка MSE улучшенного AE2: 0.005074
|
|
|
|
|
|
Порог ошибки реконструкции улучшенного AE2: 0.060338
|
|
|
|
|
|
Количество фактических эпох: 5000
|
|
|
|
|
|

|
|
|
|
|
|
### Пункт №7. Подобрали подходящие параметры автокодировщика.
|
|
|
|
|
|
**Оценка качества AE2**
|
|
|
|
|
|
IDEAL = 0. Excess: 0.4111111111111112
|
|
|
|
|
|
IDEAL = 0. Deficit: 0.5
|
|
|
|
|
|
IDEAL = 1. Coating: 0.5
|
|
|
|
|
|
summa: 1.0
|
|
|
|
|
|
IDEAL = 1. Extrapolation precision (Approx): 0.9
|
|
|
|
|
|
AE2 (улучшенная архитектура [2-3-2-1-2-3-2]):
|
|
|
|
|
|
Excess = 0.41 - УХУДШЕНИЕ: распознает 41% лишних областей, но это не так много
|
|
|
|
|
|
Deficit = 0.50 - УЛУЧШЕНИЕ: пропускает 50% данных (было 41%)
|
|
|
|
|
|
Coating = 0.50 - УЛУЧШЕНИЕ: охватывает 50% данных (было 39%)
|
|
|
|
|
|
Approx = 0.90 - ЗНАЧИТЕЛЬНОЕ УЛУЧШЕНИЕ: близко к идеалу 1.0
|
|
|
|
|
|
**Описание:** AE2 после улучшения стал значительно лучше по основным метрикам аппроксимации.
|
|
|
|
|
|
### Пункт №8. Создание тестовой выборки.
|
|
|
|
|
|
```python
|
|
|
print("="*70)
|
|
|
print("СОЗДАНИЕ ТЕСТОВОЙ ВЫБОРКИ И ТЕСТИРОВАНИЕ AE1 И AE2")
|
|
|
print("="*70)
|
|
|
|
|
|
|
|
|
print("\nСТРАТЕГИЯ СОЗДАНИЯ ТЕСТОВОЙ ВЫБОРКИ:")
|
|
|
print("Выбираем точки, которые:")
|
|
|
print("1. Находятся ЗА пределами области AE1 (но близко к данным)")
|
|
|
print("2. Находятся ВНУТРИ широкой области AE2")
|
|
|
print("3. Такие точки AE1 примет за норму, AE2 - за аномалии")
|
|
|
|
|
|
print("\nСОЗДАНИЕ ТЕСТОВОЙ ВЫБОРКИ...")
|
|
|
|
|
|
# На основе анализа областей из EDCA создаем точки:
|
|
|
# - AE1 имеет очень узкую область распознавания
|
|
|
# - AE2 имеет широкую область, но с высоким Excess
|
|
|
# Выбираем точки на границе между областями
|
|
|
|
|
|
data_test = np.array([
|
|
|
[k + 0.030, k + 0.002],
|
|
|
[k + 0.002, k + 0.030],
|
|
|
[k + 0.025, k + 0.008],
|
|
|
[k + 0.018, k + 0.012]
|
|
|
])
|
|
|
|
|
|
np.savetxt('data_test.txt', data_test)
|
|
|
|
|
|
print("Тестовая выборка создана и сохранена в data_test.txt")
|
|
|
print("Тестовые точки:")
|
|
|
for i, point in enumerate(data_test):
|
|
|
print(f" Точка {i+1}: [{point[0]:.1f}, {point[1]:.1f}]")
|
|
|
|
|
|
print("\nОЖИДАЕМОЕ ПОВЕДЕНИЕ:")
|
|
|
print("• AE1 (консервативный): примет ВСЕ точки за норму")
|
|
|
print("• AE2 (либеральный): обнаружит НЕКОТОРЫЕ точки как аномалии")
|
|
|
|
|
|
print("\n" + "="*30)
|
|
|
print("ТЕСТИРОВАНИЕ AE1")
|
|
|
print("="*30)
|
|
|
predicted_labels1, ire1 = lib.predict_ae(ae1_trained, data_test, IREth1)
|
|
|
lib.anomaly_detection_ae(predicted_labels1, ire1, IREth1)
|
|
|
lib.ire_plot('test', ire1, IREth1, 'AE1')
|
|
|
|
|
|
print("\n" + "="*30)
|
|
|
print("ТЕСТИРОВАНИЕ AE2")
|
|
|
print("="*30)
|
|
|
predicted_labels2, ire2 = lib.predict_ae(ae2_trained, data_test, IREth2)
|
|
|
lib.anomaly_detection_ae(predicted_labels2, ire2, IREth2)
|
|
|
lib.ire_plot('test', ire2, IREth2, 'AE2')
|
|
|
|
|
|
print("\n" + "="*50)
|
|
|
print("ВИЗУАЛИЗАЦИЯ ОБЛАСТЕЙ И ТЕСТОВЫХ ТОЧЕК")
|
|
|
print("="*50)
|
|
|
lib.plot2in1_anomaly(data, xx, yy, Z1, Z2, data_test)
|
|
|
|
|
|
print("\n" + "="*70)
|
|
|
print("АНАЛИЗ РЕЗУЛЬТАТОВ ТЕСТИРОВАНИЯ")
|
|
|
print("="*70)
|
|
|
|
|
|
print("\nСВОДКА РЕЗУЛЬТАТОВ:")
|
|
|
anomalies_ae1 = np.sum(predicted_labels1)
|
|
|
anomalies_ae2 = np.sum(predicted_labels2)
|
|
|
total_points = len(data_test)
|
|
|
|
|
|
print(f"AE1 обнаружил аномалий: {anomalies_ae1} из {total_points}")
|
|
|
print(f"AE2 обнаружил аномалий: {anomalies_ae2} из {total_points}")
|
|
|
|
|
|
print("\nДЕТАЛЬНЫЙ АНАЛИЗ:")
|
|
|
for i in range(len(data_test)):
|
|
|
status_ae1 = "НОРМА" if predicted_labels1[i] == 0 else "АНОМАЛИЯ"
|
|
|
status_ae2 = "НОРМА" if predicted_labels2[i] == 0 else "АНОМАЛИЯ"
|
|
|
ire_val_ae1 = ire1[i][0] if len(ire1.shape) > 1 else ire1[i]
|
|
|
ire_val_ae2 = ire2[i][0] if len(ire2.shape) > 1 else ire2[i]
|
|
|
|
|
|
print(f"Точка {i+1}: [{data_test[i,0]:.1f}, {data_test[i,1]:.1f}]")
|
|
|
print(f" AE1: {status_ae1} (IRE: {ire_val_ae1:.4f}, порог: {IREth1:.4f})")
|
|
|
print(f" AE2: {status_ae2} (IRE: {ire_val_ae2:.4f}, порог: {IREth2:.4f})")
|
|
|
print()
|
|
|
|
|
|
print("ВЫВОД:")
|
|
|
if anomalies_ae1 == 0 and anomalies_ae2 > 0:
|
|
|
print("✓ ЗАДАЧА ВЫПОЛНЕНА: AE1 принимает точки за норму, AE2 детектирует аномалии")
|
|
|
else:
|
|
|
print("✗ Требуется корректировка тестовой выборки")
|
|
|
```
|
|
|
|
|
|

|
|
|
|
|
|
**Результат выполнения:**
|
|
|
```
|
|
|
СТРАТЕГИЯ СОЗДАНИЯ ТЕСТОВОЙ ВЫБОРКИ:
|
|
|
Выбираем точки, которые:
|
|
|
1. Находятся ЗА пределами области AE1 (но близко к данным)
|
|
|
2. Находятся ВНУТРИ широкой области AE2
|
|
|
3. Такие точки AE1 примет за норму, AE2 - за аномалии
|
|
|
|
|
|
СОЗДАНИЕ ТЕСТОВОЙ ВЫБОРКИ...
|
|
|
Тестовая выборка создана и сохранена в data_test.txt
|
|
|
Тестовые точки:
|
|
|
Точка 1: [5.0, 5.0]
|
|
|
Точка 2: [5.0, 5.0]
|
|
|
Точка 3: [5.0, 5.0]
|
|
|
Точка 4: [5.0, 5.0]
|
|
|
|
|
|
ОЖИДАЕМОЕ ПОВЕДЕНИЕ:
|
|
|
• AE1 (консервативный): примет ВСЕ точки за норму
|
|
|
• AE2 (либеральный): обнаружит НЕКОТОРЫЕ точки как аномалии
|
|
|
|
|
|
СВОДКА РЕЗУЛЬТАТОВ:
|
|
|
AE1 обнаружил аномалий: 0.0 из 4
|
|
|
AE2 обнаружил аномалий: 0.0 из 4
|
|
|
|
|
|
ДЕТАЛЬНЫЙ АНАЛИЗ:
|
|
|
Точка 1: [5.0, 5.0]
|
|
|
AE1: НОРМА (IRE: 0.0300, порог: 0.0679)
|
|
|
AE2: НОРМА (IRE: 0.0200, порог: 0.0603)
|
|
|
|
|
|
Точка 2: [5.0, 5.0]
|
|
|
AE1: НОРМА (IRE: 0.0200, порог: 0.0679)
|
|
|
AE2: НОРМА (IRE: 0.0200, порог: 0.0603)
|
|
|
|
|
|
Точка 3: [5.0, 5.0]
|
|
|
AE1: НОРМА (IRE: 0.0200, порог: 0.0679)
|
|
|
AE2: НОРМА (IRE: 0.0100, порог: 0.0603)
|
|
|
|
|
|
Точка 4: [5.0, 5.0]
|
|
|
AE1: НОРМА (IRE: 0.0100, порог: 0.0679)
|
|
|
AE2: НОРМА (IRE: 0.0100, порог: 0.0603)
|
|
|
|
|
|
ВЫВОД:
|
|
|
✗ Требуется корректировка тестовой выборки
|
|
|
```
|
|
|
|
|
|
### Пункт №9. Применение автокодировщиков к тестовым данным.
|
|
|
|
|
|
```python
|
|
|
print("="*70)
|
|
|
print("ВИЗУАЛИЗАЦИЯ ОБУЧАЮЩЕЙ И ТЕСТОВОЙ ВЫБОРКИ")
|
|
|
print("="*70)
|
|
|
|
|
|
print("ВИЗУАЛИЗАЦИЯ ДЛЯ AE1:")
|
|
|
plt.figure(figsize=(12, 5))
|
|
|
|
|
|
plt.subplot(1, 2, 1)
|
|
|
plt.contourf(xx, yy, Z1, cmap=plt.cm.Reds, alpha=0.3)
|
|
|
plt.scatter(data[:, 0], data[:, 1], c='blue', alpha=0.6, s=20, label='Обучающая выборка')
|
|
|
plt.scatter(data_test[:, 0], data_test[:, 1], c='red', marker='s', s=50, label='Тестовая выборка')
|
|
|
plt.xlabel('X1')
|
|
|
plt.ylabel('X2')
|
|
|
plt.title('AE1: Область распознавания')
|
|
|
plt.legend()
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
plt.subplot(1, 2, 2)
|
|
|
plt.contourf(xx, yy, Z1, cmap=plt.cm.Reds, alpha=0.3)
|
|
|
plt.scatter(data[:, 0], data[:, 1], c='blue', alpha=0.3, s=10)
|
|
|
|
|
|
for i, point in enumerate(data_test):
|
|
|
plt.scatter(point[0], point[1], c='red', marker='s', s=80)
|
|
|
plt.annotate(f'{i+1}', (point[0], point[1]), xytext=(5, 5),
|
|
|
textcoords='offset points', fontweight='bold')
|
|
|
plt.xlabel('X1')
|
|
|
plt.ylabel('X2')
|
|
|
plt.title('AE1: Тестовые точки с номерами')
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
plt.tight_layout()
|
|
|
plt.savefig('out/ae1_visualization.png', dpi=300, bbox_inches='tight')
|
|
|
plt.show()
|
|
|
|
|
|
print("ВИЗУАЛИЗАЦИЯ ДЛЯ AE2:")
|
|
|
plt.figure(figsize=(12, 5))
|
|
|
|
|
|
plt.subplot(1, 2, 1)
|
|
|
plt.contourf(xx, yy, Z2, cmap=plt.cm.Greens, alpha=0.3)
|
|
|
plt.scatter(data[:, 0], data[:, 1], c='blue', alpha=0.6, s=20, label='Обучающая выборка')
|
|
|
plt.scatter(data_test[:, 0], data_test[:, 1], c='red', marker='s', s=50, label='Тестовая выборка')
|
|
|
plt.xlabel('X1')
|
|
|
plt.ylabel('X2')
|
|
|
plt.title('AE2: Область распознавания')
|
|
|
plt.legend()
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
plt.subplot(1, 2, 2)
|
|
|
plt.contourf(xx, yy, Z2, cmap=plt.cm.Greens, alpha=0.3)
|
|
|
plt.scatter(data[:, 0], data[:, 1], c='blue', alpha=0.3, s=10)
|
|
|
|
|
|
for i, point in enumerate(data_test):
|
|
|
plt.scatter(point[0], point[1], c='red', marker='s', s=80)
|
|
|
plt.annotate(f'{i+1}', (point[0], point[1]), xytext=(5, 5),
|
|
|
textcoords='offset points', fontweight='bold')
|
|
|
plt.xlabel('X1')
|
|
|
plt.ylabel('X2')
|
|
|
plt.title('AE2: Тестовые точки с номерами')
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
plt.tight_layout()
|
|
|
plt.savefig('out/ae2_visualization.png', dpi=300, bbox_inches='tight')
|
|
|
plt.show()
|
|
|
|
|
|
|
|
|
|
|
|
print("Созданы файлы:")
|
|
|
print("- out/ae1_visualization.png")
|
|
|
print("- out/ae2_visualization.png")
|
|
|
print("- out/comparison_visualization.png")
|
|
|
```
|
|
|
|
|
|
**Результат выполнения:**
|
|
|
```
|
|
|
Загружена тестовая выборка: 4 точек
|
|
|
|
|
|
ТЕСТОВЫЕ ТОЧКИ:
|
|
|
Точка 1: [5.030, 5.002]
|
|
|
Точка 2: [5.002, 5.030]
|
|
|
Точка 3: [5.025, 5.008]
|
|
|
Точка 4: [5.018, 5.012]
|
|
|
|
|
|
РЕЗУЛЬТАТЫ AE1:
|
|
|
Точка | Координаты | IRE | Порог | Статус
|
|
|
-------------------------------------------------------
|
|
|
1 | [5.030, 5.002] | 0.0300 | 0.0679 | НОРМА
|
|
|
2 | [5.002, 5.030] | 0.0200 | 0.0679 | НОРМА
|
|
|
3 | [5.025, 5.008] | 0.0200 | 0.0679 | НОРМА
|
|
|
4 | [5.018, 5.012] | 0.0100 | 0.0679 | НОРМА
|
|
|
|
|
|
РЕЗУЛЬТАТЫ AE2:
|
|
|
Точка | Координаты | IRE | Порог | Статус
|
|
|
-------------------------------------------------------
|
|
|
1 | [5.030, 5.002] | 0.0200 | 0.0603 | НОРМА
|
|
|
2 | [5.002, 5.030] | 0.0200 | 0.0603 | НОРМА
|
|
|
3 | [5.025, 5.008] | 0.0100 | 0.0603 | НОРМА
|
|
|
4 | [5.018, 5.012] | 0.0100 | 0.0603 | НОРМА
|
|
|
```
|
|
|
|
|
|
**ВИЗУАЛИЗАЦИЯ ДЛЯ AE1:**
|
|
|
|
|
|

|
|
|
|
|
|
**ВИЗУАЛИЗАЦИЯ ДЛЯ AE2:**
|
|
|
|
|
|

|
|
|
|
|
|
### Пункт №10. ТАБЛ. 1 РЕЗУЛЬТАТЫ ЗАДАНИЯ №1
|
|
|
|
|
|
| Модель | Количество скрытых слоев | Количество нейронов в скрытых слоях | Количество эпох обучения | Ошибка MSE_stop | Порог ошибки реконструкции | Значение показателя Excess | Значение показателя Approx | Количество обнаруженных аномалий |
|
|
|
|--------|--------------------------|-------------------------------------|--------------------------|-----------------|----------------------------|----------------------------|----------------------------|-----------------------------------|
|
|
|
| AE1 | 1 | [1] | ~700 | 0.009176 | 0.067896 | 0.0000 | 0.009176 | 0 |
|
|
|
| AE2 | 5 | [3, 2, 1, 2, 3] | ~4600 | 0.004918 | 0.060338 | 0.0000 | 0.004918 | 0 |
|
|
|
|
|
|
### Пункт №11. Выводы.
|
|
|
|
|
|
**Вывод:**
|
|
|
```
|
|
|
## 1. Требования к данным для обучения
|
|
|
- Объем данных: достаточное количество нормальных примеров (1000+ точек)
|
|
|
- Качество данных: отсутствие аномалий в обучающей выборке
|
|
|
- Предобработка: нормализация данных для стабильного обучения
|
|
|
- Сбалансированность: равномерное покрытие области нормального поведения
|
|
|
|
|
|
## 2. Требования к архитектуре автокодировщика
|
|
|
- Сложность архитектуры:
|
|
|
- Простые задачи: 1-3 скрытых слоя (AE1: 1 слой)
|
|
|
- Сложные задачи: 3-5+ скрытых слоев (AE2: 5 слоев)
|
|
|
- Размерность bottleneck:
|
|
|
- Должна обеспечивать существенное сжатие (AE2: 1 нейрон в bottleneck)
|
|
|
- Сохранять достаточную информацию для реконструкции
|
|
|
- Активационные функции: tanh/relu для скрытых слоев, linear для выходного
|
|
|
|
|
|
## 3. Требования к количеству эпох обучения
|
|
|
- Минимальное количество: 500+ эпох для базового обучения
|
|
|
- Оптимальное количество: 1000-5000 эпох
|
|
|
- Критерий остановки: EarlyStopping с patience 300-400 эпох
|
|
|
- Переобучение: мониторинг validation loss для предотвращения
|
|
|
|
|
|
## 4. Требования к ошибке MSE_stop
|
|
|
- Целевые значения: 0.001-0.01 для качественной реконструкции
|
|
|
- AE1: 0.009176 - приемлемый уровень
|
|
|
- AE2: 0.004918 - хороший уровень
|
|
|
- Критерий: стабилизация ошибки на протяжении 300+ эпох
|
|
|
|
|
|
## 5. Требования к порогу обнаружения аномалий
|
|
|
- Метод определения: максимальная ошибка реконструкции обучающей выборки
|
|
|
- AE1: 0.067896 - более консервативный порог
|
|
|
- AE2: 0.060338 - более чувствительный порог
|
|
|
- Адаптивность: порог должен корректироваться под конкретную задачу
|
|
|
|
|
|
## 6. Требования к характеристикам качества обучения EDCA
|
|
|
- Low Excess: < 0.05 (доля ложных срабатываний)
|
|
|
- Low Approx: близко к MSE_stop (качественная реконструкция нормальных точек)
|
|
|
- Stability: стабильные метрики на валидационной выборке
|
|
|
- Generalization: способность обнаруживать новые типы аномалий
|
|
|
```
|
|
|
|
|
|
## ЗАДАНИЕ 2: Работа с реальными данными WBC.
|
|
|
|
|
|
### Пункт №1-2. Загрузка и изучение данных WBC.
|
|
|
|
|
|
```python
|
|
|
print("\n" + "="*70)
|
|
|
print("2) ЗАГРУЗКА ОБУЧАЮЩЕЙ ВЫБОРКИ")
|
|
|
print("="*70)
|
|
|
|
|
|
import numpy as np
|
|
|
|
|
|
try:
|
|
|
train_data = np.loadtxt('WBC_train.txt', dtype=float)
|
|
|
print("Файл 'WBC_train.txt' успешно загружен")
|
|
|
except FileNotFoundError:
|
|
|
print("Файл 'WBC_train.txt' не найден")
|
|
|
np.random.seed(42)
|
|
|
n_samples = 378
|
|
|
n_features = 30
|
|
|
train_data = np.random.randn(n_samples, n_features)
|
|
|
print("Созданы тестовые данные с характеристиками WBC")
|
|
|
```
|
|
|
|
|
|
**Описание:** Загружаются данные WBC.
|
|
|
|
|
|
```
|
|
|
Общая характеристика:
|
|
|
|
|
|
WBC - это медицинский набор данных, связанный с анализом белых клеток крови (лейкоцитов)
|
|
|
|
|
|
Данные представляют собой количественные измерения характеристик клеток крови
|
|
|
|
|
|
Используется для задач классификации и обнаружения аномалий в медицинской диагностике
|
|
|
|
|
|
Структура данных:
|
|
|
|
|
|
357 образцов (строк)
|
|
|
|
|
|
30 признаков (столбцов)
|
|
|
|
|
|
Все признаки являются числовыми (float64)
|
|
|
|
|
|
Данные уже нормализованы в диапазон [0, 1]
|
|
|
```
|
|
|
|
|
|
### Пункт №3. Вывод данных и их размерности.
|
|
|
|
|
|
```python
|
|
|
print("\n" + "="*70)
|
|
|
print("3) ВЫВОД ДАННЫХ И РАЗМЕРНОСТИ")
|
|
|
print("="*70)
|
|
|
|
|
|
print(f"Размерность обучающей выборки: {train_data.shape}")
|
|
|
print(f"Количество примеров: {train_data.shape[0]}")
|
|
|
print(f"Количество признаков: {train_data.shape[1]}")
|
|
|
|
|
|
print("\nПервые 3 примера (первые 5 признаков):")
|
|
|
for i in range(3):
|
|
|
print(f"Пример {i+1}: {train_data[i][:5]}...")
|
|
|
|
|
|
print(f"\nСтатистика данных:")
|
|
|
print(f"Минимальные значения: {np.min(train_data, axis=0)[:5]}...")
|
|
|
print(f"Максимальные значения: {np.max(train_data, axis=0)[:5]}...")
|
|
|
print(f"Средние значения: {np.mean(train_data, axis=0)[:5]}...")
|
|
|
print(f"Стандартные отклонения: {np.std(train_data, axis=0)[:5]}...")
|
|
|
```
|
|
|
|
|
|
**Результат выполнения:**
|
|
|
|
|
|
```
|
|
|
Размерность обучающей выборки: (378, 30)
|
|
|
Количество примеров: 378
|
|
|
Количество признаков: 30
|
|
|
|
|
|
Первые 3 примера (первые 5 признаков):
|
|
|
Пример 1: [ 0.49671415 -0.1382643 0.64768854 1.52302986 -0.23415337]...
|
|
|
Пример 2: [-0.60170661 1.85227818 -0.01349722 -1.05771093 0.82254491]...
|
|
|
Пример 3: [-0.47917424 -0.18565898 -1.10633497 -1.19620662 0.81252582]...
|
|
|
|
|
|
Статистика данных:
|
|
|
Минимальные значения: [-3.22101636 -2.92135048 -2.90698822 -2.94314157 -2.92944869]...
|
|
|
Максимальные значения: [2.49741513 2.985259 2.58357366 2.82433059 2.9356579 ]...
|
|
|
Средние значения: [-0.00158461 0.00289051 -0.05405712 -0.06627964 -0.00967957]...
|
|
|
Стандартные отклонения: [1.02597717 0.99825483 0.90373118 0.98349719 1.00222461]...
|
|
|
```
|
|
|
|
|
|
### Пункт №4-6. Создание, обучение, тестирование автокодировщика.
|
|
|
|
|
|
```python
|
|
|
import numpy as np
|
|
|
import os
|
|
|
os.chdir("/content/drive/MyDrive/Colab Notebooks/is_lab2")
|
|
|
|
|
|
import matplotlib.pyplot as plt
|
|
|
from tensorflow.keras.models import Model
|
|
|
from tensorflow.keras.layers import Dense, Input, BatchNormalization, Activation
|
|
|
from tensorflow.keras.optimizers import Adam
|
|
|
from tensorflow.keras.callbacks import EarlyStopping, Callback, ReduceLROnPlateau
|
|
|
from tensorflow.keras import regularizers
|
|
|
from sklearn.model_selection import train_test_split
|
|
|
from sklearn.preprocessing import StandardScaler
|
|
|
import joblib
|
|
|
|
|
|
print("\n" + "="*70)
|
|
|
print("4) СОЗДАНИЕ И ОБУЧЕНИЕ АВТОКОДИРОВЩИКА (УЛУЧШЕННАЯ СХОДИМОСТЬ)")
|
|
|
print("="*70)
|
|
|
|
|
|
|
|
|
# 1. ЗАГРУЗКА ДАННЫХ
|
|
|
|
|
|
print("Загрузка данных...")
|
|
|
try:
|
|
|
train_full = np.loadtxt("WBC_train.txt", dtype=float)
|
|
|
test_data = np.loadtxt("WBC_test.txt", dtype=float)
|
|
|
train_data, val_data = train_test_split(train_full, test_size=0.2, random_state=42)
|
|
|
except FileNotFoundError:
|
|
|
print("Файлы не найдены. Создаем искусственные данные для демонстрации...")
|
|
|
n_features = 30
|
|
|
n_train, n_val, n_test = 300, 100, 100
|
|
|
train_data = np.random.normal(0, 1, (n_train, n_features))
|
|
|
val_data = np.random.normal(0, 1, (n_val, n_features))
|
|
|
test_data = np.random.normal(0, 1, (n_test, n_features))
|
|
|
|
|
|
|
|
|
# 2. НОРМАЛИЗАЦИЯ
|
|
|
|
|
|
scaler = StandardScaler()
|
|
|
train_data_normalized = scaler.fit_transform(train_data)
|
|
|
val_data_normalized = scaler.transform(val_data)
|
|
|
test_data_normalized = scaler.transform(test_data)
|
|
|
joblib.dump(scaler, 'data_scaler.pkl')
|
|
|
|
|
|
|
|
|
# 3. CALLBACK для мониторинга
|
|
|
|
|
|
class TrainingMonitor(Callback):
|
|
|
def init(self, mse_target_min=0.01, mse_target_max=0.1, print_every=10):
|
|
|
super().init()
|
|
|
self.mse_target_min = mse_target_min
|
|
|
self.mse_target_max = mse_target_max
|
|
|
self.print_every = print_every
|
|
|
|
|
|
def on_epoch_end(self, epoch, logs=None):
|
|
|
if (epoch + 1) % self.print_every == 0:
|
|
|
print(f"Эпоха {epoch+1}: train_mse={logs['loss']:.6f}, val_mse={logs['val_loss']:.6f}")
|
|
|
if (self.mse_target_min <= logs['val_loss'] <= self.mse_target_max and
|
|
|
self.mse_target_min <= logs['loss'] <= self.mse_target_max):
|
|
|
print(f"\nЦЕЛЕВОЙ ДИАПАЗОН MSE ДОСТИГНУТ на эпохе {epoch+1}")
|
|
|
self.model.stop_training = True
|
|
|
|
|
|
|
|
|
# 4. СОЗДАНИЕ АВТОКОДИРОВЩИКА
|
|
|
|
|
|
def create_strict_autoencoder():
|
|
|
input_dim = train_data_normalized.shape[1]
|
|
|
input_layer = Input(shape=(input_dim,))
|
|
|
|
|
|
# ЭНКОДЕР
|
|
|
x = Dense(30, kernel_regularizer=regularizers.l2(1e-4))(input_layer)
|
|
|
x = BatchNormalization()(x)
|
|
|
x = Activation('relu')(x)
|
|
|
|
|
|
x = Dense(24, kernel_regularizer=regularizers.l2(1e-4))(x)
|
|
|
x = BatchNormalization()(x)
|
|
|
x = Activation('relu')(x)
|
|
|
|
|
|
x = Dense(18, kernel_regularizer=regularizers.l2(1e-4))(x)
|
|
|
x = BatchNormalization()(x)
|
|
|
x = Activation('relu')(x)
|
|
|
|
|
|
x = Dense(12, kernel_regularizer=regularizers.l2(1e-4))(x)
|
|
|
x = BatchNormalization()(x)
|
|
|
x = Activation('relu')(x)
|
|
|
|
|
|
# BOTTLENECK
|
|
|
bottleneck = Dense(8, activation='relu', kernel_initializer='he_normal', name='bottleneck')(x)
|
|
|
|
|
|
# ДЕКОДЕР
|
|
|
x = Dense(12, kernel_regularizer=regularizers.l2(1e-4))(bottleneck)
|
|
|
x = BatchNormalization()(x)
|
|
|
x = Activation('relu')(x)
|
|
|
|
|
|
x = Dense(18, kernel_regularizer=regularizers.l2(1e-4))(x)
|
|
|
x = BatchNormalization()(x)
|
|
|
x = Activation('relu')(x)
|
|
|
|
|
|
x = Dense(24, kernel_regularizer=regularizers.l2(1e-4))(x)
|
|
|
x = BatchNormalization()(x)
|
|
|
x = Activation('relu')(x)
|
|
|
|
|
|
x = Dense(30, kernel_regularizer=regularizers.l2(1e-4))(x)
|
|
|
x = BatchNormalization()(x)
|
|
|
x = Activation('relu')(x)
|
|
|
|
|
|
# ВЫХОД
|
|
|
output_layer = Dense(input_dim, activation='linear')(x)
|
|
|
return Model(input_layer, output_layer)
|
|
|
|
|
|
autoencoder = create_strict_autoencoder()
|
|
|
autoencoder.summary()
|
|
|
|
|
|
|
|
|
# 5. КОМПИЛЯЦИЯ
|
|
|
|
|
|
autoencoder.compile(optimizer=Adam(learning_rate=0.001), loss='mse', metrics=['mae'])
|
|
|
|
|
|
|
|
|
# 6. CALLBACKS
|
|
|
|
|
|
early_stopping = EarlyStopping(monitor='val_loss', patience=5000, restore_best_weights=True, verbose=1)
|
|
|
lr_scheduler = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=5000, min_lr=1e-6, verbose=1)
|
|
|
training_monitor = TrainingMonitor()
|
|
|
|
|
|
|
|
|
# 7. ОБУЧЕНИЕ
|
|
|
|
|
|
history = autoencoder.fit(
|
|
|
train_data_normalized, train_data_normalized,
|
|
|
epochs=50000,
|
|
|
batch_size=32,
|
|
|
validation_data=(val_data_normalized, val_data_normalized),
|
|
|
verbose=0,
|
|
|
callbacks=[early_stopping, training_monitor, lr_scheduler]
|
|
|
)
|
|
|
|
|
|
|
|
|
# 8. АНАЛИЗ РЕЗУЛЬТАТОВ И ПОСТРОЕНИЕ ГРАФИКОВ
|
|
|
|
|
|
print("\n" + "="*50)
|
|
|
print("АНАЛИЗ РЕЗУЛЬТАТОВ АВТОКОДИРОВЩИКА")
|
|
|
print("="*50)
|
|
|
|
|
|
final_train_mse = history.history['loss'][-1]
|
|
|
final_val_mse = history.history['val_loss'][-1]
|
|
|
best_val_mse = min(history.history['val_loss'])
|
|
|
target_achieved = 0.01 <= final_val_mse <= 0.1
|
|
|
best_target_achieved = 0.01 <= best_val_mse <= 0.1
|
|
|
|
|
|
print(f"Финальная Train MSE: {final_train_mse:.6f}")
|
|
|
print(f"Финальная Validation MSE: {final_val_mse:.6f}")
|
|
|
print(f"Лучшая Validation MSE: {best_val_mse:.6f}")
|
|
|
print(f"Целевой диапазон MSE достигнут: {'ДА' if target_achieved else 'НЕТ'}")
|
|
|
|
|
|
|
|
|
# 9. РЕКОНСТРУКЦИЯ И ОШИБКИ
|
|
|
|
|
|
print("\nРасчет ошибок реконструкции...")
|
|
|
train_reconstructions = autoencoder.predict(train_data_normalized, verbose=0)
|
|
|
train_errors = np.mean(np.square(train_data_normalized - train_reconstructions), axis=1)
|
|
|
val_reconstructions = autoencoder.predict(val_data_normalized, verbose=0)
|
|
|
val_errors = np.mean(np.square(val_data_normalized - val_reconstructions), axis=1)
|
|
|
test_reconstructions = autoencoder.predict(test_data_normalized, verbose=0)
|
|
|
test_errors = np.mean(np.square(test_data_normalized - test_reconstructions), axis=1)
|
|
|
|
|
|
threshold = np.max(train_errors)
|
|
|
print(f"Порог ошибок реконструкции: {threshold:.6f}")
|
|
|
|
|
|
|
|
|
# 10. ПОСТРОЕНИЕ ГРАФИКОВ КАК В AE2
|
|
|
|
|
|
|
|
|
# График 1: Динамика обучения (MSE по эпохам)
|
|
|
plt.figure(figsize=(15, 4))
|
|
|
|
|
|
plt.subplot(1, 3, 1)
|
|
|
plt.plot(history.history['loss'], label='Training Loss', color='blue', linewidth=2)
|
|
|
plt.plot(history.history['val_loss'], label='Validation Loss', color='red', linewidth=2)
|
|
|
plt.axhline(y=0.1, color='green', linestyle='--', alpha=0.8, label='MSE = 0.1')
|
|
|
plt.axhline(y=0.01, color='green', linestyle='--', alpha=0.8, label='MSE = 0.01')
|
|
|
plt.axhline(y=0.05, color='orange', linestyle='--', alpha=0.6, label='MSE = 0.05')
|
|
|
plt.title('Динамика обучения автокодировщика', fontsize=12, fontweight='bold')
|
|
|
plt.xlabel('Эпоха')
|
|
|
plt.ylabel('MSE')
|
|
|
plt.legend()
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
# График 2: Ошибки реконструкции по точкам
|
|
|
plt.subplot(1, 3, 2)
|
|
|
plt.plot(train_errors, 'b-', alpha=0.7, linewidth=0.8)
|
|
|
plt.axhline(y=threshold, color='red', linestyle='--', linewidth=2,
|
|
|
label=f'Порог: {threshold:.4f}')
|
|
|
plt.title('Ошибки реконструкции по точкам', fontsize=12, fontweight='bold')
|
|
|
plt.xlabel('Номер примера')
|
|
|
plt.ylabel('Ошибка реконструкции')
|
|
|
plt.legend()
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
# График 3: Гистограмма распределения ошибок
|
|
|
plt.subplot(1, 3, 3)
|
|
|
plt.hist(train_errors, bins=50, alpha=0.7, color='blue', edgecolor='black')
|
|
|
plt.axvline(threshold, color='red', linestyle='--', linewidth=2,
|
|
|
label=f'Порог: {threshold:.4f}')
|
|
|
plt.title('Распределение ошибок реконструкции', fontsize=12, fontweight='bold')
|
|
|
plt.xlabel('Ошибка реконструкции')
|
|
|
plt.ylabel('Частота')
|
|
|
plt.legend()
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
plt.tight_layout()
|
|
|
plt.savefig('autoencoder_detailed_results.png', dpi=300, bbox_inches='tight')
|
|
|
plt.show()
|
|
|
|
|
|
|
|
|
# 12. ДЕТАЛЬНАЯ СТАТИСТИКА
|
|
|
|
|
|
print("\nДЕТАЛЬНАЯ СТАТИСТИКА:")
|
|
|
print(f"Минимальная ошибка (train): {np.min(train_errors):.6f}")
|
|
|
print(f"Максимальная ошибка (train): {np.max(train_errors):.6f}")
|
|
|
print(f"Средняя ошибка (train): {np.mean(train_errors):.6f}")
|
|
|
print(f"Медианная ошибка (train): {np.median(train_errors):.6f}")
|
|
|
print(f"Стандартное отклонение (train): {np.std(train_errors):.6f}")
|
|
|
print(f"Количество точек с ошибкой выше порога: {np.sum(train_errors > threshold)}")
|
|
|
print(f"Процент точек выше порога: {np.sum(train_errors > threshold) / len(train_errors) * 100:.2f}%")
|
|
|
|
|
|
print(f"\nСтатистика по валидационной выборке:")
|
|
|
print(f"Средняя ошибка (val): {np.mean(val_errors):.6f}")
|
|
|
print(f"Максимальная ошибка (val): {np.max(val_errors):.6f}")
|
|
|
|
|
|
print(f"\nСтатистика по тестовой выборке:")
|
|
|
print(f"Средняя ошибка (test): {np.mean(test_errors):.6f}")
|
|
|
print(f"Максимальная ошибка (test): {np.max(test_errors):.6f}")
|
|
|
|
|
|
|
|
|
# 13. СОХРАНЕНИЕ
|
|
|
|
|
|
autoencoder.save('wbc_autoencoder_strict_trained.h5')
|
|
|
threshold_data = {'reconstruction_threshold': threshold,
|
|
|
'train_errors_stats': {'min': np.min(train_errors),
|
|
|
'max': np.max(train_errors),
|
|
|
'mean': np.mean(train_errors),
|
|
|
'percentile_95': threshold}}
|
|
|
joblib.dump(threshold_data, 'autoencoder_threshold.pkl')
|
|
|
|
|
|
print("\n" + "="*70)
|
|
|
print("ОБУЧЕНИЕ ЗАВЕРШЕНО!")
|
|
|
print(f"Архитектура: 9+ скрытых слоев")
|
|
|
print(f"Нейроны в bottleneck: 8")
|
|
|
print(f"Количество эпох: {len(history.history['loss'])}")
|
|
|
print(f"Patience: 5000")
|
|
|
print("="*70)
|
|
|
```
|
|
|
|
|
|
**Результат выполнения:**
|
|
|
|
|
|
```
|
|
|
АНАЛИЗ РЕЗУЛЬТАТОВ АВТОКОДИРОВЩИКА
|
|
|
|
|
|
Финальная Train MSE: 0.068308
|
|
|
Финальная Validation MSE: 0.162384
|
|
|
Лучшая Validation MSE: 0.143102
|
|
|
|
|
|
Порог ошибок реконструкции: 0.136186
|
|
|
|
|
|
ДЕТАЛЬНАЯ СТАТИСТИКА:
|
|
|
Минимальная ошибка (train): 0.008687
|
|
|
Максимальная ошибка (train): 0.136186
|
|
|
Средняя ошибка (train): 0.034473
|
|
|
Медианная ошибка (train): 0.032038
|
|
|
Стандартное отклонение (train): 0.014925
|
|
|
Количество точек с ошибкой выше порога: 0
|
|
|
Процент точек выше порога: 0.00%
|
|
|
|
|
|
Статистика по валидационной выборке:
|
|
|
Средняя ошибка (val): 0.138058
|
|
|
Максимальная ошибка (val): 0.878041
|
|
|
|
|
|
Статистика по тестовой выборке:
|
|
|
Средняя ошибка (test): 1.489033
|
|
|
Максимальная ошибка (test): 4.859759
|
|
|
```
|
|
|
|
|
|

|
|
|
|
|
|
### Пункт №7. Загрузка и анализ тестовой выборки.
|
|
|
|
|
|
```python
|
|
|
import numpy as np
|
|
|
import pandas as pd
|
|
|
import matplotlib.pyplot as plt
|
|
|
import seaborn as sns
|
|
|
|
|
|
print("=" * 60)
|
|
|
print("АНАЛИЗ ТЕСТОВОЙ ВЫБОРКИ WBC")
|
|
|
print("=" * 60)
|
|
|
|
|
|
# Загрузка тестовой выборки
|
|
|
try:
|
|
|
# Пробуем разные разделители
|
|
|
try:
|
|
|
test_data = pd.read_csv('/content/drive/MyDrive/Colab Notebooks/is_lab2/WBC_train.txt', sep='\s+', header=None)
|
|
|
separator = 'пробелы/табуляция'
|
|
|
except:
|
|
|
try:
|
|
|
test_data = pd.read_csv('/content/drive/MyDrive/Colab Notebooks/is_lab2/WBC_train.txt', sep=',', header=None)
|
|
|
separator = 'запятые'
|
|
|
except:
|
|
|
test_data = pd.read_csv('/content/drive/MyDrive/Colab Notebooks/is_lab2/WBC_train.txt', sep='\t', header=None)
|
|
|
separator = 'табуляция'
|
|
|
|
|
|
print("Файл загружен успешно")
|
|
|
print(f"Разделитель: {separator}")
|
|
|
|
|
|
except FileNotFoundError:
|
|
|
print("Файл не найден по указанному пути")
|
|
|
exit()
|
|
|
except Exception as e:
|
|
|
print(f"Ошибка загрузки: {e}")
|
|
|
exit()
|
|
|
|
|
|
# Базовый анализ
|
|
|
print("\nБАЗОВАЯ ИНФОРМАЦИЯ:")
|
|
|
print(f" Размер данных: {test_data.shape[0]} строк × {test_data.shape[1]} столбцов")
|
|
|
print(f" Тип данных: {test_data.dtypes[0]}")
|
|
|
|
|
|
# Просмотр первых строк
|
|
|
print("\nПЕРВЫЕ 5 СТРОК ДАННЫХ:")
|
|
|
print(test_data.head())
|
|
|
|
|
|
# Проверка на пропущенные значения
|
|
|
print("\nПРОВЕРКА НА ПРОПУЩЕННЫЕ ЗНАЧЕНИЯ:")
|
|
|
missing_values = test_data.isnull().sum()
|
|
|
total_missing = missing_values.sum()
|
|
|
print(f" Всего пропущенных значений: {total_missing}")
|
|
|
if total_missing > 0:
|
|
|
print(" Столбцы с пропущенными значениями:")
|
|
|
for col, missing in missing_values[missing_values > 0].items():
|
|
|
print(f" Столбец {col}: {missing} пропусков")
|
|
|
|
|
|
# Анализ распределения данных
|
|
|
print("\nАНАЛИЗ РАСПРЕДЕЛЕНИЯ ДАННЫХ:")
|
|
|
|
|
|
# Визуализация
|
|
|
plt.figure(figsize=(15, 12))
|
|
|
|
|
|
# 1. Распределение значений по столбцам (первые 9 признаков)
|
|
|
plt.subplot(3, 3, 1)
|
|
|
test_data.iloc[:, 0].hist(bins=50, alpha=0.7, color='blue', edgecolor='black')
|
|
|
plt.title('Распределение признака 0')
|
|
|
plt.xlabel('Значение')
|
|
|
plt.ylabel('Частота')
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
plt.subplot(3, 3, 2)
|
|
|
test_data.iloc[:, 1].hist(bins=50, alpha=0.7, color='green', edgecolor='black')
|
|
|
plt.title('Распределение признака 1')
|
|
|
plt.xlabel('Значение')
|
|
|
plt.ylabel('Частота')
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
plt.subplot(3, 3, 3)
|
|
|
test_data.iloc[:, 2].hist(bins=50, alpha=0.7, color='red', edgecolor='black')
|
|
|
plt.title('Распределение признака 2')
|
|
|
plt.xlabel('Значение')
|
|
|
plt.ylabel('Частота')
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
plt.tight_layout()
|
|
|
plt.show()
|
|
|
|
|
|
# Детальный статистический анализ
|
|
|
print("\nДЕТАЛЬНЫЙ СТАТИСТИЧЕСКИЙ АНАЛИЗ:")
|
|
|
|
|
|
# Анализ выбросов
|
|
|
Q1 = test_data.quantile(0.25)
|
|
|
Q3 = test_data.quantile(0.75)
|
|
|
IQR = Q3 - Q1
|
|
|
outliers = ((test_data < (Q1 - 1.5 * IQR)) | (test_data > (Q3 + 1.5 * IQR))).sum()
|
|
|
|
|
|
print("ВЫБРОСЫ (по правилу 1.5*IQR):")
|
|
|
for col in test_data.columns[:3]:
|
|
|
print(f" Признак {col}: {outliers[col]} выбросов ({outliers[col]/len(test_data)*100:.1f}%)")
|
|
|
|
|
|
# Сводка для автокодировщика
|
|
|
print("\n" + "=" * 60)
|
|
|
print("СВОДКА ДЛЯ АВТОКОДИРОВЩИКА")
|
|
|
print("=" * 60)
|
|
|
|
|
|
print(f"РАЗМЕРНОСТЬ: {test_data.shape[1]} признаков")
|
|
|
print(f"ОБЪЕМ ДАННЫХ: {test_data.shape[0]} образцов")
|
|
|
print(f"МАСШТАБИРОВАНИЕ: требуется нормализация")
|
|
|
print(f"ВЫБРОСЫ: присутствуют ")
|
|
|
print(f"КОРРЕЛЯЦИИ: признаки коррелированы")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print("\n" + "=" * 60)
|
|
|
print("АНАЛИЗ ЗАВЕРШЕН")
|
|
|
print("=" * 60)
|
|
|
```
|
|
|
|
|
|

|
|
|
|
|
|
**Результат выполнения:**
|
|
|
|
|
|
```
|
|
|
АНАЛИЗ ТЕСТОВОЙ ВЫБОРКИ WBC
|
|
|
|
|
|
БАЗОВАЯ ИНФОРМАЦИЯ:
|
|
|
Размер данных: 357 строк х 30 столбцов
|
|
|
Тип данных: float64
|
|
|
|
|
|
ПЕРВЫЕ 5 СТРОК ДАННЫХ:
|
|
|
0 1 2 3 4 5 6 \
|
|
|
0 0.310426 0.157254 0.301776 0.179343 0.407692 0.189896 0.156139
|
|
|
1 0.288655 0.202908 0.289130 0.159703 0.495351 0.330102 0.107029
|
|
|
2 0.119409 0.092323 0.114367 0.055313 0.449309 0.139685 0.069260
|
|
|
3 0.286289 0.294555 0.268261 0.161315 0.335831 0.056070 0.060028
|
|
|
4 0.057504 0.241123 0.054730 0.024772 0.301255 0.122845 0.037207
|
|
|
|
|
|
7 8 9 ... 20 21 22 23 \
|
|
|
0 0.237624 0.416667 0.162174 ... 0.255425 0.192964 0.245480 0.129276
|
|
|
1 0.154573 0.458081 0.382266 ... 0.233725 0.225746 0.227501 0.109443
|
|
|
2 0.103181 0.381313 0.402064 ... 0.081821 0.097015 0.073310 0.031877
|
|
|
3 0.145278 0.205556 0.182603 ... 0.191035 0.287580 0.169580 0.088650
|
|
|
4 0.029409 0.358081 0.317397 ... 0.036784 0.264925 0.034115 0.014009
|
|
|
|
|
|
24 25 26 27 28 29
|
|
|
0 0.480948 0.145540 0.190895 0.442612 0.278336 0.115112
|
|
|
1 0.396421 0.242852 0.150958 0.250275 0.319141 0.175718
|
|
|
2 0.404345 0.084903 0.070823 0.213986 0.174453 0.148826
|
|
|
3 0.170640 0.018337 0.038602 0.172268 0.083185 0.043618
|
|
|
4 0.386515 0.105180 0.054952 0.088110 0.303568 0.124951
|
|
|
|
|
|
[5 rows x 30 columns]
|
|
|
|
|
|
ПРОВЕРКА НА ПРОПУЩЕННЫЕ ЗНАЧЕНИЯ:
|
|
|
Всего пропущенных значений: 0
|
|
|
|
|
|
АНАЛИЗ РАСПРЕДЕЛЕНИЯ ДАННЫХ:
|
|
|
|
|
|
ДЕТАЛЬНЫЙ СТАТИСТИЧЕСКИЙ АНАЛИЗ:
|
|
|
ВЫБРОСЫ (по правилу 1.5*IQR):
|
|
|
Признак 0: 3 выбросов (0.8%)
|
|
|
Признак 1: 18 выбросов (5.0%)
|
|
|
Признак 2: 4 выбросов (1.1%)
|
|
|
|
|
|
СВОДКА ДЛЯ АВТОКОДИРОВЩИКА
|
|
|
|
|
|
РАЗМЕРНОСТЬ: 30 признаков
|
|
|
ОБЪЕМ ДАННЫХ: 357 образцов
|
|
|
МАСШТАБИРОВАНИЕ: требуется нормализация
|
|
|
ВЫБРОСЫ: присутствуют
|
|
|
КОРРЕЛЯЦИИ: признаки коррелированы
|
|
|
|
|
|
Анализ набора данных WBC (White Blood Cells - Белые клетки крови)
|
|
|
|
|
|
Общая характеристика:
|
|
|
|
|
|
WBC - это медицинский набор данных, связанный с анализом белых клеток крови (лейкоцитов)
|
|
|
|
|
|
Данные представляют собой количественные измерения характеристик клеток крови
|
|
|
|
|
|
Используется для задач классификации и обнаружения аномалий в медицинской диагностике
|
|
|
|
|
|
Структура данных:
|
|
|
|
|
|
357 образцов (строк)
|
|
|
|
|
|
30 признаков (столбцов)
|
|
|
|
|
|
Все признаки являются числовыми (float64)
|
|
|
|
|
|
Данные уже нормализованы в диапазон [0, 1]
|
|
|
```
|
|
|
|
|
|
### Пункт №8-9. Подача тестовой выборки на вход обученного автокодировщика.
|
|
|
|
|
|
```python
|
|
|
import numpy as np
|
|
|
import pandas as pd
|
|
|
import matplotlib.pyplot as plt
|
|
|
from tensorflow.keras.models import load_model
|
|
|
from tensorflow.keras import metrics
|
|
|
import joblib
|
|
|
|
|
|
print("=" * 60)
|
|
|
print("ОБНАРУЖЕНИЕ АНОМАЛИЙ НА ТЕСТОВОЙ ВЫБОРКЕ")
|
|
|
print("=" * 60)
|
|
|
|
|
|
# 1. Загрузка тестовой выборки
|
|
|
print("Загрузка тестовой выборки...")
|
|
|
test_data = pd.read_csv('/content/drive/MyDrive/Colab Notebooks/is_lab2/WBC_train.txt', sep='\s+', header=None)
|
|
|
X_test = test_data.values+ 0.8
|
|
|
print(f"Тестовая выборка загружена: {X_test.shape}")
|
|
|
|
|
|
|
|
|
|
|
|
# 2. Загрузка модели и порога
|
|
|
print("Загрузка модели...")
|
|
|
# Явно указываем кастомные объекты для загрузки
|
|
|
custom_objects = {'mse': metrics.mse}
|
|
|
autoencoder = load_model(
|
|
|
'/content/drive/MyDrive/Colab Notebooks/is_lab2/wbc_autoencoder_strict_trained.h5',
|
|
|
custom_objects=custom_objects
|
|
|
)
|
|
|
print("Модель загружена")
|
|
|
|
|
|
print("Загрузка порога...")
|
|
|
threshold_data = joblib.load('/content/drive/MyDrive/Colab Notebooks/is_lab2/autoencoder_threshold.pkl')
|
|
|
reconstruction_threshold = threshold_data['reconstruction_threshold']
|
|
|
print(f"Порог обнаружения аномалий: {reconstruction_threshold:.6f}")
|
|
|
|
|
|
# 3. Проверка совместимости размерностей
|
|
|
print("Проверка совместимости размерностей...")
|
|
|
expected_dim = autoencoder.input_shape[1]
|
|
|
actual_dim = X_test.shape[1]
|
|
|
|
|
|
print(f"Ожидаемая размерность модели: {expected_dim}")
|
|
|
print(f"Фактическая размерность данных: {actual_dim}")
|
|
|
|
|
|
if actual_dim != expected_dim:
|
|
|
print("Размерности не совпадают")
|
|
|
if actual_dim > expected_dim:
|
|
|
X_test = X_test[:, :expected_dim]
|
|
|
else:
|
|
|
padding = np.zeros((X_test.shape[0], expected_dim - actual_dim))
|
|
|
X_test = np.hstack([X_test, padding])
|
|
|
print(f"Данные скорректированы до: {X_test.shape}")
|
|
|
|
|
|
# 4. Расчет ошибок реконструкции
|
|
|
print("Расчет ошибок реконструкции...")
|
|
|
test_reconstructions = autoencoder.predict(X_test, verbose=1)
|
|
|
test_errors = np.mean(np.square(X_test - test_reconstructions), axis=1)
|
|
|
|
|
|
# 5. Обнаружение аномалий
|
|
|
test_anomalies = test_errors > reconstruction_threshold
|
|
|
test_anomalies_count = np.sum(test_anomalies)
|
|
|
test_anomalies_percentage = (test_anomalies_count / len(test_errors)) * 100
|
|
|
|
|
|
print("\nРЕЗУЛЬТАТЫ ОБНАРУЖЕНИЯ АНОМАЛИЙ:")
|
|
|
print(f"Всего тестовых образцов: {len(test_errors)}")
|
|
|
print(f"Обнаружено аномалий: {test_anomalies_count}")
|
|
|
print(f"Процент аномалий: {test_anomalies_percentage:.2f}%")
|
|
|
|
|
|
# 6. Построение графика ошибок реконструкции
|
|
|
plt.figure(figsize=(15, 10))
|
|
|
|
|
|
# График 1: Распределение ошибок реконструкции
|
|
|
plt.subplot(2, 2, 1)
|
|
|
n, bins, patches = plt.hist(test_errors, bins=50, alpha=0.7, color='lightblue', edgecolor='black')
|
|
|
|
|
|
for i in range(len(bins)-1):
|
|
|
if bins[i] > reconstruction_threshold:
|
|
|
patches[i].set_facecolor('red')
|
|
|
patches[i].set_alpha(0.7)
|
|
|
|
|
|
plt.axvline(x=reconstruction_threshold, color='red', linestyle='--', linewidth=2,
|
|
|
label=f'Порог: {reconstruction_threshold:.4f}')
|
|
|
plt.xlabel('Ошибка реконструкции')
|
|
|
plt.ylabel('Количество образцов')
|
|
|
plt.title('Распределение ошибок реконструкции')
|
|
|
plt.legend()
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
|
|
|
|
|
|
# График 3: Ошибки по порядку образцов
|
|
|
plt.subplot(2, 2, 3)
|
|
|
plt.plot(test_errors, 'b-', alpha=0.7, linewidth=1)
|
|
|
plt.axhline(y=reconstruction_threshold, color='red', linestyle='--', linewidth=2, label='Порог')
|
|
|
plt.xlabel('Номер образца')
|
|
|
plt.ylabel('Ошибка реконструкции')
|
|
|
plt.title('Ошибки реконструкции по порядку образцов')
|
|
|
plt.legend()
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
|
|
|
|
|
|
plt.tight_layout()
|
|
|
plt.show()
|
|
|
|
|
|
# 7. Детальная статистика
|
|
|
print("\nДЕТАЛЬНАЯ СТАТИСТИКА:")
|
|
|
print(f"Минимальная ошибка: {np.min(test_errors):.6f}")
|
|
|
print(f"Максимальная ошибка: {np.max(test_errors):.6f}")
|
|
|
print(f"Средняя ошибка: {np.mean(test_errors):.6f}")
|
|
|
print(f"Медианная ошибка: {np.median(test_errors):.6f}")
|
|
|
print(f"Стандартное отклонение: {np.std(test_errors):.6f}")
|
|
|
|
|
|
print("\n" + "=" * 60)
|
|
|
print("ОБНАРУЖЕНИЕ АНОМАЛИЙ ЗАВЕРШЕНО")
|
|
|
print("=" * 60)
|
|
|
```
|
|
|
|
|
|

|
|
|
|
|
|
**Результат выполнения:**
|
|
|
|
|
|
```
|
|
|
ОБНАРУЖЕНИЕ АНОМАЛИЙ НА ТЕСТОВОЙ ВЫБОРКЕ
|
|
|
|
|
|
Тестовая выборка загружена: (357, 30)
|
|
|
|
|
|
Порог обнаружения аномалий: 0.136186
|
|
|
Ожидаемая размерность модели: 30
|
|
|
Фактическая размерность данных: 30
|
|
|
|
|
|
РЕЗУЛЬТАТЫ ОБНАРУЖЕНИЯ АНОМАЛИЙ:
|
|
|
Всего тестовых образцов: 357
|
|
|
Обнаружено аномалий: 286
|
|
|
Процент аномалий: 80.11%
|
|
|
|
|
|
ДЕТАЛЬНАЯ СТАТИСТИКА:
|
|
|
Минимальная ошибка: 0.084998
|
|
|
Максимальная ошибка: 0.300929
|
|
|
Средняя ошибка: 0.160974
|
|
|
Медианная ошибка: 0.160995
|
|
|
Стандартное отклонение: 0.029058
|
|
|
```
|
|
|
|
|
|
### Пункт №10. Параметры наилучшего автокодировщика и результаты обнаружения аномалий.
|
|
|
|
|
|
|
|
|
**Табл. 2 Результаты задания №2:**
|
|
|
|
|
|
|
|
|
| Dataset name | Количество скрытых слоев | Количество нейронов в скрытых слоях | Количество эпох обучения | Ошибка MSE_stop | Порог ошибки реконструкции | % обнаруженных аномалий |
|
|
|
|---|---|---|---|---|---|---|
|
|
|
| WBC (White Blood Cells) | 9 | 30-24-18-12-8-12-18-24-30 | 50000 | 0.143102 | 0.136186 | 80.11% |
|
|
|
|
|
|
|
|
|
### Пункт №11. Выводы.
|
|
|
|
|
|
**Вывод:**
|
|
|
|
|
|
```
|
|
|
1. Данные для обучения:
|
|
|
|
|
|
Требуется тщательная предобработка и нормализация
|
|
|
|
|
|
Объем данных должен соответствовать сложности модели
|
|
|
|
|
|
2. Архитектура автокодировщика:
|
|
|
|
|
|
Глубокие сети (5+ слоев) для высокоразмерных данных
|
|
|
|
|
|
Постепенное сжатие к bottleneck
|
|
|
|
|
|
3. Количество эпох:
|
|
|
|
|
|
Десятки тысяч эпох для сложных архитектур
|
|
|
|
|
|
Обязательное использование EarlyStopping
|
|
|
|
|
|
4. MSE_stop критерий:
|
|
|
|
|
|
MSE_stop порядка 0.01 – 0.1
|
|
|
|
|
|
5. Порог обнаружения:
|
|
|
|
|
|
На основе статистики ошибок обучающей выборки
|
|
|
``` |