實戰四:手把手教你實現數字識別

mind_programmonkey發表於2019-04-10

                          實戰四:手把手教你實現數字識別

一、KNN實現數字識別

1.原理

       最簡單最初級的分類器是將全部的訓練資料所對應的類別都記錄下來,當測試物件的屬性和某個訓練物件的屬性完全分配時,便可以對其進行分類。但是怎麼可能所有測試物件都會找到與之完全匹配的訓練物件呢,其次就是存在一個測試物件同時與多個訓練物件匹配,導致一個訓練物件被分到了多個類的問題,基於這些問題呢,就產生了KNN。

      鄰近演算法,或者說K最近鄰(KNN,k-NearestNeighbor)分類演算法是資料探勘分類技術中最簡單的方法之一。所謂K最近鄰,就是K個最近的鄰居的意思,說的是每個樣本都可以用它最接近的k個鄰居來代表。

       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個點中出現頻率最高的類別作為測試資料的預測分類。

2.KNN實現數字識別

(1)概要

載入mnist資料集,mnist資料集分為四組資料,訓練圖片,訓練標籤,測試圖片,測試標籤。

而這裡我們實現的功能:從訓練圖片中隨機抽取一定數量的訓練圖片,並從測試圖片中也隨機抽取一定數量的測試圖片,然後這些測試與訓練圖片進行KNN計算,並從這些一定數量的訓練圖片中找出K張與當前測試圖片KNN距離最近的照片,然後解析訓練圖片中的內容,從而預測出數字,並檢測結果是否正確。

(2)實現整體步驟

a.載入mnist資料集

b.選取一定數量的測試圖片與訓練圖片

c.測試圖片與訓練圖片進行KNN計算,測試圖片分別於訓練圖片做差,並找出K張訓練圖片與當前測試圖片最近的

d.解析當前K張訓練圖片,得到其訓練圖片標籤

e.將圖片標籤轉化成具體的數字,得到預測資料

f.獲取測試圖片的標籤是資料並與上述預測資料對比,得出成功率。

(3)程式碼實現

# CNN 卷積神經網路

import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data

# load data
mnist = input_data.read_data_sets('MNIST_data/',one_hot=True)

# 設定input
imageInput = tf.placeholder(tf.float32,[None,784]) #輸入圖片28*28=784維
labelInput = tf.placeholder(tf.float32,[None,10]) #標籤 參考CNN內容

# 資料維度的調整 data reshape 由[None,784]-->M*28*28*1 即2維轉換成4維
imageInputReshape = tf.reshape(imageInput,[-1,28,28,1]) #完成維度的調整

# 卷積運算 w0是權重矩陣 本質是卷積核心 5*5 output 32  一維 1 stddev 方差
w0 = tf.Variable(tf.truncated_normal([5,5,1,32],stddev=0.1))
b0 = tf.Variable(tf.constant(0.1,shape=[32]))

#layer1:激勵函式+卷積運算
# imageInputReshape: M*28*28*1 w0:5,5,1,32 strides:步長 padding:卷積核可以停留到影象的邊緣
layer1 = tf.nn.relu(tf.nn.conv2d(imageInputReshape,w0,strides=[1,1,1,1],padding='SAME')+b0)
# M*28*28*32 ===>M*7*7*32
# 池化層 下采樣 資料量減少了很多
layer1_pool = tf.nn.max_pool(layer1,ksize=[1,4,4,1],strides=[1,4,4,1],padding='SAME')


#layer2(output輸出層):softmax(激勵函式+乘加運算)
w1 = tf.Variable(tf.truncated_normal([7*7*32,1024],stddev=0.1))
b1 = tf.Variable(tf.constant(0.1,shape=[1024]))
h_reshape = tf.reshape(layer1_pool,[-1,7*7*32]) #M*7*7*32->N*N1
# [N*7*7*32] [7*7*32,1024]=N*1024
h1 = tf.nn.relu(tf.matmul(h_reshape,w1)+b1)

# softmax
w2 = tf.Variable(tf.truncated_normal([1024,10],stddev=0.1))
b2 = tf.Variable(tf.constant(0.1,shape=[10]))
pred = tf.nn.softmax(tf.matmul(h1,w2)+b2) # N*1024 1024*10=N*10
# N*10(概率)
loss0 = labelInput*tf.log(pred)
loss1 = 0
for m in range(0,100):
	for n in range(0,10):
		loss1 = loss1 + loss0[m,n]
loss = loss1/100

# train 訓練
train = tf.train.GradientDescentOptimizer(0.01).minimize(loss)

# run 執行
with tf.Session() as sess:
	sess.run(tf.global_variables_initializer())
	for i in range(100):
		images,labels = mnist.train.next_batch(500)
		sess.run(train,feed_dict={imageInput:images,labelInput:labels})

		pred_test = sess.run(pred,feed_dict={imageInput:mnist.test.images,labelInput:labels})
		acc = tf.equal(tf.arg_max(pred_test,1),tf.arg_max(mnist.test.labels,1))
		acc_float = tf.reduce_mean(tf.cast(acc,tf.float32))
		acc_result = sess.run(acc_float,feed_dict={imageInput:mnist.test.images,labelInput:mnist.test.labels})
		print(acc_result)

(4)結果展示

p9是預測結果

p10是真實結果

ac是準確率

二、CNN實現數字識別

https://blog.csdn.net/sinat_35821976/article/details/81503953

CNN這裡掌握的並不是很好,具體有關CNN的基礎知識可參考上述部落格地址,

# KNN 最近臨域
# CNN 卷積神經網路

# 舊瓶裝新酒:數字識別的不同
# 樣本地址:http://yann.lecun.com/exdb/mnist/
# 程式碼下載
# from tensorflow.examples.tutorials.mnist import input_data  #第一次下載資料時用

# data = input_data.read_data_sets('MNIST_data/')

# Knn test 樣本 K個 max
# 資料都是以隨機數載入,四組資料,訓練圖片,訓練標籤,測試圖片,測試標籤。


# 1 load data
# 2 knn test train distance
# 3 knn k個最近圖片 5張測試 500張訓練圖片做差 -->500張找出4張與當前最近的照片
# 4 解析圖片中的內容parse centent==>label
# 5 label轉化成具體的數字
# 6 檢測結果是否正確
import tensorflow as tf
import numpy as np
import random
from tensorflow.examples.tutorials.mnist import input_data

# load data 資料裝載
mnist = input_data.read_data_sets('MNIST_data/',one_hot=True)

# 屬性設定
trainNum = 55000
testNum = 10000
trainSize = 500
testSize = 5
k = 4
# 隨機選取一定數量的測試圖片與訓練圖片 在0-trainNum之間隨機選取trainSize個數字,不可重複
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) 28*28=784圖片所有畫素點
print('trainLabel.shape',trainLabel.shape) #(500,10) 500行表示500個數,10列用來表示第幾個數
print('testData.shape',testData.shape) #(5,784)
print('testLabel.shape',testLabel.shape) #(5,10)
print('testLabel',testLabel)

# TensorFlow input輸入的定義
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)

# KNN 距離 distance
# f1測試資料輸入維度擴充套件 由5*784==>5*1*784
f1 = tf.expand_dims(testDataInput,1)
# f2測試圖片與訓練圖片兩者之差
f2 = tf.subtract(trainDataInput,f1)
# f3完成資料累加 784個畫素點的差值
f3 = tf.reduce_sum(tf.abs(f2),reduction_indices=2)
# f4對f3取反
f4 = tf.negative(f3)
# f5,f6 選取f4中最大的4個數,即選取f3中最小的4個數(值的內容及值的下標)
f5,f6 = tf.nn.top_k(f4,k=4)
# f6 儲存最近的四張圖片的下標
f7 = tf.gather(trainLabelInput,f6)
# f8 將最近的四張圖片 累加 維度為1
f8 = tf.reduce_sum(f7,reduction_indices=1)
# f9 根據訓練資料 推測的值
f9 = tf.argmax(f8,dimension=1)


with tf.Session() as sess:
	p1 = sess.run(f1,feed_dict={testDataInput:testData[0:5]})
	print('p1=',p1.shape) #(5,1,784)
	p2 = sess.run(f2,feed_dict={trainDataInput:trainData,testDataInput:testData[0:5]})
	print('p2=',p2.shape) #(5,500,784)
	p3 =sess.run(f3,feed_dict={trainDataInput:trainData,testDataInput:testData[0:5]})
	print('p3=',p3.shape) #(5,500)
	print('p3[0,0]',p3[0,0])

	p4 = sess.run(f4,feed_dict={trainDataInput:trainData,testDataInput:testData[0:5]})
	print('p4[0,0]',p4[0,0])

	p5,p6 = sess.run((f5,f6),feed_dict={trainDataInput:trainData,testDataInput:testData[0:5]})
	print('p5=',p5.shape)
	print('p6=',p6.shape)
	#p5=(5,4) 每一張測試圖片(5張)分別對應當前四張最近的圖片
	#p6=(5,4) 每一張測試圖片(5張)分別對應當前四張最近的圖片下標
	print('p5[0,0]=',p5[0])
	print('p6[0,0]=',p6[0])

	p7 = sess.run(f7,feed_dict={trainDataInput:trainData,testDataInput:testData[0:5],trainLabelInput:trainLabel})
	print('p7=',p7.shape) #(5,4,10)
	print('p7[]=',p7)

	p8 = sess.run(f8,feed_dict={trainDataInput:trainData,testDataInput:testData[0:5],trainLabelInput:trainLabel})
	print('p8=',p8.shape) #(5,10)
	print('p8[]=',p8)

	p9 = sess.run(f9,feed_dict={trainDataInput:trainData,testDataInput:testData[0:5],trainLabelInput:trainLabel})
	print('p9=',p9.shape)
	print('p9[]=',p9)

	# p10 根據測試資料 得到的值
	p10 = np.argmax(testLabel[0:5],axis=1)
	print('p10[]=',p10)

# 比較p9和p10,計算準確率
j = 0
for i in range(0,5):
	if p10[i] == p9[i]:
		j=j+1
print('ac=',j*100/5)

相關文章