# Лабораторная работа №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) ``` ![Результаты](1.png) ### Пункт №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 ![Результаты AE1](2.png) ### Пункт №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% ![Результаты AE2](3.png) ### Пункт №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 ![график](4.png) ![график](5.png) ![график](6.png) ![график](7.png) ![график](8.png) **ВЫВОД О ПРИГОДНОСТИ 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 ![Результаты улучшенного AE2](9.png) ### Пункт №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 после улучшения стал значительно лучше по основным метрикам аппроксимации. ### Пункт №7. Создание тестовой выборки.