Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

22 KiB

Лабораторная работа №3: Распознавание изображений

Пивоваров Я.В; Сидора Д.А. — А-02-22

Номер бригады - 4

Цель работы

Получить практические навыки создания, обучения и применения сверточных нейронных сетей для распознавания изображений. Познакомиться с классическими показателями качества классификации.

Определение варианта

  • Номер бригады: k = 4
  • random_state = (4k - 1) = 15

Подготовка среды

import os 
os.chdir('/content/drive/MyDrive/Colab Notebooks/IS_LR3')

ЗАДАНИЕ 1

Пункт №1. Импорт необходимых для работы библиотек и модулей.

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.

from keras.datasets import mnist 
(X_train, y_train), (X_test, y_test) = mnist.load_data()

Пункт №3. Разбиение набора данных на обучающие и тестовые данные.

# создание своего разбиения датасета 
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 = 15)

# вывод размерностей 
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. Проведене предобработки данных.

# Зададим параметры данных и модели 
num_classes = 10 
input_shape = (28, 28, 1) 
 
# Приведение входных данных к диапазону [0, 1]  
X_train = X_train / 255 
X_test = X_test / 255 
 
# Расширяем размерность входных данных, чтобы каждое изображение имело 
# размерность (высота, ширина, количество каналов) 

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 
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. Реализация модели сверточной нейронной сети и ее обучение.

# создаем модель 
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()

Результат выполнения:

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

Model: "sequential" Total params: 34,826 (136.04 KB) Trainable params: 34,826 (136.04 KB) Non-trainable params: 0 (0.00 B)

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. Оценка качества обучения на тестовых данных.

# Оценка качества работы модели на тестовых данных 
scores = model.evaluate(X_test, y_test) 
print('Loss on test data:', scores[0]) 
print('Accuracy on test data:', scores[1])

Результат выполнения:

accuracy: 0.9879 - loss: 0.0347
Loss on test data: 0.029493918642401695
Accuracy on test data: 0.9897000193595886

Пункт №7. Выведение изображения, истинных меток и результатов распознавания.

# вывод первого тестового изображения и результата распознавания 
n = 123
result = model.predict(X_test[n:n+1]) 
print('NN output:', result) 
plt.show() 
plt.imshow(X_test[n].reshape(28,28), cmap=plt.get_cmap('gray')) 
print('Real mark: ', np.argmax(y_test[n])) 
print('NN answer: ', np.argmax(result))

Результаты

Результат выполнения:

NN output: [[2.3518596e-06 6.1697922e-09 4.1554195e-08 9.1088831e-10 6.7171044e-08
  4.2173593e-07 9.9999619e-01 4.8130029e-12 9.8848705e-07 3.4416045e-10]]
Real mark:  6
NN answer:  6
# вывод второго тестового изображения и результата распознавания 
n = 110
result = model.predict(X_test[n:n+1]) 
print('NN output:', result) 
plt.show() 
plt.imshow(X_test[n].reshape(28,28), cmap=plt.get_cmap('gray')) 
print('Real mark: ', np.argmax(y_test[n])) 
print('NN answer: ', np.argmax(result))

Результаты

Результат выполнения:

NN output: [[1.0611644e-07 1.0055461e-09 2.8356731e-06 1.8714800e-05 1.1500048e-09
  8.8623995e-07 1.1646066e-07 5.1164142e-12 9.9997735e-01 4.7718437e-08]]
Real mark:  8
NN answer:  8

Пункт №8. Вывод отчета о качестве классификации тестовой выборки.

# истинные метки классов 
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()

Результаты

Результат выполнения:

              precision    recall  f1-score   support

           0       0.99      0.99      0.99       980
           1       0.99      1.00      0.99      1135
           2       0.98      0.99      0.99      1032
           3       0.99      0.99      0.99      1010
           4       0.99      0.99      0.99       982
           5       0.99      0.99      0.99       892
           6       1.00      0.99      0.99       958
           7       0.99      0.98      0.99      1028
           8       0.98      0.99      0.99       974
           9       0.99      0.98      0.99      1009

    accuracy                           0.99     10000
   macro avg       0.99      0.99      0.99     10000
weighted avg       0.99      0.99      0.99     10000

Пункт №9. Подача на вход обученной нейронной сети собственного изображения.

# загрузка собственного изображения 1
from PIL import Image 
file_data = Image.open('test.png') 
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
# загрузка собственного изображения 2
from PIL import Image 
file_data = Image.open('test_2.png') 
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  8

Пункт №10. Загрузка с диска модели, сохраненной при выполнении лабораторной работы №1.

# путь к сохранённой модели из ЛР1
model_fc = keras.models.load_model('/content/drive/MyDrive/Colab Notebooks/best_model/model100.keras')

# архитектура модели
model_fc.summary()

Результат выполнения:

Layer (type) Output Shape Param #
dense_1 (Dense) (None, 100) 78,500
dense_2 (Dense) (None, 10) 1,010

Model: "sequential_1" Total params: 79,512 (310.60 KB)
Trainable params: 79,510 (310.59 KB)
Non-trainable params: 0 (0.00 B)
Optimizer params: 2 (12.00 B)

# подготовка тестовых данных для полносвязной модели
X_test_fc = X_test.reshape(X_test.shape[0], 28*28)  # (10000, 784)
y_test_fc = y_test  # если в ЛР3 ты уже перевёл метки в one-hot

# оценка качества, как в п. 6
scores = model_fc.evaluate(X_test_fc, y_test_fc, verbose=0)
print('Loss on test data (FC model):', scores[0])
print('Accuracy on test data (FC model):', scores[1])

Результат выполнения:

Loss on test data (FC model): 0.19745591282844543
Accuracy on test data (FC model): 0.9442999958992004

Пункт №11. Сравнение обученной модели сверточной сети и наилучшей модели полносвязной сети из лабораторной работы №1.

Сравнение моделей:

Количество настраиваемых параметров в сети:
Сверточная сеть: 34 826 параметров.
Полносвязная сеть: 79 512 параметров.
При том что число параметров сверточной сети меньше в 2 раза, она показывает более высокие результаты. Это связано с более эффективным использовании весов за счёт свёрток и фильтров.

Количество эпох обучения:
Сверточная сеть обучалась 15 эпох.
Полносвязная сеть обучалась 100 эпох.
Cверточная модель достигает лучшего результата при меньшем количестве эпох, то есть сходится быстрее и обучается эффективнее.

Качество классификации тестовой выборки:
Сверточная сеть: Accuracy ≈ 0.989, loss ≈ 0.025.
Полносвязная сеть: Accuracy ≈ 0.944, loss ≈ 0.197.
Сверточная нейросеть точнее на 4,5 процента, при этом её ошибка почти в 8 раз меньше.

Вывод:
Использование сверточной нейронной сети для распознавания изображений даёт ощутимо лучший результат по сравнению с полносвязной моделью. Сверточная нейронная сеть требует меньше параметров, быстрее обучается и точнее распознаёт изображения, поскольку учитывает их структуру и выделяет важные визуальные особенности.

ЗАДАНИЕ 2

Пункт №1. Импорт необходимых для работы библиотек и модулей.

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. Загрузка набора данных CIFAR-10.

from keras.datasets import cifar10 
 (X_train, y_train), (X_test, y_test) = cifar10.load_data()

Пункт №3. Разбиение набора данных на обучающие и тестовые данные.

# создание своего разбиения датасета
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 = 50000,
                                                    random_state = 15)
# вывод размерностей 
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 изображений из обучающей выборки с подписями классов 
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()

Результаты

Пункт №4. Проведене предобработки данных.

# Зададим параметры данных и модели 
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 
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)

Пункт №5. Реализация модели сверточной нейронной сети и ее обучение.

# создаем модель 
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.Conv2D(128, kernel_size=(3, 3), activation="relu")) 
model.add(layers.MaxPooling2D(pool_size=(2, 2))) 
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()

Результат выполнения:

Layer (type) Output Shape Param #
conv2d_2 (Conv2D) (None, 30, 30, 32) 896
max_pooling2d_2 (MaxPooling2D) (None, 15, 15, 32) 0
conv2d_3 (Conv2D) (None, 13, 13, 64) 18,496
max_pooling2d_3 (MaxPooling2D) (None, 6, 6, 64) 0
conv2d_4 (Conv2D) (None, 4, 4, 128) 73,856
max_pooling2d_4 (MaxPooling2D) (None, 2, 2, 128) 0
flatten_1 (Flatten) (None, 512) 0
dense_1 (Dense) (None, 128) 65,664
dropout_1 (Dropout) (None, 128) 0
dense_2 (Dense) (None, 10) 1,290

Model: "sequential_1" Total params: 160,202 (625.79 KB)
Trainable params: 160,202 (625.79 KB)
Non-trainable params: 0 (0.00 B)

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. Оценка качества обучения на тестовых данных.

# Оценка качества работы модели на тестовых данных 
scores = model.evaluate(X_test, y_test) 
print('Loss on test data:', scores[0]) 
print('Accuracy on test data:', scores[1])

Результат выполнения:

accuracy: 0.6606 - loss: 0.9661
Loss on test data: 0.9636631608009338
Accuracy on test data: 0.6610000133514404

Пункт №7. Выведение изображения, истинных меток и результатов распознавания.

# правильно распознанное изображение
n = 10
result = model.predict(X_test[n:n+1])
print('NN output:', result)

plt.imshow(X_test[n])
plt.show()

print('Real class: ', np.argmax(y_test[n]), '->', class_names[np.argmax(y_test[n])])
print('NN answer:', np.argmax(result), '->', class_names[np.argmax(result)])

Результаты

Результат выполнения:

NN output: [[0.10896349 0.00272794 0.09209334 0.0585838  0.10545123 0.01161931 0.02007959 0.00301177 0.5926725  0.00479708]]

Real class:  8 -> ship
NN answer: 8 -> ship
# неверно распознанное изображение
n = 9
result = model.predict(X_test[n:n+1])
print('NN output:', result)

plt.imshow(X_test[n])
plt.show()

print('Real class: ', np.argmax(y_test[n]), '->', class_names[np.argmax(y_test[n])])
print('NN answer:', np.argmax(result), '->', class_names[np.argmax(result)])

Результаты

Результат выполнения:

NN output: [[1.3848362e-03 7.8314954e-01 3.4030385e-05 9.6045173e-04 9.4775232e-06 1.3942986e-04 1.3377360e-03 4.9578721e-06 9.0055494e-03 2.0397398e-01]]

Real class:  9 -> truck
NN answer: 1 -> automobile

Пункт №8. Вывод отчета о качестве классификации тестовой выборки.

# истинные метки классов 
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)

# отрисовка матрицы ошибок в виде "тепловой карты" 
display = ConfusionMatrixDisplay(confusion_matrix=conf_matrix,
                                 display_labels=class_names)
display.plot(xticks_rotation=45)
plt.show()

Результаты

Результат выполнения:

              precision    recall  f1-score   support

    airplane       0.74      0.65      0.69      1015
  automobile       0.81      0.76      0.78       933
        bird       0.54      0.54      0.54      1010
         cat       0.50      0.40      0.44      1025
        deer       0.60      0.61      0.60       998
         dog       0.52      0.62      0.57      1006
        frog       0.70      0.77      0.73      1010
       horse       0.73      0.70      0.71      1005
        ship       0.77      0.79      0.78      1001
       truck       0.72      0.78      0.75       997

    accuracy                           0.66     10000
   macro avg       0.66      0.66      0.66     10000
weighted avg       0.66      0.66      0.66     10000