最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python-OpenCV實戰(zhàn):利用 KNN 算法識別手寫數(shù)字

 更新時間:2021年12月16日 09:08:46   作者:盼小輝丶  
K-最近鄰(KNN)是監(jiān)督學(xué)習(xí)中最簡單的算法之一,KNN可用于分類和回歸問題。本文將為大家介紹的是通過KNN算法實現(xiàn)識別手寫數(shù)字。文中的示例代碼介紹詳細,需要的朋友可以參考一下

前言

K-最近鄰 (k-nearest neighbours, KNN) 是監(jiān)督學(xué)習(xí)中最簡單的算法之一,KNN 可用于分類和回歸問題,在博文《Python OpenCV實戰(zhàn)之與機器學(xué)習(xí)的碰撞》中,我們已經(jīng)學(xué)習(xí)了如何在 OpenCV 中實現(xiàn)和訓(xùn)練 KNN 聚類算法,同時通過簡單的示例了解了 KNN 算法的用法。在本文中,我們將學(xué)習(xí)如何使用 KNN 分類器執(zhí)行手寫數(shù)字識別,同時我們將從基礎(chǔ)程序開始,并通過對其進行改進以提高其性能。

手寫數(shù)字?jǐn)?shù)據(jù)集 MNIST 介紹

為了保證完整性,從算法所用的訓(xùn)練數(shù)據(jù)講起,訓(xùn)練數(shù)據(jù)是由 MNIST 手寫數(shù)字組成的,MNIST 數(shù)據(jù)集來自美國國家標(biāo)準(zhǔn)與技術(shù)研究所,由來自 250 個不同人手寫的數(shù)字構(gòu)成,其中訓(xùn)練集包含 60000 張圖片,測試集包含 10000 張圖片,每個圖片都有其標(biāo)簽,圖片大小為 28*28。許多機器學(xué)習(xí)庫提供了加載 MNIST 數(shù)據(jù)集的方法,這里使用 keras 庫進行加載:

# 導(dǎo)入 keras 庫
import keras
# 加載數(shù)據(jù)
(train_dataset, train_labels), (test_dataset, test_labels) = keras.datasets.mnist.load_data()
train_labels = np.array(train_labels, dtype=np.int32)
# 打印數(shù)據(jù)集形狀
print(train_dataset.shape, test_dataset.shape)
# 圖像預(yù)覽
for i in range(40):
    plt.subplot(4, 10, i+1)
    plt.imshow(train_dataset[i], cmap='gray')
    plt.title(train_labels[i], fontsize=10)
    plt.axis('off')
plt.show()

基準(zhǔn)模型——利用 KNN 算法識別手寫數(shù)字

加載數(shù)據(jù)集后,我們嘗試使用 KNN 分類器識別數(shù)字,在原始方法中,我們首先使用原始像素值作為特征,因此圖像描述符的大小為 28 × 28 = 784。

首先利用 keras 加載所有數(shù)字圖像,為了了解數(shù)據(jù)訓(xùn)練的全部流程,我們將加載的訓(xùn)練數(shù)據(jù)集劃分為 訓(xùn)練數(shù)據(jù)集 + 測試數(shù)據(jù)集,每部分占比 50%:

# 加載數(shù)據(jù)集
(train_dataset, train_labels), (test_dataset, test_labels) = keras.datasets.mnist.load_data()
train_labels = np.array(train_labels, dtype=np.int32)
# 將原始圖像作為描述符
def raw_pixels(img):
    return img.flatten()
# 數(shù)據(jù)打散
shuffle = np.random.permutation(len(train_dataset))
train_dataset, train_labels = train_dataset[shuffle], train_labels[shuffle]
# 計算每個圖像的描述符,這里特征描述符是原始像素
raw_descriptors = []
for img in train_dataset:
    raw_descriptors.append(np.float32(raw_pixels(img)))
raw_descriptors = np.squeeze(raw_descriptors)
# 將數(shù)據(jù)拆分為訓(xùn)練和測試數(shù)據(jù)(各占 50%)
# 因此,使用 30000 個數(shù)字來訓(xùn)練分類器,30000 位數(shù)字來測試訓(xùn)練后的分類器
partition = int(0.5 * len(raw_descriptors))
raw_descriptors_train, raw_descriptors_test = np.split(raw_descriptors, [partition])
labels_train, labels_test = np.split(train_labels, [partition])

現(xiàn)在,我們就可以使用 knn.train() 方法訓(xùn)練 KNN 模型并使用 get_accuracy() 函數(shù)對其進行測試:

# 訓(xùn)練 KNN 模型
knn = cv2.ml.KNearest_create()
knn.train(raw_descriptors_train, cv2.ml.ROW_SAMPLE, labels_train)
# 測試 kNN 模型
k = 5
ret, result, neighbours, dist = knn.findNearest(raw_descriptors_test, k)
# 根據(jù)真實值和預(yù)測值計算準(zhǔn)確率
def get_accuracy(predictions, labels):
    acc = (np.squeeze(predictions) == labels).mean()
    return acc * 100
acc = get_accuracy(result, labels_test)
print("Accuracy: {}".format(acc))

我們可以看到當(dāng) K = 5 時,KNN 模型可以獲得 96.48% 的準(zhǔn)確率,但我們?nèi)匀豢梢詫ζ溥M行改進,以獲取更高性能。

改進模型1——參數(shù) K 對識別手寫數(shù)字精確度的影響

我們已經(jīng)知道在 KNN 算法中,一個影響算法性能的重要參數(shù)就是 K,因此,我們可以首先嘗試使用不同的 K 值,查看其對識別手寫數(shù)字精確度的影響。

為了比較不同 K 值時模型的準(zhǔn)確率,我們首先需要創(chuàng)建一個字典來存儲測試不同 K 值時的準(zhǔn)確率:

from collections import defaultdict
results = defaultdict(list)

接下來,計算 knn.findNearest() 方法,改變 K 參數(shù),并將結(jié)果存儲在字典中:

# K 取值范圍為 (1, 9)
for k in range(1, 10):
    ret, result, neighbours, dist = knn.findNearest(raw_descriptors_test, k)
    acc = get_accuracy(result, labels_test)
    print(" {}".format("%.2f" % acc))
    results['50'].append(acc)

最后,繪制結(jié)果:

ax = plt.subplot(1, 1, 1)
ax.set_xlim(0, 10)
dim = np.arange(1, 10)
for key in results:
    ax.plot(dim, results[key], linestyle='--', marker='o', label="50%")
    
plt.legend(loc='upper left', title="% training")
plt.title('Accuracy of the K-NN model varying k')
plt.xlabel("number of k")
plt.ylabel("accuracy")
plt.show()

程序運行結(jié)果如下圖所示:

如上圖所示,改變 K 參數(shù)獲得的準(zhǔn)確率也是不同的,因此,在應(yīng)用程序用可以通過調(diào)整 K 參數(shù)來獲取最佳性能。

改進模型2——訓(xùn)練數(shù)據(jù)量對識別手寫數(shù)字精確度的影響

在機器學(xué)習(xí)中,使用更多的數(shù)據(jù)訓(xùn)練分類器通常會提高模型的性能,這是由于分類器可以更好地學(xué)習(xí)特征的結(jié)構(gòu)。在 KNN 分類器中,增加訓(xùn)練數(shù)也會增加在特征空間中找到測試數(shù)據(jù)正確匹配的概率。

接下來,我們就修改=用于訓(xùn)練和測試模型的圖像百分比,來觀察訓(xùn)練數(shù)據(jù)量對識別手寫數(shù)字精確度的影響:

# 劃分訓(xùn)練數(shù)據(jù)集和測試數(shù)據(jù)集
split_values = np.arange(0.1, 1, 0.1)
# 存儲結(jié)果準(zhǔn)確率
results = defaultdict(list)
# 創(chuàng)建模型
knn = cv2.ml.KNearest_create()
# 不同訓(xùn)練數(shù)據(jù)量對識別手寫數(shù)字精確度的影響
for split_value in split_values:
    # 將數(shù)據(jù)集劃分為訓(xùn)練和測試數(shù)據(jù)集
    partition = int(split_value * len(raw_descriptors))
    raw_descriptors_train, raw_descriptors_test = np.split(raw_descriptors, [partition])
    labels_train, labels_test = np.split(train_labels, [partition])
    # 訓(xùn)練 KNN 模型
    print('Training KNN model - raw pixels as features')
    knn.train(raw_descriptors_train, cv2.ml.ROW_SAMPLE, labels_train)
    # 同時對于每種劃分測試不同 K 值影響
    for k in range(1, 10):
        ret, result, neighbours, dist = knn.findNearest(raw_descriptors_test, k)
        acc = get_accuracy(result, labels_test)
        print("{}".format("%.2f" % acc))
        results[int(split_value * 100)].append(acc)

訓(xùn)練算法的數(shù)字圖像的百分比為10%、20%、…、90%,測試算法的數(shù)字百分比為90%、80%、…、10%,最后,繪制結(jié)果:

ax = plt.subplot(1, 1, 1)
ax.set_xlim(0, 10)
dim = np.arange(1, 10)
for key in results:
    ax.plot(dim, results[key], linestyle='--', marker='o', label=str(key) + "%")

plt.legend(loc='upper left', title="% training")
plt.title('Accuracy of the KNN model varying both k and the percentage of images to train/test')
plt.xlabel("number of k")
plt.ylabel("accuracy")
plt.show()

從上圖可以看出,隨著訓(xùn)練圖像數(shù)量的增加,準(zhǔn)確率也會增加。因此當(dāng)條件允許的情況下,可以通過增加訓(xùn)練數(shù)據(jù)量來提高模型性能。

雖然可以看到準(zhǔn)確率雖然已經(jīng)可以到達97%以上,但是我們不能就此止步。

改進模型3——預(yù)處理對識別手寫數(shù)字精確度的影響

在以上示例中,我們均使用原始像素值作為特征來訓(xùn)練分類器。在機器學(xué)習(xí)中,訓(xùn)練分類器之前的一個通??梢詫斎霐?shù)據(jù)進行某種預(yù)處理,用以提高分類器訓(xùn)練性能,因此,接下來我們應(yīng)用預(yù)處理以查看其對識別手寫數(shù)字精確度的影響。

預(yù)處理函數(shù) desew() 如下:

def deskew(img):
    m = cv2.moments(img)
    if abs(m['mu02']) < 1e-2:
        return img.copy()
    skew = m['mu11'] / m['mu02']
    M = np.float32([[1, skew, -0.5 * SIZE_IMAGE * skew], [0, 1, 0]])
    img = cv2.warpAffine(img, M, (SIZE_IMAGE, SIZE_IMAGE), flags=cv2.WARP_INVERSE_MAP | cv2.INTER_LINEAR)

    return img

desew() 函數(shù)通過使用其二階矩對數(shù)字進行去歪斜。更具體地說,可以通過兩個中心矩的比值 (mu11/mu02) 計算偏斜的度量。計算出的偏斜用于計算仿射變換,從而消除數(shù)字的偏斜。接下來對比預(yù)處理的前后圖片效果:

for i in range(10):
    plt.subplot(2, 10, i+1)
    plt.imshow(train_dataset[i], cmap='gray')
    plt.title(train_labels[i], fontsize=10)
    plt.axis('off')
    plt.subplot(2, 10, i+11)
    plt.imshow(deskew(train_dataset[i]), cmap='gray')
    plt.axis('off')
plt.show()

在下圖的第一行顯示了原始數(shù)字圖像,第二行顯示了預(yù)處理后的數(shù)字圖像:

通過應(yīng)用此預(yù)處理,識別的準(zhǔn)確率得到提高,準(zhǔn)確率曲線如下圖所示:

可以看到經(jīng)過預(yù)處理的分類器準(zhǔn)確率甚至可以接近98%,考慮到我們僅僅是使用了簡單的 KNN 模型,效果已經(jīng)很不錯了,但是我們還可以進一步提高模型性能。

改進模型4——使用高級描述符作為圖像特征提高 KNN 算法準(zhǔn)確率

在以上示例中,我們一直使用原始像素值作為特征描述符。在機器學(xué)習(xí)中,一種常見的方法是使用更高級的描述符,接下來將使用定向梯度直方圖 (Histogram of Oriented Gradients, HOG) 作為圖像特征用以提高 KNN 算法準(zhǔn)確率。

特征描述符是圖像的一種表示,它通過提取描述基本特征(例如形狀、顏色或紋理等)的有用信息來簡化圖像。通常,特征描述符將圖像轉(zhuǎn)換為長度為 n 的特征向量,HOG 是一種用于計算機視覺的流行特征描述符。

接下來定義 get_hog() 函數(shù)獲取 HOG 描述符:

(train_dataset, train_labels), (test_dataset, test_labels) = keras.datasets.mnist.load_data()
SIZE_IMAGE = train_dataset.shape[1]
train_labels = np.array(train_labels, dtype=np.int32)
def get_hog():
    hog = cv2.HOGDescriptor((SIZE_IMAGE, SIZE_IMAGE), (8, 8), (4, 4), (8, 8), 9, 1, -1, 0, 0.2, 1, 64, True)
    print("hog descriptor size: {}".format(hog.getDescriptorSize()))
    return hog

然后使用 HOG 特征訓(xùn)練 KNN 模型

hog = get_hog()

hog_descriptors = []
for img in train_dataset:
    hog_descriptors.append(hog.compute(deskew(img)))
hog_descriptors = np.squeeze(hog_descriptors)

訓(xùn)練完成的模型的準(zhǔn)確率,如下圖所示:

通過上述改進過程,可以看到編寫機器學(xué)習(xí)模型時的一個好方法是從解決問題的基本基線模型開始,然后通過添加更好的預(yù)處理、更高級的特征描述符或其他機器學(xué)習(xí)技術(shù)來迭代改進模型。最后,如果條件允許,可以收集更多數(shù)據(jù)用于訓(xùn)練和測試模型。

完整代碼

最終完整代碼如下所示,改進過程中的其他代碼可以根據(jù)上述講解對以下代碼進行簡單修改獲得:

import cv2
import numpy as np
import matplotlib.pyplot as plt
from collections import defaultdict
import keras

(train_dataset, train_labels), (test_dataset, test_labels) = keras.datasets.mnist.load_data()

SIZE_IMAGE = train_dataset.shape[1]

train_labels = np.array(train_labels, dtype=np.int32)
def get_accuracy(predictions, labels):
    acc = (np.squeeze(predictions) == labels).mean()
    return acc * 100
    
def raw_pixels(img):
    return img.flatten()

def deskew(img):
    m = cv2.moments(img)
    if abs(m['mu02']) < 1e-2:
        return img.copy()
    skew = m['mu11'] / m['mu02']
    M = np.float32([[1, skew, -0.5 * SIZE_IMAGE * skew], [0, 1, 0]])
    img = cv2.warpAffine(img, M, (SIZE_IMAGE, SIZE_IMAGE), flags=cv2.WARP_INVERSE_MAP | cv2.INTER_LINEAR)

    return img

def get_hog():
    hog = cv2.HOGDescriptor((SIZE_IMAGE, SIZE_IMAGE), (8, 8), (4, 4), (8, 8), 9, 1, -1, 0, 0.2, 1, 64, True)
    print("hog descriptor size: {}".format(hog.getDescriptorSize()))

    return hog

shuffle = np.random.permutation(len(train_dataset))
train_dataset, train_labels = train_dataset[shuffle], train_labels[shuffle]
# 高級圖像描述符
hog = get_hog()
hog_descriptors = []
for img in train_dataset:
    hog_descriptors.append(hog.compute(deskew(img)))
hog_descriptors = np.squeeze(hog_descriptors)
# 數(shù)據(jù)劃分
split_values = np.arange(0.1, 1, 0.1)

# 創(chuàng)建字典用于存儲準(zhǔn)確率
results = defaultdict(list)

# 創(chuàng)建 KNN 模型
knn = cv2.ml.KNearest_create()

for split_value in split_values:
    partition = int(split_value * len(hog_descriptors))
    hog_descriptors_train, hog_descriptors_test = np.split(hog_descriptors, [partition])
    labels_train, labels_test = np.split(train_labels, [partition])

    print('Training KNN model - HOG features')
    knn.train(hog_descriptors_train, cv2.ml.ROW_SAMPLE, labels_train)

    # 存儲準(zhǔn)確率
    for k in np.arange(1, 10):
        ret, result, neighbours, dist = knn.findNearest(hog_descriptors_test, k)
        acc = get_accuracy(result, labels_test)
        print(" {}".format("%.2f" % acc))
        results[int(split_value * 100)].append(acc)

fig = plt.figure(figsize=(12, 5))
plt.suptitle("k-NN handwritten digits recognition", fontsize=14, fontweight='bold')

ax = plt.subplot(1, 1, 1)
ax.set_xlim(0, 10)
dim = np.arange(1, 10)

for key in results:
    ax.plot(dim, results[key], linestyle='--', marker='o', label=str(key) + "%")

plt.legend(loc='upper left', title="% training")
plt.title('Accuracy of the k-NN model varying both k and the percentage of images to train/test with pre-processing '
          'and HoG features')
plt.xlabel("number of k")
plt.ylabel("accuracy")
plt.show()

相關(guān)鏈接

Python OpenCV實戰(zhàn)之與機器學(xué)習(xí)的碰撞

以上就是Python-OpenCV實戰(zhàn):利用 KNN 算法識別手寫數(shù)字的詳細內(nèi)容,更多關(guān)于Python OpenCV KNN算法識別手寫數(shù)字的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • python中列表的含義及用法

    python中列表的含義及用法

    在本篇文章里小編給大家分享的是關(guān)于python中列表的含義及用法,需要的朋友們可以參考學(xué)習(xí)下。
    2020-05-05
  • Python使用logging結(jié)合decorator模式實現(xiàn)優(yōu)化日志輸出的方法

    Python使用logging結(jié)合decorator模式實現(xiàn)優(yōu)化日志輸出的方法

    這篇文章主要介紹了Python使用logging結(jié)合decorator模式實現(xiàn)優(yōu)化日志輸出的方法,實例分析了Python使用logging模塊操作日志的相關(guān)技巧,需要的朋友可以參考下
    2016-04-04
  • 詳解Python如何編寫類型提示

    詳解Python如何編寫類型提示

    為了提高代碼的可讀性、可維護性,Python 在 PEP 484 中引入了類型提示( type hinting),它是 Python 中一個可選但非常有用的功能,可以使代碼更易于閱讀和調(diào)試,下面我們就來學(xué)習(xí)一下如何編寫類型提示吧
    2023-12-12
  • Python中字符串,列表與字典的常用拼接方法總結(jié)

    Python中字符串,列表與字典的常用拼接方法總結(jié)

    有時在數(shù)據(jù)處理時,需要對數(shù)據(jù)進行拼接處理,比如字符串的拼接、列表的拼接等,本文主要是介紹了字符串、列表、字典常用的拼接方法,希望對大家有所幫助
    2024-02-02
  • Python圖片檢索之以圖搜圖

    Python圖片檢索之以圖搜圖

    由于很多論文里面的測試圖片沒有標(biāo)號,就不能確定它們是Testset數(shù)據(jù)集中哪幾張圖片.為了能解決這個問題,需要完成以圖片去搜索整個數(shù)據(jù)集文件目錄的任務(wù).本文有非常詳細的圖文示例,需要的朋友可以參考下
    2021-05-05
  • 基于python的字節(jié)編譯詳解

    基于python的字節(jié)編譯詳解

    下面小編就為大家?guī)硪黄趐ython的字節(jié)編譯詳解。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • 最新評論

    洛扎县| 石渠县| 辽源市| 山丹县| 雷波县| 江陵县| 松滋市| 成都市| 龙井市| 裕民县| 北海市| 东丽区| 杭锦后旗| 阳东县| 滕州市| 桐乡市| 蓝山县| 灯塔市| 巫山县| 神农架林区| 金寨县| 通山县| 祁东县| 陆河县| 江门市| 高邮市| 聂拉木县| 清水河县| 昌吉市| 招远市| 黄石市| 嘉定区| 四川省| 綦江县| 怀远县| 望奎县| 图木舒克市| 台北市| 读书| 青阳县| 翁牛特旗|