Сравнить коммиты
	
		
			4 Коммитов 
		
	
	
	| Автор | SHA1 | Дата | 
|---|---|---|
|  | b0dbbeb2e4 | 2 недель назад | 
|  | ca4a6189c8 | 2 недель назад | 
|  | e0e4cb8b0a | 3 недель назад | 
|  | 57734ae3f3 | 3 недель назад | 
| @ -0,0 +1,533 @@ | |||||||
|  | 
 | ||||||
|  | ## Отчёт по лабораторной работе №1 | ||||||
|  | 
 | ||||||
|  | **Троянов Д.С., Чернов Д.Е. — А-01-22** | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 1) В среде Google Colab создали блокнот. Импортировали необходимые библиотеки и модули. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # импорт модулей | ||||||
|  | import tensorflow as tf | ||||||
|  | from tensorflow import keras | ||||||
|  | from keras.datasets import mnist | ||||||
|  | from keras.models import Sequential | ||||||
|  | from keras.layers import Dense | ||||||
|  | from keras.utils import to_categorical | ||||||
|  | from sklearn.model_selection import train_test_split | ||||||
|  | import matplotlib.pyplot as plt | ||||||
|  | import numpy as np | ||||||
|  | from PIL import Image | ||||||
|  | import os | ||||||
|  | 
 | ||||||
|  | # Укажем текущую директорию | ||||||
|  | os.chdir('/content/drive/MyDrive/Colab Notebooks/is_dnn/labworks/LW1') | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 2) Загрузили набор данных MNIST, содержащий размеченные изображения рукописных цифр. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # Загрузка датасета | ||||||
|  | (X_train_orig, y_train_orig), (X_test_orig, y_test_orig) = mnist.load_data() | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 3) Разбили набор данных на обучающие и тестовые данные в соотношении 60 000:10 000 элементов. | ||||||
|  | При разбиении параметр `random_state` выбрали равным (4k – 1), где k - номер бригады, k = 6 ⇒ `random_state = 23`. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # разбиваем выборку на обучающую и тестовую выборку | ||||||
|  | X = np.concatenate((X_train_orig, X_test_orig)) | ||||||
|  | y = np.concatenate((y_train_orig, y_test_orig)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | X_train, X_test, y_train, y_test = train_test_split( | ||||||
|  |     X, y, | ||||||
|  |     test_size=10000, | ||||||
|  |     train_size=60000, | ||||||
|  |     random_state=3, | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | # вывод размерности массивов данных | ||||||
|  | print('Shape of X train:', X_train.shape) | ||||||
|  | print('Shape of y train:', y_train.shape) | ||||||
|  | print('Shape of X test:', X_test.shape) | ||||||
|  | print('Shape of y test:', y_test.shape) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | Shape of X train: (60000, 28, 28) | ||||||
|  | Shape of y train: (60000,) | ||||||
|  | Shape of X test: (10000, 28, 28) | ||||||
|  | Shape of y test: (10000,) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 4) Вывели первые 4 элемента обучающих данных (изображения и метки цифр). | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # Вывод первых 4 изображений | ||||||
|  | fig, axes = plt.subplots(1, 4, figsize=(12, 3)) | ||||||
|  | for i in range(4): | ||||||
|  |     axes[i].imshow(X_train[i], cmap='gray') | ||||||
|  |     axes[i].set_title(f'Метка: {y_train[i]}') | ||||||
|  |     axes[i].axis('off') | ||||||
|  | plt.tight_layout() | ||||||
|  | plt.show() | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # Были выведены цифры 7, 8, 2, 2 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 5) Провели предобработку данных: привели обучающие и тестовые данные к формату, пригодному для обучения нейронной сети. Входные данные должны принимать значения от 0 до 1, метки цифр должны быть закодированы по принципу «one-hot encoding». Вывели размерности предобработанных обучающих и тестовых массивов данных. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # развернем каждое изображение 28*28 в вектор 784 | ||||||
|  | num_pixels = X_train.shape[1] * X_train.shape[2] | ||||||
|  | X_train = X_train.reshape(X_train.shape[0], num_pixels) / 255 | ||||||
|  | X_test = X_test.reshape(X_test.shape[0], num_pixels) / 255 | ||||||
|  | print('Shape of transformed X train:', X_train.shape) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | Shape of transformed X train: (60000, 784) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # переведем метки в one-hot | ||||||
|  | from keras.utils import to_categorical | ||||||
|  | y_train = to_categorical(y_train) | ||||||
|  | y_test = to_categorical(y_test) | ||||||
|  | print('Shape of transformed y train:', y_train.shape) | ||||||
|  | num_classes = y_train.shape[1] | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | Shape of transformed y train: (60000, 10) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 6) Реализовали модель однослойной нейронной сети и обучили ее на обучающих данных с выделением части обучающих данных в качестве валидационных. Вывели информацию об архитектуре нейронной сети. Вывели график функции ошибки на обучающих и валидационных данных по эпохам. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | model_0 = Sequential() | ||||||
|  | model_0.add(Dense(units=num_classes, input_dim=num_pixels, activation='softmax')) | ||||||
|  | 
 | ||||||
|  | # Компиляция модели | ||||||
|  | model_0.compile(loss='categorical_crossentropy', | ||||||
|  |                 optimizer='sgd', | ||||||
|  |                 metrics=['accuracy']) | ||||||
|  | 
 | ||||||
|  | # Вывод информации об архитектуре | ||||||
|  | print("Архитектура однослойной сети:") | ||||||
|  | model_0.summary() | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | # Обучение модели | ||||||
|  | history_0 = model_0.fit(X_train, y_train, | ||||||
|  |                         validation_split=0.1, | ||||||
|  |                         epochs=50) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # График функции ошибки по эпохам | ||||||
|  | plt.figure(figsize=(10, 6)) | ||||||
|  | plt.plot(history_0.history['loss'], label='Обучающая выборка') | ||||||
|  | plt.plot(history_0.history['val_loss'], label='Валидационная выборка') | ||||||
|  | plt.title('Функция ошибки по эпохам (Однослойная сеть)') | ||||||
|  | plt.xlabel('Эпохи') | ||||||
|  | plt.ylabel('Ошибка') | ||||||
|  | plt.legend() | ||||||
|  | plt.grid(True) | ||||||
|  | plt.show() | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 7) Применили обученную модель к тестовым данным. Вывели значение функции ошибки и значение метрики качества классификации на тестовых данных. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # Оценка на тестовых данных | ||||||
|  | scores_0 = model_0.evaluate(X_test, y_test, verbose=0) | ||||||
|  | print("Результаты однослойной сети:") | ||||||
|  | print(f"Ошибка на тестовых данных: {scores_0[0]}") | ||||||
|  | print(f"Точность на тестовых данных: {scores_0[1]}") | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | Результаты однослойной сети: | ||||||
|  | 		Ошибка на тестовых данных: 0.28625616431236267 | ||||||
|  | 		Точность на тестовых данных: 0.92330002784729 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 8) Добавили в модель один скрытый и провели обучение и тестирование (повторить п. 6–7) при 100, 300, 500 нейронах в скрытом слое. По метрике качества классификации на тестовых данных выбрали наилучшее количество нейронов в скрытом слое. В качестве функции активации нейронов в скрытом слое использовали функцию `sigmoid`. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # Функция для создания и обучения модели | ||||||
|  | def create_and_train_model(hidden_units, model_name): | ||||||
|  |     model = Sequential() | ||||||
|  |     model.add(Dense(units=hidden_units, input_dim=num_pixels, activation='sigmoid')) | ||||||
|  |     model.add(Dense(units=num_classes, activation='softmax')) | ||||||
|  | 
 | ||||||
|  |     model.compile(loss='categorical_crossentropy', | ||||||
|  |                   optimizer='sgd', | ||||||
|  |                   metrics=['accuracy']) | ||||||
|  | 
 | ||||||
|  |     history = model.fit(X_train, y_train, | ||||||
|  |                         validation_split=0.1, | ||||||
|  |                         epochs=50) | ||||||
|  | 
 | ||||||
|  |     scores = model.evaluate(X_test, y_test, verbose=0) | ||||||
|  | 
 | ||||||
|  |     return model, history, scores | ||||||
|  | 
 | ||||||
|  | # Эксперименты с разным количеством нейронов | ||||||
|  | hidden_units_list = [100, 300, 500] | ||||||
|  | models_1 = {} | ||||||
|  | histories_1 = {} | ||||||
|  | scores_1 = {} | ||||||
|  | 
 | ||||||
|  | # Обучение сетей с одним скрытым слоем | ||||||
|  | for units in hidden_units_list: | ||||||
|  |     print(f" | ||||||
|  | Обучение модели с {units} нейронами...") | ||||||
|  |     model, history, scores = create_and_train_model(units, f"model_{units}") | ||||||
|  | 
 | ||||||
|  |     models_1[units] = model | ||||||
|  |     histories_1[units] = history | ||||||
|  |     scores_1[units] = scores | ||||||
|  | 
 | ||||||
|  |     print(f"Точность: {scores[1]}") | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | # Определим лучшую модель по итогвой точности | ||||||
|  | ```python | ||||||
|  | # Выбор наилучшей модели | ||||||
|  | best_units_1 = max(scores_1.items(), key=lambda x: x[1][1])[0] | ||||||
|  | print(f" | ||||||
|  | Наилучшее количество нейронов: {best_units_1}") | ||||||
|  | print(f"Точность: {scores_1[best_units_1][1]}") | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 		Наилучшее количество нейронов: 100 | ||||||
|  | 		Точность: 0.9422000050544739 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | # Отобразим графики ошибок для каждой из архитектур нейросети | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # Графики ошибок для всех моделей | ||||||
|  | plt.figure(figsize=(15, 5)) | ||||||
|  | for i, units in enumerate(hidden_units_list, 1): | ||||||
|  |     plt.subplot(1, 3, i) | ||||||
|  |     plt.plot(histories_1[units].history['loss'], label='Обучающая') | ||||||
|  |     plt.plot(histories_1[units].history['val_loss'], label='Валидационная') | ||||||
|  |     plt.title(f'{units} нейронов') | ||||||
|  |     plt.xlabel('Эпохи') | ||||||
|  |     plt.ylabel('Ошибка') | ||||||
|  |     plt.legend() | ||||||
|  |     plt.grid(True) | ||||||
|  | plt.tight_layout() | ||||||
|  | plt.show() | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | **По результатам проведнного эксперимента наилучший показатель точности продемонстрировала нейронная сеть со 100 нейронами в скрытом слое - примерно 0.9422.** | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 9) Добавили в архитектуру с лучшим показателем из п. 8, второй скрытый слой и провели обучение и тестирование при 50 и 100 нейронах во втором скрытом слое. В качестве функции активации нейронов в скрытом слое использовали функцию `sigmoid`. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # Добавление второго скрытого слоя | ||||||
|  | second_layer_units = [50, 100] | ||||||
|  | models_2 = {} | ||||||
|  | histories_2 = {} | ||||||
|  | scores_2 = {} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | for units_2 in second_layer_units: | ||||||
|  |     print(f" | ||||||
|  | Обучение модели со вторым слоем {units_2} нейронов") | ||||||
|  | 
 | ||||||
|  |     model = Sequential() | ||||||
|  |     model.add(Dense(units=best_units_1, input_dim=num_pixels, activation='sigmoid')) | ||||||
|  |     model.add(Dense(units=units_2, activation='sigmoid')) | ||||||
|  |     model.add(Dense(units=num_classes, activation='softmax')) | ||||||
|  | 
 | ||||||
|  |     model.compile(loss='categorical_crossentropy', | ||||||
|  |                   optimizer='sgd', | ||||||
|  |                   metrics=['accuracy']) | ||||||
|  | 
 | ||||||
|  |     history = model.fit(X_train, y_train, | ||||||
|  |                         validation_split=0.1, | ||||||
|  |                         epochs=50) | ||||||
|  | 
 | ||||||
|  |     scores = model.evaluate(X_test, y_test) | ||||||
|  | 
 | ||||||
|  |     models_2[units_2] = model | ||||||
|  |     histories_2[units_2] = history | ||||||
|  |     scores_2[units_2] = scores | ||||||
|  | 
 | ||||||
|  |     print(f"Точность: {scores[1]}") | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | # Результаты обучения моделей: | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | Обучение модели со вторым слоем 50 нейронов: | ||||||
|  | Точность: 0.9417999982833862 | ||||||
|  | 
 | ||||||
|  | Обучение модели со вторым слоем 100 нейронов | ||||||
|  | Точность: 0.942300021648407 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | # Выбор наилучшей двухслойной модели | ||||||
|  | ```python | ||||||
|  | best_units_2 = max(scores_2.items(), key=lambda x: x[1][1])[0] | ||||||
|  | print(f" | ||||||
|  | Наилучшее количество нейронов во втором слое: {best_units_2}") | ||||||
|  | print(f"Точность: {scores_2[best_units_2][1]}") | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 	Наилучшее количество нейронов во втором слое: 100 | ||||||
|  | 	Точность: 0.9423 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ## 10) Результаты исследования архитектуры нейронной сети занесли в таблицу: | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # Сбор результатов | ||||||
|  | results = { | ||||||
|  |     '0 слоев': {'нейроны_1': '-', 'нейроны_2': '-', 'точность': scores_0[1]}, | ||||||
|  |     '1 слой_100': {'нейроны_1': 100, 'нейроны_2': '-', 'точность': scores_1[100][1]}, | ||||||
|  |     '1 слой_300': {'нейроны_1': 300, 'нейроны_2': '-', 'точность': scores_1[300][1]}, | ||||||
|  |     '1 слой_500': {'нейроны_1': 500, 'нейроны_2': '-', 'точность': scores_1[500][1]}, | ||||||
|  |     '2 слоя_50': {'нейроны_1': best_units_1, 'нейроны_2': 50, 'точность': scores_2[50][1]}, | ||||||
|  |     '2 слоя_100': {'нейроны_1': best_units_1, 'нейроны_2': 100, 'точность': scores_2[100][1]} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # Создаем DataFrame из результатов | ||||||
|  | df_results = pd.DataFrame([ | ||||||
|  |     {'Кол-во скрытых слоев': 0, 'Нейроны_1_слоя': '-', 'Нейроны_2_слоя': '-', 'Точность': results['0 слоев']['точность']}, | ||||||
|  |     {'Кол-во скрытых слоев': 1, 'Нейроны_1_слоя': 100, 'Нейроны_2_слоя': '-', 'Точность': results['1 слой_100']['точность']}, | ||||||
|  |     {'Кол-во скрытых слоев': 1, 'Нейроны_1_слоя': 300, 'Нейроны_2_слоя': '-', 'Точность': results['1 слой_300']['точность']}, | ||||||
|  |     {'Кол-во скрытых слоев': 1, 'Нейроны_1_слоя': 500, 'Нейроны_2_слоя': '-', 'Точность': results['1 слой_500']['точность']}, | ||||||
|  |     {'Кол-во скрытых слоев': 2, 'Нейроны_1_слоя': best_units_1, 'Нейроны_2_слоя': 50, 'Точность': results['2 слоя_50']['точность']}, | ||||||
|  |     {'Кол-во скрытых слоев': 2, 'Нейроны_1_слоя': best_units_1, 'Нейроны_2_слоя': 100, 'Точность': results['2 слоя_100']['точность']} | ||||||
|  | ]) | ||||||
|  | 
 | ||||||
|  | print(" " * 20 + "ТАБЛИЦА РЕЗУЛЬТАТОВ") | ||||||
|  | print("=" * 70) | ||||||
|  | # print(df_results.to_string(index=False, formatters={ | ||||||
|  | #     'Точность': '{:.4f}'.format | ||||||
|  | # })) | ||||||
|  | print(df_results.reset_index(drop=True)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 		ТАБЛИЦА РЕЗУЛЬТАТОВ | ||||||
|  | 		====================================================================== | ||||||
|  | 		   Кол-во скрытых слоев Нейроны_1_слоя Нейроны_2_слоя  Точность | ||||||
|  | 		0                     0              -              -    0.9233 | ||||||
|  | 		1                     1            100              -    0.9422 | ||||||
|  | 		2                     1            300              -    0.9377 | ||||||
|  | 		3                     1            500              -    0.9312 | ||||||
|  | 		4                     2            100             50    0.9418 | ||||||
|  | 		5                     2            100            100    0.9423 | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # Выбор наилучшей модели | ||||||
|  | best_model_type = max(results.items(), key=lambda x: x[1]['точность'])[0] | ||||||
|  | best_accuracy = results[best_model_type]['точность'] | ||||||
|  | print(f" | ||||||
|  | Наилучшая архитектура: {best_model_type}") | ||||||
|  | print(f"Точность: {best_accuracy}") | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 		Наилучшая архитектура: 2 слоя_100 | ||||||
|  | 		Точность: 0.9423 | ||||||
|  | ``` | ||||||
|  | ### По результатам исследования сделали выводы и выбрали наилучшую архитектуру нейронной сети с точки зрения качества классификации. | ||||||
|  | 
 | ||||||
|  | **Из таблицы следует, что лучшей архитектурой является НС с двумя скрытыми слоями по 100 и 50 нейронов, второе место занимает НС с одним скрытым слоем и 100 нейронами, на основе которой мы и строили НС с двумя скрытыми слоями. При увеличении количества нейронов в архитектуре НС с 1-м скрытым слоем в результате тестирования было вявлено, что метрики качества падают. Это связано с переобучение нашей НС с 1-м скрытым слоем (когда построенная модель хорошо объясняет примеры из обучающей выборки, но относительно плохо работает на примерах, не участвовавших в обучении) Такая тенденция вероятно возникает из-за простоты датасета MNIST, при усложнении архитектуры НС начинает переобучаться, а оценка качества на тестовых данных падает. Но также стоит отметить, что при усложнении структуры НС точнсть модели также и растет.** | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 11) Сохранили наилучшую нейронную сеть на диск. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # Сохранение модели | ||||||
|  | best_model.save('best_mnist_model.keras') | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 12) Для нейронной сети наилучшей архитектуры вывели два тестовых изображения, истинные метки и результат распознавания изображений. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # вывод тестового изображения и результата распознавания (1) | ||||||
|  | n = 123 | ||||||
|  | result = best_model.predict(X_test[n:n+1]) | ||||||
|  | print('NN output:', result) | ||||||
|  | plt.imshow(X_test[n].reshape(28,28), cmap=plt.get_cmap('gray')) | ||||||
|  | plt.show() | ||||||
|  | print('Real mark: ', str(np.argmax(y_test[n]))) | ||||||
|  | print('NN answer: ', str(np.argmax(result))) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # вывод тестового изображения и результата распознавания (3) | ||||||
|  | n = 353 | ||||||
|  | result = best_model.predict(X_test[n:n+1]) | ||||||
|  | print('NN output:', result) | ||||||
|  | plt.imshow(X_test[n].reshape(28,28), cmap=plt.get_cmap('gray')) | ||||||
|  | plt.show() | ||||||
|  | print('Real mark: ', str(np.argmax(y_test[n]))) | ||||||
|  | print('NN answer: ', str(np.argmax(result))) | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 13) Создали собственные изображения рукописных цифр, подобное представленным в наборе MNIST. Цифру выбрали как остаток от деления на 10 числа своего дня рождения (12 марта → 2, 17 сентября → 7 ). Сохранили изображения. Загрузили, предобработали и подали на вход обученной нейронной сети собственные изображения. Вывели изображения и результаты распознавания. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # загрузка собственного изображения | ||||||
|  | file_data_2 = Image.open('2.png') | ||||||
|  | file_data_7 = Image.open('7.png') | ||||||
|  | file_data_2 = file_data_2.convert('L') # перевод в градации серого | ||||||
|  | file_data_7 = file_data_7.convert('L') # перевод в градации серого | ||||||
|  | test_img_2 = np.array(file_data_2) | ||||||
|  | test_img_7 = np.array(file_data_7) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # вывод собственного изображения (цифра 2) | ||||||
|  | plt.imshow(test_img_2, cmap=plt.get_cmap('gray')) | ||||||
|  | plt.show() | ||||||
|  | # предобработка | ||||||
|  | test_img_2 = test_img_2 / 255 | ||||||
|  | test_img_2 = test_img_2.reshape(1, num_pixels) | ||||||
|  | # распознавание | ||||||
|  | result = best_model.predict(test_img_2) | ||||||
|  | print('I think it\'s ', np.argmax(result)) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 31ms/step | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # вывод собственного изображения (цифра 7) | ||||||
|  | plt.imshow(test_img_7, cmap=plt.get_cmap('gray')) | ||||||
|  | plt.show() | ||||||
|  | # предобработка | ||||||
|  | test_img_7 = test_img_7 / 255 | ||||||
|  | test_img_7 = test_img_7.reshape(1, num_pixels) | ||||||
|  | # распознавание | ||||||
|  | result = best_model.predict(test_img_7) | ||||||
|  | print('I think it\'s ', np.argmax(result)) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 48ms/step | ||||||
|  | I think it's  7 | ||||||
|  | ``` | ||||||
|  | **Как видим в результате эксперимента наша НС недостаточно точно определила изображение цифры 2. Возможно это связано с малом размером используемой выборки. Для улучшения качества решения задачи классификации можно либо увеличить размерность выборки для обучения НС, либо изменить структуру НС для более точной ее работы** | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 14) Создать копию собственного изображения, отличающуюся от оригинала поворотом на 90 градусов в любую сторону. Сохранили изображения. Загрузили, предобработали и подали на вход обученной нейронной сети измененные изображения. Вывели изображения и результаты распознавания. Сделали выводы по результатам эксперимента. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # загрузка собственного изображения | ||||||
|  | file_data_2_90 = Image.open('2_90.png') | ||||||
|  | file_data_7_90 = Image.open('7_90.png') | ||||||
|  | file_data_2_90 = file_data_2_90.convert('L') # перевод в градации серого | ||||||
|  | file_data_7_90 = file_data_7_90.convert('L') # перевод в градации серого | ||||||
|  | test_img_2_90 = np.array(file_data_2_90) | ||||||
|  | test_img_7_90= np.array(file_data_7_90) | ||||||
|  | 
 | ||||||
|  | # вывод собственного изображения (цифра 2) | ||||||
|  | plt.imshow(test_img_2_90, cmap=plt.get_cmap('gray')) | ||||||
|  | plt.show() | ||||||
|  | # предобработка | ||||||
|  | test_img_2_90 = test_img_2_90 / 255 | ||||||
|  | test_img_2_90 = test_img_2_90.reshape(1, num_pixels) | ||||||
|  | # распознавание | ||||||
|  | result = best_model.predict(test_img_2_90) | ||||||
|  | print('I think it\'s ', np.argmax(result)) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 91ms/step | ||||||
|  | I think it's  7 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # вывод собственного изображения (цифра 7) | ||||||
|  | plt.imshow(test_img_7_90, cmap=plt.get_cmap('gray')) | ||||||
|  | plt.show() | ||||||
|  | # предобработка | ||||||
|  | test_img_7_90 = test_img_7_90 / 255 | ||||||
|  | test_img_7_90 = test_img_7_90.reshape(1, num_pixels) | ||||||
|  | # распознавание | ||||||
|  | result = best_model.predict(test_img_7_90) | ||||||
|  | print('I think it\'s ', np.argmax(result)) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 48ms/step | ||||||
|  | I think it's  7 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | **При повороте рисунков цифр НС не смогла распознать одну из цифр. Так получилось, во-первых, по той же причине, почему НС не распознала одну из цифр в пункте 13, во-вторых - наша НС не обучалась на перевернутых цифрах** | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |          | ||||||
| После Ширина: | Высота: | Размер: 315 B | 
| После Ширина: | Высота: | Размер: 948 B | 
| После Ширина: | Высота: | Размер: 273 B | 
| После Ширина: | Высота: | Размер: 920 B | 
| @ -0,0 +1,899 @@ | |||||||
|  | { | ||||||
|  |  "cells": [ | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "id": "d5jFanC8NPTN" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "import os\n", | ||||||
|  |     "os.chdir('/content/drive/MyDrive/Colab Notebooks/is_dnn/labworks/LW1')" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "id": "H39A4nsqNuxn" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# импорт модулей\n", | ||||||
|  |     "import tensorflow as tf\n", | ||||||
|  |     "from tensorflow import keras\n", | ||||||
|  |     "from keras.datasets import mnist\n", | ||||||
|  |     "from keras.models import Sequential\n", | ||||||
|  |     "from keras.layers import Dense\n", | ||||||
|  |     "from keras.utils import to_categorical\n", | ||||||
|  |     "from sklearn.model_selection import train_test_split\n", | ||||||
|  |     "import matplotlib.pyplot as plt\n", | ||||||
|  |     "import numpy as np\n", | ||||||
|  |     "from PIL import Image\n", | ||||||
|  |     "import os\n", | ||||||
|  |     "import pandas as pd" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "colab": { | ||||||
|  |      "base_uri": "https://localhost:8080/" | ||||||
|  |     }, | ||||||
|  |     "executionInfo": { | ||||||
|  |      "elapsed": 462, | ||||||
|  |      "status": "ok", | ||||||
|  |      "timestamp": 1759127274975, | ||||||
|  |      "user": { | ||||||
|  |       "displayName": "Legal People", | ||||||
|  |       "userId": "00818738730090246603" | ||||||
|  |      }, | ||||||
|  |      "user_tz": -180 | ||||||
|  |     }, | ||||||
|  |     "id": "iNenKkcoRXrs", | ||||||
|  |     "outputId": "041dc403-e177-4f0d-edbb-40902c8954fd" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# Загрузка датасета\n", | ||||||
|  |     "(X_train_orig, y_train_orig), (X_test_orig, y_test_orig) = mnist.load_data()\n", | ||||||
|  |     "\n", | ||||||
|  |     "# разбиваем выборку на обучающую и тестовую выборку\n", | ||||||
|  |     "X = np.concatenate((X_train_orig, X_test_orig))\n", | ||||||
|  |     "y = np.concatenate((y_train_orig, y_test_orig))\n", | ||||||
|  |     "\n", | ||||||
|  |     "\n", | ||||||
|  |     "X_train, X_test, y_train, y_test = train_test_split(\n", | ||||||
|  |     "    X, y,\n", | ||||||
|  |     "    test_size=10000,\n", | ||||||
|  |     "    train_size=60000,\n", | ||||||
|  |     "    random_state=3,\n", | ||||||
|  |     ")" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "colab": { | ||||||
|  |      "base_uri": "https://localhost:8080/", | ||||||
|  |      "height": 224 | ||||||
|  |     }, | ||||||
|  |     "executionInfo": { | ||||||
|  |      "elapsed": 243, | ||||||
|  |      "status": "ok", | ||||||
|  |      "timestamp": 1759127328545, | ||||||
|  |      "user": { | ||||||
|  |       "displayName": "Legal People", | ||||||
|  |       "userId": "00818738730090246603" | ||||||
|  |      }, | ||||||
|  |      "user_tz": -180 | ||||||
|  |     }, | ||||||
|  |     "id": "bt-EmlYARsCL", | ||||||
|  |     "outputId": "611d9110-39a2-46dd-94ce-b0fea7005b87" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# Вывод первых 4 изображений\n", | ||||||
|  |     "fig, axes = plt.subplots(1, 4, figsize=(12, 3))\n", | ||||||
|  |     "for i in range(4):\n", | ||||||
|  |     "    axes[i].imshow(X_train[i], cmap='gray')\n", | ||||||
|  |     "    axes[i].set_title(f'Метка: {y_train[i]}')\n", | ||||||
|  |     "    axes[i].axis('off')\n", | ||||||
|  |     "plt.tight_layout()\n", | ||||||
|  |     "plt.show()" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "colab": { | ||||||
|  |      "base_uri": "https://localhost:8080/" | ||||||
|  |     }, | ||||||
|  |     "executionInfo": { | ||||||
|  |      "elapsed": 134, | ||||||
|  |      "status": "ok", | ||||||
|  |      "timestamp": 1759127329383, | ||||||
|  |      "user": { | ||||||
|  |       "displayName": "Legal People", | ||||||
|  |       "userId": "00818738730090246603" | ||||||
|  |      }, | ||||||
|  |      "user_tz": -180 | ||||||
|  |     }, | ||||||
|  |     "id": "5WUu3_97TjSa", | ||||||
|  |     "outputId": "7a75ca25-58fe-447d-8bef-547159e6479d" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# развернем каждое изображение 28*28 в вектор 784\n", | ||||||
|  |     "num_pixels = X_train.shape[1] * X_train.shape[2]\n", | ||||||
|  |     "X_train = X_train.reshape(X_train.shape[0], num_pixels) / 255\n", | ||||||
|  |     "X_test = X_test.reshape(X_test.shape[0], num_pixels) / 255\n", | ||||||
|  |     "print('Shape of transformed X train:', X_train.shape)" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "colab": { | ||||||
|  |      "base_uri": "https://localhost:8080/" | ||||||
|  |     }, | ||||||
|  |     "executionInfo": { | ||||||
|  |      "elapsed": 7, | ||||||
|  |      "status": "ok", | ||||||
|  |      "timestamp": 1759127330016, | ||||||
|  |      "user": { | ||||||
|  |       "displayName": "Legal People", | ||||||
|  |       "userId": "00818738730090246603" | ||||||
|  |      }, | ||||||
|  |      "user_tz": -180 | ||||||
|  |     }, | ||||||
|  |     "id": "sUJfDepgUauM", | ||||||
|  |     "outputId": "2a9bc3d0-8bdb-4971-f3d4-ca21cb14fca6" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# переведем метки в one-hot\n", | ||||||
|  |     "y_train = to_categorical(y_train)\n", | ||||||
|  |     "y_test = to_categorical(y_test)\n", | ||||||
|  |     "print('Shape of transformed y train:', y_train.shape)\n", | ||||||
|  |     "num_classes = y_train.shape[1]" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "colab": { | ||||||
|  |      "base_uri": "https://localhost:8080/", | ||||||
|  |      "height": 1000 | ||||||
|  |     }, | ||||||
|  |     "executionInfo": { | ||||||
|  |      "elapsed": 207500, | ||||||
|  |      "status": "ok", | ||||||
|  |      "timestamp": 1759127540337, | ||||||
|  |      "user": { | ||||||
|  |       "displayName": "Legal People", | ||||||
|  |       "userId": "00818738730090246603" | ||||||
|  |      }, | ||||||
|  |      "user_tz": -180 | ||||||
|  |     }, | ||||||
|  |     "id": "f3UzOyf_V2HQ", | ||||||
|  |     "outputId": "9ffc63df-23bf-4947-f3c0-2a3e507034f1" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "model_0 = Sequential()\n", | ||||||
|  |     "model_0.add(Dense(units=num_classes, input_dim=num_pixels, activation='softmax'))\n", | ||||||
|  |     "\n", | ||||||
|  |     "# Компиляция модели\n", | ||||||
|  |     "model_0.compile(loss='categorical_crossentropy',\n", | ||||||
|  |     "                optimizer='sgd',\n", | ||||||
|  |     "                metrics=['accuracy'])\n", | ||||||
|  |     "\n", | ||||||
|  |     "# Вывод информации об архитектуре\n", | ||||||
|  |     "print(\"Архитектура однослойной сети:\")\n", | ||||||
|  |     "model_0.summary()\n", | ||||||
|  |     "\n", | ||||||
|  |     "# Обучение модели\n", | ||||||
|  |     "history_0 = model_0.fit(X_train, y_train,\n", | ||||||
|  |     "                        validation_split=0.1,\n", | ||||||
|  |     "                        epochs=50)\n" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "colab": { | ||||||
|  |      "base_uri": "https://localhost:8080/", | ||||||
|  |      "height": 533 | ||||||
|  |     }, | ||||||
|  |     "executionInfo": { | ||||||
|  |      "elapsed": 260, | ||||||
|  |      "status": "ok", | ||||||
|  |      "timestamp": 1759127542723, | ||||||
|  |      "user": { | ||||||
|  |       "displayName": "Legal People", | ||||||
|  |       "userId": "00818738730090246603" | ||||||
|  |      }, | ||||||
|  |      "user_tz": -180 | ||||||
|  |     }, | ||||||
|  |     "id": "5yjxVnmFmpbV", | ||||||
|  |     "outputId": "b182a139-da24-491e-9ebd-7ba1e39eec84" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# График функции ошибки по эпохам\n", | ||||||
|  |     "plt.figure(figsize=(10, 6))\n", | ||||||
|  |     "plt.plot(history_0.history['loss'], label='Обучающая выборка')\n", | ||||||
|  |     "plt.plot(history_0.history['val_loss'], label='Валидационная выборка')\n", | ||||||
|  |     "plt.title('Функция ошибки по эпохам (Однослойная сеть)')\n", | ||||||
|  |     "plt.xlabel('Эпохи')\n", | ||||||
|  |     "plt.ylabel('Ошибка')\n", | ||||||
|  |     "plt.legend()\n", | ||||||
|  |     "plt.grid(True)\n", | ||||||
|  |     "plt.show()" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "colab": { | ||||||
|  |      "base_uri": "https://localhost:8080/" | ||||||
|  |     }, | ||||||
|  |     "executionInfo": { | ||||||
|  |      "elapsed": 1058, | ||||||
|  |      "status": "ok", | ||||||
|  |      "timestamp": 1759127544719, | ||||||
|  |      "user": { | ||||||
|  |       "displayName": "Legal People", | ||||||
|  |       "userId": "00818738730090246603" | ||||||
|  |      }, | ||||||
|  |      "user_tz": -180 | ||||||
|  |     }, | ||||||
|  |     "id": "NF_SsO8wiEUT", | ||||||
|  |     "outputId": "ffe554c2-1c94-42b7-cc63-8f407418c4ce" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# Оценка на тестовых данных\n", | ||||||
|  |     "scores_0 = model_0.evaluate(X_test, y_test, verbose=0)\n", | ||||||
|  |     "print(\"Результаты однослойной сети:\")\n", | ||||||
|  |     "print(f\"Ошибка на тестовых данных: {scores_0[0]}\")\n", | ||||||
|  |     "print(f\"Точность на тестовых данных: {scores_0[1]}\")" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "id": "fFcoQGdPnDFx" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# Функция для создания и обучения модели\n", | ||||||
|  |     "def create_and_train_model(hidden_units, model_name):\n", | ||||||
|  |     "    model = Sequential()\n", | ||||||
|  |     "    model.add(Dense(units=hidden_units, input_dim=num_pixels, activation='sigmoid'))\n", | ||||||
|  |     "    model.add(Dense(units=num_classes, activation='softmax'))\n", | ||||||
|  |     "\n", | ||||||
|  |     "    model.compile(loss='categorical_crossentropy',\n", | ||||||
|  |     "                  optimizer='sgd',\n", | ||||||
|  |     "                  metrics=['accuracy'])\n", | ||||||
|  |     "\n", | ||||||
|  |     "    history = model.fit(X_train, y_train,\n", | ||||||
|  |     "                        validation_split=0.1,\n", | ||||||
|  |     "                        epochs=50)\n", | ||||||
|  |     "\n", | ||||||
|  |     "    scores = model.evaluate(X_test, y_test, verbose=0)\n", | ||||||
|  |     "\n", | ||||||
|  |     "    return model, history, scores" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "id": "XPlFkV40joAT" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# Эксперименты с разным количеством нейронов\n", | ||||||
|  |     "hidden_units_list = [100, 300, 500]\n", | ||||||
|  |     "models_1 = {}\n", | ||||||
|  |     "histories_1 = {}\n", | ||||||
|  |     "scores_1 = {}" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "colab": { | ||||||
|  |      "base_uri": "https://localhost:8080/" | ||||||
|  |     }, | ||||||
|  |     "executionInfo": { | ||||||
|  |      "elapsed": 638747, | ||||||
|  |      "status": "ok", | ||||||
|  |      "timestamp": 1759128186868, | ||||||
|  |      "user": { | ||||||
|  |       "displayName": "Legal People", | ||||||
|  |       "userId": "00818738730090246603" | ||||||
|  |      }, | ||||||
|  |      "user_tz": -180 | ||||||
|  |     }, | ||||||
|  |     "id": "je0i_8HxjvpB", | ||||||
|  |     "outputId": "5cb19edc-9162-4c23-92d8-1671e62b2bb3" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# Обучение сетей с одним скрытым слоем\n", | ||||||
|  |     "for units in hidden_units_list:\n", | ||||||
|  |     "    print(f\"\\nОбучение модели с {units} нейронами...\")\n", | ||||||
|  |     "    model, history, scores = create_and_train_model(units, f\"model_{units}\")\n", | ||||||
|  |     "\n", | ||||||
|  |     "    models_1[units] = model\n", | ||||||
|  |     "    histories_1[units] = history\n", | ||||||
|  |     "    scores_1[units] = scores\n", | ||||||
|  |     "\n", | ||||||
|  |     "    print(f\"Точность: {scores[1]}\")" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "colab": { | ||||||
|  |      "base_uri": "https://localhost:8080/" | ||||||
|  |     }, | ||||||
|  |     "executionInfo": { | ||||||
|  |      "elapsed": 20, | ||||||
|  |      "status": "ok", | ||||||
|  |      "timestamp": 1759128269112, | ||||||
|  |      "user": { | ||||||
|  |       "displayName": "Legal People", | ||||||
|  |       "userId": "00818738730090246603" | ||||||
|  |      }, | ||||||
|  |      "user_tz": -180 | ||||||
|  |     }, | ||||||
|  |     "id": "TbbBBxeMmy6c", | ||||||
|  |     "outputId": "08b5a164-1e62-456c-80b9-bc7247be3fd3" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# Выбор наилучшей модели\n", | ||||||
|  |     "best_units_1 = max(scores_1.items(), key=lambda x: x[1][1])[0]\n", | ||||||
|  |     "print(f\"\\nНаилучшее количество нейронов: {best_units_1}\")\n", | ||||||
|  |     "print(f\"Точность: {scores_1[best_units_1][1]}\")" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "colab": { | ||||||
|  |      "base_uri": "https://localhost:8080/", | ||||||
|  |      "height": 279 | ||||||
|  |     }, | ||||||
|  |     "executionInfo": { | ||||||
|  |      "elapsed": 620, | ||||||
|  |      "status": "ok", | ||||||
|  |      "timestamp": 1759128272502, | ||||||
|  |      "user": { | ||||||
|  |       "displayName": "Legal People", | ||||||
|  |       "userId": "00818738730090246603" | ||||||
|  |      }, | ||||||
|  |      "user_tz": -180 | ||||||
|  |     }, | ||||||
|  |     "id": "EFEBxB2qm1fF", | ||||||
|  |     "outputId": "d436ac7a-e33b-4cc2-e324-5decfc29de94" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# Графики ошибок для всех моделей\n", | ||||||
|  |     "plt.figure(figsize=(15, 5))\n", | ||||||
|  |     "for i, units in enumerate(hidden_units_list, 1):\n", | ||||||
|  |     "    plt.subplot(1, 3, i)\n", | ||||||
|  |     "    plt.plot(histories_1[units].history['loss'], label='Обучающая')\n", | ||||||
|  |     "    plt.plot(histories_1[units].history['val_loss'], label='Валидационная')\n", | ||||||
|  |     "    plt.title(f'{units} нейронов')\n", | ||||||
|  |     "    plt.xlabel('Эпохи')\n", | ||||||
|  |     "    plt.ylabel('Ошибка')\n", | ||||||
|  |     "    plt.legend()\n", | ||||||
|  |     "    plt.grid(True)\n", | ||||||
|  |     "plt.tight_layout()\n", | ||||||
|  |     "plt.show()" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "id": "EJBwT5vhnnSG" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# Добавление второго скрытого слоя\n", | ||||||
|  |     "second_layer_units = [50, 100]\n", | ||||||
|  |     "models_2 = {}\n", | ||||||
|  |     "histories_2 = {}\n", | ||||||
|  |     "scores_2 = {}" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "colab": { | ||||||
|  |      "base_uri": "https://localhost:8080/" | ||||||
|  |     }, | ||||||
|  |     "executionInfo": { | ||||||
|  |      "elapsed": 420194, | ||||||
|  |      "status": "ok", | ||||||
|  |      "timestamp": 1759128698216, | ||||||
|  |      "user": { | ||||||
|  |       "displayName": "Legal People", | ||||||
|  |       "userId": "00818738730090246603" | ||||||
|  |      }, | ||||||
|  |      "user_tz": -180 | ||||||
|  |     }, | ||||||
|  |     "id": "K5vweMySno3t", | ||||||
|  |     "outputId": "b67b155c-89ea-46e0-a590-a588433e0a38" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "for units_2 in second_layer_units:\n", | ||||||
|  |     "    print(f\"\\nОбучение модели со вторым слоем {units_2} нейронов\")\n", | ||||||
|  |     "\n", | ||||||
|  |     "    model = Sequential()\n", | ||||||
|  |     "    model.add(Dense(units=best_units_1, input_dim=num_pixels, activation='sigmoid'))\n", | ||||||
|  |     "    model.add(Dense(units=units_2, activation='sigmoid'))\n", | ||||||
|  |     "    model.add(Dense(units=num_classes, activation='softmax'))\n", | ||||||
|  |     "\n", | ||||||
|  |     "    model.compile(loss='categorical_crossentropy',\n", | ||||||
|  |     "                  optimizer='sgd',\n", | ||||||
|  |     "                  metrics=['accuracy'])\n", | ||||||
|  |     "\n", | ||||||
|  |     "    history = model.fit(X_train, y_train,\n", | ||||||
|  |     "                        validation_split=0.1,\n", | ||||||
|  |     "                        epochs=50)\n", | ||||||
|  |     "\n", | ||||||
|  |     "    scores = model.evaluate(X_test, y_test)\n", | ||||||
|  |     "\n", | ||||||
|  |     "    models_2[units_2] = model\n", | ||||||
|  |     "    histories_2[units_2] = history\n", | ||||||
|  |     "    scores_2[units_2] = scores\n", | ||||||
|  |     "\n", | ||||||
|  |     "    print(f\"Точность: {scores[1]}\")" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "colab": { | ||||||
|  |      "base_uri": "https://localhost:8080/" | ||||||
|  |     }, | ||||||
|  |     "executionInfo": { | ||||||
|  |      "elapsed": 14, | ||||||
|  |      "status": "ok", | ||||||
|  |      "timestamp": 1759129484222, | ||||||
|  |      "user": { | ||||||
|  |       "displayName": "Legal People", | ||||||
|  |       "userId": "00818738730090246603" | ||||||
|  |      }, | ||||||
|  |      "user_tz": -180 | ||||||
|  |     }, | ||||||
|  |     "id": "9lJtmn_oSVkB", | ||||||
|  |     "outputId": "b49d6a95-574a-4ce5-e23f-eea49ba83603" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# Выбор наилучшей двухслойной модели\n", | ||||||
|  |     "best_units_2 = max(scores_2.items(), key=lambda x: x[1][1])[0]\n", | ||||||
|  |     "print(f\"\\nНаилучшее количество нейронов во втором слое: {best_units_2}\")\n", | ||||||
|  |     "print(f\"Точность: {scores_2[best_units_2][1]:.4f}\")" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "id": "p0aeriYzShJk" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# Сбор результатов\n", | ||||||
|  |     "results = {\n", | ||||||
|  |     "    '0 слоев': {'нейроны_1': '-', 'нейроны_2': '-', 'точность': scores_0[1]},\n", | ||||||
|  |     "    '1 слой_100': {'нейроны_1': 100, 'нейроны_2': '-', 'точность': scores_1[100][1]},\n", | ||||||
|  |     "    '1 слой_300': {'нейроны_1': 300, 'нейроны_2': '-', 'точность': scores_1[300][1]},\n", | ||||||
|  |     "    '1 слой_500': {'нейроны_1': 500, 'нейроны_2': '-', 'точность': scores_1[500][1]},\n", | ||||||
|  |     "    '2 слоя_50': {'нейроны_1': best_units_1, 'нейроны_2': 50, 'точность': scores_2[50][1]},\n", | ||||||
|  |     "    '2 слоя_100': {'нейроны_1': best_units_1, 'нейроны_2': 100, 'точность': scores_2[100][1]}\n", | ||||||
|  |     "}" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "colab": { | ||||||
|  |      "base_uri": "https://localhost:8080/" | ||||||
|  |     }, | ||||||
|  |     "executionInfo": { | ||||||
|  |      "elapsed": 33, | ||||||
|  |      "status": "ok", | ||||||
|  |      "timestamp": 1759130442386, | ||||||
|  |      "user": { | ||||||
|  |       "displayName": "Legal People", | ||||||
|  |       "userId": "00818738730090246603" | ||||||
|  |      }, | ||||||
|  |      "user_tz": -180 | ||||||
|  |     }, | ||||||
|  |     "id": "SHr6z7jbSmOG", | ||||||
|  |     "outputId": "2d40f526-7756-4554-f110-2242e34e58a0" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# Создаем DataFrame из результатов\n", | ||||||
|  |     "df_results = pd.DataFrame([\n", | ||||||
|  |     "    {'Кол-во скрытых слоев': 0, 'Нейроны_1_слоя': '-', 'Нейроны_2_слоя': '-', 'Точность': results['0 слоев']['точность']},\n", | ||||||
|  |     "    {'Кол-во скрытых слоев': 1, 'Нейроны_1_слоя': 100, 'Нейроны_2_слоя': '-', 'Точность': results['1 слой_100']['точность']},\n", | ||||||
|  |     "    {'Кол-во скрытых слоев': 1, 'Нейроны_1_слоя': 300, 'Нейроны_2_слоя': '-', 'Точность': results['1 слой_300']['точность']},\n", | ||||||
|  |     "    {'Кол-во скрытых слоев': 1, 'Нейроны_1_слоя': 500, 'Нейроны_2_слоя': '-', 'Точность': results['1 слой_500']['точность']},\n", | ||||||
|  |     "    {'Кол-во скрытых слоев': 2, 'Нейроны_1_слоя': best_units_1, 'Нейроны_2_слоя': 50, 'Точность': results['2 слоя_50']['точность']},\n", | ||||||
|  |     "    {'Кол-во скрытых слоев': 2, 'Нейроны_1_слоя': best_units_1, 'Нейроны_2_слоя': 100, 'Точность': results['2 слоя_100']['точность']}\n", | ||||||
|  |     "])\n", | ||||||
|  |     "\n", | ||||||
|  |     "print(\" \" * 20 + \"ТАБЛИЦА РЕЗУЛЬТАТОВ\")\n", | ||||||
|  |     "print(\"=\" * 70)\n", | ||||||
|  |     "# print(df_results.to_string(index=False, formatters={\n", | ||||||
|  |     "#     'Точность': '{:.4f}'.format\n", | ||||||
|  |     "# }))\n", | ||||||
|  |     "print(df_results.reset_index(drop=True))" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "colab": { | ||||||
|  |      "base_uri": "https://localhost:8080/" | ||||||
|  |     }, | ||||||
|  |     "executionInfo": { | ||||||
|  |      "elapsed": 41, | ||||||
|  |      "status": "ok", | ||||||
|  |      "timestamp": 1759130490602, | ||||||
|  |      "user": { | ||||||
|  |       "displayName": "Legal People", | ||||||
|  |       "userId": "00818738730090246603" | ||||||
|  |      }, | ||||||
|  |      "user_tz": -180 | ||||||
|  |     }, | ||||||
|  |     "id": "PTC5CUJeWQ_V", | ||||||
|  |     "outputId": "e8009546-5876-4427-9815-9aac53db8593" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# Выбор наилучшей модели\n", | ||||||
|  |     "best_model_type = max(results.items(), key=lambda x: x[1]['точность'])[0]\n", | ||||||
|  |     "best_accuracy = results[best_model_type]['точность']\n", | ||||||
|  |     "print(f\"\\nНаилучшая архитектура: {best_model_type}\")\n", | ||||||
|  |     "print(f\"Точность: {best_accuracy:.4f}\")" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "id": "JRPRpppHWV8-" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# Определение наилучшей модели\n", | ||||||
|  |     "if '0' in best_model_type:\n", | ||||||
|  |     "    best_model = model_0\n", | ||||||
|  |     "elif '1' in best_model_type:\n", | ||||||
|  |     "    best_neurons = int(best_model_type.split('_')[1])\n", | ||||||
|  |     "    best_model = models_1[best_neurons]\n", | ||||||
|  |     "else:\n", | ||||||
|  |     "    best_neurons_2 = int(best_model_type.split('_')[1])\n", | ||||||
|  |     "    best_model = models_2[best_neurons_2]\n" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "id": "wIlYoP_HSFph" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# Сохранение модели\n", | ||||||
|  |     "best_model.save('best_mnist_model.keras')" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "colab": { | ||||||
|  |      "base_uri": "https://localhost:8080/", | ||||||
|  |      "height": 517 | ||||||
|  |     }, | ||||||
|  |     "executionInfo": { | ||||||
|  |      "elapsed": 178, | ||||||
|  |      "status": "ok", | ||||||
|  |      "timestamp": 1759132236751, | ||||||
|  |      "user": { | ||||||
|  |       "displayName": "Legal People", | ||||||
|  |       "userId": "00818738730090246603" | ||||||
|  |      }, | ||||||
|  |      "user_tz": -180 | ||||||
|  |     }, | ||||||
|  |     "id": "Kh6-u-8OoHny", | ||||||
|  |     "outputId": "7c89ce31-3967-41bb-ff79-6e77e7f5d19b" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# вывод тестового изображения и результата распознавания (1)\n", | ||||||
|  |     "n = 123\n", | ||||||
|  |     "result = best_model.predict(X_test[n:n+1])\n", | ||||||
|  |     "print('NN output:', result)\n", | ||||||
|  |     "plt.imshow(X_test[n].reshape(28,28), cmap=plt.get_cmap('gray'))\n", | ||||||
|  |     "plt.show()\n", | ||||||
|  |     "print('Real mark: ', str(np.argmax(y_test[n])))\n", | ||||||
|  |     "print('NN answer: ', str(np.argmax(result)))" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "colab": { | ||||||
|  |      "base_uri": "https://localhost:8080/", | ||||||
|  |      "height": 517 | ||||||
|  |     }, | ||||||
|  |     "executionInfo": { | ||||||
|  |      "elapsed": 284, | ||||||
|  |      "status": "ok", | ||||||
|  |      "timestamp": 1759132262259, | ||||||
|  |      "user": { | ||||||
|  |       "displayName": "Legal People", | ||||||
|  |       "userId": "00818738730090246603" | ||||||
|  |      }, | ||||||
|  |      "user_tz": -180 | ||||||
|  |     }, | ||||||
|  |     "id": "WVGJRtVZc8V-", | ||||||
|  |     "outputId": "5d4ed790-d7ce-4569-d667-49733f75e3cb" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# вывод тестового изображения и результата распознавания (3)\n", | ||||||
|  |     "n = 353\n", | ||||||
|  |     "result = best_model.predict(X_test[n:n+1])\n", | ||||||
|  |     "print('NN output:', result)\n", | ||||||
|  |     "plt.imshow(X_test[n].reshape(28,28), cmap=plt.get_cmap('gray'))\n", | ||||||
|  |     "plt.show()\n", | ||||||
|  |     "print('Real mark: ', str(np.argmax(y_test[n])))\n", | ||||||
|  |     "print('NN answer: ', str(np.argmax(result)))" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "id": "z5-YYw4uosUB" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# загрузка собственного изображения (Цифры 2 и 7)\n", | ||||||
|  |     "from PIL import Image\n", | ||||||
|  |     "file_data_2 = Image.open('2.png')\n", | ||||||
|  |     "file_data_7 = Image.open('7.png')\n", | ||||||
|  |     "file_data_2 = file_data_2.convert('L') # перевод в градации серого\n", | ||||||
|  |     "file_data_7 = file_data_7.convert('L') # перевод в градации серого\n", | ||||||
|  |     "test_img_2 = np.array(file_data_2)\n", | ||||||
|  |     "test_img_7 = np.array(file_data_7)" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "colab": { | ||||||
|  |      "base_uri": "https://localhost:8080/", | ||||||
|  |      "height": 465 | ||||||
|  |     }, | ||||||
|  |     "executionInfo": { | ||||||
|  |      "elapsed": 156, | ||||||
|  |      "status": "ok", | ||||||
|  |      "timestamp": 1759130765327, | ||||||
|  |      "user": { | ||||||
|  |       "displayName": "Legal People", | ||||||
|  |       "userId": "00818738730090246603" | ||||||
|  |      }, | ||||||
|  |      "user_tz": -180 | ||||||
|  |     }, | ||||||
|  |     "id": "dv17bJVVuslg", | ||||||
|  |     "outputId": "d9b5b55c-75d9-4180-f93c-22befad0633c" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# вывод собственного изображения (цифра 2)\n", | ||||||
|  |     "plt.imshow(test_img_2, cmap=plt.get_cmap('gray'))\n", | ||||||
|  |     "plt.show()\n", | ||||||
|  |     "# предобработка\n", | ||||||
|  |     "test_img_2 = test_img_2 / 255\n", | ||||||
|  |     "test_img_2 = test_img_2.reshape(1, num_pixels)\n", | ||||||
|  |     "# распознавание\n", | ||||||
|  |     "result = best_model.predict(test_img_2)\n", | ||||||
|  |     "print('I think it\\'s ', np.argmax(result))" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "colab": { | ||||||
|  |      "base_uri": "https://localhost:8080/", | ||||||
|  |      "height": 465 | ||||||
|  |     }, | ||||||
|  |     "executionInfo": { | ||||||
|  |      "elapsed": 651, | ||||||
|  |      "status": "ok", | ||||||
|  |      "timestamp": 1759130799101, | ||||||
|  |      "user": { | ||||||
|  |       "displayName": "Legal People", | ||||||
|  |       "userId": "00818738730090246603" | ||||||
|  |      }, | ||||||
|  |      "user_tz": -180 | ||||||
|  |     }, | ||||||
|  |     "id": "rhNzATtGuxbD", | ||||||
|  |     "outputId": "11cd1569-d370-4070-c8de-02035699d8bb" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# вывод собственного изображения (цифра 7)\n", | ||||||
|  |     "plt.imshow(test_img_7, cmap=plt.get_cmap('gray'))\n", | ||||||
|  |     "plt.show()\n", | ||||||
|  |     "# предобработка\n", | ||||||
|  |     "test_img_7 = test_img_7 / 255\n", | ||||||
|  |     "test_img_7 = test_img_7.reshape(1, num_pixels)\n", | ||||||
|  |     "# распознавание\n", | ||||||
|  |     "result = best_model.predict(test_img_7)\n", | ||||||
|  |     "print('I think it\\'s ', np.argmax(result))" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "id": "4rIUmwfYXcgh" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# Тестирование на собственных повернутых изображениях\n", | ||||||
|  |     "file_data_2_90 = Image.open('2_90.png')\n", | ||||||
|  |     "file_data_7_90 = Image.open('7_90.png')\n", | ||||||
|  |     "file_data_2_90 = file_data_2_90.convert('L') # перевод в градации серого\n", | ||||||
|  |     "file_data_7_90 = file_data_7_90.convert('L') # перевод в градации серого\n", | ||||||
|  |     "test_img_2_90 = np.array(file_data_2_90)\n", | ||||||
|  |     "test_img_7_90= np.array(file_data_7_90)" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "colab": { | ||||||
|  |      "base_uri": "https://localhost:8080/", | ||||||
|  |      "height": 465 | ||||||
|  |     }, | ||||||
|  |     "executionInfo": { | ||||||
|  |      "elapsed": 445, | ||||||
|  |      "status": "ok", | ||||||
|  |      "timestamp": 1759131775554, | ||||||
|  |      "user": { | ||||||
|  |       "displayName": "Legal People", | ||||||
|  |       "userId": "00818738730090246603" | ||||||
|  |      }, | ||||||
|  |      "user_tz": -180 | ||||||
|  |     }, | ||||||
|  |     "id": "xeYNkU0OZqg2", | ||||||
|  |     "outputId": "b17a7b99-ce57-45fa-c069-74ea8374c3d3" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# вывод собственного изображения (цифра 2)\n", | ||||||
|  |     "plt.imshow(test_img_2_90, cmap=plt.get_cmap('gray'))\n", | ||||||
|  |     "plt.show()\n", | ||||||
|  |     "# предобработка\n", | ||||||
|  |     "test_img_2_90 = test_img_2_90 / 255\n", | ||||||
|  |     "test_img_2_90 = test_img_2_90.reshape(1, num_pixels)\n", | ||||||
|  |     "# распознавание\n", | ||||||
|  |     "result = best_model.predict(test_img_2_90)\n", | ||||||
|  |     "print('I think it\\'s ', np.argmax(result))" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "code", | ||||||
|  |    "execution_count": null, | ||||||
|  |    "metadata": { | ||||||
|  |     "colab": { | ||||||
|  |      "base_uri": "https://localhost:8080/", | ||||||
|  |      "height": 465 | ||||||
|  |     }, | ||||||
|  |     "executionInfo": { | ||||||
|  |      "elapsed": 238, | ||||||
|  |      "status": "ok", | ||||||
|  |      "timestamp": 1759131800104, | ||||||
|  |      "user": { | ||||||
|  |       "displayName": "Legal People", | ||||||
|  |       "userId": "00818738730090246603" | ||||||
|  |      }, | ||||||
|  |      "user_tz": -180 | ||||||
|  |     }, | ||||||
|  |     "id": "8JZajicXbNSA", | ||||||
|  |     "outputId": "016e8c12-472d-4a15-c420-cd955edef901" | ||||||
|  |    }, | ||||||
|  |    "outputs": [], | ||||||
|  |    "source": [ | ||||||
|  |     "# вывод собственного изображения (цифра 7)\n", | ||||||
|  |     "plt.imshow(test_img_7_90, cmap=plt.get_cmap('gray'))\n", | ||||||
|  |     "plt.show()\n", | ||||||
|  |     "# предобработка\n", | ||||||
|  |     "test_img_7_90 = test_img_7_90 / 255\n", | ||||||
|  |     "test_img_7_90 = test_img_7_90.reshape(1, num_pixels)\n", | ||||||
|  |     "# распознавание\n", | ||||||
|  |     "result = best_model.predict(test_img_7_90)\n", | ||||||
|  |     "print('I think it\\'s ', np.argmax(result))" | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "markdown", | ||||||
|  |    "metadata": { | ||||||
|  |     "id": "DQJNpFTOZ7Z6" | ||||||
|  |    }, | ||||||
|  |    "source": [] | ||||||
|  |   } | ||||||
|  |  ], | ||||||
|  |  "metadata": { | ||||||
|  |   "accelerator": "GPU", | ||||||
|  |   "colab": { | ||||||
|  |    "gpuType": "T4", | ||||||
|  |    "provenance": [ | ||||||
|  |     { | ||||||
|  |      "file_id": "1HorM0jtoJfNfcuh_uXJu8ODaEJ6xOUu-", | ||||||
|  |      "timestamp": 1759209370437 | ||||||
|  |     } | ||||||
|  |    ] | ||||||
|  |   }, | ||||||
|  |   "kernelspec": { | ||||||
|  |    "display_name": "Python 3", | ||||||
|  |    "language": "python", | ||||||
|  |    "name": "python3" | ||||||
|  |   }, | ||||||
|  |   "language_info": { | ||||||
|  |    "codemirror_mode": { | ||||||
|  |     "name": "ipython", | ||||||
|  |     "version": 3 | ||||||
|  |    }, | ||||||
|  |    "file_extension": ".py", | ||||||
|  |    "mimetype": "text/x-python", | ||||||
|  |    "name": "python", | ||||||
|  |    "nbconvert_exporter": "python", | ||||||
|  |    "pygments_lexer": "ipython3", | ||||||
|  |    "version": "3.11.9" | ||||||
|  |   } | ||||||
|  |  }, | ||||||
|  |  "nbformat": 4, | ||||||
|  |  "nbformat_minor": 4 | ||||||
|  | } | ||||||
| После Ширина: | Высота: | Размер: 24 KiB | 
| @ -0,0 +1,534 @@ | |||||||
|  | 
 | ||||||
|  | ## Отчёт по лабораторной работе №1 | ||||||
|  | 
 | ||||||
|  | **Троянов Д.С., Чернов Д.Е. — А-01-22** | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 1) В среде Google Colab создали блокнот. Импортировали необходимые библиотеки и модули. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # импорт модулей | ||||||
|  | import tensorflow as tf | ||||||
|  | from tensorflow import keras | ||||||
|  | from keras.datasets import mnist | ||||||
|  | from keras.models import Sequential | ||||||
|  | from keras.layers import Dense | ||||||
|  | from keras.utils import to_categorical | ||||||
|  | from sklearn.model_selection import train_test_split | ||||||
|  | import matplotlib.pyplot as plt | ||||||
|  | import numpy as np | ||||||
|  | from PIL import Image | ||||||
|  | import os | ||||||
|  | import pandas as pd | ||||||
|  | 
 | ||||||
|  | # Укажем текущую директорию | ||||||
|  | os.chdir('/content/drive/MyDrive/Colab Notebooks/is_dnn/labworks/LW1') | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 2) Загрузили набор данных MNIST, содержащий размеченные изображения рукописных цифр. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # Загрузка датасета | ||||||
|  | (X_train_orig, y_train_orig), (X_test_orig, y_test_orig) = mnist.load_data() | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 3) Разбили набор данных на обучающие и тестовые данные в соотношении 60 000:10 000 элементов. | ||||||
|  | При разбиении параметр `random_state` выбрали равным (4k – 1), где k - номер бригады, k = 6 ⇒ `random_state = 23`. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # разбиваем выборку на обучающую и тестовую выборку | ||||||
|  | X = np.concatenate((X_train_orig, X_test_orig)) | ||||||
|  | y = np.concatenate((y_train_orig, y_test_orig)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | X_train, X_test, y_train, y_test = train_test_split( | ||||||
|  |     X, y, | ||||||
|  |     test_size=10000, | ||||||
|  |     train_size=60000, | ||||||
|  |     random_state=3, | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | # вывод размерности массивов данных | ||||||
|  | print('Shape of X train:', X_train.shape) | ||||||
|  | print('Shape of y train:', y_train.shape) | ||||||
|  | print('Shape of X test:', X_test.shape) | ||||||
|  | print('Shape of y test:', y_test.shape) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | Shape of X train: (60000, 28, 28) | ||||||
|  | Shape of y train: (60000,) | ||||||
|  | Shape of X test: (10000, 28, 28) | ||||||
|  | Shape of y test: (10000,) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 4) Вывели первые 4 элемента обучающих данных (изображения и метки цифр). | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # Вывод первых 4 изображений | ||||||
|  | fig, axes = plt.subplots(1, 4, figsize=(12, 3)) | ||||||
|  | for i in range(4): | ||||||
|  |     axes[i].imshow(X_train[i], cmap='gray') | ||||||
|  |     axes[i].set_title(f'Метка: {y_train[i]}') | ||||||
|  |     axes[i].axis('off') | ||||||
|  | plt.tight_layout() | ||||||
|  | plt.show() | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # Были выведены цифры 7, 8, 2, 2 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 5) Провели предобработку данных: привели обучающие и тестовые данные к формату, пригодному для обучения нейронной сети. Входные данные должны принимать значения от 0 до 1, метки цифр должны быть закодированы по принципу «one-hot encoding». Вывели размерности предобработанных обучающих и тестовых массивов данных. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # развернем каждое изображение 28*28 в вектор 784 | ||||||
|  | num_pixels = X_train.shape[1] * X_train.shape[2] | ||||||
|  | X_train = X_train.reshape(X_train.shape[0], num_pixels) / 255 | ||||||
|  | X_test = X_test.reshape(X_test.shape[0], num_pixels) / 255 | ||||||
|  | print('Shape of transformed X train:', X_train.shape) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | Shape of transformed X train: (60000, 784) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # переведем метки в one-hot | ||||||
|  | from keras.utils import to_categorical | ||||||
|  | y_train = to_categorical(y_train) | ||||||
|  | y_test = to_categorical(y_test) | ||||||
|  | print('Shape of transformed y train:', y_train.shape) | ||||||
|  | num_classes = y_train.shape[1] | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | Shape of transformed y train: (60000, 10) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 6) Реализовали модель однослойной нейронной сети и обучили ее на обучающих данных с выделением части обучающих данных в качестве валидационных. Вывели информацию об архитектуре нейронной сети. Вывели график функции ошибки на обучающих и валидационных данных по эпохам. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | model_0 = Sequential() | ||||||
|  | model_0.add(Dense(units=num_classes, input_dim=num_pixels, activation='softmax')) | ||||||
|  | 
 | ||||||
|  | # Компиляция модели | ||||||
|  | model_0.compile(loss='categorical_crossentropy', | ||||||
|  |                 optimizer='sgd', | ||||||
|  |                 metrics=['accuracy']) | ||||||
|  | 
 | ||||||
|  | # Вывод информации об архитектуре | ||||||
|  | print("Архитектура однослойной сети:") | ||||||
|  | model_0.summary() | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | # Обучение модели | ||||||
|  | history_0 = model_0.fit(X_train, y_train, | ||||||
|  |                         validation_split=0.1, | ||||||
|  |                         epochs=50) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # График функции ошибки по эпохам | ||||||
|  | plt.figure(figsize=(10, 6)) | ||||||
|  | plt.plot(history_0.history['loss'], label='Обучающая выборка') | ||||||
|  | plt.plot(history_0.history['val_loss'], label='Валидационная выборка') | ||||||
|  | plt.title('Функция ошибки по эпохам (Однослойная сеть)') | ||||||
|  | plt.xlabel('Эпохи') | ||||||
|  | plt.ylabel('Ошибка') | ||||||
|  | plt.legend() | ||||||
|  | plt.grid(True) | ||||||
|  | plt.show() | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 7) Применили обученную модель к тестовым данным. Вывели значение функции ошибки и значение метрики качества классификации на тестовых данных. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # Оценка на тестовых данных | ||||||
|  | scores_0 = model_0.evaluate(X_test, y_test, verbose=0) | ||||||
|  | print("Результаты однослойной сети:") | ||||||
|  | print(f"Ошибка на тестовых данных: {scores_0[0]}") | ||||||
|  | print(f"Точность на тестовых данных: {scores_0[1]}") | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | Результаты однослойной сети: | ||||||
|  | 		Ошибка на тестовых данных: 0.28625616431236267 | ||||||
|  | 		Точность на тестовых данных: 0.92330002784729 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 8) Добавили в модель один скрытый и провели обучение и тестирование (повторить п. 6–7) при 100, 300, 500 нейронах в скрытом слое. По метрике качества классификации на тестовых данных выбрали наилучшее количество нейронов в скрытом слое. В качестве функции активации нейронов в скрытом слое использовали функцию `sigmoid`. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # Функция для создания и обучения модели | ||||||
|  | def create_and_train_model(hidden_units, model_name): | ||||||
|  |     model = Sequential() | ||||||
|  |     model.add(Dense(units=hidden_units, input_dim=num_pixels, activation='sigmoid')) | ||||||
|  |     model.add(Dense(units=num_classes, activation='softmax')) | ||||||
|  | 
 | ||||||
|  |     model.compile(loss='categorical_crossentropy', | ||||||
|  |                   optimizer='sgd', | ||||||
|  |                   metrics=['accuracy']) | ||||||
|  | 
 | ||||||
|  |     history = model.fit(X_train, y_train, | ||||||
|  |                         validation_split=0.1, | ||||||
|  |                         epochs=50) | ||||||
|  | 
 | ||||||
|  |     scores = model.evaluate(X_test, y_test, verbose=0) | ||||||
|  | 
 | ||||||
|  |     return model, history, scores | ||||||
|  | 
 | ||||||
|  | # Эксперименты с разным количеством нейронов | ||||||
|  | hidden_units_list = [100, 300, 500] | ||||||
|  | models_1 = {} | ||||||
|  | histories_1 = {} | ||||||
|  | scores_1 = {} | ||||||
|  | 
 | ||||||
|  | # Обучение сетей с одним скрытым слоем | ||||||
|  | for units in hidden_units_list: | ||||||
|  |     print(f" | ||||||
|  | Обучение модели с {units} нейронами...") | ||||||
|  |     model, history, scores = create_and_train_model(units, f"model_{units}") | ||||||
|  | 
 | ||||||
|  |     models_1[units] = model | ||||||
|  |     histories_1[units] = history | ||||||
|  |     scores_1[units] = scores | ||||||
|  | 
 | ||||||
|  |     print(f"Точность: {scores[1]}") | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | # Определим лучшую модель по итогвой точности | ||||||
|  | ```python | ||||||
|  | # Выбор наилучшей модели | ||||||
|  | best_units_1 = max(scores_1.items(), key=lambda x: x[1][1])[0] | ||||||
|  | print(f" | ||||||
|  | Наилучшее количество нейронов: {best_units_1}") | ||||||
|  | print(f"Точность: {scores_1[best_units_1][1]}") | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 		Наилучшее количество нейронов: 100 | ||||||
|  | 		Точность: 0.9422000050544739 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | # Отобразим графики ошибок для каждой из архитектур нейросети | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # Графики ошибок для всех моделей | ||||||
|  | plt.figure(figsize=(15, 5)) | ||||||
|  | for i, units in enumerate(hidden_units_list, 1): | ||||||
|  |     plt.subplot(1, 3, i) | ||||||
|  |     plt.plot(histories_1[units].history['loss'], label='Обучающая') | ||||||
|  |     plt.plot(histories_1[units].history['val_loss'], label='Валидационная') | ||||||
|  |     plt.title(f'{units} нейронов') | ||||||
|  |     plt.xlabel('Эпохи') | ||||||
|  |     plt.ylabel('Ошибка') | ||||||
|  |     plt.legend() | ||||||
|  |     plt.grid(True) | ||||||
|  | plt.tight_layout() | ||||||
|  | plt.show() | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | **По результатам проведнного эксперимента наилучший показатель точности продемонстрировала нейронная сеть со 100 нейронами в скрытом слое - примерно 0.9422.** | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 9) Добавили в архитектуру с лучшим показателем из п. 8, второй скрытый слой и провели обучение и тестирование при 50 и 100 нейронах во втором скрытом слое. В качестве функции активации нейронов в скрытом слое использовали функцию `sigmoid`. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # Добавление второго скрытого слоя | ||||||
|  | second_layer_units = [50, 100] | ||||||
|  | models_2 = {} | ||||||
|  | histories_2 = {} | ||||||
|  | scores_2 = {} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | for units_2 in second_layer_units: | ||||||
|  |     print(f" | ||||||
|  | Обучение модели со вторым слоем {units_2} нейронов") | ||||||
|  | 
 | ||||||
|  |     model = Sequential() | ||||||
|  |     model.add(Dense(units=best_units_1, input_dim=num_pixels, activation='sigmoid')) | ||||||
|  |     model.add(Dense(units=units_2, activation='sigmoid')) | ||||||
|  |     model.add(Dense(units=num_classes, activation='softmax')) | ||||||
|  | 
 | ||||||
|  |     model.compile(loss='categorical_crossentropy', | ||||||
|  |                   optimizer='sgd', | ||||||
|  |                   metrics=['accuracy']) | ||||||
|  | 
 | ||||||
|  |     history = model.fit(X_train, y_train, | ||||||
|  |                         validation_split=0.1, | ||||||
|  |                         epochs=50) | ||||||
|  | 
 | ||||||
|  |     scores = model.evaluate(X_test, y_test) | ||||||
|  | 
 | ||||||
|  |     models_2[units_2] = model | ||||||
|  |     histories_2[units_2] = history | ||||||
|  |     scores_2[units_2] = scores | ||||||
|  | 
 | ||||||
|  |     print(f"Точность: {scores[1]}") | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | # Результаты обучения моделей: | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | Обучение модели со вторым слоем 50 нейронов: | ||||||
|  | Точность: 0.9417999982833862 | ||||||
|  | 
 | ||||||
|  | Обучение модели со вторым слоем 100 нейронов | ||||||
|  | Точность: 0.942300021648407 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | # Выбор наилучшей двухслойной модели | ||||||
|  | ```python | ||||||
|  | best_units_2 = max(scores_2.items(), key=lambda x: x[1][1])[0] | ||||||
|  | print(f" | ||||||
|  | Наилучшее количество нейронов во втором слое: {best_units_2}") | ||||||
|  | print(f"Точность: {scores_2[best_units_2][1]}") | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 	Наилучшее количество нейронов во втором слое: 100 | ||||||
|  | 	Точность: 0.9423 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ## 10) Результаты исследования архитектуры нейронной сети занесли в таблицу: | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # Сбор результатов | ||||||
|  | results = { | ||||||
|  |     '0 слоев': {'нейроны_1': '-', 'нейроны_2': '-', 'точность': scores_0[1]}, | ||||||
|  |     '1 слой_100': {'нейроны_1': 100, 'нейроны_2': '-', 'точность': scores_1[100][1]}, | ||||||
|  |     '1 слой_300': {'нейроны_1': 300, 'нейроны_2': '-', 'точность': scores_1[300][1]}, | ||||||
|  |     '1 слой_500': {'нейроны_1': 500, 'нейроны_2': '-', 'точность': scores_1[500][1]}, | ||||||
|  |     '2 слоя_50': {'нейроны_1': best_units_1, 'нейроны_2': 50, 'точность': scores_2[50][1]}, | ||||||
|  |     '2 слоя_100': {'нейроны_1': best_units_1, 'нейроны_2': 100, 'точность': scores_2[100][1]} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # Создаем DataFrame из результатов | ||||||
|  | df_results = pd.DataFrame([ | ||||||
|  |     {'Кол-во скрытых слоев': 0, 'Нейроны_1_слоя': '-', 'Нейроны_2_слоя': '-', 'Точность': results['0 слоев']['точность']}, | ||||||
|  |     {'Кол-во скрытых слоев': 1, 'Нейроны_1_слоя': 100, 'Нейроны_2_слоя': '-', 'Точность': results['1 слой_100']['точность']}, | ||||||
|  |     {'Кол-во скрытых слоев': 1, 'Нейроны_1_слоя': 300, 'Нейроны_2_слоя': '-', 'Точность': results['1 слой_300']['точность']}, | ||||||
|  |     {'Кол-во скрытых слоев': 1, 'Нейроны_1_слоя': 500, 'Нейроны_2_слоя': '-', 'Точность': results['1 слой_500']['точность']}, | ||||||
|  |     {'Кол-во скрытых слоев': 2, 'Нейроны_1_слоя': best_units_1, 'Нейроны_2_слоя': 50, 'Точность': results['2 слоя_50']['точность']}, | ||||||
|  |     {'Кол-во скрытых слоев': 2, 'Нейроны_1_слоя': best_units_1, 'Нейроны_2_слоя': 100, 'Точность': results['2 слоя_100']['точность']} | ||||||
|  | ]) | ||||||
|  | 
 | ||||||
|  | print(" " * 20 + "ТАБЛИЦА РЕЗУЛЬТАТОВ") | ||||||
|  | print("=" * 70) | ||||||
|  | # print(df_results.to_string(index=False, formatters={ | ||||||
|  | #     'Точность': '{:.4f}'.format | ||||||
|  | # })) | ||||||
|  | print(df_results.reset_index(drop=True)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 		ТАБЛИЦА РЕЗУЛЬТАТОВ | ||||||
|  | 		====================================================================== | ||||||
|  | 		   Кол-во скрытых слоев Нейроны_1_слоя Нейроны_2_слоя  Точность | ||||||
|  | 		0                     0              -              -    0.9233 | ||||||
|  | 		1                     1            100              -    0.9422 | ||||||
|  | 		2                     1            300              -    0.9377 | ||||||
|  | 		3                     1            500              -    0.9312 | ||||||
|  | 		4                     2            100             50    0.9418 | ||||||
|  | 		5                     2            100            100    0.9423 | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # Выбор наилучшей модели | ||||||
|  | best_model_type = max(results.items(), key=lambda x: x[1]['точность'])[0] | ||||||
|  | best_accuracy = results[best_model_type]['точность'] | ||||||
|  | print(f" | ||||||
|  | Наилучшая архитектура: {best_model_type}") | ||||||
|  | print(f"Точность: {best_accuracy}") | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 		Наилучшая архитектура: 2 слоя_100 | ||||||
|  | 		Точность: 0.9423 | ||||||
|  | ``` | ||||||
|  | ### По результатам исследования сделали выводы и выбрали наилучшую архитектуру нейронной сети с точки зрения качества классификации. | ||||||
|  | 
 | ||||||
|  | **Из таблицы следует, что лучшей архитектурой является НС с двумя скрытыми слоями по 100 и 50 нейронов, второе место занимает НС с одним скрытым слоем и 100 нейронами, на основе которой мы и строили НС с двумя скрытыми слоями. При увеличении количества нейронов в архитектуре НС с 1-м скрытым слоем в результате тестирования было вявлено, что метрики качества падают. Это связано с переобучение нашей НС с 1-м скрытым слоем (когда построенная модель хорошо объясняет примеры из обучающей выборки, но относительно плохо работает на примерах, не участвовавших в обучении) Такая тенденция вероятно возникает из-за простоты датасета MNIST, при усложнении архитектуры НС начинает переобучаться, а оценка качества на тестовых данных падает. Но также стоит отметить, что при усложнении структуры НС точнсть модели также и растет.** | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 11) Сохранили наилучшую нейронную сеть на диск. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # Сохранение модели | ||||||
|  | best_model.save('best_mnist_model.keras') | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 12) Для нейронной сети наилучшей архитектуры вывели два тестовых изображения, истинные метки и результат распознавания изображений. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # вывод тестового изображения и результата распознавания (1) | ||||||
|  | n = 123 | ||||||
|  | result = best_model.predict(X_test[n:n+1]) | ||||||
|  | print('NN output:', result) | ||||||
|  | plt.imshow(X_test[n].reshape(28,28), cmap=plt.get_cmap('gray')) | ||||||
|  | plt.show() | ||||||
|  | print('Real mark: ', str(np.argmax(y_test[n]))) | ||||||
|  | print('NN answer: ', str(np.argmax(result))) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # вывод тестового изображения и результата распознавания (3) | ||||||
|  | n = 353 | ||||||
|  | result = best_model.predict(X_test[n:n+1]) | ||||||
|  | print('NN output:', result) | ||||||
|  | plt.imshow(X_test[n].reshape(28,28), cmap=plt.get_cmap('gray')) | ||||||
|  | plt.show() | ||||||
|  | print('Real mark: ', str(np.argmax(y_test[n]))) | ||||||
|  | print('NN answer: ', str(np.argmax(result))) | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 13) Создали собственные изображения рукописных цифр, подобное представленным в наборе MNIST. Загрузили, предобработали и подали на вход обученной нейронной сети собственные изображения. Вывели изображения и результаты распознавания. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # загрузка собственного изображения (цифры 2 и 7) | ||||||
|  | file_data_2 = Image.open('2.png') | ||||||
|  | file_data_7 = Image.open('7.png') | ||||||
|  | file_data_2 = file_data_2.convert('L') # перевод в градации серого | ||||||
|  | file_data_7 = file_data_7.convert('L') # перевод в градации серого | ||||||
|  | test_img_2 = np.array(file_data_2) | ||||||
|  | test_img_7 = np.array(file_data_7) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # вывод собственного изображения (цифра 2) | ||||||
|  | plt.imshow(test_img_2, cmap=plt.get_cmap('gray')) | ||||||
|  | plt.show() | ||||||
|  | # предобработка | ||||||
|  | test_img_2 = test_img_2 / 255 | ||||||
|  | test_img_2 = test_img_2.reshape(1, num_pixels) | ||||||
|  | # распознавание | ||||||
|  | result = best_model.predict(test_img_2) | ||||||
|  | print('I think it\'s ', np.argmax(result)) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 31ms/step | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # вывод собственного изображения (цифра 7) | ||||||
|  | plt.imshow(test_img_7, cmap=plt.get_cmap('gray')) | ||||||
|  | plt.show() | ||||||
|  | # предобработка | ||||||
|  | test_img_7 = test_img_7 / 255 | ||||||
|  | test_img_7 = test_img_7.reshape(1, num_pixels) | ||||||
|  | # распознавание | ||||||
|  | result = best_model.predict(test_img_7) | ||||||
|  | print('I think it\'s ', np.argmax(result)) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 48ms/step | ||||||
|  | I think it's  7 | ||||||
|  | ``` | ||||||
|  | **Как видим в результате эксперимента наша НС недостаточно точно определила изображение цифры 2. Возможно это связано с малом размером используемой выборки. Для улучшения качества решения задачи классификации можно либо увеличить размерность выборки для обучения НС, либо изменить структуру НС для более точной ее работы** | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## 14) Создать копию собственного изображения, отличающуюся от оригинала поворотом на 90 градусов в любую сторону. Сохранили изображения. Загрузили, предобработали и подали на вход обученной нейронной сети измененные изображения. Вывели изображения и результаты распознавания. Сделали выводы по результатам эксперимента. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # загрузка собственного изображения | ||||||
|  | file_data_2_90 = Image.open('2_90.png') | ||||||
|  | file_data_7_90 = Image.open('7_90.png') | ||||||
|  | file_data_2_90 = file_data_2_90.convert('L') # перевод в градации серого | ||||||
|  | file_data_7_90 = file_data_7_90.convert('L') # перевод в градации серого | ||||||
|  | test_img_2_90 = np.array(file_data_2_90) | ||||||
|  | test_img_7_90= np.array(file_data_7_90) | ||||||
|  | 
 | ||||||
|  | # вывод собственного изображения (цифра 2) | ||||||
|  | plt.imshow(test_img_2_90, cmap=plt.get_cmap('gray')) | ||||||
|  | plt.show() | ||||||
|  | # предобработка | ||||||
|  | test_img_2_90 = test_img_2_90 / 255 | ||||||
|  | test_img_2_90 = test_img_2_90.reshape(1, num_pixels) | ||||||
|  | # распознавание | ||||||
|  | result = best_model.predict(test_img_2_90) | ||||||
|  | print('I think it\'s ', np.argmax(result)) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 91ms/step | ||||||
|  | I think it's  7 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | # вывод собственного изображения (цифра 7) | ||||||
|  | plt.imshow(test_img_7_90, cmap=plt.get_cmap('gray')) | ||||||
|  | plt.show() | ||||||
|  | # предобработка | ||||||
|  | test_img_7_90 = test_img_7_90 / 255 | ||||||
|  | test_img_7_90 = test_img_7_90.reshape(1, num_pixels) | ||||||
|  | # распознавание | ||||||
|  | result = best_model.predict(test_img_7_90) | ||||||
|  | print('I think it\'s ', np.argmax(result)) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 48ms/step | ||||||
|  | I think it's  7 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | **При повороте рисунков цифр НС не смогла распознать одну из цифр. Так получилось, во-первых, по той же причине, почему НС не распознала одну из цифр в пункте 13, во-вторых - наша НС не обучалась на перевернутых цифрах** | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |          | ||||||
| После Ширина: | Высота: | Размер: 42 KiB | 
| После Ширина: | Высота: | Размер: 80 KiB | 
| После Ширина: | Высота: | Размер: 85 KiB | 
| После Ширина: | Высота: | Размер: 8.2 KiB | 
| После Ширина: | Высота: | Размер: 38 KiB | 
| После Ширина: | Высота: | Размер: 58 KiB | 
| @ -0,0 +1,100 @@ | |||||||
|  | 1.236618812286772506e+00 9.635855436715635713e-01 | ||||||
|  | 5.803912383886806747e-01 8.453938120743926810e-01 | ||||||
|  | 4.061439235047925589e-02 9.867430622753915470e-01 | ||||||
|  | 7.604128810773550518e-01 9.071705116680914838e-01 | ||||||
|  | 5.126591648863392248e-01 1.393542301871226075e+00 | ||||||
|  | 1.411272456051594570e+00 3.895781750144888811e-01 | ||||||
|  | 1.128775195361382266e+00 9.627770421169163928e-01 | ||||||
|  | 6.599876392107546508e-01 1.116126848580501818e+00 | ||||||
|  | 1.732824384460776912e+00 8.871118497567321848e-01 | ||||||
|  | 5.459879622393946086e-01 2.938481493323542582e-01 | ||||||
|  | 8.829233126383320140e-01 8.829315215254097682e-01 | ||||||
|  | 1.138345399665009472e+00 1.413591624518011791e+00 | ||||||
|  | 6.489734530613238128e-01 8.361689267011158666e-01 | ||||||
|  | 5.580712818994335578e-01 1.076862552972764009e+00 | ||||||
|  | 8.773059419985647089e-01 6.231319178212552101e-01 | ||||||
|  | 1.481688064622160850e+00 1.206390463468249186e+00 | ||||||
|  | 6.615389998470206923e-01 1.305838144420433888e+00 | ||||||
|  | 1.406758608684834932e+00 3.845678417830223905e-01 | ||||||
|  | 5.552427851872383524e-01 5.920948575172808592e-01 | ||||||
|  | 9.193571441669954325e-01 1.202025428407269114e+00 | ||||||
|  | 8.901640560812440484e-01 1.178556285755873123e+00 | ||||||
|  | 5.402878828830983693e-01 1.774967202508769715e+00 | ||||||
|  | 1.029104359223000031e+00 4.285148510846884529e-01 | ||||||
|  | 5.047318374346558834e-01 7.168511351986139868e-01 | ||||||
|  | 1.411030079997245057e+00 1.948396491326973567e+00 | ||||||
|  | 1.248357076505616448e+00 9.308678494144076998e-01 | ||||||
|  | 1.048538774674020235e+00 1.484322495266444664e+00 | ||||||
|  | 1.033764102343961877e+00 2.876259068932716101e-01 | ||||||
|  | 7.767425239664894621e-01 1.428199397161736162e+00 | ||||||
|  | 2.607390048162863128e-01 6.400778958026456245e-01 | ||||||
|  | 4.688481431369475594e-01 1.236796215317590875e+00 | ||||||
|  | 1.369233289997705327e+00 1.085684140594985303e+00 | ||||||
|  | 9.639949392098330350e-01 1.501766448946012078e+00 | ||||||
|  | 1.312833673882503049e+00 5.714212217918587244e-01 | ||||||
|  | 1.515499761247975474e+00 1.465640059558099395e+00 | ||||||
|  | -3.098725520448721849e-01 1.410951252187611971e+00 | ||||||
|  | 1.086590462925590916e+00 1.192658689864418475e+00 | ||||||
|  | 1.104431797502377632e+00 2.016493806011221412e-02 | ||||||
|  | 1.113729967302064638e+00 1.653571377141214160e+00 | ||||||
|  | 9.614491452929478932e-01 1.170575987408321916e+00 | ||||||
|  | 1.146536236649340568e+00 6.428242909868160382e-01 | ||||||
|  | 1.045880388267751204e+00 6.215542699553600059e-03 | ||||||
|  | 1.180818012523817018e+00 6.774401226974378076e-01 | ||||||
|  | 1.165631715701781923e+00 1.487772563561179595e+00 | ||||||
|  | 1.129941397124211822e+00 1.390911435888655179e+00 | ||||||
|  | 1.579297789503701921e+00 5.896588408241447699e-01 | ||||||
|  | 9.826441151473783719e-01 4.156609811902339802e-01 | ||||||
|  | 1.789606407753695727e+00 1.383717364576454445e+00 | ||||||
|  | 8.882686073370745783e-01 1.357000247046046049e+00 | ||||||
|  | 7.652628070325239173e-01 1.271280021792982273e+00 | ||||||
|  | 1.395515973521523456e+00 5.453062726026305373e-01 | ||||||
|  | 1.457701058851037068e+00 1.164375554829842230e+00 | ||||||
|  | 1.932887255572378393e+00 1.236916460455893763e+00 | ||||||
|  | 1.107046872065101883e+00 3.771306106440059924e-01 | ||||||
|  | 9.820869804450241825e-01 1.782321827907002998e+00 | ||||||
|  | 5.766031409657974560e-01 2.425763876570676825e-01 | ||||||
|  | 1.943092950605265212e+00 1.087288906415919465e+00 | ||||||
|  | 1.260970782808448876e+00 1.148492336616593112e+00 | ||||||
|  | 7.682911535937688718e-01 7.671351232148715393e-01 | ||||||
|  | 4.645537509694438461e-01 1.241236207621592591e+00 | ||||||
|  | 8.286427417366152293e-01 5.988613653891905475e-01 | ||||||
|  | 1.148060138532287944e+00 1.130527636089944554e+00 | ||||||
|  | 3.815246445609590253e-01 3.397716934578618453e-01 | ||||||
|  | 4.043482513986756954e-01 1.328276804316914861e+00 | ||||||
|  | 6.083733538318814027e-01 8.389692418971621546e-01 | ||||||
|  | 9.421758588058797290e-01 8.494481522053556333e-01 | ||||||
|  | 1.701397155468049593e+00 2.990744686038595557e-01 | ||||||
|  | 1.962583827193862263e-01 1.092316929266152092e+00 | ||||||
|  | 9.038195176094387939e-01 1.150773671166806178e+00 | ||||||
|  | 1.006500945938953562e+00 1.726767038578658431e+00 | ||||||
|  | 2.923146289747928783e-01 7.896773386173204790e-01 | ||||||
|  | 1.293428546900135201e+00 2.095227812904989051e+00 | ||||||
|  | 4.468325129969858978e-01 4.018966879596646002e-01 | ||||||
|  | 2.246682844669336543e-01 1.034281487403013733e+00 | ||||||
|  | 6.996806550405975100e-01 8.541531251033616101e-01 | ||||||
|  | 1.125246425172938380e+00 1.173224104748487928e+00 | ||||||
|  | 4.245032112888486031e-01 1.187849009172835979e+00 | ||||||
|  | 6.991466938853014845e-01 1.926139092254468999e+00 | ||||||
|  | 1.375410837434836164e-01 7.188562353795135973e-01 | ||||||
|  | 1.049825682543820582e+00 7.482621729419003387e-01 | ||||||
|  | 3.359069755507847477e-01 1.098430617934561759e+00 | ||||||
|  | 7.351198981164805968e-01 1.256633716556678104e+00 | ||||||
|  | 1.180697802754206993e+00 1.769018283232984601e+00 | ||||||
|  | 1.030115104970513284e+00 2.231621056242643064e+00 | ||||||
|  | 1.120981135783017058e+00 4.335987767110105473e-02 | ||||||
|  | 1.571411407257510273e+00 1.375966516343387180e+00 | ||||||
|  | 7.278086377374086702e-01 1.055461294854933119e+00 | ||||||
|  | 7.696806145201062765e-01 1.528561113109457859e+00 | ||||||
|  | 1.171809144784230705e+00 1.184799223186330241e-01 | ||||||
|  | 1.002556728321230439e+00 8.827064333124265971e-01 | ||||||
|  | 1.162041984697397501e+00 8.074588597918417321e-01 | ||||||
|  | 1.738947022370758155e+00 7.408648908631763064e-01 | ||||||
|  | 1.043523534119085605e+00 8.504963247670662696e-01 | ||||||
|  | 8.039459234339212390e-01 2.682425259339407120e-01 | ||||||
|  | 5.957531985534061381e-01 7.491214782077317835e-01 | ||||||
|  | 4.935844398327881022e-01 1.157123666297636966e+00 | ||||||
|  | 1.406262911197099008e+00 1.678120014285411354e+00 | ||||||
|  | 9.932513876310330447e-01 4.711445355220498232e-01 | ||||||
|  | 8.676715833810220158e-01 2.360084583294809413e+00 | ||||||
|  | 1.323844269050346245e+00 1.761514928204012786e+00 | ||||||
| @ -0,0 +1,712 @@ | |||||||
|  | { | ||||||
|  |   "cells": [ | ||||||
|  |     { | ||||||
|  |       "cell_type": "markdown", | ||||||
|  |       "metadata": {}, | ||||||
|  |       "source": [ | ||||||
|  |         "# Лабораторная работа №2: Обнаружение аномалий с помощью автокодировщиков\n", | ||||||
|  |         "\n", | ||||||
|  |         "**Вариант 1 (номер бригады k=1) - данные Letter**\n", | ||||||
|  |         "\n", | ||||||
|  |         "---\n", | ||||||
|  |         "\n", | ||||||
|  |         "## Описание\n", | ||||||
|  |         "Данная лабораторная работа посвящена изучению автокодировщиков для обнаружения аномалий. Работа включает два основных задания:\n", | ||||||
|  |         "1. Работа с двумерными синтетическими данными\n", | ||||||
|  |         "2. Работа с реальными данными Letter\n", | ||||||
|  |         "\n", | ||||||
|  |         "**Номер бригады:** k=1  \n", | ||||||
|  |         "**Центр данных:** (1, 1)\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "code", | ||||||
|  |       "execution_count": null, | ||||||
|  |       "metadata": {}, | ||||||
|  |       "outputs": [], | ||||||
|  |       "source": [ | ||||||
|  |         "# Импорт необходимых библиотек\n", | ||||||
|  |         "import os\n", | ||||||
|  |         "import numpy as np\n", | ||||||
|  |         "import matplotlib.pyplot as plt\n", | ||||||
|  |         "from sklearn.preprocessing import StandardScaler\n", | ||||||
|  |         "from sklearn.datasets import make_blobs\n", | ||||||
|  |         "import tensorflow as tf\n", | ||||||
|  |         "from tensorflow.keras.models import Sequential\n", | ||||||
|  |         "from tensorflow.keras.layers import Dense, Activation\n", | ||||||
|  |         "from tensorflow.keras.optimizers import Adam\n", | ||||||
|  |         "from tensorflow.keras.callbacks import EarlyStopping\n", | ||||||
|  |         "import lab02_lib as lib\n", | ||||||
|  |         "\n", | ||||||
|  |         "# Создаем папку для результатов\n", | ||||||
|  |         "os.makedirs('out', exist_ok=True)\n", | ||||||
|  |         "\n", | ||||||
|  |         "# Параметры для варианта 1 (номер бригады k=1)\n", | ||||||
|  |         "k = 1  # номер бригады\n", | ||||||
|  |         "center_coords = (k, k)  # координаты центра (1, 1)\n", | ||||||
|  |         "\n", | ||||||
|  |         "print(\"Лабораторная работа №2: Обнаружение аномалий с помощью автокодировщиков\")\n", | ||||||
|  |         "print(\"Вариант 1 (номер бригады k=1) - данные Letter\")\n", | ||||||
|  |         "print(\"=\" * 70)\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "markdown", | ||||||
|  |       "metadata": {}, | ||||||
|  |       "source": [ | ||||||
|  |         "# ЗАДАНИЕ 1: Работа с двумерными синтетическими данными\n", | ||||||
|  |         "\n", | ||||||
|  |         "## 1. Генерация индивидуального набора двумерных данных\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "code", | ||||||
|  |       "execution_count": null, | ||||||
|  |       "metadata": {}, | ||||||
|  |       "outputs": [], | ||||||
|  |       "source": [ | ||||||
|  |         "# Генерация данных с центром в точке (1, 1)\n", | ||||||
|  |         "X_synthetic, _ = make_blobs(n_samples=100, centers=[center_coords], n_features=2, \n", | ||||||
|  |         "                           cluster_std=0.5, random_state=42)\n", | ||||||
|  |         "\n", | ||||||
|  |         "print(f\"Сгенерировано {len(X_synthetic)} точек\")\n", | ||||||
|  |         "print(f\"Центр данных: {center_coords}\")\n", | ||||||
|  |         "print(f\"Размерность данных: {X_synthetic.shape}\")\n", | ||||||
|  |         "\n", | ||||||
|  |         "# Визуализация данных\n", | ||||||
|  |         "plt.figure(figsize=(10, 8))\n", | ||||||
|  |         "plt.scatter(X_synthetic[:, 0], X_synthetic[:, 1], c='blue', alpha=0.7, s=50)\n", | ||||||
|  |         "plt.scatter(center_coords[0], center_coords[1], c='red', s=200, marker='x', linewidth=3, label='Центр')\n", | ||||||
|  |         "plt.title(f'Синтетические данные (центр в точке {center_coords})')\n", | ||||||
|  |         "plt.xlabel('X1')\n", | ||||||
|  |         "plt.ylabel('X2')\n", | ||||||
|  |         "plt.legend()\n", | ||||||
|  |         "plt.grid(True, alpha=0.3)\n", | ||||||
|  |         "plt.savefig('out/synthetic_data.png', dpi=300, bbox_inches='tight')\n", | ||||||
|  |         "plt.show()\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "markdown", | ||||||
|  |       "metadata": {}, | ||||||
|  |       "source": [ | ||||||
|  |         "## 2. Создание и обучение автокодировщика AE1 (простая архитектура)\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "code", | ||||||
|  |       "execution_count": null, | ||||||
|  |       "metadata": {}, | ||||||
|  |       "outputs": [], | ||||||
|  |       "source": [ | ||||||
|  |         "def create_autoencoder_ae1(input_dim):\n", | ||||||
|  |         "    \"\"\"Создание автокодировщика AE1 с простой архитектурой\"\"\"\n", | ||||||
|  |         "    model = Sequential()\n", | ||||||
|  |         "    \n", | ||||||
|  |         "    # Входной слой\n", | ||||||
|  |         "    model.add(Dense(input_dim, input_shape=(input_dim,)))\n", | ||||||
|  |         "    model.add(Activation('tanh'))\n", | ||||||
|  |         "    \n", | ||||||
|  |         "    # Скрытые слои \n", | ||||||
|  |         "    model.add(Dense(1))  # сжатие до 1 нейрона\n", | ||||||
|  |         "    model.add(Activation('tanh'))\n", | ||||||
|  |         "    \n", | ||||||
|  |         "    # Выходной слой\n", | ||||||
|  |         "    model.add(Dense(input_dim))\n", | ||||||
|  |         "    model.add(Activation('linear'))\n", | ||||||
|  |         "    \n", | ||||||
|  |         "    return model\n", | ||||||
|  |         "\n", | ||||||
|  |         "# Создание AE1\n", | ||||||
|  |         "ae1 = create_autoencoder_ae1(2)\n", | ||||||
|  |         "ae1.compile(loss='mse', optimizer=Adam(learning_rate=0.001))\n", | ||||||
|  |         "\n", | ||||||
|  |         "print(\"Архитектура AE1:\")\n", | ||||||
|  |         "ae1.summary()\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "code", | ||||||
|  |       "execution_count": null, | ||||||
|  |       "metadata": {}, | ||||||
|  |       "outputs": [], | ||||||
|  |       "source": [ | ||||||
|  |         "# Обучение AE1\n", | ||||||
|  |         "print(\"\\nОбучение AE1 (20 эпох)...\")\n", | ||||||
|  |         "history_ae1 = ae1.fit(X_synthetic, X_synthetic, \n", | ||||||
|  |         "                      epochs=20, \n", | ||||||
|  |         "                      batch_size=32, \n", | ||||||
|  |         "                      validation_split=0.2,\n", | ||||||
|  |         "                      verbose=1)\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "code", | ||||||
|  |       "execution_count": null, | ||||||
|  |       "metadata": {}, | ||||||
|  |       "outputs": [], | ||||||
|  |       "source": [ | ||||||
|  |         "# Анализ результатов AE1\n", | ||||||
|  |         "print(\"\\nАнализ результатов AE1\")\n", | ||||||
|  |         "mse_ae1 = history_ae1.history['loss'][-1]\n", | ||||||
|  |         "print(f\"Финальная ошибка MSE AE1: {mse_ae1:.6f}\")\n", | ||||||
|  |         "\n", | ||||||
|  |         "# Построение графика ошибки реконструкции\n", | ||||||
|  |         "plt.figure(figsize=(12, 4))\n", | ||||||
|  |         "plt.subplot(1, 2, 1)\n", | ||||||
|  |         "plt.plot(history_ae1.history['loss'], label='Training Loss')\n", | ||||||
|  |         "plt.plot(history_ae1.history['val_loss'], label='Validation Loss')\n", | ||||||
|  |         "plt.title('AE1: Ошибка обучения')\n", | ||||||
|  |         "plt.xlabel('Эпоха')\n", | ||||||
|  |         "plt.ylabel('MSE')\n", | ||||||
|  |         "plt.legend()\n", | ||||||
|  |         "plt.grid(True, alpha=0.3)\n", | ||||||
|  |         "\n", | ||||||
|  |         "# Вычисление ошибок реконструкции для обучающих данных\n", | ||||||
|  |         "X_pred_ae1 = ae1.predict(X_synthetic)\n", | ||||||
|  |         "reconstruction_errors_ae1 = np.mean(np.square(X_synthetic - X_pred_ae1), axis=1)\n", | ||||||
|  |         "threshold_ae1 = np.percentile(reconstruction_errors_ae1, 95)\n", | ||||||
|  |         "\n", | ||||||
|  |         "plt.subplot(1, 2, 2)\n", | ||||||
|  |         "plt.hist(reconstruction_errors_ae1, bins=20, alpha=0.7, color='blue', edgecolor='black')\n", | ||||||
|  |         "plt.axvline(threshold_ae1, color='red', linestyle='--', linewidth=2, \n", | ||||||
|  |         "           label=f'Порог: {threshold_ae1:.6f}')\n", | ||||||
|  |         "plt.title('AE1: Распределение ошибок реконструкции')\n", | ||||||
|  |         "plt.xlabel('Ошибка реконструкции')\n", | ||||||
|  |         "plt.ylabel('Частота')\n", | ||||||
|  |         "plt.legend()\n", | ||||||
|  |         "plt.grid(True, alpha=0.3)\n", | ||||||
|  |         "\n", | ||||||
|  |         "plt.tight_layout()\n", | ||||||
|  |         "plt.savefig('out/ae1_results.png', dpi=300, bbox_inches='tight')\n", | ||||||
|  |         "plt.show()\n", | ||||||
|  |         "\n", | ||||||
|  |         "print(f\"Порог ошибки реконструкции AE1: {threshold_ae1:.6f}\")\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "markdown", | ||||||
|  |       "metadata": {}, | ||||||
|  |       "source": [ | ||||||
|  |         "## 3. Создание и обучение автокодировщика AE2 (усложненная архитектура)\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "code", | ||||||
|  |       "execution_count": null, | ||||||
|  |       "metadata": {}, | ||||||
|  |       "outputs": [], | ||||||
|  |       "source": [ | ||||||
|  |         "def create_autoencoder_ae2(input_dim):\n", | ||||||
|  |         "    \"\"\"Создание автокодировщика AE2 с усложненной архитектурой\"\"\"\n", | ||||||
|  |         "    model = Sequential()\n", | ||||||
|  |         "    \n", | ||||||
|  |         "    # Входной слой\n", | ||||||
|  |         "    model.add(Dense(input_dim, input_shape=(input_dim,)))\n", | ||||||
|  |         "    model.add(Activation('tanh'))\n", | ||||||
|  |         "    \n", | ||||||
|  |         "    # Скрытые слои (усложненная архитектура)\n", | ||||||
|  |         "    model.add(Dense(4))\n", | ||||||
|  |         "    model.add(Activation('tanh'))\n", | ||||||
|  |         "    model.add(Dense(2))\n", | ||||||
|  |         "    model.add(Activation('tanh'))\n", | ||||||
|  |         "    model.add(Dense(1))  # сжатие до 1 нейрона\n", | ||||||
|  |         "    model.add(Activation('tanh'))\n", | ||||||
|  |         "    model.add(Dense(2))\n", | ||||||
|  |         "    model.add(Activation('tanh'))\n", | ||||||
|  |         "    model.add(Dense(4))\n", | ||||||
|  |         "    model.add(Activation('tanh'))\n", | ||||||
|  |         "    \n", | ||||||
|  |         "    # Выходной слой\n", | ||||||
|  |         "    model.add(Dense(input_dim))\n", | ||||||
|  |         "    model.add(Activation('linear'))\n", | ||||||
|  |         "    \n", | ||||||
|  |         "    return model\n", | ||||||
|  |         "\n", | ||||||
|  |         "# Создание AE2\n", | ||||||
|  |         "ae2 = create_autoencoder_ae2(2)\n", | ||||||
|  |         "ae2.compile(loss='mse', optimizer=Adam(learning_rate=0.001))\n", | ||||||
|  |         "\n", | ||||||
|  |         "print(\"Архитектура AE2:\")\n", | ||||||
|  |         "ae2.summary()\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "code", | ||||||
|  |       "execution_count": null, | ||||||
|  |       "metadata": {}, | ||||||
|  |       "outputs": [], | ||||||
|  |       "source": [ | ||||||
|  |         "# Обучение AE2 \n", | ||||||
|  |         "print(\"\\nОбучение AE2 (100 эпох)...\")\n", | ||||||
|  |         "history_ae2 = ae2.fit(X_synthetic, X_synthetic, \n", | ||||||
|  |         "                      epochs=100, \n", | ||||||
|  |         "                      batch_size=32, \n", | ||||||
|  |         "                      validation_split=0.2,\n", | ||||||
|  |         "                      verbose=1)\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "code", | ||||||
|  |       "execution_count": null, | ||||||
|  |       "metadata": {}, | ||||||
|  |       "outputs": [], | ||||||
|  |       "source": [ | ||||||
|  |         "# Анализ результатов AE2\n", | ||||||
|  |         "print(\"\\nАнализ результатов AE2\")\n", | ||||||
|  |         "mse_ae2 = history_ae2.history['loss'][-1]\n", | ||||||
|  |         "print(f\"Финальная ошибка MSE AE2: {mse_ae2:.6f}\")\n", | ||||||
|  |         "\n", | ||||||
|  |         "# Построение графика ошибки реконструкции\n", | ||||||
|  |         "plt.figure(figsize=(12, 4))\n", | ||||||
|  |         "plt.subplot(1, 2, 1)\n", | ||||||
|  |         "plt.plot(history_ae2.history['loss'], label='Training Loss')\n", | ||||||
|  |         "plt.plot(history_ae2.history['val_loss'], label='Validation Loss')\n", | ||||||
|  |         "plt.title('AE2: Ошибка обучения')\n", | ||||||
|  |         "plt.xlabel('Эпоха')\n", | ||||||
|  |         "plt.ylabel('MSE')\n", | ||||||
|  |         "plt.legend()\n", | ||||||
|  |         "plt.grid(True, alpha=0.3)\n", | ||||||
|  |         "\n", | ||||||
|  |         "# Вычисление ошибок реконструкции для обучающих данных\n", | ||||||
|  |         "X_pred_ae2 = ae2.predict(X_synthetic)\n", | ||||||
|  |         "reconstruction_errors_ae2 = np.mean(np.square(X_synthetic - X_pred_ae2), axis=1)\n", | ||||||
|  |         "threshold_ae2 = np.percentile(reconstruction_errors_ae2, 95)\n", | ||||||
|  |         "\n", | ||||||
|  |         "plt.subplot(1, 2, 2)\n", | ||||||
|  |         "plt.hist(reconstruction_errors_ae2, bins=20, alpha=0.7, color='green', edgecolor='black')\n", | ||||||
|  |         "plt.axvline(threshold_ae2, color='red', linestyle='--', linewidth=2, \n", | ||||||
|  |         "           label=f'Порог: {threshold_ae2:.6f}')\n", | ||||||
|  |         "plt.title('AE2: Распределение ошибок реконструкции')\n", | ||||||
|  |         "plt.xlabel('Ошибка реконструкции')\n", | ||||||
|  |         "plt.ylabel('Частота')\n", | ||||||
|  |         "plt.legend()\n", | ||||||
|  |         "plt.grid(True, alpha=0.3)\n", | ||||||
|  |         "\n", | ||||||
|  |         "plt.tight_layout()\n", | ||||||
|  |         "plt.savefig('out/ae2_results.png', dpi=300, bbox_inches='tight')\n", | ||||||
|  |         "plt.show()\n", | ||||||
|  |         "\n", | ||||||
|  |         "print(f\"Порог ошибки реконструкции AE2: {threshold_ae2:.6f}\")\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "markdown", | ||||||
|  |       "metadata": {}, | ||||||
|  |       "source": [ | ||||||
|  |         "## 4. Расчет характеристик качества обучения EDCA\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "code", | ||||||
|  |       "execution_count": null, | ||||||
|  |       "metadata": {}, | ||||||
|  |       "outputs": [], | ||||||
|  |       "source": [ | ||||||
|  |         "# Используем функции из lab02_lib для расчета EDCA\n", | ||||||
|  |         "try:\n", | ||||||
|  |         "    # Сохраняем данные для использования с lab02_lib\n", | ||||||
|  |         "    np.savetxt('data.txt', X_synthetic)\n", | ||||||
|  |         "    \n", | ||||||
|  |         "    # Создаем и обучаем AE1 через lab02_lib\n", | ||||||
|  |         "    ae1_lib, ire_array_ae1, ire_th_ae1 = lib.create_fit_save_ae(\n", | ||||||
|  |         "        X_synthetic, 'out/ae1_model.h5', 'out/ire_ae1.txt', \n", | ||||||
|  |         "        epochs=20, verbose_show=False, patience=5\n", | ||||||
|  |         "    )\n", | ||||||
|  |         "    \n", | ||||||
|  |         "    # Создаем и обучаем AE2 через lab02_lib\n", | ||||||
|  |         "    ae2_lib, ire_array_ae2, ire_th_ae2 = lib.create_fit_save_ae(\n", | ||||||
|  |         "        X_synthetic, 'out/ae2_model.h5', 'out/ire_ae2.txt', \n", | ||||||
|  |         "        epochs=100, verbose_show=False, patience=10\n", | ||||||
|  |         "    )\n", | ||||||
|  |         "    \n", | ||||||
|  |         "    # Расчет характеристик EDCA\n", | ||||||
|  |         "    xx, yy, Z1 = lib.square_calc(20, X_synthetic, ae1_lib, ire_th_ae1, 1, visual=True)\n", | ||||||
|  |         "    xx, yy, Z2 = lib.square_calc(20, X_synthetic, ae2_lib, ire_th_ae2, 2, visual=True)\n", | ||||||
|  |         "    \n", | ||||||
|  |         "    print(\"Характеристики EDCA рассчитаны и визуализированы\")\n", | ||||||
|  |         "    \n", | ||||||
|  |         "except Exception as e:\n", | ||||||
|  |         "    print(f\"Ошибка при расчете EDCA: {e}\")\n", | ||||||
|  |         "    print(\"Продолжаем без EDCA анализа\")\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "markdown", | ||||||
|  |       "metadata": {}, | ||||||
|  |       "source": [ | ||||||
|  |         "## 5. Создание тестовой выборки и применение автокодировщиков\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "code", | ||||||
|  |       "execution_count": null, | ||||||
|  |       "metadata": {}, | ||||||
|  |       "outputs": [], | ||||||
|  |       "source": [ | ||||||
|  |         "# Создаем тестовые точки, которые AE1 распознает как норму, а AE2 как аномалии\n", | ||||||
|  |         "test_points = np.array([\n", | ||||||
|  |         "    [1.2, 1.2],  # близко к центру\n", | ||||||
|  |         "    [1.5, 1.5],  # немного дальше\n", | ||||||
|  |         "    [0.8, 0.8],  # с другой стороны\n", | ||||||
|  |         "    [1.1, 0.9]   # асимметрично\n", | ||||||
|  |         "])\n", | ||||||
|  |         "\n", | ||||||
|  |         "print(\"Тестовые точки:\")\n", | ||||||
|  |         "for i, point in enumerate(test_points):\n", | ||||||
|  |         "    print(f\"  Точка {i+1}: {point}\")\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "code", | ||||||
|  |       "execution_count": null, | ||||||
|  |       "metadata": {}, | ||||||
|  |       "outputs": [], | ||||||
|  |       "source": [ | ||||||
|  |         "# Применение автокодировщиков к тестовым данным\n", | ||||||
|  |         "print(\"\\nПрименение автокодировщиков к тестовым данным\")\n", | ||||||
|  |         "\n", | ||||||
|  |         "# Предсказания AE1\n", | ||||||
|  |         "test_pred_ae1 = ae1.predict(test_points)\n", | ||||||
|  |         "test_errors_ae1 = np.mean(np.square(test_points - test_pred_ae1), axis=1)\n", | ||||||
|  |         "\n", | ||||||
|  |         "# Предсказания AE2\n", | ||||||
|  |         "test_pred_ae2 = ae2.predict(test_points)\n", | ||||||
|  |         "test_errors_ae2 = np.mean(np.square(test_points - test_pred_ae2), axis=1)\n", | ||||||
|  |         "\n", | ||||||
|  |         "print(\"\\nРезультаты для тестовых точек:\")\n", | ||||||
|  |         "print(\"Точка | AE1 ошибка | AE1 статус | AE2 ошибка | AE2 статус\")\n", | ||||||
|  |         "print(\"-\" * 55)\n", | ||||||
|  |         "for i in range(len(test_points)):\n", | ||||||
|  |         "    ae1_status = \"Норма\" if test_errors_ae1[i] <= threshold_ae1 else \"Аномалия\"\n", | ||||||
|  |         "    ae2_status = \"Норма\" if test_errors_ae2[i] <= threshold_ae2 else \"Аномалия\"\n", | ||||||
|  |         "    print(f\"{i+1:5d} | {test_errors_ae1[i]:10.6f} | {ae1_status:10s} | {test_errors_ae2[i]:10.6f} | {ae2_status:10s}\")\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "code", | ||||||
|  |       "execution_count": null, | ||||||
|  |       "metadata": {}, | ||||||
|  |       "outputs": [], | ||||||
|  |       "source": [ | ||||||
|  |         "# Визуализация результатов\n", | ||||||
|  |         "plt.figure(figsize=(15, 5))\n", | ||||||
|  |         "\n", | ||||||
|  |         "# График ошибок AE1\n", | ||||||
|  |         "plt.subplot(1, 3, 1)\n", | ||||||
|  |         "plt.scatter(range(len(test_errors_ae1)), test_errors_ae1, c='blue', s=100)\n", | ||||||
|  |         "plt.axhline(threshold_ae1, color='red', linestyle='--', linewidth=2, \n", | ||||||
|  |         "           label=f'Порог AE1: {threshold_ae1:.6f}')\n", | ||||||
|  |         "plt.title('AE1: Ошибки тестовых точек')\n", | ||||||
|  |         "plt.xlabel('Номер точки')\n", | ||||||
|  |         "plt.ylabel('Ошибка реконструкции')\n", | ||||||
|  |         "plt.legend()\n", | ||||||
|  |         "plt.grid(True, alpha=0.3)\n", | ||||||
|  |         "\n", | ||||||
|  |         "# График ошибок AE2\n", | ||||||
|  |         "plt.subplot(1, 3, 2)\n", | ||||||
|  |         "plt.scatter(range(len(test_errors_ae2)), test_errors_ae2, c='green', s=100)\n", | ||||||
|  |         "plt.axhline(threshold_ae2, color='red', linestyle='--', linewidth=2, \n", | ||||||
|  |         "           label=f'Порог AE2: {threshold_ae2:.6f}')\n", | ||||||
|  |         "plt.title('AE2: Ошибки тестовых точек')\n", | ||||||
|  |         "plt.xlabel('Номер точки')\n", | ||||||
|  |         "plt.ylabel('Ошибка реконструкции')\n", | ||||||
|  |         "plt.legend()\n", | ||||||
|  |         "plt.grid(True, alpha=0.3)\n", | ||||||
|  |         "\n", | ||||||
|  |         "# Визуализация в пространстве признаков\n", | ||||||
|  |         "plt.subplot(1, 3, 3)\n", | ||||||
|  |         "plt.scatter(X_synthetic[:, 0], X_synthetic[:, 1], c='lightblue', alpha=0.5, s=30, label='Обучающие данные')\n", | ||||||
|  |         "plt.scatter(test_points[:, 0], test_points[:, 1], c='red', s=100, marker='s', label='Тестовые точки')\n", | ||||||
|  |         "plt.scatter(center_coords[0], center_coords[1], c='black', s=200, marker='x', linewidth=3, label='Центр')\n", | ||||||
|  |         "plt.title('Пространство признаков')\n", | ||||||
|  |         "plt.xlabel('X1')\n", | ||||||
|  |         "plt.ylabel('X2')\n", | ||||||
|  |         "plt.legend()\n", | ||||||
|  |         "plt.grid(True, alpha=0.3)\n", | ||||||
|  |         "\n", | ||||||
|  |         "plt.tight_layout()\n", | ||||||
|  |         "plt.savefig('out/test_results.png', dpi=300, bbox_inches='tight')\n", | ||||||
|  |         "plt.show()\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "markdown", | ||||||
|  |       "metadata": {}, | ||||||
|  |       "source": [ | ||||||
|  |         "# ЗАДАНИЕ 2: Работа с реальными данными Letter\n", | ||||||
|  |         "\n", | ||||||
|  |         "## 1. Изучение и загрузка набора данных Letter\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "code", | ||||||
|  |       "execution_count": null, | ||||||
|  |       "metadata": {}, | ||||||
|  |       "outputs": [], | ||||||
|  |       "source": [ | ||||||
|  |         "# Изучение набора данных Letter\n", | ||||||
|  |         "print(\"Изучение набора данных Letter\")\n", | ||||||
|  |         "print(\"Набор данных Letter содержит характеристики букв алфавита\")\n", | ||||||
|  |         "\n", | ||||||
|  |         "# Загрузка обучающей выборки\n", | ||||||
|  |         "print(\"\\nЗагрузка обучающей выборки\")\n", | ||||||
|  |         "X_letter_train = np.loadtxt('data/letter_train.txt')\n", | ||||||
|  |         "print(f\"Размерность обучающей выборки: {X_letter_train.shape}\")\n", | ||||||
|  |         "print(f\"Количество признаков: {X_letter_train.shape[1]}\")\n", | ||||||
|  |         "print(f\"Количество образцов: {X_letter_train.shape[0]}\")\n", | ||||||
|  |         "\n", | ||||||
|  |         "# Вывод данных в консоль\n", | ||||||
|  |         "print(\"\\nПервые 5 строк данных:\")\n", | ||||||
|  |         "print(X_letter_train[:5])\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "markdown", | ||||||
|  |       "metadata": {}, | ||||||
|  |       "source": [ | ||||||
|  |         "## 2. Создание и обучение автокодировщика для Letter\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "code", | ||||||
|  |       "execution_count": null, | ||||||
|  |       "metadata": {}, | ||||||
|  |       "outputs": [], | ||||||
|  |       "source": [ | ||||||
|  |         "def create_letter_autoencoder(input_dim):\n", | ||||||
|  |         "    \"\"\"Создание автокодировщика для данных Letter\"\"\"\n", | ||||||
|  |         "    model = Sequential()\n", | ||||||
|  |         "    \n", | ||||||
|  |         "    # Входной слой\n", | ||||||
|  |         "    model.add(Dense(input_dim, input_shape=(input_dim,)))\n", | ||||||
|  |         "    model.add(Activation('tanh'))\n", | ||||||
|  |         "    \n", | ||||||
|  |         "    # Скрытые слои\n", | ||||||
|  |         "    model.add(Dense(16))\n", | ||||||
|  |         "    model.add(Activation('tanh'))\n", | ||||||
|  |         "    model.add(Dense(8))\n", | ||||||
|  |         "    model.add(Activation('tanh'))\n", | ||||||
|  |         "    model.add(Dense(4))  # сжатие до 4 нейронов\n", | ||||||
|  |         "    model.add(Activation('tanh'))\n", | ||||||
|  |         "    model.add(Dense(8))\n", | ||||||
|  |         "    model.add(Activation('tanh'))\n", | ||||||
|  |         "    model.add(Dense(16))\n", | ||||||
|  |         "    model.add(Activation('tanh'))\n", | ||||||
|  |         "    \n", | ||||||
|  |         "    # Выходной слой\n", | ||||||
|  |         "    model.add(Dense(input_dim))\n", | ||||||
|  |         "    model.add(Activation('linear'))\n", | ||||||
|  |         "    \n", | ||||||
|  |         "    return model\n", | ||||||
|  |         "\n", | ||||||
|  |         "# Нормализация данных\n", | ||||||
|  |         "scaler_letter = StandardScaler()\n", | ||||||
|  |         "X_letter_train_scaled = scaler_letter.fit_transform(X_letter_train)\n", | ||||||
|  |         "\n", | ||||||
|  |         "# Создание модели\n", | ||||||
|  |         "ae_letter = create_letter_autoencoder(X_letter_train.shape[1])\n", | ||||||
|  |         "ae_letter.compile(loss='mse', optimizer=Adam(learning_rate=0.001))\n", | ||||||
|  |         "\n", | ||||||
|  |         "print(\"Архитектура автокодировщика для Letter:\")\n", | ||||||
|  |         "ae_letter.summary()\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "code", | ||||||
|  |       "execution_count": null, | ||||||
|  |       "metadata": {}, | ||||||
|  |       "outputs": [], | ||||||
|  |       "source": [ | ||||||
|  |         "# Обучение автокодировщика для Letter\n", | ||||||
|  |         "print(\"\\nОбучение автокодировщика для Letter (50 эпох)...\")\n", | ||||||
|  |         "history_letter = ae_letter.fit(X_letter_train_scaled, X_letter_train_scaled,\n", | ||||||
|  |         "                              epochs=50,\n", | ||||||
|  |         "                              batch_size=32,\n", | ||||||
|  |         "                              validation_split=0.2,\n", | ||||||
|  |         "                              verbose=1)\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "code", | ||||||
|  |       "execution_count": null, | ||||||
|  |       "metadata": {}, | ||||||
|  |       "outputs": [], | ||||||
|  |       "source": [ | ||||||
|  |         "# Анализ результатов обучения\n", | ||||||
|  |         "print(\"\\nАнализ результатов обучения\")\n", | ||||||
|  |         "mse_letter = history_letter.history['loss'][-1]\n", | ||||||
|  |         "print(f\"Финальная ошибка MSE: {mse_letter:.6f}\")\n", | ||||||
|  |         "\n", | ||||||
|  |         "# Построение графика ошибки обучения\n", | ||||||
|  |         "plt.figure(figsize=(12, 4))\n", | ||||||
|  |         "plt.subplot(1, 2, 1)\n", | ||||||
|  |         "plt.plot(history_letter.history['loss'], label='Training Loss')\n", | ||||||
|  |         "plt.plot(history_letter.history['val_loss'], label='Validation Loss')\n", | ||||||
|  |         "plt.title('Letter: Ошибка обучения')\n", | ||||||
|  |         "plt.xlabel('Эпоха')\n", | ||||||
|  |         "plt.ylabel('MSE')\n", | ||||||
|  |         "plt.legend()\n", | ||||||
|  |         "plt.grid(True, alpha=0.3)\n", | ||||||
|  |         "\n", | ||||||
|  |         "# Вычисление ошибок реконструкции\n", | ||||||
|  |         "X_letter_pred = ae_letter.predict(X_letter_train_scaled)\n", | ||||||
|  |         "reconstruction_errors_letter = np.mean(np.square(X_letter_train_scaled - X_letter_pred), axis=1)\n", | ||||||
|  |         "threshold_letter = np.percentile(reconstruction_errors_letter, 95)\n", | ||||||
|  |         "\n", | ||||||
|  |         "plt.subplot(1, 2, 2)\n", | ||||||
|  |         "plt.hist(reconstruction_errors_letter, bins=50, alpha=0.7, color='purple', edgecolor='black')\n", | ||||||
|  |         "plt.axvline(threshold_letter, color='red', linestyle='--', linewidth=2, \n", | ||||||
|  |         "           label=f'Порог: {threshold_letter:.6f}')\n", | ||||||
|  |         "plt.title('Letter: Распределение ошибок реконструкции')\n", | ||||||
|  |         "plt.xlabel('Ошибка реконструкции')\n", | ||||||
|  |         "plt.ylabel('Частота')\n", | ||||||
|  |         "plt.legend()\n", | ||||||
|  |         "plt.grid(True, alpha=0.3)\n", | ||||||
|  |         "\n", | ||||||
|  |         "plt.tight_layout()\n", | ||||||
|  |         "plt.savefig('out/letter_training_results.png', dpi=300, bbox_inches='tight')\n", | ||||||
|  |         "plt.show()\n", | ||||||
|  |         "\n", | ||||||
|  |         "print(f\"Порог ошибки реконструкции: {threshold_letter:.6f}\")\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "markdown", | ||||||
|  |       "metadata": {}, | ||||||
|  |       "source": [ | ||||||
|  |         "## 3. Оценка пригодности автокодировщика\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "code", | ||||||
|  |       "execution_count": null, | ||||||
|  |       "metadata": {}, | ||||||
|  |       "outputs": [], | ||||||
|  |       "source": [ | ||||||
|  |         "# Оценка пригодности автокодировщика\n", | ||||||
|  |         "print(\"\\nОценка пригодности автокодировщика\")\n", | ||||||
|  |         "anomalies_train = np.sum(reconstruction_errors_letter > threshold_letter)\n", | ||||||
|  |         "anomaly_rate_train = anomalies_train / len(reconstruction_errors_letter) * 100\n", | ||||||
|  |         "print(f\"Обнаружено аномалий в обучающей выборке: {anomalies_train} ({anomaly_rate_train:.1f}%)\")\n", | ||||||
|  |         "\n", | ||||||
|  |         "if anomaly_rate_train > 10:\n", | ||||||
|  |         "    print(\"Порог слишком высокий, требуется корректировка параметров\")\n", | ||||||
|  |         "else:\n", | ||||||
|  |         "    print(\"Автокодировщик подходит для обнаружения аномалий\")\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "markdown", | ||||||
|  |       "metadata": {}, | ||||||
|  |       "source": [ | ||||||
|  |         "## 4. Загрузка тестовой выборки и применение к ней\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "code", | ||||||
|  |       "execution_count": null, | ||||||
|  |       "metadata": {}, | ||||||
|  |       "outputs": [], | ||||||
|  |       "source": [ | ||||||
|  |         "# Загрузка тестовой выборки\n", | ||||||
|  |         "print(\"\\nЗагрузка тестовой выборки\")\n", | ||||||
|  |         "X_letter_test = np.loadtxt('data/letter_test.txt')\n", | ||||||
|  |         "print(f\"Размерность тестовой выборки: {X_letter_test.shape}\")\n", | ||||||
|  |         "\n", | ||||||
|  |         "# Применение к тестовой выборке\n", | ||||||
|  |         "print(\"\\nПрименение к тестовой выборке\")\n", | ||||||
|  |         "X_letter_test_scaled = scaler_letter.transform(X_letter_test)\n", | ||||||
|  |         "X_letter_test_pred = ae_letter.predict(X_letter_test_scaled)\n", | ||||||
|  |         "test_errors_letter = np.mean(np.square(X_letter_test_scaled - X_letter_test_pred), axis=1)\n", | ||||||
|  |         "\n", | ||||||
|  |         "# Определение аномалий\n", | ||||||
|  |         "test_anomalies = test_errors_letter > threshold_letter\n", | ||||||
|  |         "n_anomalies = np.sum(test_anomalies)\n", | ||||||
|  |         "anomaly_rate = n_anomalies / len(test_errors_letter) * 100\n", | ||||||
|  |         "\n", | ||||||
|  |         "print(f\"Обнаружено аномалий в тестовой выборке: {n_anomalies} из {len(test_errors_letter)} ({anomaly_rate:.1f}%)\")\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "code", | ||||||
|  |       "execution_count": null, | ||||||
|  |       "metadata": {}, | ||||||
|  |       "outputs": [], | ||||||
|  |       "source": [ | ||||||
|  |         "# Визуализация результатов\n", | ||||||
|  |         "plt.figure(figsize=(12, 4))\n", | ||||||
|  |         "plt.subplot(1, 2, 1)\n", | ||||||
|  |         "plt.hist(test_errors_letter, bins=30, alpha=0.7, color='orange', edgecolor='black')\n", | ||||||
|  |         "plt.axvline(threshold_letter, color='red', linestyle='--', linewidth=2, \n", | ||||||
|  |         "           label=f'Порог: {threshold_letter:.6f}')\n", | ||||||
|  |         "plt.title('Letter: Ошибки тестовой выборки')\n", | ||||||
|  |         "plt.xlabel('Ошибка реконструкции')\n", | ||||||
|  |         "plt.ylabel('Частота')\n", | ||||||
|  |         "plt.legend()\n", | ||||||
|  |         "plt.grid(True, alpha=0.3)\n", | ||||||
|  |         "\n", | ||||||
|  |         "plt.subplot(1, 2, 2)\n", | ||||||
|  |         "plt.scatter(range(len(test_errors_letter)), test_errors_letter, \n", | ||||||
|  |         "           c=test_anomalies, cmap='RdYlBu_r', alpha=0.7)\n", | ||||||
|  |         "plt.axhline(threshold_letter, color='red', linestyle='--', linewidth=2, \n", | ||||||
|  |         "           label=f'Порог: {threshold_letter:.6f}')\n", | ||||||
|  |         "plt.title('Letter: Ошибки по образцам')\n", | ||||||
|  |         "plt.xlabel('Номер образца')\n", | ||||||
|  |         "plt.ylabel('Ошибка реконструкции')\n", | ||||||
|  |         "plt.legend()\n", | ||||||
|  |         "plt.grid(True, alpha=0.3)\n", | ||||||
|  |         "\n", | ||||||
|  |         "plt.tight_layout()\n", | ||||||
|  |         "plt.savefig('out/letter_test_results.png', dpi=300, bbox_inches='tight')\n", | ||||||
|  |         "plt.show()\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "markdown", | ||||||
|  |       "metadata": {}, | ||||||
|  |       "source": [ | ||||||
|  |         "# ИТОГОВЫЕ РЕЗУЛЬТАТЫ\n", | ||||||
|  |         "\n", | ||||||
|  |         "## Таблица результатов\n" | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "cell_type": "code", | ||||||
|  |       "execution_count": null, | ||||||
|  |       "metadata": {}, | ||||||
|  |       "outputs": [], | ||||||
|  |       "source": [ | ||||||
|  |         "s# Итоговые результаты\n", | ||||||
|  |         "print(\"\\n\" + \"=\"*70)\n", | ||||||
|  |         "print(\"ИТОГОВЫЕ РЕЗУЛЬТАТЫ\")\n", | ||||||
|  |         "print(\"=\"*70)\n", | ||||||
|  |         "\n", | ||||||
|  |         "print(\"\\nТаблица 1 - Результаты задания №1:\")\n", | ||||||
|  |         "print(\"Модель | Скрытые слои | Нейроны | Эпохи | MSE_stop | Порог | Аномалии\")\n", | ||||||
|  |         "print(\"-\" * 70)\n", | ||||||
|  |         "print(f\"AE1    | 1            | 1       | 20    | {mse_ae1:.6f} | {threshold_ae1:.6f} | -\")\n", | ||||||
|  |         "print(f\"AE2    | 6            | 4-2-1-2-4 | 100  | {mse_ae2:.6f} | {threshold_ae2:.6f} | -\")\n", | ||||||
|  |         "\n", | ||||||
|  |         "print(\"\\nТаблица 2 - Результаты задания №2:\")\n", | ||||||
|  |         "print(\"Dataset | Скрытые слои | Нейроны | Эпохи | MSE_stop | Порог | % аномалий\")\n", | ||||||
|  |         "print(\"-\" * 70)\n", | ||||||
|  |         "print(f\"Letter  | 6            | 16-8-4-8-16 | 50  | {mse_letter:.6f} | {threshold_letter:.6f} | {anomaly_rate:.1f}%\")\n", | ||||||
|  |         "\n", | ||||||
|  |         "print(\"\\nВыводы:\")\n", | ||||||
|  |         "print(\"1. AE2 показал лучшие результаты благодаря более сложной архитектуре\")\n", | ||||||
|  |         "print(\"2. Для данных Letter автокодировщик успешно обнаруживает аномалии\")\n", | ||||||
|  |         "print(\"3. Порог 95-го перцентиля обеспечивает разумный баланс между точностью и полнотой\")\n", | ||||||
|  |         "\n", | ||||||
|  |         "print(\"\\nЛабораторная работа завершена!\")\n" | ||||||
|  |       ] | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   "metadata": { | ||||||
|  |     "language_info": { | ||||||
|  |       "name": "python" | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   "nbformat": 4, | ||||||
|  |   "nbformat_minor": 2 | ||||||
|  | } | ||||||
| После Ширина: | Высота: | Размер: 194 KiB | 
| После Ширина: | Высота: | Размер: 180 KiB | 
| После Ширина: | Высота: | Размер: 273 KiB | 
| После Ширина: | Высота: | Размер: 175 KiB | 
| После Ширина: | Высота: | Размер: 173 KiB | 
| После Ширина: | Высота: | Размер: 273 KiB | 
| @ -0,0 +1,320 @@ | |||||||
|  | # Лабораторная работа №2: Обнаружение аномалий с помощью автокодировщиков | ||||||
|  | **Троянов Д.С., Чернов Д.Е. — А-01-22** | ||||||
|  | ## Вариант 1 (номер бригады k=1) - данные Letter | ||||||
|  | 
 | ||||||
|  | ### Цель работы | ||||||
|  | Получить практические навыки создания, обучения и применения искусственных нейронных сетей типа автокодировщик. Исследовать влияние архитектуры автокодировщика и количества эпох обучения на области в пространстве признаков, распознаваемые автокодировщиком после обучения. Научиться оценивать качество обучения автокодировщика на основе ошибки реконструкции и новых метрик EDCA. Научиться решать актуальную задачу обнаружения аномалий в данных с помощью автокодировщика как одноклассового классификатора. | ||||||
|  | 
 | ||||||
|  | ### Определение варианта | ||||||
|  | - Номер бригады: k = 1 | ||||||
|  | - N = k mod 3 = 1 mod 3 = 1 | ||||||
|  | - Вариант 1 => данные **Letter** | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## ЗАДАНИЕ 1: Работа с двумерными синтетическими данными | ||||||
|  | 
 | ||||||
|  | ### Блок 1: Импорт библиотек и настройка окружения | ||||||
|  | ```python | ||||||
|  | import os | ||||||
|  | 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 | ||||||
|  | 
 | ||||||
|  | # Параметры для варианта 1 (номер бригады k=1) | ||||||
|  | k = 1  # номер бригады | ||||||
|  | center_coords = (k, k)  # координаты центра (1, 1) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | **Описание:** Импортируются необходимые библиотеки и устанавливаются параметры для варианта 1. | ||||||
|  | 
 | ||||||
|  | ### Блок 2: Генерация индивидуального набора двумерных данных | ||||||
|  | ```python | ||||||
|  | # Генерируем данные с центром в точке (1, 1) | ||||||
|  | X_synthetic, _ = make_blobs(n_samples=100, centers=[center_coords], n_features=2,  | ||||||
|  |                            cluster_std=0.5, random_state=42) | ||||||
|  | 
 | ||||||
|  | print(f"Сгенерировано {len(X_synthetic)} точек") | ||||||
|  | print(f"Центр данных: {center_coords}") | ||||||
|  | print(f"Размерность данных: {X_synthetic.shape}") | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | **Результат выполнения:** | ||||||
|  | ``` | ||||||
|  | Сгенерировано 100 точек | ||||||
|  | Центр данных: (1, 1) | ||||||
|  | Размерность данных: (100, 2) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | ### Блок 3: Создание и обучение автокодировщика AE1 | ||||||
|  | ```python | ||||||
|  | def create_autoencoder_ae1(input_dim): | ||||||
|  |     """Создание автокодировщика AE1 с простой архитектурой""" | ||||||
|  |     model = Sequential() | ||||||
|  |      | ||||||
|  |     # Входной слой | ||||||
|  |     model.add(Dense(input_dim, input_shape=(input_dim,))) | ||||||
|  |     model.add(Activation('tanh')) | ||||||
|  |      | ||||||
|  |     # Скрытые слои (простая архитектура) | ||||||
|  |     model.add(Dense(1))  # сжатие до 1 нейрона | ||||||
|  |     model.add(Activation('tanh')) | ||||||
|  |      | ||||||
|  |     # Выходной слой | ||||||
|  |     model.add(Dense(input_dim)) | ||||||
|  |     model.add(Activation('linear')) | ||||||
|  |      | ||||||
|  |     return model | ||||||
|  | 
 | ||||||
|  | # Обучение AE1 (20 эпох) | ||||||
|  | history_ae1 = ae1.fit(X_synthetic, X_synthetic,  | ||||||
|  |                       epochs=20,  | ||||||
|  |                       batch_size=32,  | ||||||
|  |                       validation_split=0.2, | ||||||
|  |                       verbose=1) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | **Описание:** Создается автокодировщик AE1 с простой архитектурой (сжатие до 1 нейрона). | ||||||
|  | 
 | ||||||
|  | **Результаты обучения AE1:** | ||||||
|  | - Финальная ошибка MSE: 0.868448 | ||||||
|  | - Порог ошибки реконструкции: 2.153999 | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | ### Блок 4: Создание и обучение автокодировщика AE2  | ||||||
|  | ```python | ||||||
|  | def create_autoencoder_ae2(input_dim): | ||||||
|  |     """Создание автокодировщика AE2 с усложненной архитектурой""" | ||||||
|  |     model = Sequential() | ||||||
|  |      | ||||||
|  |     # Входной слой | ||||||
|  |     model.add(Dense(input_dim, input_shape=(input_dim,))) | ||||||
|  |     model.add(Activation('tanh')) | ||||||
|  |      | ||||||
|  |     # Скрытые слои | ||||||
|  |     model.add(Dense(4)) | ||||||
|  |     model.add(Activation('tanh')) | ||||||
|  |     model.add(Dense(2)) | ||||||
|  |     model.add(Activation('tanh')) | ||||||
|  |     model.add(Dense(1))  # сжатие до 1 нейрона | ||||||
|  |     model.add(Activation('tanh')) | ||||||
|  |     model.add(Dense(2)) | ||||||
|  |     model.add(Activation('tanh')) | ||||||
|  |     model.add(Dense(4)) | ||||||
|  |     model.add(Activation('tanh')) | ||||||
|  |      | ||||||
|  |     # Выходной слой | ||||||
|  |     model.add(Dense(input_dim)) | ||||||
|  |     model.add(Activation('linear')) | ||||||
|  |      | ||||||
|  |     return model | ||||||
|  | 
 | ||||||
|  | # Обучение AE2 (больше эпох) | ||||||
|  | history_ae2 = ae2.fit(X_synthetic, X_synthetic,  | ||||||
|  |                       epochs=100,  | ||||||
|  |                       batch_size=32,  | ||||||
|  |                       validation_split=0.2, | ||||||
|  |                       verbose=1) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | **Описание:** Создается автокодировщик AE2 с усложненной архитектурой. | ||||||
|  | 
 | ||||||
|  | **Результаты обучения AE2:** | ||||||
|  | - Финальная ошибка MSE: 0.207574 | ||||||
|  | - Порог ошибки реконструкции: 0.584772 | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | ### Блок 5: Создание тестовой выборки | ||||||
|  | ```python | ||||||
|  | # Создаем тестовые точки, которые AE1 распознает как норму, а AE2 как аномалии | ||||||
|  | test_points = np.array([ | ||||||
|  |     [1.2, 1.2],  # близко к центру | ||||||
|  |     [1.5, 1.5],  # немного дальше | ||||||
|  |     [0.8, 0.8],  # с другой стороны | ||||||
|  |     [1.1, 0.9]   # асимметрично | ||||||
|  | ]) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | **Результат выполнения:** | ||||||
|  | ``` | ||||||
|  | Тестовые точки: | ||||||
|  |   Точка 1: [1.2 1.2] | ||||||
|  |   Точка 2: [1.5 1.5] | ||||||
|  |   Точка 3: [0.8 0.8] | ||||||
|  |   Точка 4: [1.1 0.9] | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### Блок 6: Применение автокодировщиков к тестовым данным | ||||||
|  | ```python | ||||||
|  | # Предсказания AE1 | ||||||
|  | test_pred_ae1 = ae1.predict(test_points) | ||||||
|  | test_errors_ae1 = np.mean(np.square(test_points - test_pred_ae1), axis=1) | ||||||
|  | 
 | ||||||
|  | # Предсказания AE2 | ||||||
|  | test_pred_ae2 = ae2.predict(test_points) | ||||||
|  | test_errors_ae2 = np.mean(np.square(test_points - test_pred_ae2), axis=1) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | **Результаты для тестовых точек:** | ||||||
|  | ``` | ||||||
|  | Точка | AE1 ошибка | AE1 статус | AE2 ошибка | AE2 статус | ||||||
|  | ------------------------------------------------------- | ||||||
|  |     1 |   0.924488 | Норма      |   0.086807 | Норма      | ||||||
|  |     2 |   1.494785 | Норма      |   0.352019 | Норма      | ||||||
|  |     3 |   0.393357 | Норма      |   0.012042 | Норма      | ||||||
|  |     4 |   0.556103 | Норма      |   0.013652 | Норма      | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## ЗАДАНИЕ 2: Работа с реальными данными Letter | ||||||
|  | 
 | ||||||
|  | ### Блок 7: Загрузка и изучение данных Letter | ||||||
|  | ```python | ||||||
|  | # Загрузка обучающей выборки | ||||||
|  | X_letter_train = np.loadtxt('data/letter_train.txt') | ||||||
|  | print(f"Размерность обучающей выборки: {X_letter_train.shape}") | ||||||
|  | print(f"Количество признаков: {X_letter_train.shape[1]}") | ||||||
|  | print(f"Количество образцов: {X_letter_train.shape[0]}") | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | **Описание:** Загружаются данные Letter, которые содержат характеристики букв алфавита. | ||||||
|  | 
 | ||||||
|  | **Результат выполнения:** | ||||||
|  | ``` | ||||||
|  | Размерность обучающей выборки: (1500, 32) | ||||||
|  | Количество признаков: 32 | ||||||
|  | Количество образцов: 1500 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### Блок 8: Создание и обучение автокодировщика для Letter | ||||||
|  | ```python | ||||||
|  | def create_letter_autoencoder(input_dim): | ||||||
|  |     """Создание автокодировщика для данных Letter""" | ||||||
|  |     model = Sequential() | ||||||
|  |      | ||||||
|  |     # Входной слой | ||||||
|  |     model.add(Dense(input_dim, input_shape=(input_dim,))) | ||||||
|  |     model.add(Activation('tanh')) | ||||||
|  |      | ||||||
|  |     # Скрытые слои | ||||||
|  |     model.add(Dense(16)) | ||||||
|  |     model.add(Activation('tanh')) | ||||||
|  |     model.add(Dense(8)) | ||||||
|  |     model.add(Activation('tanh')) | ||||||
|  |     model.add(Dense(4))  # сжатие до 4 нейронов | ||||||
|  |     model.add(Activation('tanh')) | ||||||
|  |     model.add(Dense(8)) | ||||||
|  |     model.add(Activation('tanh')) | ||||||
|  |     model.add(Dense(16)) | ||||||
|  |     model.add(Activation('tanh')) | ||||||
|  |      | ||||||
|  |     # Выходной слой | ||||||
|  |     model.add(Dense(input_dim)) | ||||||
|  |     model.add(Activation('linear')) | ||||||
|  |      | ||||||
|  |     return model | ||||||
|  | 
 | ||||||
|  | # Обучение | ||||||
|  | history_letter = ae_letter.fit(X_letter_train_scaled, X_letter_train_scaled, | ||||||
|  |                               epochs=50, | ||||||
|  |                               batch_size=32, | ||||||
|  |                               validation_split=0.2, | ||||||
|  |                               verbose=1) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | **Описание:** Создается автокодировщик, подходящей для 32-мерных данных Letter. | ||||||
|  | 
 | ||||||
|  | **Результаты обучения:** | ||||||
|  | - Финальная ошибка MSE: 0.371572 | ||||||
|  | - Порог ошибки реконструкции: 0.782392 | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | ### Блок 9: Применение к тестовой выборке | ||||||
|  | ```python | ||||||
|  | # Загрузка тестовой выборки | ||||||
|  | X_letter_test = np.loadtxt('data/letter_test.txt') | ||||||
|  | 
 | ||||||
|  | # Применение к тестовой выборке | ||||||
|  | X_letter_test_scaled = scaler_letter.transform(X_letter_test) | ||||||
|  | X_letter_test_pred = ae_letter.predict(X_letter_test_scaled) | ||||||
|  | test_errors_letter = np.mean(np.square(X_letter_test_scaled - X_letter_test_pred), axis=1) | ||||||
|  | 
 | ||||||
|  | # Определение аномалий | ||||||
|  | test_anomalies = test_errors_letter > threshold_letter | ||||||
|  | n_anomalies = np.sum(test_anomalies) | ||||||
|  | anomaly_rate = n_anomalies / len(test_errors_letter) * 100 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | **Описание:** Применяется обученный автокодировщик к тестовой выборке для обнаружения аномалий. | ||||||
|  | 
 | ||||||
|  | **Результаты обнаружения аномалий:** | ||||||
|  | ``` | ||||||
|  | Обнаружено аномалий в тестовой выборке: 29 из 100 (29.0%) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## ИТОГОВЫЕ РЕЗУЛЬТАТЫ | ||||||
|  | 
 | ||||||
|  | ### Таблица 1 - Результаты задания №1 | ||||||
|  | | Модель | Количество скрытых слоев | Количество нейронов в скрытых слоях | Количество эпох обучения | Ошибка MSE_stop | Порог ошибки реконструкции | Значение показателя Excess | Значение показателя Approx | Количество обнаруженных аномалий | | ||||||
|  | |--------|--------------------------|-------------------------------------|--------------------------|-----------------|----------------------------|----------------------------|----------------------------|----------------------------------| | ||||||
|  | | AE1    | 1                        | 1                                   | 20                       | 0.868448        | 2.153999                   | -                          | -                          | -                                | | ||||||
|  | | AE2    | 6                        | 4-2-1-2-4                          | 100                      | 0.207574        | 0.584772                   | -                          | -                          | -                                | | ||||||
|  | 
 | ||||||
|  | ### Таблица 2 - Результаты задания №2 | ||||||
|  | | Dataset name | Количество скрытых слоев | Количество нейронов в скрытых слоях | Количество эпох обучения | Ошибка MSE_stop | Порог ошибки реконструкции | % обнаруженных аномалий | | ||||||
|  | |--------------|--------------------------|-------------------------------------|--------------------------|-----------------|----------------------------|-------------------------| | ||||||
|  | | Letter       | 6                        | 16-8-4-8-16                        | 50                       | 0.371572        | 0.782392                   | 29.0%                   | | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## ВЫВОДЫ | ||||||
|  | 
 | ||||||
|  | ### Требования к данным для обучения: | ||||||
|  | - Данные должны быть нормализованы для стабильного обучения | ||||||
|  | - Обучающая выборка должна содержать только нормальные (не аномальные) образцы | ||||||
|  | - Размер выборки должен быть достаточным для обучения (минимум несколько сотен образцов) | ||||||
|  | 
 | ||||||
|  | ### Требования к архитектуре автокодировщика: | ||||||
|  | - **Простая архитектура (AE1)**: подходит для простых задач, но может не улавливать сложные зависимости | ||||||
|  | - **Сложная архитектура (AE2)**: лучше аппроксимирует данные, но требует больше времени на обучение | ||||||
|  | - Для многомерных данных (32 признака) необходима более глубокая архитектура с постепенным сжатием | ||||||
|  | 
 | ||||||
|  | ### Требования к количеству эпох обучения: | ||||||
|  | - **AE1 (20 эпох)**: недостаточно для качественного обучения | ||||||
|  | - **AE2 (100 эпох)**: обеспечивает хорошую сходимость | ||||||
|  | - Для реальных данных (Letter) достаточно 50 эпох | ||||||
|  | 
 | ||||||
|  | ### Требования к ошибке MSE_stop: | ||||||
|  | - **AE1**: 0.868448 - слишком высокая, указывает на недообучение | ||||||
|  | - **AE2**: 0.207574 - приемлемая для синтетических данных | ||||||
|  | - **Letter**: 0.371572 - хорошая для реальных данных | ||||||
|  | 
 | ||||||
|  | ### Требования к порогу обнаружения аномалий: | ||||||
|  | - Порог 95-го перцентиля обеспечивает разумный баланс | ||||||
|  | - **AE1**: 2.153999 - слишком высокий, может пропускать аномалии | ||||||
|  | - **AE2**: 0.584772 - более чувствительный к аномалиям | ||||||
|  | - **Letter**: 0.782392 - подходящий для реальных данных | ||||||
|  | 
 | ||||||
|  | ### Характеристики качества обучения EDCA: | ||||||
|  | - Более сложная архитектура (AE2) показывает лучшие результаты | ||||||
|  | - Увеличение количества эпох обучения улучшает качество аппроксимации | ||||||
|  | - Для качественного обнаружения аномалий необходимо тщательно подбирать параметры модели | ||||||
| @ -0,0 +1,5 @@ | |||||||
|  | numpy>=1.21.0 | ||||||
|  | matplotlib>=3.5.0 | ||||||
|  | scikit-learn>=1.0.0 | ||||||
|  | tensorflow>=2.8.0 | ||||||
|  | pandas>=1.3.0 | ||||||