Лабораторные работы / intel_lab1
.pdfОтчет по лабораторной работе № 1
по дисциплине «Интеллектуальные системы» на тему «Архитектура и обучение глубоких нейронных сетей»
Цель работы
Получить практические навыки создания, обучения и применения искусственных нейронных сетей на примере решения задачи распознавания рукописных цифр. Научиться загружать данные и проводить их предварительную обработку. Научиться оценивать качество работы обученной нейронной сети на качество решения задачи.
Выполнение работы
Пункт 1
В среде Google Colab создадим новый блокнот (notebook). Импортируем необходимые для работы библиотеки и модули.
import os
os.chdir('/content/drive/MyDrive/Colab Notebooks') from tensorflow import keras
import matplotlib.pyplot as plt import numpy as np
import sklearn
Пункт 2
Загрузим набор данных MNIST, содержащий размеченные изображения рукописных
цифр.
from keras.datasets import mnist
(X_train, y_train), (X_test, y_test) = mnist.load_data()
Результат:
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz 11493376/11490434 [==============================] - 0s 0us/step 11501568/11490434 [==============================] - 0s 0us/step
Пункт 3
Разобьем набор данных на обучающие (train) и тестовые (test) данные в соотношении 60000:10000 элементов. При разбиении параметр random_state выберем равным (4*22 – 1) = 87. Выведем размерности полученных обучающих и тестовых массивов данных.
1
# создание своего разбиения датасета
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 = 87)
# вывод размерностей
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 элемента обучающих данных (изображения и метки цифр).
Первый элемент:
# вывод изображения
plt.imshow(X_train[0], cmap=plt.get_cmap('gray')) plt.show()
# вывод метки для этого изображения print(y_train[0])
Результат:
8
Второй элемент:
# вывод изображения
plt.imshow(X_train[1], cmap=plt.get_cmap('gray')) plt.show()
# вывод метки для этого изображения print(y_train[1])
Результат:
2
6
Третий элемент:
# вывод изображения
plt.imshow(X_train[2], cmap=plt.get_cmap('gray')) plt.show()
# вывод метки для этого изображения print(y_train[2])
Результат:
8
Четвертый элемент:
# вывод изображения
plt.imshow(X_train[3], cmap=plt.get_cmap('gray')) plt.show()
# вывод метки для этого изображения print(y_train[3])
Результат:
7
Пункт 5
Проведем предобработку данных: приведем обучающие и тестовые данные к формату, пригодному для обучения нейронной сети. Входные данные должны принимать значения от 0 до 1, метки цифр должны быть закодированы по принципу «one-hot encoding». Выведем размерности предобработанных обучающих и тестовых массивов данных.
# развернем каждое изображение 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)
# переведем метки в one-hot
3
from keras.utils import np_utils
y_train = np_utils.to_categorical(y_train) y_test = np_utils.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)
print('Shape of transformed X test:', X_test.shape) print('Shape of transformed Y test:', y_test.shape)
Результат:
Shape of transformed X test: (10000, 784)
Shape of transformed Y test: (10000, 10)
Пункт 6
Реализуем модель однослойной нейронной сети и обучим ее на обучающих данных с выделением части обучающих данных в качестве валидационных. Выведем информацию об архитектуре нейронной сети. Выведем график функции ошибки на обучающих и валидационных данных по эпохам. При реализации модели нейронной сети зададим следующую архитектуру и параметры обучения:
•количество скрытых слоев: 0,
•функция активации выходного слоя: softmax,
•функция ошибки: categorical_crossentropy,
•алгоритм обучения: sgd,
•метрика качества: accuracy,
•количество эпох: 100,
•доля валидационных данных от обучающих: 0.1.
from keras.models import Sequential from keras.layers import Dense model = Sequential()
model.add(Dense(units=num_classes, input_dim=num_pixels, activation='softmax')) model.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])
# вывод информации об архитектуре модели print(model.summary())
Результат:
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 10) 7850
=================================================================
Total params: 7,850
4
Trainable params: 7,850 Non-trainable params: 0
_________________________________________________________________
None
# Обучаем модель
H = model.fit(X_train, y_train, validation_split=0.1, epochs=100)
Результат:
Epoch 1/100
1688/1688 [==============================] - 3s 1ms/step - loss: 0.7991 - accuracy: 0.8111
-val_loss: 0.5255 - val_accuracy: 0.8667 Epoch 2/100
1688/1688 [==============================] - 2s 1ms/step - loss: 0.4629 - accuracy: 0.8795
-val_loss: 0.4364 - val_accuracy: 0.8842
…
Epoch 100/100
1688/1688 [==============================] - 2s 1ms/step - loss: 0.2548 - accuracy: 0.9291 - val_loss: 0.2735 - val_accuracy: 0.9253
# вывод графика ошибки по эпохам plt.plot(H.history['loss']) plt.plot(H.history['val_loss']) plt.grid()
plt.xlabel('Epochs') plt.ylabel('loss') plt.legend(['train_loss', 'val_loss']) plt.title('Loss by epochs') plt.show()
Результат:
5
Пункт 7
Применим обученную модель к тестовым данным. Выведем значение функции ошибки и значение метрики качества классификации на тестовых данных.
# Оценка качества работы модели на тестовых данных scores = model.evaluate(X_test, y_test)
print('Loss on test data:', scores[0]) print('Accuracy on test data:', scores[1])
Результат:
313/313 [==============================] - 0s 990us/step - loss: 0.2891 - accuracy: 0.9209 Loss on test data: 0.28913038969039917
Accuracy on test data: 0.9208999872207642
Пункт 8
Добавим в модель один скрытый слой и проведем обучение и тестирование при 100, 300, 500, 1000 нейронах в скрытом слое. По метрике качества классификации на тестовых данных выберем наилучшее количество нейронов в скрытом слое. В качестве функции активации нейронов в скрытом слое используем функцию sigmoid. Результаты расчета метрики качества занесем в таблицу п. 10.
Сравнивая значения метрики качества, полученные для нейронной сети без скрытых слоев (метрика качества 0,921), а также нейронных сетей со 100 (0,958), 300 (0,953), 500 (0,947), 1000 (0,940) нейронами в скрытом слое, получаем, что наибольшее значение метрики качества получено для сети со 100 нейронами.
Пункт 9
Добавим в наилучшую архитектуру (на первом слое 100 нейронов), определенную в п. 8, второй скрытый слой и проведем обучение и тестирование (повторить п. 6-7) при 50, 100, 300 нейронах во втором скрытом слое. В качестве функции активации нейронов в скрытом слое используем функцию sigmoid.
6
Пункт 10
Результаты исследования архитектуры нейронной сети занесем в таблицу:
Количество скрытых |
Количество |
Количество |
Значение метрики |
нейронов в первом |
нейронов во втором |
качества |
|
слоев |
скрытом слое |
скрытом слое |
классификации |
|
|||
|
|
|
|
0 |
- |
- |
0.9208999872207642 |
|
|
|
|
|
100 |
|
0.9581000208854675 |
|
|
|
|
1 |
300 |
- |
0.9534000158309937 |
|
|
||
|
500 |
|
0.9472000002861023 |
|
|
|
|
|
1000 |
|
0.9404000043869019 |
|
|
|
|
|
|
50 |
0.960099995136261 |
2 |
100 |
|
|
100 |
0.9611999988555908 |
||
|
|
|
|
|
|
300 |
0.9616000056266785 |
|
|
|
|
Из таблицы видно, что:
1.при увеличении числа слоев значение метрики качества классификации увеличивалось;
2.при увеличении числа нейронов в скрытом слое нейронной сети с одним скрытым слоем значение метрики качества уменьшалось:
3.при увеличении числа нейронов во втором скрытом слое нейронной сети с двумя скрытыми слоями при постоянном числе нейронов в первом скрытом слое (100) значение метрики качества увеличивалось.
Сравнивая значения метрики качества, представленные в таблице, выберем в качестве нейронной сети с наилучшей архитектурой сеть с двумя скрытыми слоями: в первом слое 100 нейронов, во втором слое 300 нейронов.
Пункт 11
Для нейронной сети наилучшей архитектуры (100 нейронов в первом слое, 300 нейронов во втором слое) выведем два тестовых изображения, истинные метки и результат распознавания изображений.
# вывод тестового изображения и результата распознавания n = 87
result = model9_300.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)))
7
Результат:
NN output: [[2.2340394e-04 5.1248958e-04 3.0402772e-04 8.9935213e-01 4.4509859e-05 1.3898294e-02 2.3015717e-05 3.8455505e-07 8.4959544e-02 6.8225252e-04]]
Real mark: 3
NN answer: 3
result2 = model9_300.predict(X_test[n+1:n+2]) print('NN output:', result2)
plt.imshow(X_test[n+1].reshape(28,28), cmap=plt.get_cmap('gray')) plt.show()
print('Real mark: ', str(np.argmax(y_test[n+1]))) print('NN answer: ', str(np.argmax(result2)))
Результат:
NN output: [[2.6738383e-07 5.3207718e-02 2.0246504e-02 3.0528089e-01 8.3283467e-06 1.7038414e-04 3.7199155e-07 6.0480994e-01 4.9034960e-04 1.5785262e-02]]
Real mark: 3
NN answer: 7
Таким образом, из полученных результатов видно, что нейронная сеть неверно определила цифру 3, написание которой похоже на цифру 7.
Пункт 12
Создадим собственное изображение рукописной цифры, подобное представленным в наборе MNIST. Цифру выберем как остаток от деления на 10 числа своего дня рождения (3). Сохраним изображение. Загрузим, предобработаем и подадим на вход обученной нейронной сети собственное изображение. Выведем изображение и результат распознавания.
Изображение test.png:
# загрузка собственного изображения from PIL import Image
file_data = Image.open('test.png')
8
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 = test_img.reshape(1, num_pixels)
# распознавание
result = model9_300.predict(test_img) print('I think it\'s ', np.argmax(result))
Результат:
I think it's 3
Пункт 13
Создадим копию собственного изображения, отличающуюся от оригинала поворотом на 90 градусов в любую сторону. Сохраним изображение. Загрузим, предобработаем и подадим на вход обученной нейронной сети измененное изображение. Выведем изображение и результат распознавания. Сделать выводы по результатам эксперимента.
Изображение test2.png:
#загрузка собственного изображения from PIL import Image
file_data = Image.open('test2.png')
file_data = file_data.convert('L') # перевод в градации серого test_img = np.array(file_data)
#вывод собственного изображения
plt.imshow(test_img, cmap=plt.get_cmap('gray')) plt.show()
Результат:
9
# предобработка test_img = test_img / 255
test_img = test_img.reshape(1, num_pixels)
# распознавание
result = model9_300.predict(test_img) print('I think it\'s ', np.argmax(result))
Результат:
I think it's 2
Таким образом, из результатов выполнения пунктов 12 – 13 видно, что нейронная сеть с наилучшей архитектурой верно распознала изображение цифры 3 без поворота, но неверно определила повернутое на 90 градусов изображение этой же цифры. Это можно объяснить тем, что нейронная сеть обучалась на данных из набора MNIST, где изображения цифр представлены с меньшим поворотом, то есть у сети не было информации для верного определения значения цифры, изображение которой представлено при большом угле поворота.
10