Создание программы распознавания рукописных цифр с использованием классификатора ближайшего соседа

Классификатор ближайшего соседа - один из самых базовых алгоритмов машинного обучения. В этом руководстве описывается очень простой метод создания программы распознавания цифр. Мы не будем использовать здесь какие-либо библиотеки машинного обучения на Python. Итак, приступим

Импорт необходимых библиотек

from sklearn import datasets
import matplotlib.pyplot as plt
import numpy as np

Цифровые данные sklearn будут использоваться в этом руководстве.

Загрузка набора данных

digits = datasets.load_digits()

Визуализация данных

digits.data содержит изображения в линейном массиве (в данном случае 64 x 1), а digits.images хранит их в массиве 8 x 8. Выведем число

fig = plt.figure()
plt.imshow(digits.images[23],cmap = plt.cm.gray_r)
txt = "This is %d"%digits.target[23]
fig.text(0.1,0.1,txt)
plt.show()

это даст нам изображение с индексом 23

Теперь давайте посмотрим, как это же изображение выглядит как массив.

digits.images[23]

Это даст результат как

array([[  0.,   1.,   8.,  12.,  15.,  14.,   4.,   0.],
       [  0.,   3.,  11.,   8.,   8.,  12.,  12.,   0.],
       [  0.,   0.,   0.,   0.,   2.,  13.,   7.,   0.],
       [  0.,   0.,   0.,   2.,  15.,  12.,   1.,   0.],
       [  0.,   0.,   0.,   0.,  13.,   5.,   0.,   0.],
       [  0.,   0.,   0.,   0.,   9.,  13.,   0.,   0.],
       [  0.,   0.,   7.,   8.,  14.,  15.,   0.,   0.],
       [  0.,   0.,  14.,  15.,  11.,   2.,   0.,   0.]])

Чем темнее пиксель, тем больше номер. Если вы наведете курсор на большие числа в массиве, вы увидите, что он создает 3 ».

Набор данных для обучения и тестирования

Мы выберем первые 100 изображений в качестве набора данных для обучения.

x = 100 #length of training data set
X_train = digits.data[0:x]
Y_train = digits.target[0:x]

Набор данных тестирования

pred = 813
X_test = digits.data[pred]
print "X_test's real value is %d"%digits.target[pred]

Для нашей программы мы найдем расстояния тестового изображения для каждого тренировочного изображения, а изображение с наименьшим расстоянием является прогнозируемым значением. Под расстоянием я подразумеваю евклидово расстояние в 64 измерениях. Чтобы вычислить евклидово расстояние, мы просто найдем разницу между числами в каждом индексе, возведем их в квадрат, сложим и затем извлечем квадратный корень. Итак, давайте определим функцию dist.

def dist(x,y):
 return np.sqrt(np.sum((x-y)**2))

Эта функция будет работать для любого размерного массива, если и x, и y имеют одинаковые размеры (одна из причин, почему я люблю python: P).

Теперь давайте предскажем тестовые данные с помощью функции dist.

l = len(X_train)
distance = np.zeros(l) 
for i in range(l):
 distance[i] = dist(X_train[i],X_test)
min_index = np.argmin(distance)
print "Preditcted value is ",
print(Y_train[min_index])

Это напечатает прогнозируемое значение, которое в данном случае равно 9.

Точность нашей модели

Теперь давайте посмотрим, насколько хорошо наша модель предсказывает.

l = len(X_train)
no_err = 0
distance = np.zeros(l)
for j in range(1697,1797):
 X_test = digits.data[j]
 for i in range(l):
  distance[i] = dist(X_train[i],X_test)
 min_index = np.argmin(distance)
 if Y_train[min_index] != digits.target[j]:
  no_err+=1
print "Total errors for train length = %d is %d"%(x,no_err)

В нашем наборе данных тестирования 100 примеров. В цикле for он предсказывает номер изображения по индексу j и сравнивает его с его фактическим значением, а затем печатает общее количество ошибок. Когда значения x = 100 14/100 предсказаны неверно, а для x = 1696 2/100 значения неверно предсказаны. Таким образом, наша модель предсказывает изображения с точностью 98%.

Прогнозирование пользовательских входов (если вы хотите кому-то показать: P)

Это вторая часть руководства, в которой мы будем делать прогнозы для пользовательских входных данных. Вы можете использовать любой редактор изображений, здесь мы будем использовать G.I.M.P.

Следуй этим шагам

  1. Откройте GIMP
  2. Ctrl + N
  3. В следующем окне укажите высоту и ширину как 8. Возможно, вам придется увеличить масштаб, так как лист очень маленький.
  4. Теперь прокрутите. Если размер указателя меняется, переходите к следующему шагу, в противном случае следуйте этому, чтобы вы могли изменить размер указателя.
  5. Уменьшите размер указателя до минимума.
  6. Выберите Инструменты → Инструменты для рисования → Кисть или нажмите P.
  7. Скажите человеку нарисовать число в этом файле.
  8. Перейдите в Файл → Экспорт и сохраните изображение как test.png.

Код Python для доступа к изображению test.png

from scipy import misc
image = misc.imread("/path_to_test.png/test.png",flatten = 1)

Теперь, если вы напечатаете digits.images[0], вы увидите, что белый пиксель эквивалентен 0 и больше значения, темнее будет пиксель, но если вы напечатаете image, который находится в стандартной форме, 255 для белого и 0 для полного черного. Поэтому нам нужно преобразовать его так, чтобы белый цвет соответствовал 0, а затем мы изменим форму изображения с 8 x 8 на 64 x 1.

image1 = 255 - image
image2 = np.reshape(image1,64)

Если вы посмотрите на любой пример digits.images, вы увидите, что самый черный пиксель соответствует ~ 15, но максимальное значение любого пикселя в вашем пользовательском вводе может быть 255, поэтому, чтобы избежать каких-либо ошибок из-за этого эффекта, мы нормализуем данные (т.е. измените масштаб между 0 и 1). Для этого мы просто найдем максимальное число в массиве и разделим каждый элемент на это максимальное число.

# Training data
for i in xrange(len(X_train)):
 maximum = np.amax(X_train[i])
 X_train[i]/=maximum
#Testing data
maximum = np.amax(X_test)
X_test/=maximum

Теперь все готово. Прогнозируем :)

l = len(X_train)
distance = np.zeros(l) #This will store the distance of test from every training value
for i in range(l):
 distance[i] = dist(X_train[i],X_test)
min_index = np.argmin(distance)
# print X_test
print "Preditcted value is "
print(Y_train[min_index])

Это напечатает

Predicted value is 2

Вы можете делать больше изображений и предсказывать их.

Весь код доступен здесь [https://github.com/Salil-Jain/DigitRecognizer]

Спасибо.