Сравнить коммиты
13 Коммитов
| Автор | SHA1 | Дата |
|---|---|---|
|
|
e63b79b0d8 | 6 дней назад |
|
|
a1882005e2 | 1 неделю назад |
|
|
4d582975e4 | 1 неделю назад |
|
|
dac4716238 | 1 месяц назад |
|
|
5ef722a5f7 | 1 месяц назад |
|
|
4f43b51700 | 1 месяц назад |
|
|
973b1aee0e | 1 месяц назад |
|
|
f9d7f9a9a9 | 1 месяц назад |
|
|
0e1939abd4 | 1 месяц назад |
|
|
b0dbbeb2e4 | 2 месяцев назад |
|
|
ca4a6189c8 | 2 месяцев назад |
|
|
e0e4cb8b0a | 2 месяцев назад |
|
|
57734ae3f3 | 2 месяцев назад |
@ -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,742 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Лабораторная работа №2\n",
|
||||
"## Обнаружение аномалий с помощью автокодировщиков\n",
|
||||
"\n",
|
||||
"**Выполнили:** Троянов Даниил Сергеевич, Чернов Данила Евгеньевич \n",
|
||||
"**Группа:** А-01-22 \n",
|
||||
"**Бригада:** 1\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Задание 1\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 1) Импорт необходимых библиотек и модулей\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"import numpy as np\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import lab02_lib as lib\n",
|
||||
"from unittest.mock import patch\n",
|
||||
"import builtins\n",
|
||||
"\n",
|
||||
"# Создаем директорию для выходных файлов\n",
|
||||
"os.makedirs('out', exist_ok=True)\n",
|
||||
"\n",
|
||||
"print('Библиотеки успешно импортированы')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 2) Генерация индивидуального набора двумерных данных\n",
|
||||
"\n",
|
||||
"Сгенерируем набор данных с координатами центра (1, 1), где 1 – номер бригады.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Генерация датасета для бригады 1\n",
|
||||
"brigade_num = 1\n",
|
||||
"data = lib.datagen(brigade_num, brigade_num, 1000, 2)\n",
|
||||
"\n",
|
||||
"# Вывод данных и размерности\n",
|
||||
"print('Исходные данные (первые 10 строк):')\n",
|
||||
"print(data[:10])\n",
|
||||
"print('\\nРазмерность данных:')\n",
|
||||
"print(data.shape)\n",
|
||||
"print(f'\\nЦентр кластера: ({brigade_num}, {brigade_num})')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 3) Создание и обучение автокодировщика AE1 простой архитектуры\n",
|
||||
"\n",
|
||||
"Создадим простой автокодировщик с минимальной архитектурой и небольшим количеством эпох обучения.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Обучение AE1 с использованием функции из lab02_lib\n",
|
||||
"# Для простой архитектуры используем вариант с пользовательской архитектурой\n",
|
||||
"# Архитектура: 2 -> 1 -> 2 (1 скрытый слой с 1 нейроном)\n",
|
||||
"\n",
|
||||
"print('Обучение автокодировщика AE1...')\n",
|
||||
"print('Архитектура: 2 -> 1 -> 2 (простая)')\n",
|
||||
"\n",
|
||||
"# Автоматизируем ввод для выбора пользовательской архитектуры\n",
|
||||
"with patch('builtins.input', side_effect=['1', '1', '1']):\n",
|
||||
" ae1_trained, IRE1, IREth1 = lib.create_fit_save_ae(\n",
|
||||
" data, \n",
|
||||
" 'out/AE1.h5', \n",
|
||||
" 'out/AE1_ire_th.txt',\n",
|
||||
" 1000, # epochs\n",
|
||||
" True, # verbose_show\n",
|
||||
" 300, # patience\n",
|
||||
" early_stopping_delta=0.001\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"# Вычисление MSE из истории обучения (приблизительно)\n",
|
||||
"# Для точного значения нужно сохранить историю, но функция не возвращает её\n",
|
||||
"# Используем предсказание для оценки\n",
|
||||
"X_pred_ae1 = ae1_trained.predict(data, verbose=0)\n",
|
||||
"mse_ae1 = np.mean((data - X_pred_ae1) ** 2)\n",
|
||||
"\n",
|
||||
"print(f'\\nОбучение завершено!')\n",
|
||||
"print(f'MSE_stop (приблизительно): {mse_ae1:.6f}')\n",
|
||||
"print(f'Порог IRE: {IREth1:.6f}')\n",
|
||||
"print(f'Количество скрытых слоев: 1')\n",
|
||||
"print(f'Количество нейронов в скрытых слоях: 1')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 4) Построение графика ошибки реконструкции для AE1\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Построение графика ошибки реконструкции\n",
|
||||
"lib.ire_plot('training', IRE1, IREth1, 'AE1')\n",
|
||||
"print(f'Порог ошибки реконструкции (IREth1): {IREth1:.6f}')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 5) Создание и обучение автокодировщика AE2 с усложненной архитектурой\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Обучение AE2 с использованием функции из lab02_lib\n",
|
||||
"# Для усложненной архитектуры используем вариант с пользовательской архитектурой\n",
|
||||
"# Архитектура: 2 -> 8 -> 4 -> 2 -> 1 -> 2 -> 4 -> 8 -> 2 (6 скрытых слоев)\n",
|
||||
"\n",
|
||||
"print('Обучение автокодировщика AE2...')\n",
|
||||
"print('Архитектура: 2 -> 8 -> 4 -> 2 -> 1 -> 2 -> 4 -> 8 -> 2 (усложненная)')\n",
|
||||
"\n",
|
||||
"# Автоматизируем ввод для выбора пользовательской архитектуры\n",
|
||||
"# 7 скрытых слоев: 8 4 2 1 2 4 8\n",
|
||||
"with patch('builtins.input', side_effect=['1', '7', '8 4 2 1 2 4 8']):\n",
|
||||
" ae2_trained, IRE2, IREth2 = lib.create_fit_save_ae(\n",
|
||||
" data, \n",
|
||||
" 'out/AE2.h5', \n",
|
||||
" 'out/AE2_ire_th.txt',\n",
|
||||
" 3000, # epochs\n",
|
||||
" True, # verbose_show\n",
|
||||
" 300, # patience\n",
|
||||
" early_stopping_delta=0.001\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"# Вычисление MSE из предсказания\n",
|
||||
"X_pred_ae2 = ae2_trained.predict(data, verbose=0)\n",
|
||||
"mse_ae2 = np.mean((data - X_pred_ae2) ** 2)\n",
|
||||
"\n",
|
||||
"print(f'\\nОбучение завершено!')\n",
|
||||
"print(f'MSE_stop (приблизительно): {mse_ae2:.6f}')\n",
|
||||
"print(f'Порог IRE: {IREth2:.6f}')\n",
|
||||
"print(f'Количество скрытых слоев: 6')\n",
|
||||
"print(f'Количество нейронов в скрытых слоях: 8-4-2-1-2-4-8')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 6) Построение графика ошибки реконструкции для AE2\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Построение графика ошибки реконструкции\n",
|
||||
"lib.ire_plot('training', IRE2, IREth2, 'AE2')\n",
|
||||
"print(f'Порог ошибки реконструкции (IREth2): {IREth2:.6f}')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 7) Расчет характеристик качества обучения EDCA для AE1 и AE2\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Расчет EDCA для AE1\n",
|
||||
"numb_square = 20\n",
|
||||
"xx, yy, Z1 = lib.square_calc(numb_square, data, ae1_trained, IREth1, '1', True)\n",
|
||||
"\n",
|
||||
"# Сохраняем результаты EDCA для AE1 сразу после расчета\n",
|
||||
"excess_ae1 = None\n",
|
||||
"approx_ae1 = None\n",
|
||||
"try:\n",
|
||||
" with open('out/result.txt', 'r') as f:\n",
|
||||
" content = f.read()\n",
|
||||
" if 'AE1' in content:\n",
|
||||
" lines = content.split('\\n')\n",
|
||||
" for line in lines:\n",
|
||||
" if 'Excess' in line and excess_ae1 is None:\n",
|
||||
" excess_ae1 = float(line.split('=')[1].strip())\n",
|
||||
" elif 'Approx' in line and approx_ae1 is None:\n",
|
||||
" approx_ae1 = float(line.split('=')[1].strip())\n",
|
||||
"except:\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
"print(f'\\nСохраненные результаты для AE1:')\n",
|
||||
"print(f'Excess: {excess_ae1}')\n",
|
||||
"print(f'Approx: {approx_ae1}')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Расчет EDCA для AE2\n",
|
||||
"xx, yy, Z2 = lib.square_calc(numb_square, data, ae2_trained, IREth2, '2', True)\n",
|
||||
"\n",
|
||||
"# Сохраняем результаты EDCA для AE2 сразу после расчета\n",
|
||||
"excess_ae2 = None\n",
|
||||
"approx_ae2 = None\n",
|
||||
"try:\n",
|
||||
" with open('out/result.txt', 'r') as f:\n",
|
||||
" content = f.read()\n",
|
||||
" if 'AE2' in content:\n",
|
||||
" lines = content.split('\\n')\n",
|
||||
" for line in lines:\n",
|
||||
" if 'Excess' in line and excess_ae2 is None:\n",
|
||||
" excess_ae2 = float(line.split('=')[1].strip())\n",
|
||||
" elif 'Approx' in line and approx_ae2 is None:\n",
|
||||
" approx_ae2 = float(line.split('=')[1].strip())\n",
|
||||
"except:\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
"print(f'\\nСохраненные результаты для AE2:')\n",
|
||||
"print(f'Excess: {excess_ae2}')\n",
|
||||
"print(f'Approx: {approx_ae2}')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Сравнение характеристик качества обучения и областей аппроксимации\n",
|
||||
"lib.plot2in1(data, xx, yy, Z1, Z2)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 8) Создание тестовой выборки\n",
|
||||
"\n",
|
||||
"Создадим тестовую выборку из элементов, которые AE1 распознает как норму, а AE2 детектирует как аномалии.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Создание тестовой выборки\n",
|
||||
"# Точки, которые находятся на среднем расстоянии от центра (1, 1)\n",
|
||||
"# чтобы AE1 их не распознал как аномалии (IRE < порог AE1 ~2.06),\n",
|
||||
"# но AE2 распознал как аномалии (IRE > порог AE2 ~0.41)\n",
|
||||
"# Выбираем точки на расстоянии примерно 1-1.5 от центра\n",
|
||||
"data_test = np.array([\n",
|
||||
" [-0.5, 0.5], \n",
|
||||
" [1, 0.5], \n",
|
||||
" [0.2, 1.2], \n",
|
||||
" [0, 0.1] \n",
|
||||
"])\n",
|
||||
"\n",
|
||||
"print('Тестовая выборка:')\n",
|
||||
"print(data_test)\n",
|
||||
"print(f'\\nРазмерность: {data_test.shape}')\n",
|
||||
"print(f'\\nЦентр обучающих данных: (1, 1)')\n",
|
||||
"print(f'Расстояния от центра:')\n",
|
||||
"for i, point in enumerate(data_test):\n",
|
||||
" dist = np.sqrt((point[0] - 1)**2 + (point[1] - 1)**2)\n",
|
||||
" print(f' Точка {i+1} {point}: расстояние = {dist:.3f}')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 9) Применение автокодировщиков к тестовым данным\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Тестирование AE1\n",
|
||||
"predicted_labels1, ire1_test = lib.predict_ae(ae1_trained, data_test, IREth1)\n",
|
||||
"lib.anomaly_detection_ae(predicted_labels1, ire1_test, IREth1)\n",
|
||||
"lib.ire_plot('test', ire1_test, IREth1, 'AE1')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Тестирование AE2\n",
|
||||
"predicted_labels2, ire2_test = lib.predict_ae(ae2_trained, data_test, IREth2)\n",
|
||||
"lib.anomaly_detection_ae(predicted_labels2, ire2_test, IREth2)\n",
|
||||
"lib.ire_plot('test', ire2_test, IREth2, 'AE2')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Визуализация элементов обучающей и тестовой выборки\n",
|
||||
"lib.plot2in1_anomaly(data, xx, yy, Z1, Z2, data_test)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Подсчет обнаруженных аномалий\n",
|
||||
"anomalies_ae1 = int(predicted_labels1.sum())\n",
|
||||
"anomalies_ae2 = int(predicted_labels2.sum())\n",
|
||||
"\n",
|
||||
"# Используем сохраненные ранее значения EDCA метрик\n",
|
||||
"# (они были сохранены в ячейках после вызова square_calc)\n",
|
||||
"# Если переменные не определены, пытаемся прочитать из файла\n",
|
||||
"try:\n",
|
||||
" excess_ae1_val = excess_ae1 if excess_ae1 is not None else None\n",
|
||||
"except NameError:\n",
|
||||
" excess_ae1_val = None\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" approx_ae1_val = approx_ae1 if approx_ae1 is not None else None\n",
|
||||
"except NameError:\n",
|
||||
" approx_ae1_val = None\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" excess_ae2_val = excess_ae2 if excess_ae2 is not None else None\n",
|
||||
"except NameError:\n",
|
||||
" excess_ae2_val = None\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" approx_ae2_val = approx_ae2 if approx_ae2 is not None else None\n",
|
||||
"except NameError:\n",
|
||||
" approx_ae2_val = None\n",
|
||||
"\n",
|
||||
"print('Таблица 1 - Результаты задания №1')\n",
|
||||
"print('=' * 120)\n",
|
||||
"print(f'{\"Модель\":<10} {\"Скрытых слоев\":<15} {\"Нейроны\":<25} {\"Эпох\":<10} {\"MSE_stop\":<12} {\"Порог IRE\":<12} {\"Excess\":<10} {\"Approx\":<10} {\"Аномалий\":<10}')\n",
|
||||
"print('-' * 120)\n",
|
||||
"print(f'AE1 {1:<15} {1:<25} {1000:<10} {mse_ae1:<12.6f} {IREth1:<12.6f} {excess_ae1_val if excess_ae1_val is not None else \"N/A\":<10} {approx_ae1_val if approx_ae1_val is not None else \"N/A\":<10} {anomalies_ae1}/{len(data_test):<10}')\n",
|
||||
"print(f'AE2 {6:<15} {\"8-4-2-1-2-4-8\":<25} {3000:<10} {mse_ae2:<12.6f} {IREth2:<12.6f} {excess_ae2_val if excess_ae2_val is not None else \"N/A\":<10} {approx_ae2_val if approx_ae2_val is not None else \"N/A\":<10} {anomalies_ae2}/{len(data_test):<10}')\n",
|
||||
"print('=' * 120)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Задание 2\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 1) Изучение набора реальных данных Letter\n",
|
||||
"\n",
|
||||
"Набор данных Letter представляет собой характеристики букв английского алфавита. Для обнаружения аномалий нормальные примеры используются для обучения, а аномальные - для тестирования.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Загрузка обучающей и тестовой выборки Letter\n",
|
||||
"train_letter = np.loadtxt('data/letter_train.txt', dtype=float)\n",
|
||||
"test_letter = np.loadtxt('data/letter_test.txt', dtype=float)\n",
|
||||
"\n",
|
||||
"print('Обучающая выборка Letter:')\n",
|
||||
"print(f'Размерность: {train_letter.shape}')\n",
|
||||
"print(f'Количество признаков: {train_letter.shape[1]}')\n",
|
||||
"print(f'Количество примеров: {train_letter.shape[0]}')\n",
|
||||
"print(f'\\nПервые 5 строк:')\n",
|
||||
"print(train_letter[:5])\n",
|
||||
"\n",
|
||||
"print(f'\\nТестовая выборка Letter:')\n",
|
||||
"print(f'Размерность: {test_letter.shape}')\n",
|
||||
"print(f'Количество примеров: {test_letter.shape[0]}')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 2.1) Нормализация данных (дополнительное исследование, для сравнения)\n",
|
||||
"\n",
|
||||
"Создадим нормализованную версию данных для сравнения результатов обучения.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Нормализация данных для сравнения результатов\n",
|
||||
"from sklearn.preprocessing import StandardScaler\n",
|
||||
"\n",
|
||||
"# Создаем нормализованные версии данных\n",
|
||||
"scaler = StandardScaler()\n",
|
||||
"train_letter_normalized = scaler.fit_transform(train_letter)\n",
|
||||
"test_letter_normalized = scaler.transform(test_letter)\n",
|
||||
"\n",
|
||||
"print('Нормализация данных выполнена')\n",
|
||||
"print(f'\\nИсходные данные (первые 3 признака первого примера):')\n",
|
||||
"print(f' train_letter[0, :3] = {train_letter[0, :3]}')\n",
|
||||
"print(f'\\nНормализованные данные (первые 3 признака первого примера):')\n",
|
||||
"print(f' train_letter_normalized[0, :3] = {train_letter_normalized[0, :3]}')\n",
|
||||
"print(f'\\nСтатистика нормализованных данных:')\n",
|
||||
"print(f' Среднее: {train_letter_normalized.mean(axis=0)[:5]}...')\n",
|
||||
"print(f' Стд. отклонение: {train_letter_normalized.std(axis=0)[:5]}...')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 2.2) Обучение автокодировщика на ненормализованных данных\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Обучение автокодировщика для Letter на НЕнормализованных данных\n",
|
||||
"# Входной и выходной слои создаются автоматически по размеру данных (32 признака)\n",
|
||||
"# Мы задаем только скрытые слои\n",
|
||||
"# Полная архитектура: 32(вход) -> 100 -> 68 -> 48 -> 32 -> 24 -> 16 -> 8 -> 16 -> 24 -> 32 -> 48 -> 64 -> 100 -> 32(выход)\n",
|
||||
"# 11 скрытых слоев: 100 64 48 32 24 16 8 16 24 32 48 64 100 \n",
|
||||
"\n",
|
||||
"import warnings\n",
|
||||
"# Подавляем предупреждение о формате сохранения HDF5\n",
|
||||
"warnings.filterwarnings('ignore', category=UserWarning, module='absl')\n",
|
||||
"\n",
|
||||
"print('Обучение автокодировщика для данных Letter (НЕнормализованные данные)...')\n",
|
||||
"print('Архитектура: 32(вход) -> 100 -> 68 -> 48 -> 32 -> 24 -> 16 -> 8 -> 16 -> 24 -> 32 -> 48 -> 64 -> 100 -> 32(выход)')\n",
|
||||
"\n",
|
||||
"# Автоматизируем ввод для выбора пользовательской архитектуры\n",
|
||||
"with patch('builtins.input', side_effect=['1', '17', ' 100 86 72 64 48 32 24 16 8 16 24 32 48 64 72 86 100']):\n",
|
||||
" ae_letter_raw, IRE_letter_raw, IREth_letter_raw = lib.create_fit_save_ae(\n",
|
||||
" train_letter, \n",
|
||||
" 'out/Letter_AE_raw.h5', \n",
|
||||
" 'out/Letter_AE_raw_ire_th.txt',\n",
|
||||
" 100000, # epochs\n",
|
||||
" False, # verbose_show\n",
|
||||
" 10000, # patience\n",
|
||||
" verbose_every_n_epochs=500\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"# Вычисление MSE из предсказания\n",
|
||||
"X_pred_letter_raw = ae_letter_raw.predict(train_letter, verbose=0)\n",
|
||||
"mse_letter_raw = np.mean((train_letter - X_pred_letter_raw) ** 2)\n",
|
||||
"\n",
|
||||
"print(f'\\nОбучение завершено (НЕнормализованные данные)!')\n",
|
||||
"print(f'MSE_stop (приблизительно): {mse_letter_raw:.6f}')\n",
|
||||
"print(f'Порог IRE: {IREth_letter_raw:.6f}')\n",
|
||||
"print(f'Количество скрытых слоев: 11')\n",
|
||||
"print(f'Количество нейронов в скрытых слоях: 100 -> 68 -> 48 -> 32 -> 24 -> 16 -> 8 -> 16 -> 24 -> 32 -> 48 -> 64 -> 100')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 2.3) Обучение автокодировщика на нормализованных данных\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Обучение автокодировщика для Letter на нормализованных данных\n",
|
||||
"# Та же архитектура для сравнения: 32(вход) -> 100 -> 68 -> 48 -> 32 -> 24 -> 16 -> 8 -> 16 -> 24 -> 32 -> 48 -> 64 -> 100 -> 32(выход)\n",
|
||||
"# 11 скрытых слоев: 100 86 72 64 48 32 24 16 8 16 24 32 48 64 72 86 100\n",
|
||||
"\n",
|
||||
"print('Обучение автокодировщика для данных Letter (нормализованные данные)...')\n",
|
||||
"print('Архитектура: 32(вход) -> 100 -> 68 -> 48 -> 32 -> 24 -> 16 -> 8 -> 16 -> 24 -> 32 -> 48 -> 64 -> 100 -> 32(выход)')\n",
|
||||
"\n",
|
||||
"# Автоматизируем ввод для выбора пользовательской архитектуры\n",
|
||||
"with patch('builtins.input', side_effect=['1', '17', ' 100 86 72 64 48 32 24 16 8 16 24 32 48 64 72 86 100']):\n",
|
||||
" ae_letter_norm, IRE_letter_norm, IREth_letter_norm = lib.create_fit_save_ae(\n",
|
||||
" train_letter_normalized, \n",
|
||||
" 'out/Letter_AE_norm.h5', \n",
|
||||
" 'out/Letter_AE_norm_ire_th.txt',\n",
|
||||
" 20000, # epochs\n",
|
||||
" True, # verbose_show\n",
|
||||
" 200, # patience\n",
|
||||
" verbose_every_n_epochs=500\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"# Вычисление MSE из предсказания\n",
|
||||
"X_pred_letter_norm = ae_letter_norm.predict(train_letter_normalized, verbose=0)\n",
|
||||
"mse_letter_norm = np.mean((train_letter_normalized - X_pred_letter_norm) ** 2)\n",
|
||||
"\n",
|
||||
"print(f'\\nОбучение завершено (нормализованные данные)!')\n",
|
||||
"print(f'MSE_stop (приблизительно): {mse_letter_norm:.6f}')\n",
|
||||
"print(f'Порог IRE: {IREth_letter_norm:.6f}')\n",
|
||||
"print(f'Количество скрытых слоев: 11')\n",
|
||||
"print(f'Количество нейронов в скрытых слоях: 100 -> 68 -> 48 -> 32 -> 24 -> 16 -> 8 -> 16 -> 24 -> 32 -> 48 -> 64 -> 100')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 2.4) Сравнение результатов обучения на нормализованных и ненормализованных данных\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Сравнение результатов\n",
|
||||
"print('=' * 100)\n",
|
||||
"print('СРАВНЕНИЕ РЕЗУЛЬТАТОВ ОБУЧЕНИЯ')\n",
|
||||
"print('=' * 100)\n",
|
||||
"print(f'{\"Параметр\"} {\"НЕнормализованные\"} {\"Нормализованные\"}')\n",
|
||||
"print('-' * 100)\n",
|
||||
"print(f'{\"MSE_stop\"} {mse_letter_raw} {mse_letter_norm}')\n",
|
||||
"print(f'{\"Порог IRE\"} {IREth_letter_raw} {IREth_letter_norm:}')\n",
|
||||
"print(f'{\"Архитектура\":<30} {\"17 слоев\"} {\"17 слоев\"}')\n",
|
||||
"print(f'{\"Нейроны\"} {\"32(вход) -> 100 -> 68 -> 48 -> 32 -> 24 -> 16 -> 8 -> 16 -> 24 -> 32 -> 48 -> 64 -> 100 -> 32(выход)\"} {\"32(вход) -> 100 -> 68 -> 48 -> 32 -> 24 -> 16 -> 8 -> 16 -> 24 -> 32 -> 48 -> 64 -> 100 -> 32(выход)\"}')\n",
|
||||
"print('=' * 100)\n",
|
||||
"\n",
|
||||
"# Выбираем лучшую модель для дальнейшей работы\n",
|
||||
"if mse_letter_norm < mse_letter_raw:\n",
|
||||
" print('\\nЛучшая модель: НОРМАЛИЗОВАННЫЕ данные')\n",
|
||||
" ae_letter = ae_letter_norm\n",
|
||||
" IRE_letter = IRE_letter_norm\n",
|
||||
" IREth_letter = IREth_letter_norm\n",
|
||||
" mse_letter = mse_letter_norm\n",
|
||||
" test_letter_used = test_letter_normalized\n",
|
||||
" print(f'Используем эту модель для дальнейших экспериментов')\n",
|
||||
"else:\n",
|
||||
" print('\\nЛучшая модель: НЕнормализованные данные')\n",
|
||||
" ae_letter = ae_letter_raw\n",
|
||||
" IRE_letter = IRE_letter_raw\n",
|
||||
" IREth_letter = IREth_letter_raw\n",
|
||||
" mse_letter = mse_letter_raw\n",
|
||||
" test_letter_used = test_letter\n",
|
||||
" print(f'Используем эту модель для дальнейших экспериментов')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 3) Построение графика ошибки реконструкции для Letter\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Построение графика ошибки реконструкции для выбранной модели\n",
|
||||
"lib.ire_plot('training', IRE_letter, IREth_letter, 'Letter_AE')\n",
|
||||
"print(f'Порог ошибки реконструкции: {IREth_letter:.6f}')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 4) Применение автокодировщика к тестовой выборке Letter\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Тестирование автокодировщика на тестовой выборке\n",
|
||||
"# Используем выбранную модель (лучшую из нормализованных/ненормализованных)\n",
|
||||
"predicted_labels_letter, ire_letter_test = lib.predict_ae(ae_letter, test_letter_used, IREth_letter)\n",
|
||||
"\n",
|
||||
"# Подсчет обнаруженных аномалий\n",
|
||||
"num_anomalies = int(predicted_labels_letter.sum())\n",
|
||||
"total_test = len(test_letter_used)\n",
|
||||
"anomaly_percentage = (num_anomalies / total_test) * 100\n",
|
||||
"\n",
|
||||
"print(f'Обнаружено аномалий: {num_anomalies} из {total_test}')\n",
|
||||
"print(f'Процент обнаруженных аномалий: {anomaly_percentage:.1f}%')\n",
|
||||
"\n",
|
||||
"lib.anomaly_detection_ae(predicted_labels_letter, ire_letter_test, IREth_letter)\n",
|
||||
"lib.ire_plot('test', ire_letter_test, IREth_letter, 'Letter_AE')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 5) Результаты задания №2\n",
|
||||
"\n",
|
||||
"Результаты исследования занесены в таблицу:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print('Таблица 2 - Результаты задания №2')\n",
|
||||
"print('=' * 100)\n",
|
||||
"print(f'{\"Dataset\":<15} {\"Скрытых слоев\":<15} {\"Нейроны\":<40} {\"Эпох\":<10} {\"MSE_stop\":<12} {\"Порог IRE\":<12} {\"% аномалий\":<12}')\n",
|
||||
"print('-' * 100)\n",
|
||||
"print(f'Letter {11:<15} {\"32(вход) -> 100 -> 68 -> 48 -> 32 -> 24 -> 16 -> 8 -> 16 -> 24 -> 32 -> 48 -> 64 -> 100 -> 32(выход)\":<40} {20000:<10} {mse_letter:<12.6f} {IREth_letter:<12.6f} {anomaly_percentage:.1f}%')\n",
|
||||
"print('=' * 100)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Выводы\n",
|
||||
"\n",
|
||||
"### Требования к данным для обучения:\n",
|
||||
"- Данные для обучения должны быть без аномалий, чтобы автокодировщик смог рассчитать верное пороговое значение\n",
|
||||
"\n",
|
||||
"### Требования к архитектуре автокодировщика:\n",
|
||||
"- Архитектура должна постепенно сужаться к бутылочному горлышку, а затем постепенно возвращаться к исходным выходным размерам\n",
|
||||
"- Для двумерных данных оптимальное количество скрытых слоев: 3-6\n",
|
||||
"- Для многомерных данных (32 признака) оптимальное количество скрытых слоев: от 7-ми\n",
|
||||
"\n",
|
||||
"### Требования к количеству эпох обучения:\n",
|
||||
"- Для простых данных (2D): 1000-3000 эпох\n",
|
||||
"- Для сложных данных (многомерных): до 100000 эпох\n",
|
||||
"\n",
|
||||
"### Требования к ошибке MSE_stop:\n",
|
||||
"- Для двумерных данных: оптимальная ошибка MSE-stop в районе 0.01\n",
|
||||
"- Для многомерных данных: оптимальная ошибка MSE-stop в районе 0.1-0.01\n",
|
||||
"\n",
|
||||
"### Требования к порогу обнаружения аномалий:\n",
|
||||
"- Для двумерных данных: значение порога в районе 0.4-2.5\n",
|
||||
"- Для многомерных данных: значение порога не больше 1.6\n",
|
||||
"\n",
|
||||
"### Требования к характеристикам качества обучения EDCA:\n",
|
||||
"- Значение Excess должно быть как можно ближе к 0\n",
|
||||
"- Значение Deficit должно быть как можно ближе к 0 \n",
|
||||
"- Значение Coating должно быть как можно ближе к 1 \n",
|
||||
"- Значение Approx должно быть как можно ближе к 1\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"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": 2
|
||||
}
|
||||
|
После Ширина: | Высота: | Размер: 21 KiB |
|
После Ширина: | Высота: | Размер: 22 KiB |
@ -0,0 +1 @@
|
||||
0.56
|
||||
|
После Ширина: | Высота: | Размер: 34 KiB |
@ -0,0 +1 @@
|
||||
0.38
|
||||
|
После Ширина: | Высота: | Размер: 31 KiB |
|
После Ширина: | Высота: | Размер: 42 KiB |
|
После Ширина: | Высота: | Размер: 34 KiB |
|
После Ширина: | Высота: | Размер: 74 KiB |
|
После Ширина: | Высота: | Размер: 110 KiB |
|
После Ширина: | Высота: | Размер: 104 KiB |
|
После Ширина: | Высота: | Размер: 93 KiB |
@ -0,0 +1 @@
|
||||
29.84
|
||||
@ -0,0 +1 @@
|
||||
1.62
|
||||
@ -0,0 +1 @@
|
||||
11.1
|
||||
|
После Ширина: | Высота: | Размер: 74 KiB |
|
После Ширина: | Высота: | Размер: 88 KiB |
|
После Ширина: | Высота: | Размер: 63 KiB |
|
После Ширина: | Высота: | Размер: 76 KiB |
@ -0,0 +1,5 @@
|
||||
------------Оценка качества AE2 С ПОМОЩЬЮ НОВЫХ МЕТРИК------------
|
||||
Approx = 0.7142857142857142
|
||||
Excess = 0.4
|
||||
Deficit = 0.0
|
||||
Coating = 1.0
|
||||
|
После Ширина: | Высота: | Размер: 44 KiB |
@ -0,0 +1,478 @@
|
||||
# Отчёт по лабораторной работе №2
|
||||
## Обнаружение аномалий с помощью автокодировщиков
|
||||
|
||||
**Выполнили:** Троянов Даниил Сергеевич, Чернов Данила Евгеньевич
|
||||
**Группа:** А-01-22
|
||||
**Бригада:** 1
|
||||
|
||||
---
|
||||
|
||||
## Задание 1
|
||||
|
||||
### 1) Подготовка рабочей среды и импорт библиотек
|
||||
|
||||
В среде Jupyter Notebook был создан новый блокнот для выполнения лабораторной работы. Импортированы необходимые библиотеки и модули для работы с данными и нейронными сетями.
|
||||
|
||||
```python
|
||||
import os
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import lab02_lib as lib
|
||||
from unittest.mock import patch
|
||||
import builtins
|
||||
|
||||
# Создаем директорию для выходных файлов
|
||||
os.makedirs('out', exist_ok=True)
|
||||
```
|
||||
|
||||
### 2) Генерация синтетического набора двумерных данных
|
||||
|
||||
Сгенерирован индивидуальный набор двумерных данных в пространстве признаков с координатами центра (1, 1), где 1 – номер бригады. Данные представлены в виде кластера из 1000 точек.
|
||||
|
||||
```python
|
||||
# Генерация датасета для бригады 1
|
||||
brigade_num = 1
|
||||
data = lib.datagen(brigade_num, brigade_num, 1000, 2)
|
||||
```
|
||||
|
||||
Размерность данных: (1000, 2)
|
||||
|
||||

|
||||
|
||||
### 3) Создание и обучение автокодировщика AE1 с простой архитектурой
|
||||
|
||||
Создан первый автокодировщик AE1 с минимальной архитектурой, состоящей из одного скрытого слоя с одним нейроном. Обучение проводилось в течение 1000 эпох.
|
||||
|
||||
```python
|
||||
# Обучение AE1
|
||||
with patch('builtins.input', side_effect=['1', '1', '1']):
|
||||
ae1_trained, IRE1, IREth1 = lib.create_fit_save_ae(
|
||||
data,
|
||||
'out/AE1.h5',
|
||||
'out/AE1_ire_th.txt',
|
||||
1000, # epochs
|
||||
True, # verbose_show
|
||||
200, # patience
|
||||
)
|
||||
```
|
||||
|
||||
Архитектура: 2 → 1 → 2 (1 скрытый слой с 1 нейроном)
|
||||
|
||||
### 4) Анализ результатов обучения AE1
|
||||
|
||||
Зафиксирована ошибка MSE, на которой завершилось обучение. Построен график ошибки реконструкции обучающей выборки. Определён порог ошибки реконструкции для обнаружения аномалий.
|
||||
|
||||
Ошибка MSE_AE1 ≈ 0.025
|
||||
|
||||
```python
|
||||
# Построение графика ошибки реконструкции
|
||||
lib.ire_plot('training', IRE1, IREth1, 'AE1')
|
||||
```
|
||||
|
||||

|
||||
|
||||
Порог ошибки реконструкции (IREth1) ≈ 0.56
|
||||
|
||||
### 5) Создание и обучение автокодировщика AE2 с усложнённой архитектурой
|
||||
|
||||
Создан второй автокодировщик AE2 с более сложной архитектурой, включающей 7 скрытых слоёв. Обучение проводилось в течение 3000 эпох для достижения лучшего качества аппроксимации области нормальных данных.
|
||||
|
||||
```python
|
||||
# Обучение AE2
|
||||
with patch('builtins.input', side_effect=['1', '7', '8 4 2 1 2 4 8']):
|
||||
ae2_trained, IRE2, IREth2 = lib.create_fit_save_ae(
|
||||
data,
|
||||
'out/AE2.h5',
|
||||
'out/AE2_ire_th.txt',
|
||||
3000, # epochs
|
||||
True, # verbose_show
|
||||
200, # patience
|
||||
)
|
||||
|
||||
# Вычисление MSE из предсказания
|
||||
X_pred_ae2 = ae2_trained.predict(data, verbose=0)
|
||||
mse_ae2 = np.mean((data - X_pred_ae2) ** 2)
|
||||
|
||||
print(f'\nОбучение завершено!')
|
||||
print(f'MSE_stop (приблизительно): {mse_ae2:.6f}')
|
||||
print(f'Порог IRE: {IREth2:.6f}')
|
||||
print(f'Количество скрытых слоев: 7')
|
||||
print(f'Количество нейронов в скрытых слоях: 8-4-2-1-2-4-8')
|
||||
```
|
||||
|
||||
Архитектура: 2 → 8 → 4 → 2 → 1 → 2 → 4 → 8 → 2 (7 скрытых слоёв: 8-4-2-1-2-4-8)
|
||||
|
||||
### 6) Анализ результатов обучения AE2
|
||||
|
||||
Зафиксирована ошибка MSE, на которой завершилось обучение. Построен график ошибки реконструкции обучающей выборки. Определён порог ошибки реконструкции для обнаружения аномалий.
|
||||
|
||||
Ошибка MSE_AE2 ≈ 0.0098
|
||||
|
||||
```python
|
||||
# Построение графика ошибки реконструкции
|
||||
lib.ire_plot('training', IRE2, IREth2, 'AE2')
|
||||
```
|
||||
|
||||

|
||||
|
||||
Порог ошибки реконструкции (IREth2) ≈ 0.38
|
||||
|
||||
### 7) Оценка качества обучения с помощью метрик EDCA
|
||||
|
||||
Рассчитаны характеристики качества обучения EDCA (Excess, Deficit, Coating, Approx) для обоих автокодировщиков. Визуализированы и сравнены области пространства признаков, распознаваемые автокодировщиками AE1 и AE2.
|
||||
|
||||
```python
|
||||
# Расчет характеристик качества обучения для AE1
|
||||
numb_square = 20
|
||||
xx, yy, Z1 = lib.square_calc(numb_square, data, ae1_trained, IREth1, '1', True)
|
||||
```
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
Результаты для AE1:
|
||||
- Excess ≈ 5.75
|
||||
- Approx ≈ 0.148
|
||||
|
||||
```python
|
||||
# Расчет характеристик качества обучения для AE2
|
||||
xx, yy, Z2 = lib.square_calc(numb_square, data, ae2_trained, IREth2, '2', True)
|
||||
```
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
Результаты для AE2:
|
||||
- Excess ≈ 0.4
|
||||
- Approx ≈ 0.714
|
||||
|
||||
```python
|
||||
# Сравнение областей аппроксимации
|
||||
lib.plot2in1(data, xx, yy, Z1, Z2)
|
||||
```
|
||||
|
||||

|
||||
|
||||
### 8) Оценка пригодности автокодировщиков
|
||||
|
||||
Полученные показатели EDCA для автокодировщика AE2 демонстрируют значительно лучшее качество аппроксимации по сравнению с AE1. Значение Approx для AE2 (0.714) существенно выше, чем для AE1 (0.148), что указывает на более точную аппроксимацию области обучающих данных. Значение Excess для AE2 (0.4) значительно ниже, чем для AE1 (5.75), что подтверждает более качественное обучение модели AE2.
|
||||
|
||||
### 9) Подготовка тестовой выборки
|
||||
|
||||
Создана тестовая выборка, состоящая из 4 элементов, не входящих в обучающую выборку. Элементы подобраны таким образом, чтобы AE1 распознавал их как норму, а AE2 обнаруживал как аномалии.
|
||||
|
||||
```python
|
||||
# Тестовая выборка
|
||||
data_test = np.array([[2.2, 1.2], [1.2, 2.2], [0.2, 1.2], [1.2, 0.2]])
|
||||
```
|
||||
|
||||
### 10) Применение автокодировщиков к тестовым данным
|
||||
|
||||
Применены обученные автокодировщики AE1 и AE2 к тестовым данным. Выведены значения ошибки реконструкции для каждого элемента тестовой выборки относительно порога на график и в консоль.
|
||||
|
||||
```python
|
||||
# Тестирование AE1
|
||||
predicted_labels1, ire1 = lib.predict_ae(ae1_trained, data_test, IREth1)
|
||||
lib.anomaly_detection_ae(predicted_labels1, ire1, IREth1)
|
||||
lib.ire_plot('test', ire1, IREth1, 'AE1')
|
||||
```
|
||||
|
||||

|
||||
|
||||
Результат для AE1: аномалий не обнаружено (0 из 4)
|
||||
|
||||
```python
|
||||
# Тестирование AE2
|
||||
predicted_labels2, ire2 = lib.predict_ae(ae2_trained, data_test, IREth2)
|
||||
lib.anomaly_detection_ae(predicted_labels2, ire2, IREth2)
|
||||
lib.ire_plot('test', ire2, IREth2, 'AE2')
|
||||
```
|
||||
|
||||

|
||||
|
||||
Результат для AE2: обнаружено 4 аномалии из 4
|
||||
|
||||
### 11) Визуализация результатов тестирования
|
||||
|
||||
Визуализированы элементы обучающей и тестовой выборки в областях пространства признаков, распознаваемых автокодировщиками AE1 и AE2.
|
||||
|
||||
```python
|
||||
# Построение областей аппроксимации и точек тестового набора
|
||||
lib.plot2in1_anomaly(data, xx, yy, Z1, Z2, data_test)
|
||||
```
|
||||
|
||||

|
||||
|
||||
### 12) Сводная таблица результатов задания №1
|
||||
|
||||
**Табл. 1 Результаты задания №1**
|
||||
|
||||
| | Количество<br>скрытых слоев | Количество<br>нейронов в скрытых слоях | Количество<br>эпох обучения | Ошибка<br>MSE_stop | Порог ошибки<br>реконструкции | Значение показателя<br>Excess | Значение показателя<br>Approx | Количество обнаруженных<br>аномалий |
|
||||
|-----:|------------------------------|----------------------------------------|-----------------------------|--------------------|-------------------------------|-------------------------------|--------------------------------|-------------------------------------|
|
||||
| AE1 | 1 | 1 | 1000 | 0.025 | 0.56 | 5.75 | 0.148 | 0 |
|
||||
| AE2 | 7 | 8-4-2-1-2-4-8 | 3000 | 0.0098 | 0.38 | 0.4 | 0.714 | 4 |
|
||||
|
||||
### 13) Выводы по заданию 1
|
||||
|
||||
На основе проведённых экспериментов сформированы следующие выводы о требованиях к параметрам автокодировщиков для качественного обнаружения аномалий:
|
||||
|
||||
**Требования к данным для обучения:**
|
||||
- Данные для обучения должны быть без аномалий, чтобы автокодировщик смог рассчитать верное пороговое значение ошибки реконструкции.
|
||||
|
||||
**Требования к архитектуре автокодировщика:**
|
||||
- Архитектура должна постепенно сужаться к бутылочному горлышку (bottleneck), а затем постепенно возвращаться к исходным выходным размерам.
|
||||
- Для двумерных данных оптимальное количество скрытых слоёв: 3-6.
|
||||
- Простая архитектура с одним скрытым слоем показывает низкое качество аппроксимации (Excess = 5.75, Approx = 0.148), что подтверждается результатами AE1.
|
||||
|
||||
**Требования к количеству эпох обучения:**
|
||||
- Для простых данных (2D): 1000-3000 эпох.
|
||||
- При использовании ранней остановки (early stopping) обучение может завершиться раньше при достижении оптимальных значений.
|
||||
|
||||
**Требования к ошибке MSE_stop:**
|
||||
- Для двумерных данных: оптимальная ошибка MSE-stop в районе 0.01.
|
||||
- Более высокие значения (например, 0.025) указывают на недостаточное качество обучения и требуют улучшения архитектуры или увеличения количества эпох.
|
||||
|
||||
**Требования к порогу обнаружения аномалий:**
|
||||
- Для двумерных данных: значение порога в районе 0.4-2.5.
|
||||
- Более высокие пороги (например, 0.56) могут пропускать аномалии.
|
||||
|
||||
**Требования к характеристикам качества обучения EDCA:**
|
||||
|
||||
- Значение Excess должно быть как можно ближе к 0. Для AE2 получено 0.4, что является приемлемым.
|
||||
- Значение Deficit должно быть как можно ближе к 0.
|
||||
- Значение Coating должно быть как можно ближе к 1.
|
||||
- Значение Approx должно быть как можно ближе к 1. Для AE2 получено 0.714, что соответствует требованиям.
|
||||
---
|
||||
|
||||
## Задание 2
|
||||
|
||||
### 1) Изучение набора реальных данных Letter
|
||||
|
||||
Бригада 1 работает с набором данных **Letter**. Это реальный набор данных, представляющий собой характеристики букв латинского алфавита, извлечённые из изображений. Каждый пример содержит 32 признака, описывающих различные геометрические и статистические характеристики буквы.
|
||||
|
||||
| Параметр | Значение |
|
||||
|----------|----------|
|
||||
| Количество признаков | 32 |
|
||||
| Количество примеров в обучающей выборке | 1500 |
|
||||
| Количество примеров в тестовой выборке | 500 |
|
||||
|
||||
### 2) Загрузка многомерной обучающей выборки
|
||||
|
||||
Загружена многомерная обучающая выборка реальных данных Letter.
|
||||
|
||||
```python
|
||||
# Загрузка обучающей и тестовой выборки Letter
|
||||
train_letter = np.loadtxt('data/letter_train.txt', dtype=float)
|
||||
test_letter = np.loadtxt('data/letter_test.txt', dtype=float)
|
||||
```
|
||||
|
||||
### 3) Вывод данных и их размерности
|
||||
|
||||
Выведены полученные данные и их размерность в консоль.
|
||||
|
||||
```python
|
||||
print('Обучающая выборка Letter:')
|
||||
print(f'Размерность: {train_letter.shape}')
|
||||
print(f'Количество признаков: {train_letter.shape[1]}')
|
||||
print(f'Количество примеров: {train_letter.shape[0]}')
|
||||
```
|
||||
|
||||
Размерность обучающей выборки: (1500, 32)
|
||||
Размерность тестовой выборки: (500, 32)
|
||||
|
||||
### 4) Нормализация данных (для сравнения результатов)
|
||||
|
||||
Для сравнения результатов обучения создана нормализованная версия данных с использованием StandardScaler.
|
||||
|
||||
```python
|
||||
from sklearn.preprocessing import StandardScaler
|
||||
|
||||
scaler = StandardScaler()
|
||||
train_letter_normalized = scaler.fit_transform(train_letter)
|
||||
test_letter_normalized = scaler.transform(test_letter)
|
||||
```
|
||||
|
||||
### 5) Обучение автокодировщика на ненормализованных данных
|
||||
|
||||
Создан и обучен автокодировщик с подходящей для данных архитектурой на ненормализованных данных. Выбрано необходимое количество эпох обучения.
|
||||
|
||||
```python
|
||||
# Обучение автокодировщика для Letter на НЕнормализованных данных
|
||||
# Входной и выходной слои создаются автоматически по размеру данных (32 признака)
|
||||
# Мы задаем только скрытые слои
|
||||
# Полная архитектура: 32(вход) -> 100 -> 68 -> 48 -> 32 -> 24 -> 16 -> 8 -> 16 -> 24 -> 32 -> 48 -> 64 -> 100 -> 32(выход)
|
||||
# 11 скрытых слоев: 100 64 48 32 24 16 8 16 24 32 48 64 100
|
||||
|
||||
import warnings
|
||||
# Подавляем предупреждение о формате сохранения HDF5
|
||||
warnings.filterwarnings('ignore', category=UserWarning, module='absl')
|
||||
|
||||
print('Обучение автокодировщика для данных Letter (НЕнормализованные данные)...')
|
||||
print('Архитектура: 32(вход) -> 100 -> 68 -> 48 -> 32 -> 24 -> 16 -> 8 -> 16 -> 24 -> 32 -> 48 -> 64 -> 100 -> 32(выход)')
|
||||
|
||||
# Автоматизируем ввод для выбора пользовательской архитектуры
|
||||
with patch('builtins.input', side_effect=['1', '17', ' 100 86 72 64 48 32 24 16 8 16 24 32 48 64 72 86 100']):
|
||||
ae_letter_raw, IRE_letter_raw, IREth_letter_raw = lib.create_fit_save_ae(
|
||||
train_letter,
|
||||
'out/Letter_AE_raw.h5',
|
||||
'out/Letter_AE_raw_ire_th.txt',
|
||||
100000, # epochs
|
||||
False, # verbose_show
|
||||
10000, # patience
|
||||
verbose_every_n_epochs=500
|
||||
)
|
||||
|
||||
# Вычисление MSE из предсказания
|
||||
X_pred_letter_raw = ae_letter_raw.predict(train_letter, verbose=0)
|
||||
mse_letter_raw = np.mean((train_letter - X_pred_letter_raw) ** 2)
|
||||
|
||||
print(f'\nОбучение завершено (НЕнормализованные данные)!')
|
||||
print(f'MSE_stop (приблизительно): {mse_letter_raw:.6f}')
|
||||
print(f'Порог IRE: {IREth_letter_raw:.6f}')
|
||||
print(f'Количество скрытых слоев: 11')
|
||||
print(f'Количество нейронов в скрытых слоях: 100 -> 68 -> 48 -> 32 -> 24 -> 16 -> 8 -> 16 -> 24 -> 32 -> 48 -> 64 -> 100')
|
||||
```
|
||||
|
||||
Архитектура: 32 → 100 → 68 → 48 → 32 → 24 → 16 → 8 → 16 → 24 → 32 → 48 → 64 → 100 → 32
|
||||
Количество скрытых слоёв: 13
|
||||
Нейроны в скрытых слоях: 100 → 68 → 48 → 32 → 24 → 16 → 8 → 16 → 24 → 32 → 48 → 64 → 100
|
||||
|
||||
### 6) Обучение автокодировщика на нормализованных данных
|
||||
|
||||
Создан и обучен автокодировщик с той же архитектурой на нормализованных данных для сравнения результатов.
|
||||
|
||||
```python
|
||||
# Обучение автокодировщика для Letter на нормализованных данных
|
||||
# Та же архитектура для сравнения: 32(вход) -> 100 -> 68 -> 48 -> 32 -> 24 -> 16 -> 8 -> 16 -> 24 -> 32 -> 48 -> 64 -> 100 -> 32(выход)
|
||||
# 11 скрытых слоев: 100 86 72 64 48 32 24 16 8 16 24 32 48 64 72 86 100
|
||||
|
||||
print('Обучение автокодировщика для данных Letter (нормализованные данные)...')
|
||||
print('Архитектура: 32(вход) -> 100 -> 68 -> 48 -> 32 -> 24 -> 16 -> 8 -> 16 -> 24 -> 32 -> 48 -> 64 -> 100 -> 32(выход)')
|
||||
|
||||
# Автоматизируем ввод для выбора пользовательской архитектуры
|
||||
with patch('builtins.input', side_effect=['1', '17', ' 100 86 72 64 48 32 24 16 8 16 24 32 48 64 72 86 100']):
|
||||
ae_letter_norm, IRE_letter_norm, IREth_letter_norm = lib.create_fit_save_ae(
|
||||
train_letter_normalized,
|
||||
'out/Letter_AE_norm.h5',
|
||||
'out/Letter_AE_norm_ire_th.txt',
|
||||
20000, # epochs
|
||||
True, # verbose_show
|
||||
200, # patience
|
||||
verbose_every_n_epochs=500
|
||||
)
|
||||
|
||||
# Вычисление MSE из предсказания
|
||||
X_pred_letter_norm = ae_letter_norm.predict(train_letter_normalized, verbose=0)
|
||||
mse_letter_norm = np.mean((train_letter_normalized - X_pred_letter_norm) ** 2)
|
||||
|
||||
print(f'\nОбучение завершено (нормализованные данные)!')
|
||||
print(f'MSE_stop (приблизительно): {mse_letter_norm:.6f}')
|
||||
print(f'Порог IRE: {IREth_letter_norm:.6f}')
|
||||
print(f'Количество скрытых слоев: 11')
|
||||
print(f'Количество нейронов в скрытых слоях: 100 -> 68 -> 48 -> 32 -> 24 -> 16 -> 8 -> 16 -> 24 -> 32 -> 48 -> 64 -> 100')
|
||||
|
||||
```
|
||||
|
||||
### 7) Сравнение результатов обучения
|
||||
|
||||
Проведено сравнение результатов обучения на нормализованных и ненормализованных данных. Выбрана лучшая модель для дальнейшей работы.
|
||||
|
||||
**Сравнение результатов:**
|
||||
|
||||
| Параметр | Ненормализованные | Нормализованные |
|
||||
|----------|-------------------|-----------------|
|
||||
| MSE_stop | 0.340 | 0.026 |
|
||||
| Порог IRE | 11.1 | 1.62 |
|
||||
|
||||
На основе сравнения результатов выбрана модель, обученная на нормализованных данных, так как она показала значительно лучшее качество (MSE = 0.026 против 0.340) и более низкий порог обнаружения аномалий (1.62 против 11.1).
|
||||
|
||||
### 8) Анализ результатов обучения
|
||||
|
||||
Зафиксирована ошибка MSE, на которой завершилось обучение. Построен график ошибки реконструкции обучающей выборки. Определён порог ошибки реконструкции для обнаружения аномалий.
|
||||
|
||||
```python
|
||||
# Построение графика ошибки реконструкции
|
||||
lib.ire_plot('training', IRE_letter, IREth_letter, 'Letter_AE')
|
||||
```
|
||||
|
||||

|
||||
|
||||
### 9) Применение автокодировщика к тестовой выборке
|
||||
|
||||
Применён обученный автокодировщик к тестовой выборке для обнаружения аномалий. Выведен график ошибки реконструкции элементов тестовой выборки относительно порога.
|
||||
|
||||
```python
|
||||
# Тестирование автокодировщика
|
||||
predicted_labels_letter, ire_letter_test = lib.predict_ae(ae_letter, test_letter_used, IREth_letter)
|
||||
lib.anomaly_detection_ae(predicted_labels_letter, ire_letter_test, IREth_letter)
|
||||
lib.ire_plot('test', ire_letter_test, IREth_letter, 'Letter_AE')
|
||||
```
|
||||
|
||||

|
||||
|
||||
### 10) Сводная таблица результатов задания №2
|
||||
|
||||
**Табл. 2 Результаты задания №2**
|
||||
|
||||
| Dataset | Количество<br>скрытых слоев | Количество<br>нейронов в скрытых слоях | Количество<br>эпох обучения | Ошибка<br>MSE_stop | Порог ошибки<br>реконструкции | % обнаруженных<br>аномалий |
|
||||
|:--------|:----------------------------|:---------------------------------------|:----------------------------|:-------------------|:------------------------------|:---------------------------|
|
||||
| Letter | 13 | 100 → 68 → 48 → 32 → 24 → 16 → 8 → 16 → 24 → 32 → 48 → 64 → 100 | 20000 | 0.026 | 1.62 | 100.0% |
|
||||
|
||||
*Примечание: Результаты получены для модели, обученной на нормализованных данных.*
|
||||
|
||||
### 11) Выводы по заданию 2
|
||||
|
||||
На основе проведённых экспериментов с многомерными данными (32 признака) сформированы следующие выводы:
|
||||
|
||||
**Требования к данным для обучения:**
|
||||
- Данные для обучения должны быть без аномалий, чтобы автокодировщик смог рассчитать верное пороговое значение ошибки реконструкции.
|
||||
- Для многомерных данных нормализация признаков значительно улучшает сходимость обучения и качество обнаружения аномалий. Как показали эксперименты, нормализация снизила MSE с 0.340 до 0.026 и порог IRE с 11.1 до 1.62.
|
||||
|
||||
**Требования к архитектуре автокодировщика:**
|
||||
- Для многомерных данных требуется более сложная архитектура с большим количеством скрытых слоёв.
|
||||
- Архитектура должна постепенно сужаться к бутылочному горлышку (bottleneck), а затем постепенно возвращаться к исходным выходным размерам.
|
||||
- Широкая архитектура с большим количеством нейронов в начальных слоях (например, 100 → 68 → 48 → 32 → 24 → 16 → 8 → 16 → 24 → 32 → 48 → 64 → 100) позволяет лучше аппроксимировать сложные зависимости в многомерных данных.
|
||||
|
||||
**Требования к количеству эпох обучения:**
|
||||
- Для многомерных данных требуется значительно большее количество эпох обучения по сравнению с двумерными данными (1000-3000 эпох).
|
||||
- Использование ранней остановки (early stopping) позволяет автоматически завершить обучение при достижении оптимальных значений.
|
||||
|
||||
**Требования к ошибке MSE_stop:**
|
||||
- Для многомерных данных оптимальная ошибка MSE-stop в районе 0.01-0.01.
|
||||
- Нормализация данных может значительно улучшить качество обучения (пример: MSE снизилась с 0.340 до 0.026 при нормализации).
|
||||
|
||||
**Требования к порогу обнаружения аномалий:**
|
||||
- Для многомерных данных значение порога не больше 1.6.
|
||||
- Нормализация данных позволяет получить более низкий и стабильный порог (пример: порог снизился с 11.1 до 1.62 при нормализации).
|
||||
|
||||
**Требования к характеристикам качества обучения EDCA:**
|
||||
- Значение Excess должно быть как можно ближе к 0.
|
||||
- Значение Deficit должно быть как можно ближе к 0.
|
||||
- Значение Coating должно быть как можно ближе к 1.
|
||||
- Значение Approx должно быть как можно ближе к 1.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Общие выводы
|
||||
|
||||
В ходе выполнения лабораторной работы были исследованы возможности использования автокодировщиков для обнаружения аномалий в данных различной размерности. Показано, что качество обнаружения аномалий существенно зависит от архитектуры автокодировщика, количества эпох обучения, правильного выбора порога ошибки реконструкции и предобработки данных (нормализации).
|
||||
|
||||
**Основные выводы:**
|
||||
|
||||
1. **Влияние размерности данных**: Для многомерных данных требуется более сложная архитектура и большее количество эпох обучения по сравнению с двумерными данными.
|
||||
|
||||
2. **Архитектура**: Архитектура должна постепенно сужаться к бутылочному горлышку и постепенно возвращаться к исходным размерам. Симметричная структура обеспечивает лучшее качество аппроксимации.
|
||||
|
||||
3. **Параметры обучения**: Оптимальные значения MSE-stop и порога ошибки реконструкции различаются для данных разной размерности. Для двумерных данных MSE-stop ≈ 0.01, порог 0.4-2.5. Для многомерных данных MSE-stop ≈ 0.01-0.1, порог ≤ 1.6.
|
||||
|
||||
4. **Метрики качества**: Характеристики EDCA (Excess, Deficit, Coating, Approx) позволяют оценить качество аппроксимации области нормальных данных и пригодность автокодировщика для обнаружения аномалий.
|
||||
|
||||
5. **Нормализация данных**: Для многомерных данных нормализация признаков значительно улучшает сходимость обучения и качество обнаружения аномалий. Экспериментально подтверждено, что нормализация снижает MSE с 0.340 до 0.026 и порог IRE с 11.1 до 1.62, что приводит к обнаружению 100% аномалий в тестовой выборке.
|
||||
|
||||
|
После Ширина: | Высота: | Размер: 315 B |
|
После Ширина: | Высота: | Размер: 273 B |
|
После Ширина: | Высота: | Размер: 6.9 KiB |
|
После Ширина: | Высота: | Размер: 7.0 KiB |
|
После Ширина: | Высота: | Размер: 31 KiB |
|
После Ширина: | Высота: | Размер: 6.7 KiB |
|
После Ширина: | Высота: | Размер: 6.6 KiB |
|
После Ширина: | Высота: | Размер: 121 KiB |
|
После Ширина: | Высота: | Размер: 11 KiB |
|
После Ширина: | Высота: | Размер: 12 KiB |
|
После Ширина: | Высота: | Размер: 61 KiB |
@ -0,0 +1,815 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "oZs0KGcz01BY"
|
||||
},
|
||||
"source": [
|
||||
"## Задание 1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "gz18QPRz03Ec"
|
||||
},
|
||||
"source": [
|
||||
"### 1) Подготовка рабочей среды и импорт библиотек\n",
|
||||
"\n",
|
||||
"Инициализируем рабочую среду Google Colab и подключаем необходимые библиотеки для работы с нейронными сетями и обработки данных."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "mr9IszuQ1ANG"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Подключение необходимых библиотек и модулей\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"from tensorflow import keras\n",
|
||||
"from tensorflow.keras import layers\n",
|
||||
"from tensorflow.keras.models import Sequential\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import numpy as np\n",
|
||||
"from sklearn.metrics import classification_report, confusion_matrix\n",
|
||||
"from sklearn.metrics import ConfusionMatrixDisplay"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "FFRtE0TN1AiA"
|
||||
},
|
||||
"source": [
|
||||
"### 2) Загрузка датасета MNIST\n",
|
||||
"\n",
|
||||
"Загружаем стандартный набор данных MNIST, который содержит изображения рукописных цифр от 0 до 9 с соответствующими метками."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "Ixw5Sp0_1A-w"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Импорт и загрузка датасета MNIST\n",
|
||||
"from keras.datasets import mnist\n",
|
||||
"(X_train, y_train), (X_test, y_test) = mnist.load_data()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "aCo_lUXl1BPV"
|
||||
},
|
||||
"source": [
|
||||
"### 3) Разделение данных на обучающую и тестовую выборки\n",
|
||||
"\n",
|
||||
"Производим собственное разбиение датасета в соотношении 60 000:10 000. Для воспроизводимости результатов используем параметр random_state = 3 (вычисляется как 4k - 1, где k = 1 - номер нашей бригады)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "BrSjcpEe1BeV"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Создание собственного разбиения датасета\n",
|
||||
"from sklearn.model_selection import train_test_split\n",
|
||||
"\n",
|
||||
"# Объединение исходных обучающей и тестовой выборок в единый набор\n",
|
||||
"X = np.concatenate((X_train, X_test))\n",
|
||||
"y = np.concatenate((y_train, y_test))\n",
|
||||
"\n",
|
||||
"# Разделение на обучающую и тестовую выборки согласно заданию\n",
|
||||
"X_train, X_test, y_train, y_test = train_test_split(X, y,\n",
|
||||
" test_size = 10000,\n",
|
||||
" train_size = 60000,\n",
|
||||
" random_state = 3)\n",
|
||||
"# Вывод размерностей полученных массивов\n",
|
||||
"print('Shape of X train:', X_train.shape)\n",
|
||||
"print('Shape of y train:', y_train.shape)\n",
|
||||
"print('Shape of X test:', X_test.shape)\n",
|
||||
"print('Shape of y test:', y_test.shape)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "4hclnNaD1BuB"
|
||||
},
|
||||
"source": [
|
||||
"### 4) Предобработка данных\n",
|
||||
"\n",
|
||||
"Выполняем нормализацию пикселей изображений (приведение к диапазону [0, 1]) и преобразование меток в формат one-hot encoding для корректной работы с категориальной функцией потерь."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "xJH87ISq1B9h"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Определение параметров данных и модели\n",
|
||||
"num_classes = 10\n",
|
||||
"input_shape = (28, 28, 1)\n",
|
||||
"\n",
|
||||
"# Нормализация значений пикселей: приведение к диапазону [0, 1]\n",
|
||||
"X_train = X_train / 255\n",
|
||||
"X_test = X_test / 255\n",
|
||||
"\n",
|
||||
"# Расширяем размерность входных данных, чтобы каждое изображение имело\n",
|
||||
"# размерность (высота, ширина, количество каналов)\n",
|
||||
"\n",
|
||||
"X_train = np.expand_dims(X_train, -1)\n",
|
||||
"X_test = np.expand_dims(X_test, -1)\n",
|
||||
"print('Shape of transformed X train:', X_train.shape)\n",
|
||||
"print('Shape of transformed X test:', X_test.shape)\n",
|
||||
"\n",
|
||||
"# Преобразование меток в формат one-hot encoding\n",
|
||||
"y_train = keras.utils.to_categorical(y_train, num_classes)\n",
|
||||
"y_test = keras.utils.to_categorical(y_test, num_classes)\n",
|
||||
"print('Shape of transformed y train:', y_train.shape)\n",
|
||||
"print('Shape of transformed y test:', y_test.shape)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "7x99O8ig1CLh"
|
||||
},
|
||||
"source": [
|
||||
"### 5) Построение и обучение сверточной нейронной сети\n",
|
||||
"\n",
|
||||
"Создаем архитектуру сверточной нейронной сети с использованием сверточных слоев, пулинга и регуляризации. Обучаем модель на подготовленных данных с выделением части данных для валидации."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "Un561zSH1Cmv"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Создание модели сверточной нейронной сети\n",
|
||||
"model = Sequential()\n",
|
||||
"model.add(layers.Conv2D(32, kernel_size=(3, 3), activation=\"relu\", input_shape=input_shape))\n",
|
||||
"model.add(layers.MaxPooling2D(pool_size=(2, 2)))\n",
|
||||
"model.add(layers.Conv2D(64, kernel_size=(3, 3), activation=\"relu\"))\n",
|
||||
"model.add(layers.MaxPooling2D(pool_size=(2, 2)))\n",
|
||||
"model.add(layers.Dropout(0.5))\n",
|
||||
"model.add(layers.Flatten())\n",
|
||||
"model.add(layers.Dense(num_classes, activation=\"softmax\"))\n",
|
||||
"\n",
|
||||
"model.summary()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "q_h8PxkN9m0v"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Компиляция и обучение модели\n",
|
||||
"batch_size = 512\n",
|
||||
"epochs = 15\n",
|
||||
"model.compile(loss=\"categorical_crossentropy\", optimizer=\"adam\", metrics=[\"accuracy\"])\n",
|
||||
"model.fit(X_train, y_train, batch_size=batch_size, epochs=epochs, validation_split=0.1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "HL2_LVga1C3l"
|
||||
},
|
||||
"source": [
|
||||
"### 6) Оценка качества модели на тестовых данных\n",
|
||||
"\n",
|
||||
"Проводим финальную оценку обученной модели на независимой тестовой выборке, получая значения функции потерь и точности классификации."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "81Cgq8dn9uL6"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Оценка качества работы обученной модели на тестовой выборке\n",
|
||||
"scores = model.evaluate(X_test, y_test)\n",
|
||||
"print('Loss on test data:', scores[0])\n",
|
||||
"print('Accuracy on test data:', scores[1])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "KzrVY1SR1DZh"
|
||||
},
|
||||
"source": [
|
||||
"### 7) Демонстрация работы модели на отдельных примерах\n",
|
||||
"\n",
|
||||
"Визуализируем результаты распознавания для двух тестовых изображений, сравнивая предсказания модели с истинными метками."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "dbfkWjDI1Dp7"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Визуализация результатов распознавания для двух тестовых изображений\n",
|
||||
"\n",
|
||||
"for n in [3,26]:\n",
|
||||
" result = model.predict(X_test[n:n+1])\n",
|
||||
" print('NN output:', result)\n",
|
||||
"\n",
|
||||
" plt.imshow(X_test[n].reshape(28,28), cmap=plt.get_cmap('gray'))\n",
|
||||
" plt.show()\n",
|
||||
" print('Real mark: ', np.argmax(y_test[n]))\n",
|
||||
" print('NN answer: ', np.argmax(result))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "YgiVGr5_1D3u"
|
||||
},
|
||||
"source": [
|
||||
"### 8) Детальный анализ качества классификации\n",
|
||||
"\n",
|
||||
"Генерируем подробный отчет о качестве классификации и строим матрицу ошибок для визуального анализа работы модели по каждому классу."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "7MqcG_wl1EHI"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Получение истинных и предсказанных меток для всех тестовых данных\n",
|
||||
"true_labels = np.argmax(y_test, axis=1)\n",
|
||||
"\n",
|
||||
"predicted_labels = np.argmax(model.predict(X_test), axis=1)\n",
|
||||
"\n",
|
||||
"# Вывод подробного отчета о качестве классификации\n",
|
||||
"print(classification_report(true_labels, predicted_labels))\n",
|
||||
"# Построение и визуализация матрицы ошибок\n",
|
||||
"conf_matrix = confusion_matrix(true_labels, predicted_labels)\n",
|
||||
"\n",
|
||||
"display = ConfusionMatrixDisplay(confusion_matrix=conf_matrix)\n",
|
||||
"display.plot()\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "amaspXGW1EVy"
|
||||
},
|
||||
"source": [
|
||||
"### 9) Тестирование на собственных изображениях\n",
|
||||
"\n",
|
||||
"Загружаем и обрабатываем собственные изображения цифр, созданные ранее, и проверяем способность модели их корректно распознавать."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "ktWEeqWd1EyF"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Загрузка и обработка собственных изображений\n",
|
||||
"from PIL import Image\n",
|
||||
"\n",
|
||||
"for name_image in ['2.png', '7.png']:\n",
|
||||
" file_data = Image.open(name_image)\n",
|
||||
" file_data = file_data.convert('L') # перевод в градации серого\n",
|
||||
" test_img = np.array(file_data)\n",
|
||||
"\n",
|
||||
" # вывод собственного изображения\n",
|
||||
" plt.imshow(test_img, cmap=plt.get_cmap('gray'))\n",
|
||||
" plt.show()\n",
|
||||
"\n",
|
||||
" # предобработка\n",
|
||||
" test_img = test_img / 255\n",
|
||||
" test_img = np.reshape(test_img, (1,28,28,1))\n",
|
||||
"\n",
|
||||
" # распознавание\n",
|
||||
" result = model.predict(test_img)\n",
|
||||
" print('I think it\\'s', np.argmax(result))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "mgrihPd61E8w"
|
||||
},
|
||||
"source": [
|
||||
"### 10) Сравнение с моделью из предыдущей лабораторной работы\n",
|
||||
"\n",
|
||||
"Загружаем сохраненную полносвязную нейронную сеть из лабораторной работы №1 и оцениваем ее производительность на тех же тестовых данных для последующего сравнения."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "DblXqn3l1FL2"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"model_lr1 = keras.models.load_model(\"best_mnist_model.keras\")\n",
|
||||
"\n",
|
||||
"model_lr1.summary()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "0ki8fhJrEyEt"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Подготовка данных для полносвязной сети (преобразование изображений в векторы)\n",
|
||||
"X_train, X_test, y_train, y_test = train_test_split(X, y,\n",
|
||||
" test_size = 10000,\n",
|
||||
" train_size = 60000,\n",
|
||||
" random_state = 3)\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)\n",
|
||||
"print('Shape of transformed X train:', X_test.shape)\n",
|
||||
"\n",
|
||||
"# Преобразование меток в формат one-hot encoding\n",
|
||||
"y_train = keras.utils.to_categorical(y_train, num_classes)\n",
|
||||
"y_test = keras.utils.to_categorical(y_test, num_classes)\n",
|
||||
"print('Shape of transformed y train:', y_train.shape)\n",
|
||||
"print('Shape of transformed y test:', y_test.shape)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "0Yj0fzLNE12k"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Оценка качества работы обученной модели на тестовой выборке\n",
|
||||
"scores = model_lr1.evaluate(X_test, y_test)\n",
|
||||
"print('Loss on test data:', scores[0])\n",
|
||||
"print('Accuracy on test data:', scores[1])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "MsM3ew3d1FYq"
|
||||
},
|
||||
"source": [
|
||||
"### 11) Сравнительный анализ моделей\n",
|
||||
"\n",
|
||||
"Сравниваем сверточную нейронную сеть с полносвязной сетью по ключевым показателям: количеству параметров, времени обучения и качеству классификации."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "xxFO4CXbIG88"
|
||||
},
|
||||
"source": [
|
||||
"Таблица1:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "xvoivjuNFlEf"
|
||||
},
|
||||
"source": [
|
||||
"| Модель | Количество настраиваемых параметров | Количество эпох обучения | Качество классификации тестовой выборки |\n",
|
||||
"|----------|-------------------------------------|---------------------------|-----------------------------------------|\n",
|
||||
"| Сверточная | 34 826 | 15 | accuracy: 0.988; loss: 0.041 |\n",
|
||||
"| Полносвязная | 7 852 | 50 | accuracy: 0.923; loss: 0.286 |\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "YctF8h_sIB-P"
|
||||
},
|
||||
"source": [
|
||||
"**Выводы:**\n",
|
||||
"\n",
|
||||
"На основе проведенного анализа можно заключить, что сверточная нейронная сеть демонстрирует существенные преимущества перед полносвязной сетью при решении задач распознавания изображений:\n",
|
||||
"\n",
|
||||
"1. **Эффективность параметров**: Сверточная сеть имеет больше параметров (34 826 против 7 852), но при этом показывает значительно лучшие результаты, что говорит о более эффективном использовании параметров для извлечения пространственных признаков.\n",
|
||||
"\n",
|
||||
"2. **Скорость обучения**: Для достижения высокого качества сверточной сети требуется в 3.3 раза меньше эпох обучения (15 против 50), что существенно сокращает время обучения.\n",
|
||||
"\n",
|
||||
"3. **Точность классификации**: Сверточная сеть показывает более высокую точность (98.8% против 92.3%) и значительно меньшую функцию потерь (0.041 против 0.286). Разница в точности составляет 6.5%, что является существенным улучшением.\n",
|
||||
"\n",
|
||||
"4. **Обобщающая способность**: Сверточная сеть демонстрирует лучшую способность к обобщению, что видно из более низкой функции потерь на тестовых данных.\n",
|
||||
"\n",
|
||||
"Эти результаты подтверждают, что архитектура сверточных сетей, учитывающая пространственную структуру изображений через операции свертки и пулинга, является более подходящим выбором для задач компьютерного зрения, несмотря на большее количество параметров."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "wCLHZPGB1F1y"
|
||||
},
|
||||
"source": [
|
||||
"## Задание 2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "DUOYls124TT8"
|
||||
},
|
||||
"source": [
|
||||
"### В новом блокноте выполнили п. 2–8 задания 1, изменив набор данных MNIST на CIFAR-10, содержащий размеченные цветные изображения объектов, разделенные на 10 классов. \n",
|
||||
"### При этом:\n",
|
||||
"### - в п. 3 разбиение данных на обучающие и тестовые произвели в соотношении 50 000:10 000\n",
|
||||
"### - после разбиения данных (между п. 3 и 4) вывели 25 изображений из обучающей выборки с подписями классов\n",
|
||||
"### - в п. 7 одно из тестовых изображений должно распознаваться корректно, а другое – ошибочно. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "XDStuSpEJa8o"
|
||||
},
|
||||
"source": [
|
||||
"### 1) Загрузка датасета CIFAR-10\n",
|
||||
"\n",
|
||||
"Загружаем набор данных CIFAR-10, который содержит цветные изображения размером 32x32 пикселя, разделенные на 10 классов: самолет, автомобиль, птица, кошка, олень, собака, лягушка, лошадь, корабль, грузовик."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "y0qK7eKL4Tjy"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Импорт и загрузка датасета MNIST\n",
|
||||
"from keras.datasets import cifar10\n",
|
||||
"\n",
|
||||
"(X_train, y_train), (X_test, y_test) = cifar10.load_data()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "wTHiBy-ZJ5oh"
|
||||
},
|
||||
"source": [
|
||||
"### 2) Разделение данных на обучающую и тестовую выборки\n",
|
||||
"\n",
|
||||
"Создаем собственное разбиение датасета CIFAR-10 в соотношении 50 000:10 000. Используем random_state = 3 для воспроизводимости результатов (k = 1 - номер нашей бригады)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "DlnFbQogKD2v"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Создание собственного разбиения датасета\n",
|
||||
"\n",
|
||||
"# Объединение исходных обучающей и тестовой выборок в единый набор\n",
|
||||
"X = np.concatenate((X_train, X_test))\n",
|
||||
"y = np.concatenate((y_train, y_test))\n",
|
||||
"\n",
|
||||
"# Разделение на обучающую и тестовую выборки согласно заданию\n",
|
||||
"X_train, X_test, y_train, y_test = train_test_split(X, y,\n",
|
||||
" test_size = 10000,\n",
|
||||
" train_size = 50000,\n",
|
||||
" random_state = 3)\n",
|
||||
"# Вывод размерностей полученных массивов\n",
|
||||
"print('Shape of X train:', X_train.shape)\n",
|
||||
"print('Shape of y train:', y_train.shape)\n",
|
||||
"print('Shape of X test:', X_test.shape)\n",
|
||||
"print('Shape of y test:', y_test.shape)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "pj3bMaz1KZ3a"
|
||||
},
|
||||
"source": [
|
||||
"### Визуализация примеров из обучающей выборки\n",
|
||||
"\n",
|
||||
"Отображаем сетку из 25 изображений из обучающей выборки с подписями соответствующих классов для визуального ознакомления с данными."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "TW8D67KEKhVE"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer',\n",
|
||||
" 'dog', 'frog', 'horse', 'ship', 'truck']\n",
|
||||
"\n",
|
||||
"plt.figure(figsize=(10,10))\n",
|
||||
"for i in range(25):\n",
|
||||
" plt.subplot(5,5,i+1)\n",
|
||||
" plt.xticks([])\n",
|
||||
" plt.yticks([])\n",
|
||||
" plt.grid(False)\n",
|
||||
" plt.imshow(X_train[i])\n",
|
||||
" plt.xlabel(class_names[y_train[i][0]])\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "d3TPr2w1KQTK"
|
||||
},
|
||||
"source": [
|
||||
"### 3) Предобработка данных CIFAR-10\n",
|
||||
"\n",
|
||||
"Нормализуем значения пикселей и преобразуем метки в формат one-hot encoding для работы с категориальной функцией потерь."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "iFDpxEauLZ8j"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Определение параметров данных и модели\n",
|
||||
"num_classes = 10\n",
|
||||
"input_shape = (32, 32, 3)\n",
|
||||
"\n",
|
||||
"# Нормализация значений пикселей: приведение к диапазону [0, 1]\n",
|
||||
"X_train = X_train / 255\n",
|
||||
"X_test = X_test / 255\n",
|
||||
"\n",
|
||||
"print('Shape of transformed X train:', X_train.shape)\n",
|
||||
"print('Shape of transformed X test:', X_test.shape)\n",
|
||||
"\n",
|
||||
"# Преобразование меток в формат one-hot encoding\n",
|
||||
"y_train = keras.utils.to_categorical(y_train, num_classes)\n",
|
||||
"y_test = keras.utils.to_categorical(y_test, num_classes)\n",
|
||||
"print('Shape of transformed y train:', y_train.shape)\n",
|
||||
"print('Shape of transformed y test:', y_test.shape)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "ydNITXptLeGT"
|
||||
},
|
||||
"source": [
|
||||
"### 4) Построение и обучение сверточной сети для CIFAR-10\n",
|
||||
"\n",
|
||||
"Создаем более сложную архитектуру сверточной сети с использованием батч-нормализации и нескольких блоков свертки для работы с цветными изображениями."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "YhAD5CllLlv7"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Создание модели сверточной нейронной сети\n",
|
||||
"model = Sequential()\n",
|
||||
"\n",
|
||||
"# Блок 1\n",
|
||||
"model.add(layers.Conv2D(32, (3, 3), padding=\"same\",\n",
|
||||
" activation=\"relu\", input_shape=input_shape))\n",
|
||||
"model.add(layers.BatchNormalization())\n",
|
||||
"model.add(layers.Conv2D(32, (3, 3), padding=\"same\", activation=\"relu\"))\n",
|
||||
"model.add(layers.BatchNormalization())\n",
|
||||
"model.add(layers.MaxPooling2D((2, 2)))\n",
|
||||
"model.add(layers.Dropout(0.25))\n",
|
||||
"\n",
|
||||
"# Блок 2\n",
|
||||
"model.add(layers.Conv2D(64, (3, 3), padding=\"same\", activation=\"relu\"))\n",
|
||||
"model.add(layers.BatchNormalization())\n",
|
||||
"model.add(layers.Conv2D(64, (3, 3), padding=\"same\", activation=\"relu\"))\n",
|
||||
"model.add(layers.BatchNormalization())\n",
|
||||
"model.add(layers.MaxPooling2D((2, 2)))\n",
|
||||
"model.add(layers.Dropout(0.25))\n",
|
||||
"\n",
|
||||
"# Блок 3\n",
|
||||
"model.add(layers.Conv2D(128, (3, 3), padding=\"same\", activation=\"relu\"))\n",
|
||||
"model.add(layers.BatchNormalization())\n",
|
||||
"model.add(layers.Conv2D(128, (3, 3), padding=\"same\", activation=\"relu\"))\n",
|
||||
"model.add(layers.BatchNormalization())\n",
|
||||
"model.add(layers.MaxPooling2D((2, 2)))\n",
|
||||
"model.add(layers.Dropout(0.4))\n",
|
||||
"\n",
|
||||
"model.add(layers.Flatten())\n",
|
||||
"model.add(layers.Dense(128, activation='relu'))\n",
|
||||
"model.add(layers.Dropout(0.5))\n",
|
||||
"model.add(layers.Dense(num_classes, activation=\"softmax\"))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"model.summary()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "3otvqMjjOdq5"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Компиляция и обучение модели\n",
|
||||
"batch_size = 64\n",
|
||||
"epochs = 50\n",
|
||||
"model.compile(loss=\"categorical_crossentropy\", optimizer=\"adam\", metrics=[\"accuracy\"])\n",
|
||||
"model.fit(X_train, y_train, batch_size=batch_size, epochs=epochs, validation_split=0.1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "Vv1kUHWTLl9B"
|
||||
},
|
||||
"source": [
|
||||
"### 5) Оценка качества модели на тестовых данных\n",
|
||||
"\n",
|
||||
"Оцениваем финальную производительность обученной модели на тестовой выборке CIFAR-10."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "SaDxydiyLmRX"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Оценка качества работы обученной модели на тестовой выборке\n",
|
||||
"scores = model.evaluate(X_test, y_test)\n",
|
||||
"print('Loss on test data:', scores[0])\n",
|
||||
"print('Accuracy on test data:', scores[1])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "OdgEiyUGLmhP"
|
||||
},
|
||||
"source": [
|
||||
"### 6) Демонстрация работы модели на отдельных примерах\n",
|
||||
"\n",
|
||||
"Визуализируем результаты распознавания для двух тестовых изображений: одно должно быть распознано корректно, другое - ошибочно."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "t3yGj1MlLm9H"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Визуализация результатов распознавания для двух тестовых изображений\n",
|
||||
"\n",
|
||||
"for n in [3,14]:\n",
|
||||
" result = model.predict(X_test[n:n+1])\n",
|
||||
" print('NN output:', result)\n",
|
||||
"\n",
|
||||
" plt.imshow(X_test[n].reshape(32,32,3), cmap=plt.get_cmap('gray'))\n",
|
||||
" plt.show()\n",
|
||||
" print('Real mark: ', np.argmax(y_test[n]))\n",
|
||||
" print('NN answer: ', np.argmax(result))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "3h6VGDRrLnNC"
|
||||
},
|
||||
"source": [
|
||||
"### 7) Детальный анализ качества классификации CIFAR-10\n",
|
||||
"\n",
|
||||
"Генерируем подробный отчет о качестве классификации и строим матрицу ошибок для анализа работы модели по каждому классу."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "od56oyyzM0nw"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Получение истинных и предсказанных меток для всех тестовых данных\n",
|
||||
"true_labels = np.argmax(y_test, axis=1)\n",
|
||||
"\n",
|
||||
"predicted_labels = np.argmax(model.predict(X_test), axis=1)\n",
|
||||
"\n",
|
||||
"# Вывод подробного отчета о качестве классификации\n",
|
||||
"print(classification_report(true_labels, predicted_labels, target_names=class_names))\n",
|
||||
"# Построение и визуализация матрицы ошибок\n",
|
||||
"conf_matrix = confusion_matrix(true_labels, predicted_labels)\n",
|
||||
"\n",
|
||||
"fig, ax = plt.subplots(figsize=(6, 6))\n",
|
||||
"disp = ConfusionMatrixDisplay(confusion_matrix=conf_matrix,display_labels=class_names)\n",
|
||||
"disp.plot(ax=ax, xticks_rotation=45) # поворот подписей по X и приятная палитра\n",
|
||||
"plt.tight_layout() # чтобы всё влезло\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "RF4xK1cxamBc"
|
||||
},
|
||||
"source": [
|
||||
"**Выводы по результатам классификации CIFAR-10:**\n",
|
||||
"\n",
|
||||
"Разработанная сверточная нейронная сеть показала хорошие результаты при классификации цветных изображений из датасета CIFAR-10. Модель достигла точности классификации около 86%, что является достойным результатом для данной задачи, учитывая сложность различения объектов в низком разрешении (32x32 пикселя) и наличие 10 различных классов.\n",
|
||||
"\n",
|
||||
"Использование батч-нормализации и dropout-регуляризации позволило улучшить обобщающую способность модели и предотвратить переобучение. Архитектура с тремя блоками сверточных слоев эффективно извлекает иерархические признаки из изображений, что подтверждается полученными метриками качества."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"accelerator": "GPU",
|
||||
"colab": {
|
||||
"gpuType": "T4",
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"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": 0
|
||||
}
|
||||
@ -0,0 +1,612 @@
|
||||
# Отчёт по лабораторной работе №3
|
||||
|
||||
**Троянов Д.С., Чернов Д.Е. — А-01-22**
|
||||
|
||||
---
|
||||
|
||||
## Задание 1
|
||||
|
||||
### 1) Подготовка рабочей среды и импорт библиотек
|
||||
|
||||
Инициализируем рабочую среду и подключаем необходимые библиотеки для работы с нейронными сетями и обработки данных. Также настраиваем SSL для корректной загрузки датасетов.
|
||||
|
||||
```python
|
||||
# Подключение необходимых библиотек и модулей
|
||||
import os
|
||||
import ssl
|
||||
|
||||
# Обход проблемы с SSL сертификатами на macOS
|
||||
ssl._create_default_https_context = ssl._create_unverified_context
|
||||
|
||||
# Для работы в Google Colab раскомментируйте следующую строку:
|
||||
# os.chdir('/content/drive/MyDrive/Colab Notebooks/is_lab3')
|
||||
|
||||
from tensorflow import keras
|
||||
from tensorflow.keras import layers
|
||||
from tensorflow.keras.models import Sequential
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
from sklearn.metrics import classification_report, confusion_matrix
|
||||
from sklearn.metrics import ConfusionMatrixDisplay
|
||||
```
|
||||
|
||||
### 2) Загрузка датасета MNIST
|
||||
|
||||
Загружаем стандартный набор данных MNIST, который содержит изображения рукописных цифр от 0 до 9 с соответствующими метками.
|
||||
|
||||
```python
|
||||
# Импорт и загрузка датасета MNIST
|
||||
from keras.datasets import mnist
|
||||
(X_train, y_train), (X_test, y_test) = mnist.load_data()
|
||||
```
|
||||
|
||||
### 3) Разделение данных на обучающую и тестовую выборки
|
||||
|
||||
Производим собственное разбиение датасета в соотношении 60 000:10 000. Для воспроизводимости результатов используем параметр random_state = 3 (вычисляется как 4k - 1, где k = 1 - номер нашей бригады). Выводим размерности полученных массивов данных.
|
||||
|
||||
```python
|
||||
# Создание собственного разбиения датасета
|
||||
from sklearn.model_selection import train_test_split
|
||||
|
||||
# Объединение исходных обучающей и тестовой выборок в единый набор
|
||||
X = np.concatenate((X_train, X_test))
|
||||
y = np.concatenate((y_train, y_test))
|
||||
|
||||
# Разделение на обучающую и тестовую выборки согласно заданию
|
||||
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) Предобработка данных
|
||||
|
||||
Выполняем нормализацию пикселей изображений (приведение к диапазону [0, 1]) и преобразование меток в формат one-hot encoding для корректной работы с категориальной функцией потерь. Выводим размерности предобработанных массивов данных.
|
||||
|
||||
```python
|
||||
# Определение параметров данных и модели
|
||||
num_classes = 10
|
||||
input_shape = (28, 28, 1)
|
||||
|
||||
# Нормализация значений пикселей: приведение к диапазону [0, 1]
|
||||
X_train = X_train / 255
|
||||
X_test = X_test / 255
|
||||
|
||||
# Добавление размерности канала для корректной работы с Conv2D слоями
|
||||
# Преобразование из (высота, ширина) в (высота, ширина, каналы)
|
||||
X_train = np.expand_dims(X_train, -1)
|
||||
X_test = np.expand_dims(X_test, -1)
|
||||
print('Shape of transformed X train:', X_train.shape)
|
||||
print('Shape of transformed X test:', X_test.shape)
|
||||
|
||||
# Преобразование меток в формат one-hot encoding
|
||||
y_train = keras.utils.to_categorical(y_train, num_classes)
|
||||
y_test = keras.utils.to_categorical(y_test, num_classes)
|
||||
print('Shape of transformed y train:', y_train.shape)
|
||||
print('Shape of transformed y test:', y_test.shape)
|
||||
```
|
||||
```
|
||||
Shape of transformed X train: (60000, 28, 28, 1)
|
||||
Shape of transformed X test: (10000, 28, 28, 1)
|
||||
Shape of transformed y train: (60000, 10)
|
||||
Shape of transformed y test: (10000, 10)
|
||||
```
|
||||
|
||||
### 5) Построение и обучение сверточной нейронной сети
|
||||
|
||||
Создаем архитектуру сверточной нейронной сети с использованием сверточных слоев, пулинга и регуляризации. Обучаем модель на подготовленных данных с выделением части данных для валидации. Выводим информацию об архитектуре нейронной сети.
|
||||
|
||||
```python
|
||||
# Создание модели сверточной нейронной сети
|
||||
model = Sequential()
|
||||
model.add(layers.Conv2D(32, kernel_size=(3, 3), activation="relu", input_shape=input_shape))
|
||||
model.add(layers.MaxPooling2D(pool_size=(2, 2)))
|
||||
model.add(layers.Conv2D(64, kernel_size=(3, 3), activation="relu"))
|
||||
model.add(layers.MaxPooling2D(pool_size=(2, 2)))
|
||||
model.add(layers.Dropout(0.5))
|
||||
model.add(layers.Flatten())
|
||||
model.add(layers.Dense(num_classes, activation="softmax"))
|
||||
|
||||
model.summary()
|
||||
```
|
||||
**Model: "sequential"**
|
||||
| Layer (type) | Output Shape | Param # |
|
||||
|--------------------------------|---------------------|--------:|
|
||||
| conv2d (Conv2D) | (None, 26, 26, 32) | 320 |
|
||||
| max_pooling2d (MaxPooling2D) | (None, 13, 13, 32) | 0 |
|
||||
| conv2d_1 (Conv2D) | (None, 11, 11, 64) | 18,496 |
|
||||
| max_pooling2d_1 (MaxPooling2D) | (None, 5, 5, 64) | 0 |
|
||||
| dropout (Dropout) | (None, 5, 5, 64) | 0 |
|
||||
| flatten (Flatten) | (None, 1600) | 0 |
|
||||
| dense (Dense) | (None, 10) | 16,010 |
|
||||
**Total params:** 34,826 (136.04 KB)
|
||||
**Trainable params:** 34,826 (136.04 KB)
|
||||
**Non-trainable params:** 0 (0.00 B)
|
||||
|
||||
```python
|
||||
# Компиляция и обучение модели
|
||||
batch_size = 512
|
||||
epochs = 15
|
||||
model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])
|
||||
model.fit(X_train, y_train, batch_size=batch_size, epochs=epochs, validation_split=0.1)
|
||||
```
|
||||
|
||||
### 6) Оценка качества модели на тестовых данных
|
||||
|
||||
Проводим финальную оценку обученной модели на независимой тестовой выборке, получая значения функции потерь и точности классификации.
|
||||
|
||||
```python
|
||||
# Оценка качества работы обученной модели на тестовой выборке
|
||||
scores = model.evaluate(X_test, y_test)
|
||||
print('Loss on test data:', scores[0])
|
||||
print('Accuracy on test data:', scores[1])
|
||||
```
|
||||
```
|
||||
313/313 ━━━━━━━━━━━━━━━━━━━━ 1s 4ms/step - accuracy: 0.9884 - loss: 0.0409
|
||||
Loss on test data: 0.04092026501893997
|
||||
Accuracy on test data: 0.9883999824523926
|
||||
```
|
||||
|
||||
### 7) Демонстрация работы модели на отдельных примерах
|
||||
|
||||
Визуализируем результаты распознавания для двух тестовых изображений, сравнивая предсказания модели с истинными метками.
|
||||
|
||||
```python
|
||||
# Визуализация результатов распознавания для двух тестовых изображений
|
||||
|
||||
for n in [3,26]:
|
||||
result = 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: ', np.argmax(y_test[n]))
|
||||
print('NN answer: ', np.argmax(result))
|
||||
```
|
||||

|
||||
```
|
||||
Real mark: 6
|
||||
NN answer: 6
|
||||
```
|
||||

|
||||
```
|
||||
Real mark: 3
|
||||
NN answer: 3
|
||||
```
|
||||
|
||||
### 8) Детальный анализ качества классификации
|
||||
|
||||
Генерируем подробный отчет о качестве классификации и строим матрицу ошибок для визуального анализа работы модели по каждому классу.
|
||||
|
||||
```python
|
||||
# Получение истинных и предсказанных меток для всех тестовых данных
|
||||
true_labels = np.argmax(y_test, axis=1)
|
||||
# Предсказанные метки классов
|
||||
predicted_labels = np.argmax(model.predict(X_test), axis=1)
|
||||
|
||||
# Вывод подробного отчета о качестве классификации
|
||||
print(classification_report(true_labels, predicted_labels))
|
||||
# Построение и визуализация матрицы ошибок
|
||||
conf_matrix = confusion_matrix(true_labels, predicted_labels)
|
||||
# Отрисовка матрицы ошибок в виде "тепловой карты"
|
||||
display = ConfusionMatrixDisplay(confusion_matrix=conf_matrix)
|
||||
display.plot()
|
||||
plt.show()
|
||||
```
|
||||
```
|
||||
313/313 ━━━━━━━━━━━━━━━━━━━━ 2s 5ms/step
|
||||
precision recall f1-score support
|
||||
|
||||
0 1.00 0.99 1.00 1001
|
||||
1 0.99 1.00 0.99 1143
|
||||
2 0.99 0.99 0.99 987
|
||||
3 0.99 0.99 0.99 1023
|
||||
4 0.99 0.99 0.99 974
|
||||
5 1.00 0.98 0.99 907
|
||||
6 0.99 0.99 0.99 974
|
||||
7 0.98 0.99 0.99 1032
|
||||
8 0.98 0.98 0.98 1006
|
||||
9 0.98 0.99 0.98 953
|
||||
|
||||
accuracy 0.99 10000
|
||||
macro avg 0.99 0.99 0.99 10000
|
||||
weighted avg 0.99 0.99 0.99 10000
|
||||
```
|
||||

|
||||
|
||||
### 9) Тестирование на собственных изображениях
|
||||
|
||||
Загружаем и обрабатываем собственные изображения цифр, созданные ранее, и проверяем способность модели их корректно распознавать.
|
||||
|
||||
```python
|
||||
# Загрузка и обработка собственных изображений
|
||||
from PIL import Image
|
||||
|
||||
for name_image in ['2.png', '7.png']:
|
||||
file_data = Image.open(name_image)
|
||||
file_data = file_data.convert('L') # Перевод в градации серого
|
||||
test_img = np.array(file_data)
|
||||
|
||||
# Вывод собственного изображения
|
||||
plt.imshow(test_img, cmap=plt.get_cmap('gray'))
|
||||
plt.show()
|
||||
|
||||
# Предобработка
|
||||
test_img = test_img / 255
|
||||
test_img = np.reshape(test_img, (1,28,28,1))
|
||||
|
||||
# Распознавание
|
||||
result = model.predict(test_img)
|
||||
print('I think it\'s', np.argmax(result))
|
||||
```
|
||||

|
||||
```
|
||||
I think it's 2
|
||||
```
|
||||

|
||||
```
|
||||
I think it's 7
|
||||
```
|
||||
|
||||
### 10) Сравнение с моделью из предыдущей лабораторной работы
|
||||
|
||||
Загружаем сохраненную полносвязную нейронную сеть из лабораторной работы №1 и оцениваем ее производительность на тех же тестовых данных для последующего сравнения.
|
||||
|
||||
```python
|
||||
model_lr1 = keras.models.load_model("best_mnist_model.keras")
|
||||
|
||||
model_lr1.summary()
|
||||
```
|
||||
**Model: "sequential"**
|
||||
| Layer (type) | Output Shape | Param # |
|
||||
|------------------|-------------:|--------:|
|
||||
| dense (Dense) | (None, 10) | 7,850 |
|
||||
**Total params:** 7,852 (30.68 KB)
|
||||
**Trainable params:** 7,850 (30.66 KB)
|
||||
**Non-trainable params:** 0 (0.00 B)
|
||||
**Optimizer params:** 2 (12.00 B)
|
||||
|
||||
|
||||
```python
|
||||
# Подготовка данных для полносвязной сети (преобразование изображений в векторы)
|
||||
X_train, X_test, y_train, y_test = train_test_split(X, y,
|
||||
test_size = 10000,
|
||||
train_size = 60000,
|
||||
random_state = 3)
|
||||
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)
|
||||
print('Shape of transformed X train:', X_test.shape)
|
||||
|
||||
# Преобразование меток в формат one-hot encoding
|
||||
y_train = keras.utils.to_categorical(y_train, num_classes)
|
||||
y_test = keras.utils.to_categorical(y_test, num_classes)
|
||||
print('Shape of transformed y train:', y_train.shape)
|
||||
print('Shape of transformed y test:', y_test.shape)
|
||||
```
|
||||
```
|
||||
Shape of transformed X train: (60000, 784)
|
||||
Shape of transformed X train: (10000, 784)
|
||||
Shape of transformed y train: (60000, 10)
|
||||
Shape of transformed y test: (10000, 10)
|
||||
```
|
||||
|
||||
```python
|
||||
# Оценка качества работы модели на тестовых данных
|
||||
scores = model_lr1.evaluate(X_test, y_test)
|
||||
print('Loss on test data:', scores[0])
|
||||
print('Accuracy on test data:', scores[1])
|
||||
```
|
||||
```
|
||||
313/313 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - accuracy: 0.9233 - loss: 0.2863
|
||||
Loss on test data: 0.28625616431236267
|
||||
Accuracy on test data: 0.92330002784729
|
||||
```
|
||||
|
||||
### 11) Сравнительный анализ моделей
|
||||
|
||||
Сравниваем сверточную нейронную сеть с полносвязной сетью по ключевым показателям: количеству параметров, времени обучения и качеству классификации. Делаем выводы по результатам применения сверточной нейронной сети для распознавания изображений.
|
||||
|
||||
**Таблица сравнения моделей:**
|
||||
|
||||
| Модель | Количество настраиваемых параметров | Количество эпох обучения | Качество классификации тестовой выборки |
|
||||
|----------|-------------------------------------|---------------------------|-----------------------------------------|
|
||||
| Сверточная | 34 826 | 15 | accuracy: 0.988; loss: 0.041 |
|
||||
| Полносвязная | 7 852 | 50 | accuracy: 0.923; loss: 0.286 |
|
||||
|
||||
|
||||
**Выводы:**
|
||||
|
||||
На основе проведенного анализа можно заключить, что сверточная нейронная сеть демонстрирует существенные преимущества перед полносвязной сетью при решении задач распознавания изображений:
|
||||
|
||||
1. **Эффективность параметров**: Сверточная сеть имеет больше параметров (34 826 против 7 852), но при этом показывает значительно лучшие результаты, что говорит о более эффективном использовании параметров для извлечения пространственных признаков.
|
||||
|
||||
2. **Скорость обучения**: Для достижения высокого качества сверточной сети требуется в 3.3 раза меньше эпох обучения (15 против 50), что существенно сокращает время обучения.
|
||||
|
||||
3. **Точность классификации**: Сверточная сеть показывает более высокую точность (98.8% против 92.3%) и значительно меньшую функцию потерь (0.041 против 0.286). Разница в точности составляет 6.5 процентных пункта, что является существенным улучшением.
|
||||
|
||||
4. **Обобщающая способность**: Сверточная сеть демонстрирует лучшую способность к обобщению, что видно из более низкой функции потерь на тестовых данных.
|
||||
|
||||
Эти результаты подтверждают, что архитектура сверточных сетей, учитывающая пространственную структуру изображений через операции свертки и пулинга, является более подходящим выбором для задач компьютерного зрения, несмотря на большее количество параметров.
|
||||
|
||||
## Задание 2
|
||||
|
||||
### Работа с датасетом CIFAR-10
|
||||
|
||||
Повторяем основные этапы задания 1, но используем датасет CIFAR-10, содержащий цветные изображения объектов 10 различных классов.
|
||||
|
||||
Особенности выполнения:
|
||||
- Разделение данных производится в соотношении 50 000:10 000
|
||||
- После разделения визуализируем 25 изображений из обучающей выборки
|
||||
- При демонстрации работы модели выбираем примеры так, чтобы одно изображение распознавалось корректно, а другое - ошибочно
|
||||
|
||||
### 1) Загрузка датасета CIFAR-10
|
||||
|
||||
Загружаем набор данных CIFAR-10, который содержит цветные изображения размером 32x32 пикселя, разделенные на 10 классов: самолет, автомобиль, птица, кошка, олень, собака, лягушка, лошадь, корабль, грузовик.
|
||||
|
||||
```python
|
||||
# Импорт и загрузка датасета CIFAR-10
|
||||
from keras.datasets import cifar10
|
||||
|
||||
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
|
||||
```
|
||||
|
||||
### 2) Разделение данных на обучающую и тестовую выборки
|
||||
|
||||
Создаем собственное разбиение датасета CIFAR-10 в соотношении 50 000:10 000. Используем random_state = 3 для воспроизводимости результатов (k = 1 - номер нашей бригады). Выводим размерности полученных массивов данных.
|
||||
|
||||
```python
|
||||
# Создание собственного разбиения датасета
|
||||
|
||||
# Объединение исходных выборок
|
||||
X = np.concatenate((X_train, X_test))
|
||||
y = np.concatenate((y_train, y_test))
|
||||
|
||||
# Разделение на обучающую и тестовую выборки
|
||||
X_train, X_test, y_train, y_test = train_test_split(X, y,
|
||||
test_size = 10000,
|
||||
train_size = 50000,
|
||||
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: (50000, 32, 32, 3)
|
||||
Shape of y train: (50000, 1)
|
||||
Shape of X test: (10000, 32, 32, 3)
|
||||
Shape of y test: (10000, 1)
|
||||
```
|
||||
|
||||
### Визуализация примеров из обучающей выборки
|
||||
|
||||
Отображаем сетку из 25 изображений из обучающей выборки с подписями соответствующих классов для визуального ознакомления с данными.
|
||||
|
||||
```python
|
||||
class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer',
|
||||
'dog', 'frog', 'horse', 'ship', 'truck']
|
||||
|
||||
plt.figure(figsize=(10,10))
|
||||
for i in range(25):
|
||||
plt.subplot(5,5,i+1)
|
||||
plt.xticks([])
|
||||
plt.yticks([])
|
||||
plt.grid(False)
|
||||
plt.imshow(X_train[i])
|
||||
plt.xlabel(class_names[y_train[i][0]])
|
||||
plt.show()
|
||||
```
|
||||

|
||||
|
||||
### 3) Предобработка данных CIFAR-10
|
||||
|
||||
Нормализуем значения пикселей и преобразуем метки в формат one-hot encoding для работы с категориальной функцией потерь. Выводим размерности предобработанных массивов данных.
|
||||
|
||||
```python
|
||||
# Определение параметров данных и модели
|
||||
num_classes = 10
|
||||
input_shape = (32, 32, 3)
|
||||
|
||||
# Нормализация значений пикселей: приведение к диапазону [0, 1]
|
||||
X_train = X_train / 255
|
||||
X_test = X_test / 255
|
||||
|
||||
print('Shape of transformed X train:', X_train.shape)
|
||||
print('Shape of transformed X test:', X_test.shape)
|
||||
|
||||
# Преобразование меток в формат one-hot encoding
|
||||
y_train = keras.utils.to_categorical(y_train, num_classes)
|
||||
y_test = keras.utils.to_categorical(y_test, num_classes)
|
||||
print('Shape of transformed y train:', y_train.shape)
|
||||
print('Shape of transformed y test:', y_test.shape)
|
||||
```
|
||||
```
|
||||
Shape of transformed X train: (50000, 32, 32, 3)
|
||||
Shape of transformed X test: (10000, 32, 32, 3)
|
||||
Shape of transformed y train: (50000, 10)
|
||||
Shape of transformed y test: (10000, 10)
|
||||
```
|
||||
|
||||
### 4) Построение и обучение сверточной сети для CIFAR-10
|
||||
|
||||
Создаем более сложную архитектуру сверточной сети с использованием батч-нормализации и нескольких блоков свертки для работы с цветными изображениями. Обучаем модель на подготовленных данных с выделением части данных для валидации.
|
||||
|
||||
```python
|
||||
# Создание модели сверточной нейронной сети
|
||||
model = Sequential()
|
||||
|
||||
# Блок 1
|
||||
model.add(layers.Conv2D(32, (3, 3), padding="same",
|
||||
activation="relu", input_shape=input_shape))
|
||||
model.add(layers.BatchNormalization())
|
||||
model.add(layers.Conv2D(32, (3, 3), padding="same", activation="relu"))
|
||||
model.add(layers.BatchNormalization())
|
||||
model.add(layers.MaxPooling2D((2, 2)))
|
||||
model.add(layers.Dropout(0.25))
|
||||
|
||||
# Блок 2
|
||||
model.add(layers.Conv2D(64, (3, 3), padding="same", activation="relu"))
|
||||
model.add(layers.BatchNormalization())
|
||||
model.add(layers.Conv2D(64, (3, 3), padding="same", activation="relu"))
|
||||
model.add(layers.BatchNormalization())
|
||||
model.add(layers.MaxPooling2D((2, 2)))
|
||||
model.add(layers.Dropout(0.25))
|
||||
|
||||
# Блок 3
|
||||
model.add(layers.Conv2D(128, (3, 3), padding="same", activation="relu"))
|
||||
model.add(layers.BatchNormalization())
|
||||
model.add(layers.Conv2D(128, (3, 3), padding="same", activation="relu"))
|
||||
model.add(layers.BatchNormalization())
|
||||
model.add(layers.MaxPooling2D((2, 2)))
|
||||
model.add(layers.Dropout(0.4))
|
||||
|
||||
model.add(layers.Flatten())
|
||||
model.add(layers.Dense(128, activation='relu'))
|
||||
model.add(layers.Dropout(0.5))
|
||||
model.add(layers.Dense(num_classes, activation="softmax"))
|
||||
|
||||
|
||||
model.summary()
|
||||
```
|
||||
**Model: "sequential_9"**
|
||||
| Layer (type) | Output Shape | Param # |
|
||||
|--------------------------------------------|-------------------|---------:|
|
||||
| conv2d_41 (Conv2D) | (None, 32, 32, 32) | 896 |
|
||||
| batch_normalization_6 (BatchNormalization) | (None, 32, 32, 32) | 128 |
|
||||
| conv2d_42 (Conv2D) | (None, 32, 32, 32) | 9,248 |
|
||||
| batch_normalization_7 (BatchNormalization) | (None, 32, 32, 32) | 128 |
|
||||
| max_pooling2d_26 (MaxPooling2D) | (None, 16, 16, 32) | 0 |
|
||||
| dropout_24 (Dropout) | (None, 16, 16, 32) | 0 |
|
||||
| conv2d_43 (Conv2D) | (None, 16, 16, 64) | 18,496 |
|
||||
| batch_normalization_8 (BatchNormalization) | (None, 16, 16, 64) | 256 |
|
||||
| conv2d_44 (Conv2D) | (None, 16, 16, 64) | 36,928 |
|
||||
| batch_normalization_9 (BatchNormalization) | (None, 16, 16, 64) | 256 |
|
||||
| max_pooling2d_27 (MaxPooling2D) | (None, 8, 8, 64) | 0 |
|
||||
| dropout_25 (Dropout) | (None, 8, 8, 64) | 0 |
|
||||
| conv2d_45 (Conv2D) | (None, 8, 8, 128) | 73,856 |
|
||||
| batch_normalization_10 (BatchNormalization)| (None, 8, 8, 128) | 512 |
|
||||
| conv2d_46 (Conv2D) | (None, 8, 8, 128) | 147,584 |
|
||||
| batch_normalization_11 (BatchNormalization)| (None, 8, 8, 128) | 512 |
|
||||
| max_pooling2d_28 (MaxPooling2D) | (None, 4, 4, 128) | 0 |
|
||||
| dropout_26 (Dropout) | (None, 4, 4, 128) | 0 |
|
||||
| flatten_9 (Flatten) | (None, 2048) | 0 |
|
||||
| dense_17 (Dense) | (None, 128) | 262,272 |
|
||||
| dropout_27 (Dropout) | (None, 128) | 0 |
|
||||
| dense_18 (Dense) | (None, 10) | 1,290 |
|
||||
**Total params:** 552,362 (2.11 MB)
|
||||
**Trainable params:** 551,466 (2.10 MB)
|
||||
**Non-trainable params:** 896 (3.50 KB)
|
||||
|
||||
```python
|
||||
# Компиляция и обучение модели
|
||||
batch_size = 64
|
||||
epochs = 50
|
||||
model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])
|
||||
model.fit(X_train, y_train, batch_size=batch_size, epochs=epochs, validation_split=0.1)
|
||||
```
|
||||
|
||||
### 5) Оценка качества модели на тестовых данных
|
||||
|
||||
Оцениваем финальную производительность обученной модели на тестовой выборке CIFAR-10.
|
||||
|
||||
```python
|
||||
# Оценка качества работы модели на тестовых данных
|
||||
scores = model.evaluate(X_test, y_test)
|
||||
print('Loss on test data:', scores[0])
|
||||
print('Accuracy on test data:', scores[1])
|
||||
```
|
||||
```
|
||||
313/313 ━━━━━━━━━━━━━━━━━━━━ 7s 22ms/step - accuracy: 0.8553 - loss: 0.5210
|
||||
Loss on test data: 0.5209607481956482
|
||||
Accuracy on test data: 0.8553000092506409
|
||||
```
|
||||
|
||||
### 6) Демонстрация работы модели на отдельных примерах
|
||||
|
||||
Визуализируем результаты распознавания для двух тестовых изображений: одно должно быть распознано корректно, другое - ошибочно.
|
||||
|
||||
```python
|
||||
# Визуализация результатов распознавания для двух тестовых изображений
|
||||
|
||||
for n in [3,14]:
|
||||
result = model.predict(X_test[n:n+1])
|
||||
print('NN output:', result)
|
||||
|
||||
plt.imshow(X_test[n].reshape(32,32,3), cmap=plt.get_cmap('gray'))
|
||||
plt.show()
|
||||
print('Real mark: ', np.argmax(y_test[n]))
|
||||
print('NN answer: ', np.argmax(result))
|
||||
```
|
||||

|
||||
```
|
||||
Real mark: 6
|
||||
NN answer: 6
|
||||
```
|
||||

|
||||
```
|
||||
Real mark: 4
|
||||
NN answer: 5
|
||||
```
|
||||
|
||||
### 7) Детальный анализ качества классификации CIFAR-10
|
||||
|
||||
Генерируем подробный отчет о качестве классификации и строим матрицу ошибок для анализа работы модели по каждому классу.
|
||||
|
||||
```python
|
||||
# Получение истинных и предсказанных меток для всех тестовых данных
|
||||
true_labels = np.argmax(y_test, axis=1)
|
||||
# Предсказанные метки классов
|
||||
predicted_labels = np.argmax(model.predict(X_test), axis=1)
|
||||
|
||||
# Вывод подробного отчета о качестве классификации
|
||||
print(classification_report(true_labels, predicted_labels, target_names=class_names))
|
||||
# Построение и визуализация матрицы ошибок
|
||||
conf_matrix = confusion_matrix(true_labels, predicted_labels)
|
||||
# Отрисовка матрицы ошибок в виде "тепловой карты"
|
||||
fig, ax = plt.subplots(figsize=(6, 6))
|
||||
disp = ConfusionMatrixDisplay(confusion_matrix=conf_matrix,display_labels=class_names)
|
||||
disp.plot(ax=ax, xticks_rotation=45) # Поворот подписей по X и приятная палитра
|
||||
plt.tight_layout() # Чтобы всё влезло
|
||||
plt.show()
|
||||
```
|
||||
```
|
||||
313/313 ━━━━━━━━━━━━━━━━━━━━ 1s 4ms/step
|
||||
precision recall f1-score support
|
||||
|
||||
airplane 0.84 0.91 0.87 1007
|
||||
automobile 0.95 0.91 0.93 1037
|
||||
bird 0.83 0.79 0.81 1030
|
||||
cat 0.77 0.65 0.70 990
|
||||
deer 0.83 0.82 0.82 966
|
||||
dog 0.72 0.83 0.77 1009
|
||||
frog 0.90 0.89 0.89 972
|
||||
horse 0.87 0.89 0.88 991
|
||||
ship 0.95 0.92 0.93 990
|
||||
truck 0.89 0.93 0.91 1008
|
||||
|
||||
accuracy 0.85 10000
|
||||
macro avg 0.86 0.85 0.85 10000
|
||||
weighted avg 0.86 0.85 0.85 10000
|
||||
```
|
||||

|
||||
|
||||
**Выводы по результатам классификации CIFAR-10:**
|
||||
|
||||
Разработанная сверточная нейронная сеть показала хорошие результаты при классификации цветных изображений из датасета CIFAR-10. Модель достигла точности классификации 85.5% (accuracy: 0.855, loss: 0.521) на тестовой выборке, а в детальном отчете о классификации показала accuracy 0.85, что является достойным результатом для данной задачи, учитывая сложность различения объектов в низком разрешении (32x32 пикселя) и наличие 10 различных классов.
|
||||
|
||||
Использование батч-нормализации и dropout-регуляризации позволило улучшить обобщающую способность модели и предотвратить переобучение. Архитектура с тремя блоками сверточных слоев эффективно извлекает иерархические признаки из изображений, что подтверждается полученными метриками качества.
|
||||
|
||||
@ -0,0 +1,451 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "gz18QPRz03Ec"
|
||||
},
|
||||
"source": [
|
||||
"### 1) В среде Google Colab создали новый блокнот (notebook). Импортировали необходимые для работы библиотеки и модули."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "mr9IszuQ1ANG"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# импорт модулей\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"from tensorflow import keras\n",
|
||||
"from tensorflow.keras import layers\n",
|
||||
"from tensorflow.keras.models import Sequential\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import numpy as np\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "FFRtE0TN1AiA"
|
||||
},
|
||||
"source": [
|
||||
"### 2) Загрузили набор данных IMDb, содержащий оцифрованные отзывы на фильмы, размеченные на два класса: позитивные и негативные. При загрузке набора данных параметр seed выбрали равным значению (4k – 1)=3, где k=1 – номер бригады. Вывели размеры полученных обучающих и тестовых массивов данных."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "Ixw5Sp0_1A-w"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# загрузка датасета\n",
|
||||
"import ssl\n",
|
||||
"ssl._create_default_https_context = ssl._create_unverified_context\n",
|
||||
"\n",
|
||||
"from keras.datasets import imdb\n",
|
||||
"\n",
|
||||
"vocabulary_size = 5000\n",
|
||||
"index_from = 3\n",
|
||||
"\n",
|
||||
"(X_train, y_train), (X_test, y_test) = imdb.load_data(\n",
|
||||
" path=\"imdb.npz\",\n",
|
||||
" num_words=vocabulary_size,\n",
|
||||
" skip_top=0,\n",
|
||||
" maxlen=None,\n",
|
||||
" seed=3,\n",
|
||||
" start_char=1,\n",
|
||||
" oov_char=2,\n",
|
||||
" index_from=index_from\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"# вывод размерностей\n",
|
||||
"print('Shape of X train:', X_train.shape)\n",
|
||||
"print('Shape of y train:', y_train.shape)\n",
|
||||
"print('Shape of X test:', X_test.shape)\n",
|
||||
"print('Shape of y test:', y_test.shape)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "aCo_lUXl1BPV"
|
||||
},
|
||||
"source": [
|
||||
"### 3) Вывели один отзыв из обучающего множества в виде списка индексов слов. Преобразовали список индексов в текст и вывели отзыв в виде текста. Вывели длину отзыва. Вывели метку класса данного отзыва и название класса (1 – Positive, 0 – Negative)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "9W3RklPcZyH0"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# создание словаря для перевода индексов в слова\n",
|
||||
"# загрузка словаря \"слово:индекс\"\n",
|
||||
"word_to_id = imdb.get_word_index()\n",
|
||||
"# уточнение словаря\n",
|
||||
"word_to_id = {key:(value + index_from) for key,value in word_to_id.items()}\n",
|
||||
"word_to_id[\"<PAD>\"] = 0\n",
|
||||
"word_to_id[\"<START>\"] = 1\n",
|
||||
"word_to_id[\"<UNK>\"] = 2\n",
|
||||
"word_to_id[\"<UNUSED>\"] = 3\n",
|
||||
"# создание обратного словаря \"индекс:слово\"\n",
|
||||
"id_to_word = {value:key for key,value in word_to_id.items()}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "Nu-Bs1jnaYhB"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(X_train[26])\n",
|
||||
"print('len:',len(X_train[26]))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "JhTwTurtZ6Sp"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"review_as_text = ' '.join(id_to_word[id] for id in X_train[26])\n",
|
||||
"print(review_as_text)\n",
|
||||
"print('len:',len(review_as_text))\n",
|
||||
"\n",
|
||||
"# вывод метки класса и названия класса\n",
|
||||
"print('Label:', y_train[26])\n",
|
||||
"print('Class:', 'Positive' if y_train[26] == 1 else 'Negative')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "4hclnNaD1BuB"
|
||||
},
|
||||
"source": [
|
||||
"### 4) Вывели максимальную и минимальную длину отзыва в обучающем множестве."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "xJH87ISq1B9h"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print('MAX Len: ',len(max(X_train, key=len)))\n",
|
||||
"print('MIN Len: ',len(min(X_train, key=len)))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "7x99O8ig1CLh"
|
||||
},
|
||||
"source": [
|
||||
"### 5) Провели предобработку данных. Выбрали единую длину, к которой будут приведены все отзывы. Короткие отзывы дополнили спецсимволами, а длинные обрезали до выбранной длины."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "lrF-B2aScR4t"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# предобработка данных\n",
|
||||
"from tensorflow.keras.utils import pad_sequences\n",
|
||||
"max_words = 500\n",
|
||||
"X_train = pad_sequences(X_train, maxlen=max_words, value=0, padding='pre', truncating='post')\n",
|
||||
"X_test = pad_sequences(X_test, maxlen=max_words, value=0, padding='pre', truncating='post')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "HL2_LVga1C3l"
|
||||
},
|
||||
"source": [
|
||||
"### 6) Повторили пункт 4."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "81Cgq8dn9uL6"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print('MAX Len: ',len(max(X_train, key=len)))\n",
|
||||
"print('MIN Len: ',len(min(X_train, key=len)))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "KzrVY1SR1DZh"
|
||||
},
|
||||
"source": [
|
||||
"### 7) Повторили пункт 3. Сделали вывод о том, как отзыв преобразовался после предобработки."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "vudlgqoCbjU1"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(X_train[26])\n",
|
||||
"print('len:',len(X_train[26]))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "dbfkWjDI1Dp7"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"review_as_text = ' '.join(id_to_word[id] for id in X_train[26])\n",
|
||||
"print(review_as_text)\n",
|
||||
"print('len:',len(review_as_text))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "mJNRXo5TdPAE"
|
||||
},
|
||||
"source": [
|
||||
"#### В результате предобработки данных все отзывы были приведены к единой длине 500 токенов. Для отзывов, исходная длина которых была меньше 500, в начало последовательности были добавлены специальные токены заполнения <PAD> (со значением 0). Это обеспечило единообразие входных данных для нейронной сети и позволило эффективно обрабатывать последовательности различной длины."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "YgiVGr5_1D3u"
|
||||
},
|
||||
"source": [
|
||||
"### 8) Вывели предобработанные массивы обучающих и тестовых данных и их размерности."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "7MqcG_wl1EHI"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# вывод данных\n",
|
||||
"print('X train: \\n',X_train)\n",
|
||||
"print('X test: \\n',X_test)\n",
|
||||
"\n",
|
||||
"# вывод размерностей\n",
|
||||
"print('Shape of X train:', X_train.shape)\n",
|
||||
"print('Shape of X test:', X_test.shape)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "amaspXGW1EVy"
|
||||
},
|
||||
"source": [
|
||||
"### 9) Реализовали модель рекуррентной нейронной сети, состоящей из слоев Embedding, LSTM, Dropout, Dense, и обучили ее на обучающих данных с выделением части обучающих данных в качестве валидационных. Вывели информацию об архитектуре нейронной сети. Добились качества обучения по метрике accuracy не менее 0.8."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "ktWEeqWd1EyF"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"embed_dim = 32\n",
|
||||
"lstm_units = 64\n",
|
||||
"\n",
|
||||
"model = Sequential()\n",
|
||||
"model.add(layers.Embedding(input_dim=vocabulary_size, output_dim=embed_dim, input_length=max_words, input_shape=(max_words,)))\n",
|
||||
"model.add(layers.LSTM(lstm_units))\n",
|
||||
"model.add(layers.Dropout(0.5))\n",
|
||||
"model.add(layers.Dense(1, activation='sigmoid'))\n",
|
||||
"\n",
|
||||
"model.summary()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "CuPqKpX0kQfP"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# компилируем и обучаем модель\n",
|
||||
"batch_size = 64\n",
|
||||
"epochs = 3\n",
|
||||
"model.compile(loss=\"binary_crossentropy\", optimizer=\"adam\", metrics=[\"accuracy\"])\n",
|
||||
"model.fit(X_train, y_train, batch_size=batch_size, epochs=epochs, validation_split=0.2)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "hJIWinxymQjb"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"test_loss, test_acc = model.evaluate(X_test, y_test)\n",
|
||||
"print(f\"\\nTest accuracy: {test_acc}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "mgrihPd61E8w"
|
||||
},
|
||||
"source": [
|
||||
"### 10) Оценили качество обучения на тестовых данных:\n",
|
||||
"### - вывели значение метрики качества классификации на тестовых данных\n",
|
||||
"### - вывели отчет о качестве классификации тестовой выборки \n",
|
||||
"### - построили ROC-кривую по результату обработки тестовой выборки и вычислили площадь под ROC-кривой (AUC ROC)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "Rya5ABT8msha"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"#значение метрики качества классификации на тестовых данных\n",
|
||||
"print(f\"\\nTest accuracy: {test_acc}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "2kHjcmnCmv0Y"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"#отчет о качестве классификации тестовой выборки\n",
|
||||
"y_score = model.predict(X_test)\n",
|
||||
"y_pred = [1 if y_score[i,0]>=0.5 else 0 for i in range(len(y_score))]\n",
|
||||
"\n",
|
||||
"from sklearn.metrics import classification_report\n",
|
||||
"print(classification_report(y_test, y_pred, labels = [0, 1], target_names=['Negative', 'Positive']))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "Kp4AQRbcmwAx"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"#построение ROC-кривой и AUC ROC\n",
|
||||
"from sklearn.metrics import roc_curve, auc\n",
|
||||
"\n",
|
||||
"fpr, tpr, thresholds = roc_curve(y_test, y_score)\n",
|
||||
"plt.figure(figsize=(8, 6))\n",
|
||||
"plt.plot(fpr, tpr)\n",
|
||||
"plt.grid()\n",
|
||||
"plt.xlabel('False Positive Rate')\n",
|
||||
"plt.ylabel('True Positive Rate')\n",
|
||||
"plt.title('ROC')\n",
|
||||
"plt.savefig('roc_curve.png', dpi=150, bbox_inches='tight')\n",
|
||||
"plt.show()\n",
|
||||
"print('AUC ROC:', auc(fpr, tpr))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "MsM3ew3d1FYq"
|
||||
},
|
||||
"source": [
|
||||
"### 11) Сделали выводы по результатам применения рекуррентной нейронной сети для решения задачи определения тональности текста. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "xxFO4CXbIG88"
|
||||
},
|
||||
"source": [
|
||||
"Таблица1:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "xvoivjuNFlEf"
|
||||
},
|
||||
"source": [
|
||||
"| Модель | Количество настраиваемых параметров | Количество эпох обучения | Качество классификации тестовой выборки |\n",
|
||||
"|----------|-------------------------------------|---------------------------|-----------------------------------------|\n",
|
||||
"| Рекуррентная | 184 897 | 3 | accuracy:0.8659 ; loss:0.3207 ; AUC ROC:0.9386 |\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "YctF8h_sIB-P"
|
||||
},
|
||||
"source": [
|
||||
"#### Анализируя полученные результаты применения рекуррентной нейронной сети для классификации тональности текстовых отзывов, можно констатировать успешное выполнение поставленной задачи. Достигнутый уровень точности accuracy = 0.8659 существенно превосходит минимально необходимый порог 0.8, что свидетельствует о надежности разработанной модели. Показатель AUC ROC = 0.9386, превышающий значение 0.9, демонстрирует отличную дискриминационную способность модели в различении позитивных и негативных отзывов. Сбалансированные метрики precision и recall (0.87 для обоих классов) указывают на отсутствие значимого смещения в сторону одного из классов, что подтверждает корректность работы алгоритма классификации."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"accelerator": "GPU",
|
||||
"colab": {
|
||||
"gpuType": "T4",
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"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": 0
|
||||
}
|
||||
@ -0,0 +1,343 @@
|
||||
# Отчёт по лабораторной работе №4
|
||||
|
||||
**Троянов Д.С., Чернов Д.Е. — А-01-22**
|
||||
|
||||
---
|
||||
## Задание 1
|
||||
|
||||
### 1) В среде Google Colab создали новый блокнот (notebook). Импортировали необходимые для работы библиотеки и модули. Настроили блокнот для работы с аппаратным ускорителем GPU.
|
||||
|
||||
```python
|
||||
# импорт модулей
|
||||
import os
|
||||
os.chdir('/content/drive/MyDrive/Colab Notebooks/is_lab4')
|
||||
|
||||
from tensorflow import keras
|
||||
from tensorflow.keras import layers
|
||||
from tensorflow.keras.models import Sequential
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
```
|
||||
```python
|
||||
import tensorflow as tf
|
||||
device_name = tf.test.gpu_device_name()
|
||||
if device_name != '/device:GPU:0':
|
||||
raise SystemError('GPU device not found')
|
||||
print('Found GPU at: {}'.format(device_name))
|
||||
```
|
||||
```
|
||||
Found GPU at: /device:GPU:0
|
||||
```
|
||||
|
||||
### 2) Загрузили набор данных IMDb, содержащий оцифрованные отзывы на фильмы, размеченные на два класса: позитивные и негативные. При загрузке набора данных параметр seed выбрали равным значению (4k – 1)=3, где k=1 – номер бригады. Вывели размеры полученных обучающих и тестовых массивов данных.
|
||||
|
||||
```python
|
||||
# загрузка датасета
|
||||
import ssl
|
||||
ssl._create_default_https_context = ssl._create_unverified_context
|
||||
|
||||
from keras.datasets import imdb
|
||||
|
||||
vocabulary_size = 5000
|
||||
index_from = 3
|
||||
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data(
|
||||
path="imdb.npz",
|
||||
num_words=vocabulary_size,
|
||||
skip_top=0,
|
||||
maxlen=None,
|
||||
seed=3,
|
||||
start_char=1,
|
||||
oov_char=2,
|
||||
index_from=index_from
|
||||
)
|
||||
|
||||
# вывод размерностей
|
||||
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: (25000,)
|
||||
Shape of y train: (25000,)
|
||||
Shape of X test: (25000,)
|
||||
Shape of y test: (25000,)
|
||||
```
|
||||
|
||||
### 3) Вывели один отзыв из обучающего множества в виде списка индексов слов. Преобразовали список индексов в текст и вывели отзыв в виде текста. Вывели длину отзыва. Вывели метку класса данного отзыва и название класса (1 – Positive, 0 – Negative).
|
||||
|
||||
```python
|
||||
# создание словаря для перевода индексов в слова
|
||||
# загрузка словаря "слово:индекс"
|
||||
word_to_id = imdb.get_word_index()
|
||||
# уточнение словаря
|
||||
word_to_id = {key:(value + index_from) for key,value in word_to_id.items()}
|
||||
word_to_id["<PAD>"] = 0
|
||||
word_to_id["<START>"] = 1
|
||||
word_to_id["<UNK>"] = 2
|
||||
word_to_id["<UNUSED>"] = 3
|
||||
# создание обратного словаря "индекс:слово"
|
||||
id_to_word = {value:key for key,value in word_to_id.items()}
|
||||
```
|
||||
```python
|
||||
print(X_train[26])
|
||||
print('len:',len(X_train[26]))
|
||||
```
|
||||
```
|
||||
[1, 37, 1388, 4, 2739, 495, 94, 96, 143, 49, 2, 875, 551, 19, 195, 2210, 5, 1698, 8, 401, 4, 65, 24, 64, 1728, 21, 400, 642, 45, 77, 6, 137, 237, 207, 258, 141, 6, 1562, 1301, 1562, 737, 22, 10, 10, 4, 22, 9, 1490, 3862, 4, 744, 19, 307, 1385, 5, 2, 2, 4, 2, 2656, 2, 1669, 19, 4, 1074, 200, 4, 55, 406, 55, 3048, 5, 246, 55, 1451, 105, 688, 8, 4, 321, 177, 32, 677, 7, 4, 678, 1850, 26, 1669, 221, 5, 3921, 10, 10, 13, 386, 37, 1388, 4, 2739, 45, 6, 66, 163, 20, 15, 304, 6, 3049, 168, 33, 4, 4352, 15, 75, 70, 2, 23, 257, 85, 5, 4, 2789, 878, 21, 1305, 2, 1773, 7, 2]
|
||||
len: 130
|
||||
```
|
||||
```python
|
||||
review_as_text = ' '.join(id_to_word[id] for id in X_train[26])
|
||||
print(review_as_text)
|
||||
print('len:',len(review_as_text))
|
||||
|
||||
# вывод метки класса и названия класса
|
||||
print('Label:', y_train[26])
|
||||
print('Class:', 'Positive' if y_train[26] == 1 else 'Negative')
|
||||
```
|
||||
```
|
||||
<START> who loves the sun works its way through some <UNK> subject matter with enough wit and grace to keep the story not only engaging but often hilarious it's been a while since i've found such a thoroughly touching thoroughly enjoyable film br br the film is gorgeous drawing the eye with beautiful scenery and <UNK> <UNK> the <UNK> imagery <UNK> wonderfully with the tension between the very human very flawed and yet very likable characters due to the excellent cast all five of the major players are wonderfully interesting and dynamic br br i recommend who loves the sun it's a really funny movie that takes a poignant look at the hurts that we can <UNK> on each other and the amazingly difficult but equally <UNK> process of <UNK>
|
||||
len: 738
|
||||
Label: 1
|
||||
Class: Positive
|
||||
```
|
||||
|
||||
|
||||
### 4) Вывели максимальную и минимальную длину отзыва в обучающем множестве.
|
||||
|
||||
```python
|
||||
print('MAX Len: ',len(max(X_train, key=len)))
|
||||
print('MIN Len: ',len(min(X_train, key=len)))
|
||||
```
|
||||
```
|
||||
MAX Len: 2494
|
||||
MIN Len: 11
|
||||
```
|
||||
|
||||
### 5) Провели предобработку данных. Выбрали единую длину, к которой будут приведены все отзывы. Короткие отзывы дополнили спецсимволами, а длинные обрезали до выбранной длины.
|
||||
|
||||
```python
|
||||
# предобработка данных
|
||||
from tensorflow.keras.utils import pad_sequences
|
||||
max_words = 500
|
||||
X_train = pad_sequences(X_train, maxlen=max_words, value=0, padding='pre', truncating='post')
|
||||
X_test = pad_sequences(X_test, maxlen=max_words, value=0, padding='pre', truncating='post')
|
||||
```
|
||||
|
||||
### 6) Повторили пункт 4.
|
||||
|
||||
```python
|
||||
print('MAX Len: ',len(max(X_train, key=len)))
|
||||
print('MIN Len: ',len(min(X_train, key=len)))
|
||||
```
|
||||
```
|
||||
MAX Len: 500
|
||||
MIN Len: 500
|
||||
```
|
||||
|
||||
### 7) Повторили пункт 3. Сделали вывод о том, как отзыв преобразовался после предобработки.
|
||||
```python
|
||||
print(X_train[26])
|
||||
print('len:',len(X_train[26]))
|
||||
```
|
||||
```
|
||||
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 1 4 78
|
||||
46 304 39 2 7 968 2 295 209 101 147 65 10 10
|
||||
2643 2 497 8 30 6 147 284 5 996 174 10 10 11
|
||||
4 130 4 2 4979 11 2 10 10 2]
|
||||
len: 500
|
||||
```
|
||||
|
||||
```python
|
||||
review_as_text = ' '.join(id_to_word[id] for id in X_train[26])
|
||||
print(review_as_text)
|
||||
print('len:',len(review_as_text))
|
||||
```
|
||||
```
|
||||
<PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <PAD> <START> the bad out takes from <UNK> of fire <UNK> together without any real story br br dean <UNK> tries to be a real actor and fails again br br in the end the <UNK> quit in <UNK> br br <UNK>
|
||||
len: 2947
|
||||
```
|
||||
#### В результате предобработки данных все отзывы были приведены к единой длине 500 токенов. Для отзывов, исходная длина которых была меньше 500, в начало последовательности были добавлены специальные токены заполнения <PAD> (со значением 0). Это обеспечило единообразие входных данных для нейронной сети и позволило эффективно обрабатывать последовательности различной длины.
|
||||
|
||||
|
||||
### 8) Вывели предобработанные массивы обучающих и тестовых данных и их размерности.
|
||||
|
||||
```python
|
||||
# вывод данных
|
||||
print('X train: \n',X_train)
|
||||
print('X test: \n',X_test)
|
||||
|
||||
# вывод размерностей
|
||||
print('Shape of X train:', X_train.shape)
|
||||
print('Shape of X test:', X_test.shape)
|
||||
```
|
||||
```
|
||||
X train:
|
||||
[[ 0 0 0 ... 12 38 76]
|
||||
[ 0 0 0 ... 33 4 130]
|
||||
[ 0 0 0 ... 437 7 58]
|
||||
...
|
||||
[ 0 0 0 ... 1874 1553 422]
|
||||
[ 0 0 0 ... 18 1552 234]
|
||||
[ 0 0 0 ... 7 87 1090]]
|
||||
X test:
|
||||
[[ 0 0 0 ... 6 194 717]
|
||||
[ 0 0 0 ... 30 87 292]
|
||||
[ 0 0 0 ... 495 55 73]
|
||||
...
|
||||
[ 0 0 0 ... 7 12 908]
|
||||
[ 0 0 0 ... 61 477 2302]
|
||||
[ 0 0 0 ... 5 68 4580]]
|
||||
Shape of X train: (25000, 500)
|
||||
Shape of X test: (25000, 500)
|
||||
```
|
||||
|
||||
### 9) Реализовали модель рекуррентной нейронной сети, состоящей из слоев Embedding, LSTM, Dropout, Dense, и обучили ее на обучающих данных с выделением части обучающих данных в качестве валидационных. Вывели информацию об архитектуре нейронной сети. Добились качества обучения по метрике accuracy не менее 0.8.
|
||||
|
||||
```python
|
||||
embed_dim = 32
|
||||
lstm_units = 64
|
||||
|
||||
model = Sequential()
|
||||
model.add(layers.Embedding(input_dim=vocabulary_size, output_dim=embed_dim, input_length=max_words, input_shape=(max_words,)))
|
||||
model.add(layers.LSTM(lstm_units))
|
||||
model.add(layers.Dropout(0.5))
|
||||
model.add(layers.Dense(1, activation='sigmoid'))
|
||||
|
||||
model.summary()
|
||||
```
|
||||
|
||||
**Model: "sequential"**
|
||||
| Layer (type) | Output Shape | Param # |
|
||||
| ----------------------- | --------------- | ------: |
|
||||
| embedding_4 (Embedding) | (None, 500, 32) | 160,000 |
|
||||
| lstm_4 (LSTM) | (None, 64) | 24,832 |
|
||||
| dropout_4 (Dropout) | (None, 64) | 0 |
|
||||
| dense_4 (Dense) | (None, 1) | 65 |
|
||||
|
||||
**Total params:** 184,897 (722.25 KB)
|
||||
**Trainable params:** 184,897 (722.25 KB)
|
||||
**Non-trainable params:** 0 (0.00 B)
|
||||
|
||||
```python
|
||||
# компилируем и обучаем модель
|
||||
batch_size = 64
|
||||
epochs = 3
|
||||
model.compile(loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"])
|
||||
model.fit(X_train, y_train, batch_size=batch_size, epochs=epochs, validation_split=0.2)
|
||||
```
|
||||
```
|
||||
Epoch 1/3
|
||||
313/313 ━━━━━━━━━━━━━━━━━━━━ 108s 338ms/step - accuracy: 0.7596 - loss: 0.4853 - val_accuracy: 0.8086 - val_loss: 0.4447
|
||||
Epoch 2/3
|
||||
313/313 ━━━━━━━━━━━━━━━━━━━━ 85s 273ms/step - accuracy: 0.8680 - loss: 0.3281 - val_accuracy: 0.8228 - val_loss: 0.3993
|
||||
Epoch 3/3
|
||||
313/313 ━━━━━━━━━━━━━━━━━━━━ 84s 267ms/step - accuracy: 0.8818 - loss: 0.3008 - val_accuracy: 0.8714 - val_loss: 0.3097
|
||||
```
|
||||
```python
|
||||
test_loss, test_acc = model.evaluate(X_test, y_test)
|
||||
print(f"\nTest accuracy: {test_acc}")
|
||||
```
|
||||
```
|
||||
782/782 ━━━━━━━━━━━━━━━━━━━━ 54s 69ms/step - accuracy: 0.8659 - loss: 0.3207
|
||||
|
||||
Test accuracy: 0.865880012512207
|
||||
```
|
||||
|
||||
### 10) Оценили качество обучения на тестовых данных:
|
||||
### - вывели значение метрики качества классификации на тестовых данных
|
||||
### - вывели отчет о качестве классификации тестовой выборки
|
||||
### - построили ROC-кривую по результату обработки тестовой выборки и вычислили площадь под ROC-кривой (AUC ROC)
|
||||
|
||||
```python
|
||||
#значение метрики качества классификации на тестовых данных
|
||||
print(f"\nTest accuracy: {test_acc}")
|
||||
```
|
||||
```
|
||||
Test accuracy: 0.865880012512207
|
||||
```
|
||||
|
||||
```python
|
||||
#отчет о качестве классификации тестовой выборки
|
||||
y_score = model.predict(X_test)
|
||||
y_pred = [1 if y_score[i,0]>=0.5 else 0 for i in range(len(y_score))]
|
||||
|
||||
from sklearn.metrics import classification_report
|
||||
print(classification_report(y_test, y_pred, labels = [0, 1], target_names=['Negative', 'Positive']))
|
||||
```
|
||||
```
|
||||
precision recall f1-score support
|
||||
|
||||
Negative 0.87 0.87 0.87 12500
|
||||
Positive 0.87 0.86 0.87 12500
|
||||
|
||||
accuracy 0.87 25000
|
||||
macro avg 0.87 0.87 0.87 25000
|
||||
weighted avg 0.87 0.87 0.87 25000
|
||||
```
|
||||
|
||||
```python
|
||||
#построение ROC-кривой и AUC ROC
|
||||
from sklearn.metrics import roc_curve, auc
|
||||
|
||||
fpr, tpr, thresholds = roc_curve(y_test, y_score)
|
||||
plt.figure(figsize=(8, 6))
|
||||
plt.plot(fpr, tpr)
|
||||
plt.grid()
|
||||
plt.xlabel('False Positive Rate')
|
||||
plt.ylabel('True Positive Rate')
|
||||
plt.title('ROC')
|
||||
plt.savefig('roc_curve.png', dpi=150, bbox_inches='tight')
|
||||
plt.show()
|
||||
print('AUC ROC:', auc(fpr, tpr))
|
||||
```
|
||||

|
||||
```
|
||||
AUC ROC: 0.9386348447999999
|
||||
```
|
||||
|
||||
### 11) Сделали выводы по результатам применения рекуррентной нейронной сети для решения задачи определения тональности текста.
|
||||
|
||||
Таблица1:
|
||||
|
||||
| Модель | Количество настраиваемых параметров | Количество эпох обучения | Качество классификации тестовой выборки |
|
||||
|----------|-------------------------------------|---------------------------|-----------------------------------------|
|
||||
| Рекуррентная | 184 897 | 3 | accuracy:0.8659 ; loss:0.3207 ; AUC ROC:0.9386 |
|
||||
|
||||
|
||||
#### Анализируя полученные результаты применения рекуррентной нейронной сети для классификации тональности текстовых отзывов, можно констатировать успешное выполнение поставленной задачи. Достигнутый уровень точности accuracy = 0.8659 существенно превосходит минимально необходимый порог 0.8, что свидетельствует о надежности разработанной модели.
|
||||
#### Показатель AUC ROC = 0.9386, превышающий значение 0.9, демонстрирует отличную дискриминационную способность модели в различении позитивных и негативных отзывов. Сбалансированные метрики precision и recall (0.87 для обоих классов) указывают на отсутствие значимого смещения в сторону одного из классов, что подтверждает корректность работы алгоритма классификации.
|
||||
|
После Ширина: | Высота: | Размер: 35 KiB |