Компьютерное зрение — распознавание kNN рукописных цифр (10)

искусственный интеллект TensorFlow алгоритм компьютерное зрение

1. Введение в рукописные цифры MNIST

1. Получите образцы

База данных рукописных цифр MNIST доступна на этой странице с обучающим набором из 60 000 примеров и тестовым набором из 10 000 примеров. Это подмножество более крупного набора, предоставленного NIST. Фигуры нормализованы по размеру и центрированы на изображении фиксированного размера.

Ссылка для скачивания: http://yann.lecun.com/exdb/mnist/

Образец состоит из четырех частей:

Образ обучающего набора: train-images-idx3-ubyte.gz
(9,9 МБ, 47 МБ в разархивированном виде, содержит 60 000 образцов)

Метка, соответствующая изображению обучающего набора: train-labels-idx1-ubyte.gz
(29 КБ, 60 КБ в разархивированном виде, содержит 60 000 тегов)

Test set images: t10k-images-idx3-ubyte.gz
(1,6 МБ, 7,8 МБ в распакованном виде, содержит 10 000 образцов)

Test set labels: t10k-labels-idx1-ubyte.gz
(5 КБ, 10 КБ в разархивированном виде, содержит 10 000 тегов)

2. Анализ МНИСТ

MNIST — классическая демонстрация глубокого обучения.Он состоит из 60 000 обучающих картинок и 10 000 тестовых картинок.Каждая картинка имеет размер 28*28 (как показано на рисунке ниже) и состоит из черно-белых (здесь черный это число с плавающей запятой 0-1, чем темнее черный, тем ближе значение к 1) Эти картинки собраны разными людьми, написавшими числа от 0 до 9. TensorFlow инкапсулирует этот набор данных и связанные операции в библиотеку.Давайте шаг за шагом интерпретируем процесс глубокого обучения MNIST.

Вышеприведенное изображение представляет собой 4 изображения MNIST. Эти изображения не являются изображениями в формате png или jpg в традиционном смысле, поскольку формат изображения PNG или jpg будет нести много информации о помехах (такой как: блок данных, заголовок изображения, конец изображения, длина и т. д.), эти изображения будут be Он обрабатывается в очень простой двумерный массив, как показано на рисунке:

Видно, что график, образованный значениями в матрице, очень похож на график слева. Это делается для того, чтобы сделать модель проще и понятнее. Особенности более очевидны.

2. Принцип kNN

1. Обзор алгоритма kNN

Основная идея алгоритма   kNN состоит в том, что если большинство из k ближайших соседей выборки в пространстве признаков принадлежат к определенной категории, то выборка также принадлежит к этой категории и имеет характеристики выборок этой категории. Этот метод определяет только категорию пробы, подлежащей классификации, в соответствии с категорией ближайшей одной или нескольких проб при принятии решения о классификации.

2. Введение в алгоритм kNN

  Самый простой и основной классификатор состоит в том, чтобы записывать все категории, соответствующие обучающим данным.Когда атрибуты тестового объекта точно соответствуют атрибутам обучающего объекта, его можно классифицировать. Но как возможно, чтобы все тестовые объекты находили в точности соответствующие им обучающие объекты?Во-вторых, существует проблема, связанная с тем, что тестовый объект сопоставляется с несколькими обучающими объектами одновременно, в результате чего обучающий объект делится на несколько классов. Исходя из этих проблем, только что сгенерированный kNN.

  kNN классифицируется путем измерения расстояния между различными значениями признаков. Его идея такова: если большинство из k наиболее похожих выборок в пространстве признаков (то есть ближайших соседей в пространстве признаков) принадлежат к определенной категории, то выборка также принадлежит к этой категории. K обычно представляет собой целое число, не превышающее 20. В алгоритме kNN выбранными соседями являются все правильно классифицированные объекты. В решении о классификации этот метод определяет только категорию пробы, подлежащей классификации, в соответствии с категорией ближайшей одной или нескольких проб.

Вот простой пример для иллюстрации:

   Как показано на рисунке ниже, к какому классу должен быть отнесен зеленый кружок, красный треугольник или синий квадрат? Если K=3, поскольку пропорция красных треугольников равна 2/3, зеленому кружку будет присвоен класс красных треугольников, если K=5, так как пропорция синих четырехугольников равна 3/5, будет присвоен зеленый кружок класс синих квадов Квадратный класс.

Это также показывает, что результат алгоритма kNN в значительной степени зависит от выбора K.

  В kNN расстояние между объектами рассчитывается как индикатор несходства между каждым объектом, избегая проблемы соответствия между объектами, где расстояние обычно использует евклидово расстояние или манхэттенское расстояние:

  В то же время kNN принимает решения на основе доминирующей категории среди k объектов, а не решения по одной категории объектов. Эти два момента являются преимуществами алгоритма kNN.

Далее подытожим идею алгоритма kNN:

То есть, когда данные и метки в обучающем наборе известны, введите тестовые данные, сравните характеристики тестовых данных с соответствующими функциями в обучающем наборе и найдите наиболее похожие верхние данные K в обучающем наборе, затем тестовые данные соответствуют категории с наибольшим количеством вхождений в данных K, и ее алгоритм описывается как:

1) Рассчитать расстояние между тестовыми данными и каждыми обучающими данными;

2) Сортировка по возрастанию отношения расстояния;

3) Выберите K точек с наименьшим расстоянием;

4) Определить частоту встречаемости категории, к которой относятся первые K баллов;

5) Верните категорию с наибольшей частотой в верхних K баллах в качестве предсказанной классификации тестовых данных.

Оригинальная ссылка: https://www.cnblogs.com/sxron/p/5451923.html

Три, пример объяснения

1. Загрузите данные MNIST

TensorFlow подготовил скрипт для автоматической загрузки и импорта набора данных MNIST. Он автоматически создаст каталог «MNIST_data» для хранения данных.

import tensorflow as tf
import numpy as np
import random 
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data',one_hot=True)
# one_hot介绍 :https://blog.csdn.net/lanhaier0591/article/details/78702558

Здесь mnist — легковесный класс. Он хранит наборы данных для обучения, проверки и тестирования в виде массивов Numpy. Он также предоставляет функцию для получения мини-пакетов в итерациях, которую мы будем использовать позже.

2. Установите свойства

trainNum = 60000
# 训练图片总数
testNum = 10000
# 测试图片总数
trainSize = 500
# 训练的时候使用的图片数量
testSize = 5
# 测试的时候使用的图片数量
k = 4
# 距离最小的K个图片

3. Декомпозиция данных

Как мы уже говорили, каждое изображение имеет размер 28 * 28 = 784 пикселя, поэтому в testData.shape= (5, 784) 5 представляет количество изображений, а 784 представляет собой пиксели каждого изображения.

Что представляет собой testLabel.shape= (5, 10)?

Взгляните сначала:

  • testLabel= [[0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
    [1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
    [0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]
    [1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
    [0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]]

Первая метка [0.0.0.0.0.0.1.0.0.0.] в testLabel — это число 6, которое соответствует первым данным testData. И так далее, метка вторых данных — 0, метка третьих данных — 4, метка четвертых данных — 0, метка пятых данных — 6.

trainIndex = np.random.choice(trainNum,trainSize,replace=False)
# 在trainNum数据中,生成trainSize个不重复的随机数 
testIndex = np.random.choice(testNum,testSize,replace=False)

trainData = mnist.train.images[trainIndex]
# 训练数据集的图片是 mnist.train.images
trainLabel = mnist.train.labels[trainIndex]
# 训练数据集的标签是 mnist.train.labels
testData = mnist.test.images[testIndex]
# 测试数据集的图片是 mnist.test.images
testLabel = mnist.test.labels[testIndex]
# 测试数据集的标签是 mnist.test.labels
print('trainData.shape=',trainData.shape)
print('trainLabel.shape=',trainLabel.shape)
print('testData.shape=',testData.shape)
print('testLabel.shape=',testLabel.shape)
print('testLabel=',testLabel)

результат:

trainData.shape= (500, 784)
trainLabel.shape= (500, 10)
testData.shape= (5, 784)
testLabel.shape= (5, 10)
testLabel= [[0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
 [1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]
 [1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]]

4. Обучение данным

(1) Установить переменные

tf.placeholder(dtype, shape=None, name=None)
Эту функцию можно понимать как формальный параметр, который используется для определения процесса и присваивания определенного значения при его выполнении. параметр:

  • dtype: тип данных. Часто используемые числовые типы, такие как tf.float32, tf.float64.
  • форма: форма данных. Значение по умолчанию — «Нет», что является одномерным значением, или оно может быть многомерным.Например, [2,3], [Нет, 3] означает, что столбец равен 3, а строка не определена.
  • имя: имя.
trainDataInput = tf.placeholder(shape=[None,784],dtype=tf.float32)
trainLabelInput = tf.placeholder(shape=[None,10],dtype=tf.float32)
testDataInput = tf.placeholder(shape=[None,784],dtype=tf.float32)
testLabelInput = tf.placeholder(shape=[None,10],dtype=tf.float32)

(2) Рассчитать расстояние kNN

Используйте манхэттенское расстояние:

f1 = tf.expand_dims(testDataInput,1) 
# expand_dim()来增加维度
f2 = tf.subtract(trainDataInput,f1)
# subtract()相减,得到一个三维数据
f3 = tf.reduce_sum(tf.abs(f2),reduction_indices=2)
# tf.abs()求数据绝对值
# tf.reduce_sum()完成数据累加,把数据放到f3中
with tf.Session() as sess:
    p1 = sess.run(f1,feed_dict={testDataInput:testData[0:5]})
    print('p1=',p1.shape)
    # p1= (5, 1, 784)
    p2 = sess.run(f2,feed_dict={trainDataInput:trainData,testDataInput:testData[0:5]})
    print('p2=',p2.shape)
    # p2= (5, 500, 784) 
    p3 = sess.run(f3,feed_dict={trainDataInput:trainData,testDataInput:testData[0:5]})
    print('p3=',p3.shape)
    # p3= (5, 500)
    print('p3[0,0]=',p3[0,0]) 
    # p3[0,0]= 132.96472,表示第一张测试图片和第一张训练图片的距离是132.96472

результат:

p1= (5, 1, 784)
p2= (5, 500, 784)
p3= (5, 500)
p3[0,0]= 132.96472

###(3) Выберите K изображений с наименьшим расстоянием

tf.nn.top_k(input, k, name=None)
Цель этой функции — вернуть максимальное количество k каждой строки во входных данных и вернуть индекс их позиции.

Входные параметры:

  • ввод: тензор, тип данных должен быть одним из следующих: float32, float64, int32, int64, uint8, int16, int8. Измерение данных равно размеру_пакета, умноженному на категории.
  • k: целое число, должно быть >= 1. В каждой строке найдите k самых больших значений.
  • name: Дайте имя этой операции.

Выходные параметры:

  • Кортеж Tensor , элементами данных которого являются (значения, индексы), следующим образом:
  • values: тензор с тем же типом данных, что и на входе. Размерность данных — это размер_пакета, умноженный на k максимальных значений.
  • индексы: тензор с типом данных int32. Позиция индекса каждого максимального значения на входе.
f4 = tf.negative(f3)
# tf.negative(x,name=None),取负运算(f4 =-f3 = -132.96472)
f5,f6 = tf.nn.top_k(f4,k=4) 
# f5,选取f4最大的四个值,即f3最小的四个值
# f6,这四个值对应的索引
with tf.Session() as sess:
    p4 = sess.run(f4,feed_dict={trainDataInput:trainData,testDataInput:testData[0:5]})
    print('p4=',p4.shape)
    print('p4[0,0]=',p4[0,0])
    p5,p6 = sess.run((f5,f6),feed_dict={trainDataInput:trainData,testDataInput:testData[0:5]})
    # p5= (5, 4),每一张测试图片(共5张),分别对应4张最近训练图片,共20张
    print('p5=',p5.shape)
    print('p6=',p6.shape)
    print('p5',p5)
    print('p6',p6)

результат:

p4= (5, 500)
p4[0,0]= -132.96472
p5= (5, 4)
p6= (5, 4)
p5= [[-54.49804  -54.87059  -55.690197 -59.97647 ]
     [-49.09412  -64.74118  -68.22353  -68.76863 ]
     [-65.36079  -69.278435 -72.60785  -74.84314 ]
     [-75.46667  -78.19216  -78.36864  -80.44706 ]
     [-42.478436 -61.517654 -62.36863  -63.42353 ]]
p6= [[150 167 493 226]
     [402 268 279 164]
     [300  97  78 237]
     [387 164 268 311]
     [258 107 226 207]]

(3) Определить частоту K изображений в типе

tf.gather()
Соберите срезы с оси параметров по индексу. Индексы должны быть целочисленными тензорами любой размерности (обычно 0-D или 1-D). Сгенерируйте выходной тензор Форма тензора: params.shape[:axis] + index.shape + params.shape[axis + 1:]

Входные параметры:

  • параметры: тензор. Этот тензор используется для сбора значений. Ранг этого тензора должен быть не меньше оси + 1.
  • индексы: тензор. Должен быть одним из следующих типов: int32, int64. Тензор индекса должен быть в диапазоне [0, params.shape[axis]) .
  • ось: тензор. Должен быть одним из следующих типов: int32, int64. Соберите индекс с оси параметров. По умолчанию используется первое измерение. Отрицательные индексы поддерживаются.
  • name: Имя действия (необязательно).

Выходные параметры:

  • Функция возвращает тензор. Имеет тот же тип, что и параметр. Значения параметров собираются из индексов, заданных индексом, и имеют вид: params.shape[:axis] + index.shape + params.shape[axis + 1:].
f7 = tf.gather(trainLabelInput,f6)
# 根据索引找到对应的标签值
f8 = tf.reduce_sum(f7,reduction_indices=1)
# 累加维度1的数值
f9 = tf.argmax(f8,dimension=1)
# 返回的是f8中的最大值的索引号
with tf.Session() as sess:
    p7 = sess.run(f7,feed_dict={trainDataInput:trainData,testDataInput:testData[0:5],trainLabelInput:trainLabel})
    print('p7=',p7.shape)
    print('p7[]',p7)
    p8 = sess.run(f8,feed_dict={trainDataInput:trainData,testDataInput:testData[0:5],trainLabelInput:trainLabel})
    print('p8=',p8.shape)
    print('p8[]=',p8)
    p9 = sess.run(f9,feed_dict={trainDataInput:trainData,testDataInput:testData[0:5],trainLabelInput:trainLabel})
    print('p9=',p9.shape)
    print('p9[]=',p9)

результат:

p7= (5, 4, 10)
p7[]= [[[0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
  [0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
  [0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
  [0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]]

 [[1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
  [1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
  [1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
  [1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]

 [[0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]
  [0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]
  [0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]
  [0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]]

 [[1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
  [1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
  [1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
  [1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]

 [[0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
  [0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
  [0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
  [0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]]]
p8= (5, 10)
p8[]= [[0. 0. 0. 0. 0. 0. 4. 0. 0. 0.]
 [4. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 4. 0. 0. 0. 0. 0. 0.]
 [4. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 3. 0. 0. 1.]]
p9= (5,)
p9[]= [6 0 3 0 6]

(4) Результаты испытаний

with tf.Session() as sess:
 p10 = np.argmax(testLabel[0:5],axis=1)
 # p9=p10,代表正确
    print('p10[]=',p10)
j = 0
for i in range(0,5):
    if p10[i] == p9[i]:
        j = j+1
print('ac=',j*100/5)
# 正确率

результат:

p10[]= [6 0 3 0 6]
ac= 100.0