Machine Learning入門TF2.0(KNN手寫識別算法實現)

機器學習的形式

關於機器學習是什麼我就不過多解釋,下面僅僅對其簡單分下類:

  • 監督學習
    在學習過程中提供標籤,對錯標籤
    這一類學習目的主要是用於迴歸和分類。

  • 無監督學習
    提供未知標籤的一組樣本,然後去給這些樣本分類。也稱聚類問題。模式識別領域

  • 半監督學習
    監督學習和無監督學習組合的一種方式。

  • 強化學習(阿爾法狗 Alpha Zero)
    智能系統從環境到行爲映射的學習,以此爲獎勵信號。

  • 遷移學習

前面所介紹的學習方法從某種角度說是從數理統計角度對一些東西做出的歸納

  • 深度學習
    而深度學習是從另一方面,生物模擬這方面入手。有點仿生學的意思。模擬人類的神經元。

簡單做了一個腦圖如下:
Machine Learning

從零搭建KNN

KNN(k - nearestneighbor)算法即K最近鄰算法。該算法有點類似於類比,簡單說就是我現在有一個東西需要分類,我把它與已經分類好的東西進行比較,和誰最像,那麼這個東西就是什麼。
以下是其具體實現:

from tensorflow.keras import datasets
import tensorflow as tf
import math
import numpy as np
#雖然導入了tensorflow,但實際上並沒有用到tensorflow的神經網絡的框架,只是用它來得到並稍微處理了一下數據集

# 按照四步走來編寫代碼,四步即 準備數據->搭建網絡->訓練網絡->測試網絡
# 準備數據
(train_images, train_labels), (test_images, test_labels) = datasets.mnist.load_data()
# 訓練圖像保存在一個uint8 類型的數組中,其形狀爲(60000, 28, 28),取值區間爲[0, 255]。
# 我們需要將其變換爲一個float32 數組,其形狀爲(60000, 28 * 28),取值範圍爲0~1。
train_images = train_images.reshape(60000, 28*28).astype('float32') / 255
test_images = test_images.reshape(10000, 28*28).astype('float32') / 255
# 對標籤進行分類編碼(one-hot編碼)
train_labels = tf.keras.utils.to_categorical(train_labels)
test_labels = tf.keras.utils.to_categorical(test_labels)
# 搭建KNN並測試(此處我們用KNN來實現手寫識別嚴格意義上來說,並不是搭建一個網絡,這三個步驟都包含在下面)
# 且以下是用minst數據集的訓練集和測試集分別來測試這種最簡單的KNN算法的準確性,我的測試結果大概是90%
def knn_test(test_sum, train_sum):
    print("測試KNN算法的準備性")
    accracy = 0
    for i in range(test_sum):
        test_data = test_images[i]
        for j in range(train_sum):
            train_data = train_images[j]
            dist = get_dist(train_data, test_data)
            if j == 0:
                min_dist = dist
                min_index = j
            else:
                if dist < min_dist:
                    min_dist = dist
                    min_index = j
        predict = np.argmax(train_labels[min_index])
        real_data = np.argmax(test_labels[i])
        if predict == real_data:
            accracy += 1/test_sum
        print("預測:", predict, "實際:", real_data)
    print("準確性:", accracy)
# 求“距離”函數
def get_dist(train_data, test_data):
    data_pow = 0.
    for k in range(784):
        data_pow += math.pow(train_data[k]-test_data[k], 2)
    data_pow = math.sqrt(data_pow)
    return data_pow

# 測試
test_sum = 20
train_sum = 1000
knn_test(test_sum, train_sum)

優化

在求"距離"的時候那個循環代碼其實是可以優化的:僅用下面一行代碼即可:

min_index = np.argmin(np.sqrt(np.sum(np.square(test_data-train_data), axis=1)))

優化後的整體代碼:

from tensorflow.keras import datasets
import tensorflow as tf
import math
import numpy as np
from PIL import Image
#雖然導入了tensorflow,但實際上並沒有用到tensorflow的神經網絡的框架,只是用它來得到並稍微處理了一下數據集

# 按照四步走來編寫代碼,四步即 準備數據->搭建網絡->訓練網絡->測試網絡
# 準備數據
(train_images, train_labels), (test_images, test_labels) = datasets.mnist.load_data()
# 訓練圖像保存在一個uint8 類型的數組中,其形狀爲(60000, 28, 28),取值區間爲[0, 255]。
# 我們需要將其變換爲一個float32 數組,其形狀爲(60000, 28 * 28),取值範圍爲0~1。
train_images = train_images.reshape(60000, 28*28).astype('float32') / 255
test_images = test_images.reshape(10000, 28*28).astype('float32') / 255
# 對標籤進行分類編碼(one-hot編碼)
train_labels = tf.keras.utils.to_categorical(train_labels)
test_labels = tf.keras.utils.to_categorical(test_labels)
# 搭建KNN並測試(此處我們用KNN來實現手寫識別嚴格意義上來說,並不是搭建一個網絡,這三個步驟都包含在下面)
# 且以下是用minst數據集的訓練集和測試集分別來測試這種最簡單的KNN算法的準確性,我的測試結果大概是80%
def knn_test(test_sum, train_sum):
    print("測試KNN算法的準備性")
    accracy = 0
    for i in range(test_sum):
        test_data = test_images[i]
        train_data = train_images[0:train_sum, :]
        # 優化如下
        min_index = np.argmin(np.sqrt(np.sum(np.square(test_data-train_data), axis=1)))

        predict = np.argmax(train_labels[min_index])
        real_data = np.argmax(test_labels[i])
        if predict == real_data:
            accracy += 1/test_sum
        print("預測:", predict, "實際:", real_data)
    print("準確性:", accracy)
# 測試
test_sum = 200
train_sum = 50000
knn_test(test_sum, train_sum)

手寫識別demo

以上僅僅使用MINST數據集中的訓練集和測試集做了一下測試,如果能讓代碼識別自己寫的數字呢?其實只需要稍微改一下剛纔的代碼即可。
但是首先我們得先自己畫一個數字,可以用畫圖板畫了一個數字,並且最後得到的要是28*28像素的,因爲之前的代碼的是以這樣的圖片爲基礎寫的,你當然可以改代碼,但是簡單起見,我直接改圖片。
下面是我用windows自帶的畫圖板畫的一個數字:
圖片
識別代碼如下:

from tensorflow.keras import datasets
import tensorflow as tf
import math
import numpy as np
from PIL import Image

# 準備數據
(train_images, train_labels), (test_images, test_labels) = datasets.mnist.load_data()
train_images = train_images.reshape(60000, 28*28).astype('float32') / 255
train_labels = tf.keras.utils.to_categorical(train_labels)

# 識別自己寫的數字的代碼
def image_reshape(image_address):   # 將28*28像素圖片轉化爲28*28數組
    #注意此處輸入的image需要是28*28像素的
    image = Image.open(image_address).convert('L')  # 用PIL中的Image.open打開圖像
    image.save("test01.png")
    # .convert('L')是將圖片灰度化處理,原本是彩色圖片,也就是維度是(28,28,3),將其變爲(28,28)
    image_arr = np.array(image)  # 轉化成numpy數組

    image_arr = np.reshape(image_arr, 28 * 28).astype('float32') / 255
    #再將其變換爲一個float32 數組,其形狀爲(784,),取值範圍爲0~1。
    print(image_arr)
    return image_arr
def knn_real(image_address,train_sum):
    test_data = image_reshape(image_address)
    train_data = train_images[0:train_sum, :]
    min_index = np.argmin(np.sqrt(np.sum(np.square(test_data - train_data), axis=1)))
    predict = np.argmax(train_labels[min_index])
    print("預測:", predict)

train_sum = 40000
knn_real("test.png", train_sum)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章