LeNet-5 (Python Tensorflow, реализация)
Здравствуйте, это Арвин. В этой статье я собираюсь написать о том, как использовать Lenet-5 на наборе данных Mnist. LeNet — это простая структура сверточной нейронной сети (AKA CNN). На изображении ниже вы можете увидеть архитектуру LeNet, но я не буду вдаваться в подробности, что это значит, нас интересует только его приложение и код.
Я буду использовать Google Colab для кодирования, вы также можете использовать Jupyter Notebook для локальной реализации Священного Писания. полный код доступен по следующей ссылке
Если вы хотите ознакомиться с теорией слоев LeNet-5, перейдите по этой ссылке:
ИМПОРТ
Здесь мы импортируем все пакеты Python, которые будем использовать в блокноте. Как всегда, сначала мы импортируем «numpy» и «matplotlib.pyplot», а затем переходим к импорту множества функций и слоев tensorflow.
import numpy as np import matplotlib.pyplot as plt import tensorflow from tensorflow.keras.datasets import mnist from tensorflow.keras.utils import to_categorical from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Dropout from tensorflow.keras.layers import Flatten, Conv2D, MaxPooling2D
мы также импортируем набор данных Mnist из tensorflow.keras.datasets.
ЗАГРУЗКА ДАННЫХ
Здесь мы делаем шаги, которые мы ранее объяснили в этой статье, чтобы получить доступ к набору данных Mnist. Это означает, что прежде всего мы должны загрузить функции/цели обучения/тестирования в соответствующие массивы:
(X_train, y_train), (X_valid, y_valid) = mnist.load_data()
Вывод будет выглядеть так:
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz 11490434/11490434 [==============================] - 0s 0us/step
Теперь пришло время проверить, правильно ли загружены данные. Мы делаем это, проверяя размеры загруженных данных и некоторые образцы функций и целей. если числа совпадают, то данные готовы к использованию. Во-первых, форма:
print("Dimensions of X_train are:", X_train.shape) print("Dimensions of y_train are:", y_train.shape) print("Dimensions of X_valid are:", X_valid.shape) print("Dimensions of y_valid are:", y_valid.shape)
Вывод будет:
Dimensions of X_train are: (60000, 28, 28) Dimensions of y_train are: (60000,) Dimensions of X_valid are: (10000, 28, 28) Dimensions of y_valid are: (10000,)
Форма признаков должна состоять из:
(количество_выборок, высота_изображения, ширина_изображения)
И форма целевых массивов состоит из:
(количество_выборок)
Выходные данные прекрасно это показывают, так как для обучающих данных у нас есть 60 000 выборок, а ширина и высота равны 28 пикселям. Так что размеры совпадают. Теперь мы переходим к просмотру некоторых образцов изображений, как показано ниже:
plt.figure(figsize=(2, 4)) for k in range(4): plt.subplot(1, 4, k+1) plt.imshow(X_train[k], cmap="Greys") plt.axis("off") plt.tight_layout() plt.show() print(y_train[0:4])
И вывод этого:
[5 0 4 1]
Теперь мы уверены в загруженных данных, и я могу перестать писать то, что уже написал.
ПРЕДВАРИТЕЛЬНАЯ ОБРАБОТКА ДАННЫХ
Теперь нам нужно подготовить загруженные данные для использования в качестве входных данных для нашей модели нейронной сети. Мы преобразуем массивы в форму:
(количество_выборок, высота_изображения, ширина_изображения, количество_каналов)
и под количеством каналов я подразумеваю количество цветовых каналов, которое в изображениях в градациях серого равно 1, а в изображениях RGB равно 3. Мы также меняем тип данных на float32, потому что мы хотим иметь возможность безопасно делить числа, и это невозможно сделать, если число тип целочисленный.
X_train = X_train.reshape(-1, 28, 28, 1).astype("float32") X_valid = X_valid.reshape(-1, 28, 28, 1).astype("float32") X_train.shape
Вывод будет:
(60000, 28, 28, 1)
Далее нормализуем данные, разделив их на 255.
X_train /= 255 X_valid /= 255
После использования горячего кодировщика на целевых массивах обучения/тестирования мы закончим часть предварительной обработки.
n_classes = 10 y_train = to_categorical(y_train, n_classes) y_valid = to_categorical(y_valid, n_classes)
НЕЙРОСЕТЕВАЯ МОДЕЛЬ
Здесь мы, наконец, можем построить структуру модели. Для первого слоя у нас есть слой 2D-Convolution с 32 выходными фильтрами и ядром размером 3 * 3 и функцией активации ReLU. Для второго слоя снова у нас есть слой, аналогичный предыдущему, за исключением того, что у этого есть 64 фильтра вместо 32 выходных фильтров.
Далее следует слой MaxPooling, размер фильтра будет 2*2, а после этого будет слой отсева, слой сглаживания, слой активации ReLU, еще один отсев и, наконец, слой softmax для окончательной классификации.
model = Sequential() model.add(Conv2D(32, kernel_size=(3, 3), activation="relu", input_shape=(28, 28, 1))) model.add(Conv2D(64, kernel_size=(3, 3), activation="relu")) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) model.add(Flatten()) model.add(Dense(128, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(n_classes, activation='softmax')) model.summary()
Резюме модели:
Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d (Conv2D) (None, 26, 26, 32) 320 conv2d_1 (Conv2D) (None, 24, 24, 64) 18496 max_pooling2d (MaxPooling2D (None, 12, 12, 64) 0 ) dropout (Dropout) (None, 12, 12, 64) 0 flatten (Flatten) (None, 9216) 0 dense (Dense) (None, 128) 1179776 dropout_1 (Dropout) (None, 128) 0 dense_1 (Dense) (None, 10) 1290 ================================================================= Total params: 1,199,882 Trainable params: 1,199,882 Non-trainable params: 0 _________________________________________________________________
Изучив сводку, можно увидеть, что у нас около миллиона параметров. Теперь переходя к настройке модели, пишем следующий код:
model.compile(loss='categorical_crossentropy', optimizer='nadam', metrics=['accuracy'])
Это гарантирует, что мы используем категориальную функцию перекрестной энтропийной потери и Nadam в качестве нашего оптимизатора. Надам — это алгоритм Адама с импульсом Нестерова.
мы подгоняем модель к нашим данным
model.fit(X_train, y_train, batch_size=128, epochs=10, verbose=1, validation_data=(X_valid, y_valid))
Вывод будет выглядеть так:
Epoch 1/10 469/469 [==============================] - 5s 10ms/step - loss: 0.0486 - accuracy: 0.9841 - val_loss: 0.0316 - val_accuracy: 0.9885 ... Epoch 10/10 469/469 [==============================] - 5s 11ms/step - loss: 0.0191 - accuracy: 0.9936 - val_loss: 0.0298 - val_accuracy: 0.9919 <keras.callbacks.History at 0x7f5dd233ac70>
То есть всего за 10 эпох мы достигли уровня точности ~99%. Для окончательной оценки производительности имеем:
model.evaluate(X_valid, y_valid)
Вывод будет:
313/313 [==============================] - 1s 3ms/step - loss: 0.0298 - accuracy: 0.9919 [0.02975442260503769, 0.9919000267982483]
И мы закончили. хорошая работа всем