Создание программы распознавания рукописных цифр с использованием классификатора ближайшего соседа
Классификатор ближайшего соседа - один из самых базовых алгоритмов машинного обучения. В этом руководстве описывается очень простой метод создания программы распознавания цифр. Мы не будем использовать здесь какие-либо библиотеки машинного обучения на 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.
Следуй этим шагам
- Откройте GIMP
- Ctrl + N
- В следующем окне укажите высоту и ширину как 8. Возможно, вам придется увеличить масштаб, так как лист очень маленький.
- Теперь прокрутите. Если размер указателя меняется, переходите к следующему шагу, в противном случае следуйте этому, чтобы вы могли изменить размер указателя.
- Уменьшите размер указателя до минимума.
- Выберите Инструменты → Инструменты для рисования → Кисть или нажмите P.
- Скажите человеку нарисовать число в этом файле.
- Перейдите в Файл → Экспорт и сохраните изображение как 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]
Спасибо.