python

Распознавание цифр, для максимально маленьких (python/keras)

  • среда, 14 декабря 2022 г. в 00:44:24
https://habr.com/ru/post/705306/
  • Python


Этот пост я решил написать, для тех, кто также искал понятный код и рабочий пример, который можно было взять, вставить в гугл колаб(google colab) и сразу начать "играться" с кодом. Но не нашел. Для вас, друзья!

P.S весь код будет в конце.

Импортируем бэкэнд кераса, по началу, мы его использовать не будем, но некоторые функции нам понадобятся

import tensorflow as tf

Импортируем сам пакет машинного обучения , его и будем использовать.

import keras

Математические функции которые нам тоже понадобятся.

import numpy as np

Библиотека для вывода изображений.

import matplotlib.pyplot as plt

Для чего эта строчка? - нагуглите сами.

%matplotlib inline

Имортируем слои, вернее классы слоёв для нашей нейронной сети.

from keras.layers import Dense, Flatten

Импорт нашей последовательной модели.

from keras.models import Sequential

Импортируем набор данных MNIST для нашего обучения.

from keras.datasets import mnist

Загружаем данные функцией load_data из названия нашего датасета mnist и разделяем наш датасет на тренировочную выборку и тестовую.

(X_train, y_train), (X_test, y_test) = mnist.load_data()

Давайте посмотрим, что за изображения у нас и в какой они форме.

print(X_train.shape)

Вот, мы видим, что X_train представляет из себя массив данных с 60000 экземпляров картинок, которые имеют разрешение 28 на 28.

Теперь давайте посмотрим , что такое y_train.

print(y_train.shape)

Мы видим , что это просто массив из 60000 значений не и более того.

А теперь давайте посмотрим, что же именно храниться в массивах, если X_train - массив изображений, давайте откроем одно!

Выводим 12 изображение из массива, и это цифра 3

plt.imshow(X_train[12], cmap='binary')
plt.axis('off')
print(y_train[12])

Вот мы и видим цифра 3 и картинку с цифрой 3!

Как вы все знаете, значение пикселя может быть от 0 до 255, и если мы будем подавать в нейронную сеть такие данные. Пиксель со значением 0 и пиксель со значением 255 имеют очень разные масштабы значений. Нам очень тяжело будет учить модель.

И чтобы их "нормировать", чтобы они были от 0 до 1 в идеале, мы разделим все наше "добро" на 255.

0 / 255 = 0 , 255 / 255 = 1, а любое число в диапазоне от 0 не до 255 будет просто дробью.

X_train = X_train/255
X_test = X_test/255

Вот что мы получили:

print(y_train[0])

К сожалению, нельзя дать нейронке фото и сказать что это цифра 4, нужно это значение "векторизировать", это делается вот так:

y_train = keras.utils.to_categorical(y_train, 10)
y_test = keras.utils.to_categorical(y_test, 10)

Получилось:

print(y_train[0])

Теперь давайте напишем саму модель нейронной сети.

Инициализируем нашу модель.

model = Sequential()

Дальше создаем наш первый слой, в нём будет 32 нейрона, также нужно указать форму входимых данных.

model.add(Dense(32, activation='relu', input_shape=(X_train[0].shape)))

Ещё дальше создаем 4 нейрона с такой же функцией активации.

model.add(Dense(64, activation='relu'))
model.add(Dense(128, activation='relu'))
model.add(Dense(256, activation='relu'))
model.add(Dense(512, activation='relu'))

Мы вытягиваем данные в вектор.

model.add(Flatten())

И тут мы сравниваем вектор с вектором, по сути это так.

model.add(Dense(10, activation='sigmoid'))

Тут компилируем нашу модель, оптимайзер - адам, потому-что он очень "классный", "categorical_crossentropy" - т.к мы определяем категории объектов.

model.compile(loss='categorical_crossentropy', 
              optimizer='adam', 
              metrics=['accuracy'])

Теперь тренируем модель:

model.fit(X_train, y_train, epochs=50 )

Мы обучили нашу нейронную сеть и теперь, давайте посмотрим на результат.

Будем использовать команду "model.evaluate", если перевести дословно - модель.оценивать

Принимает проверочный датасет и смотрим какая потеря и какая точность:

Как мы видим, точность - 96%.

Создадим переменную k и запишем туда номер изображения в датасете и будем его вызывать.

Указали цифру 6, значит цифра 4 находится под индексом 6.

k = 6
plt.imshow(X_test[k], cmap='binary')
plt.axis('off')
print(y_test[k])

Давайте укажем индекс 10, получили цифру 0.

k = 10
plt.imshow(X_test[k], cmap='binary')
plt.axis('off')
print(y_test[k])

Теперь посмотрим, как именно работает наша нейронная сеть.

k = 6
plt.imshow(X_test[k], cmap='binary')
plt.axis('off')
print(y_test[k])
print(
    model.predict(np.array([X_test[k]]))
)

[0. 0. 0. 0. 1. 0. 0. 0. 0. 0.] - единичка под индексом 4 , соответственно - цифра 4. 

Визуально на картинке мы тоже видим цифру 4.

Теперь давайте рассмотрим ответ нейронной сети:

[[0.0000000e+00, 9.9408084e-18, 2.8947007e-22, 2.9116518e-10, 1.0000000e+00,

  4.6417094e-17, 3.7773155e-38, 5.8520163e-07,, 3.7786970e-24, 4.3130936e-07]]

* - буква e это значение степени, рассмотрим число - 4.6417094e-17 

число 4.6417094e-17 - это условно 4.6427 в минус 17 степени,  это  примерно 0.00000000000000004642 то есть очень маленькое число.

Посмотрим на весь массив и увидим, что есть число 0 в 0-ой степени ,  числа в отрицательной степени , и то, что нам нужно 1 в степени 0, любое число в нулевой степени равно единице.

Максимальный элемент массива под индексом 4, соответственно, цифра- 4.

Изменим индекс и посмотрим, что будет.

k = 10
plt.imshow(X_test[k], cmap='binary')
plt.axis('off')
print(y_test[k])
print(
    model.predict(np.array([X_test[k]]))
)

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

Надеюсь, вам понравился мой пост и он будет вам полезен, вот весь код для вставки в гугл колаб:

import tensorflow as tf

import keras

import numpy as np

import matplotlib.pyplot as plt
%matplotlib inline
 
from keras.layers import Dense, Flatten

from keras.models import Sequential

from keras.datasets import mnist

(X_train, y_train), (X_test, y_test) = mnist.load_data()

print(X_train.shape)

print(y_train.shape)

plt.imshow(X_train[12], cmap='binary')
plt.axis('off')
print(y_train[12])

X_train = X_train/255
X_test = X_test/255

print(y_train[0])

y_train = keras.utils.to_categorical(y_train, 10)
y_test = keras.utils.to_categorical(y_test, 10)

print(y_train[0])

model = Sequential()

model.add(Dense(32, activation='relu', input_shape=(X_train[0].shape)))

model.add(Dense(64, activation='relu'))
model.add(Dense(128, activation='relu'))
model.add(Dense(256, activation='relu'))
model.add(Dense(512, activation='relu'))

model.add(Flatten())

model.add(Dense(10, activation='sigmoid'))

model.compile(loss='categorical_crossentropy', 
              optimizer='adam', 
              metrics=['accuracy'])

model.fit(X_train, y_train, epochs=50 )


k = 6
plt.imshow(X_test[k], cmap='binary')
plt.axis('off')
print(y_test[k])

k = 10
plt.imshow(X_test[k], cmap='binary')
plt.axis('off')
print(y_test[k])

2 блок кода:

k = 6
plt.imshow(X_test[k], cmap='binary')
plt.axis('off')
print(y_test[k])
print(
    model.predict(np.array([X_test[k]]))
)


k = 10
plt.imshow(X_test[k], cmap='binary')
plt.axis('off')
print(y_test[k])
print(
    model.predict(np.array([X_test[k]]))
)