欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

KNN实现手写数字识别

程序员文章站 2024-03-08 08:18:22
...

KNN实现手写数字识别

1 重要
2 KNN最近领域 CNN 2种
3 样本准备
网站:http://yann.lecun.com./exdb/mnist
KNN实现手写数字识别

KNN实现手写数字识别

                                                                         图片 标签 监督学习

KNN实现手写数字识别

0代表空白,1代表中间的黑色区域,共同代表1

KNN实现手写数字识别

                                                                 标签,用矩阵保存标签

通过代码实现,先通过KNN最近领域法实现数字识别

  • KNN本质:测试图片与样本图片进行比较,样本K个,K个中寻找最接近的,统计出现次数最多的数字,这个数字就是最终检测的效果,例如如果10个中有8个描述1那就是1

  • 步骤:

    1、样本装载,设置训练和图片的数据和标签个数等参数(4种)。图片的选取要从加载的图片文件中随机选取。先生成随机下标,再加载随机图片。随机导致每次运行结果随机。

    2、KNN ,计算训练数据与测试数据距离之差,由于选取维度不同的,在计算之前要进行维度转换。距离使用绝对值。

    维度:f1–expand_dims

    相减:f2–subtract

    累加:f3–reduce_sum

    取反:f4–tf.negative

    3、要在计算所得的所有数据之差间选取距离最近的前K个数据

    前几个:f5 f6–top_k f6(下标)

    f5,f6 = tf.nn.top_k(f4,k=4) # 选取f4 因为已经取反最大的四个值
    

    4、寻找k个最近的图片对应的标签,找到对应的图片

    寻找训练数据的标签:f7 = tf.gather(trainLabelInput,f6)

    5、标签对应的具体数据,通过累加素质方向的标签个数,再在累加数据中寻找最大值,最大值在的位置就是具体数据

    竖直累加:f8 = tf.reduce_sum(f7,reduction_indices=1) reduction_indices=1设置竖直方向

    选取在某一个维度最大的值:f9 = tf.argmax(f8,dimension=1)

    举例:

    p7具体数值为:
     [[[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.]]
    p8对数据p7进行竖直方向累加,目标是统计出现次数最多的
    p8维度:p8= (5, 10)
    p8具体的数据:
     [[0. 0. 0. 0. 0. 4. 0. 0 0. 0.]
     [0. 0. 0. 0. 4. 0. 0. 0. 0. 0
     [0. 0. 0. 4. 0. 0. 0. 0. 0. 0.]
     [0. 0. 0. 0. 0. 0. 0. 0. 0. 4.]
     [0. 0. 0. 0. 0. 0. 0. 2. 0. 2.]]
    对p8累加结果进行分析,输出数值最大的那个标签对应的数据
    p9维度:p9= (5,)
    p9具体的数据:
     [5 4 3 9 7]
    

    6、计算准确率,p10为标准结果,测试机

  • 应用

    1、k = 4 # 分解为四种数据可修改,KNN的K

    2、

    trainNum = 55000 # 训练图片张数
    testNum = 10000 # 测试图片张数

    trainSize 、testSize 可修改但不可超过上面的数据

    trainSize = 500 # 训练使用500张
    testSize = 5 # 用5张训练

    3、修改2以后对应输出参数也要修改

    p1 = sess.run(f1,feed_dict={testDataInput:testData[0:5]})

    p2 = sess.run(f2,feed_dict={trainDataInput:trainData,testDataInput:testData[0:5]})

    4、循环次数不是,最后除的也不是5

    for i in range(0,5):
    if p10[i] == p9[i]:
    j = j+1
    print(‘正确率:ac=’,j*100/5)

    5、简单方法把testSize带入

  • 代码实现:

# 1 重要
# 2 KNN CNN 2种
# 3 样本 
# 4 旧瓶装新酒 :数字识别的不同
# 4.1 网络 4。2 每一级 4.3 先原理 后代码 
# 本质:knn test 样本 K个 max4 3个1 -》1

# 1 load Data  1.1 随机数 1.2 4组 训练 测试 (图片 和 标签)
# 2 knn test train distance 5*500 = 2500 784=28*28
# 3 knn k个最近的图片5 500 1-》500train (4)
# 4 k个最近的图片-> parse centent label
# 5 label -》 数字 p9 测试图片-》数据
# 6 检测概率统计
import tensorflow as tf
import numpy as np  #数据操作
import random # 生成随机数字
from tensorflow.examples.tutorials.mnist import input_data # 导入数据集
# 数据装载 装载完的数据放入mnistload data 
# 参数1 fileName文件夹的名称,参数的文件路径 参数2 类型(bool)one_hot : 1 一个数组中有一个为1其余的都是0
mnist = input_data.read_data_sets('MNIST_data',one_hot=True)

# 读入数据的属性设置
trainNum = 55000 # 训练图片张数
testNum = 10000  # 测试图片张数
trainSize = 500  # 训练使用500张
testSize = 5     # 用5张训练

k = 4 # 分解为四种数据
# 位于mnist的数据进行分解 参数1源数据 trainNum   参数2 最后生成范围trainSize范围0-trainNum 参数3 replace=False 不可重复
# 生成随机数,从源数据中随机选取数据
trainIndex = np.random.choice(trainNum,trainSize,replace=False)  # 分解需要先获取测试数据的下标
testIndex = np.random.choice(testNum,testSize,replace=False)   # 测试数据下标

# 利用随机下标获取数据
trainData = mnist.train.images[trainIndex] # 训练图片
trainLabel = mnist.train.labels[trainIndex]# 训练标签
testData = mnist.test.images[testIndex]    # 测试图片
testLabel = mnist.test.labels[testIndex]   # 测试标签

print('训练数据维度:trainData.shape=',trainData.shape)     # 500*784 1行数 图片个数 2列数 784=28x28
print('训练标签维度:trainLabel.shape=',trainLabel.shape)   #500*10
print('测试数据维度:testData.shape=',testData.shape)       #5*784
print('测试标签维度:testLabel.shape=',testLabel.shape)     #5*10
print('测试数据标签:testLabel\n',testLabel)                # [0. 0. 0. 0. 1. 0. 0. 0. 0. 0.]表示数据4 其余行分别为3、6、8、9 

# tensorflow相关定义 tf input  行数图片个数 列数784->表明完整图片image
trainDataInput = tf.placeholder(shape=[None,784],dtype=tf.float32) # 训练数据输入placeholder 数据加载
trainLabelInput = tf.placeholder(shape=[None,10],dtype=tf.float32) # 训练标签输入placeholder 数据加载
testDataInput = tf.placeholder(shape=[None,784],dtype=tf.float32) # 测试数据输入placeholder 数据加载
testLabelInput = tf.placeholder(shape=[None,10],dtype=tf.float32) # 测试标签输入placeholder 数据加载

#KNN具体计算 训练数据测试数据之间的距离 distance 5*785.  5*1*784
# 测试数据5 训练数据500 每个维度784 (3维数据:测试数据5,训练数据500,数据之差) 5x500x784
f1 = tf.expand_dims(testDataInput,1) # 当前维度转换扩展,为了计算测试数据和训练数据的距离之差
f2 = tf.subtract(trainDataInput,f1)  # 相减 784 sum(784)
f3 = tf.reduce_sum(tf.abs(f2),reduction_indices=2)# 完成数据累加 784 abs绝对值,原数据为3维,累加维度2
# f3:5*500
f4 = tf.negative(f3)# 取反
f5,f6 = tf.nn.top_k(f4,k=4) # 选取f4 最大的四个值
# f3 最小的四个值
# f6存储的就是下标 距离最小的对应的图片,通过索引,index->trainLabelInput
f7 = tf.gather(trainLabelInput,f6)
# f8 num reduce_sum功能累加  reduction_indices=1表示'竖直'方向 具体数据
f8 = tf.reduce_sum(f7,reduction_indices=1)
# tf.argmax 选取在某一个维度最大的值 并记录下标index
f9 = tf.argmax(f8,dimension=1)
# f9 -> test5 image -> 5 num
# 创建Session不许要手动停止
with tf.Session() as sess:
    # f1 <- testData 5张图片f
    # 源数据 
    p1 = sess.run(f1,feed_dict={testDataInput:testData[0:5]})
    print('测试数据p1的维度:p1=',p1.shape)# p1= (5, 1, 784)
    p2 = sess.run(f2,feed_dict={trainDataInput:trainData,testDataInput:testData[0:5]})
    print('像素之差p2的维度:p2=',p2.shape)#p2= (5, 500, 784) (1,100)  第2张图片与第101张图片所有像素之差
    p3 = sess.run(f3,feed_dict={trainDataInput:trainData,testDataInput:testData[0:5]})
    print('数据之差p3的维度:p3=',p3.shape)#p3= (5, 500)
    print('p3[0,0]=',p3[0,0]) #130.451 knn distance 第一张训练与第一张测试之间p3[0,0]= 155.812
    
    p4 = sess.run(f4,feed_dict={trainDataInput:trainData,testDataInput:testData[0:5]})
    print('数据之差p4的维度: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张最近训练图片
    #p6= (5, 4)
    print('p5距离数据维度p5=',p5.shape)
    print('p6距离数据维度:p6=',p6.shape)
    print('p5中距离最近的前四个距离(取反):p5[0,0]=',p5[0])
    print('p6中距离最近的前四个距离(取反):p6[0,0]',p6[0])# p6 index
    
    #p7增加了一个参数,训练标签
    p7 = sess.run(f7,feed_dict={trainDataInput:trainData,testDataInput:testData[0:5],trainLabelInput:trainLabel})
    print('p7维度:p7=',p7.shape)#p7= (5, 4, 10)
    print('p7具体数值为:\n',p7) # 每个句子四行分别代表最近的测试图片,1为标签
    
    p8 = sess.run(f8,feed_dict={trainDataInput:trainData,testDataInput:testData[0:5],trainLabelInput:trainLabel})
    print('p8对数据p7进行竖直方向累加,目标是统计出现次数最多的')
    print('p8维度:p8=',p8.shape) # 变为5行10维
    print('p8具体的数据:\n',p8)
    
    p9 = sess.run(f9,feed_dict={trainDataInput:trainData,testDataInput:testData[0:5],trainLabelInput:trainLabel})
    print('对p8累加结果进行分析,输出数值最大的那个标签对应的数据,这个是训练的识别结果:')
    print('p9维度:p9=',p9.shape)
    print('p9测试的数据:',p9)
    
    p10 = np.argmax(testLabel[0:5],axis=1)
    print('这个是训练集中正确的数据:')
    print('p10标签的数据:',p10)
    
# 计算训练识别正确率
j = 0
for i in range(0,5):
    if p10[i] == p9[i]:
        j = j+1
print('正确率:ac=',j*100/5) # 100 转化成百分比运算,5组数据
  • 输出结果:
训练数据维度:trainData.shape= (500, 784)
训练标签维度:trainLabel.shape= (500, 10)
测试数据维度:testData.shape= (5, 784)
测试标签维度:testLabel.shape= (5, 10)
测试数据标签:testLabel
 [[0. 0. 0. 0. 0. 0. 0. 0. 1. 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. 0. 1. 0. 0.]]
WARNING:tensorflow:From <ipython-input-1-fc02eca0c99f>:66: calling argmax (from tensorflow.python.ops.math_ops) with dimension is deprecated and will be removed in a future version.
Instructions for updating:
Use the `axis` argument instead
测试数据p1的维度:p1= (5, 1, 784)
像素之差p2的维度:p2= (5, 500, 784)
数据之差p3的维度:p3= (5, 500)
p3[0,0]= 128.99998
数据之差p4的维度:p4= (5, 500)
p4[0,0] -128.99998
p5距离数据维度p5= (5, 4)
p6距离数据维度:p6= (5, 4)
p5中距离最近的前四个距离(取反):p5[0,0]= [-63.89801 -69.1137  -73.13725 -77.33334]
p6中距离最近的前四个距离(取反):p6[0,0] [146 361 340 116]
p7维度:p7= (5, 4, 10)
p7具体数值为:
 [[[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.]]

 [[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.]]

 [[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. 1. 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.]]]
p8对数据p7进行竖直方向累加,目标是统计出现次数最多的
p8维度:p8= (5, 10)
p8具体的数据:
 [[0. 0. 0. 0. 0. 0. 0. 0. 4. 0.]
 [4. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [4. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 4. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 4. 0. 0.]]
对p8累加结果进行分析,输出数值最大的那个标签对应的数据,这个是训练的识别结果:
p9维度:p9= (5,)
p9测试的数据: [8 0 0 6 7]
这个是训练集中正确的数据:
p10标签的数据: [8 0 0 6 7]
正确率:ac= 100.0

4.1 网络搭建,搭建适用于数字识别的人工神经网络
4.2 每一级的级联结构,输入、输出并展示
4.3 先原理 后代码

. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 4. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 4. 0. 0.]]
对p8累加结果进行分析,输出数值最大的那个标签对应的数据,这个是训练的识别结果:
p9维度:p9= (5,)
p9测试的数据: [8 0 0 6 7]
这个是训练集中正确的数据:
p10标签的数据: [8 0 0 6 7]
正确率:ac= 100.0


4.1 网络搭建,搭建适用于数字识别的人工神经网络
4.2 每一级的级联结构,输入、输出并展示 
4.3 先原理 后代码