樸素貝葉斯在mnist上應用

貝葉斯方法在mnist手寫數據集上應用

理論基礎

ImgImg爲待識別的照片,YY爲種類集合,那麼根據貝葉斯公式可知
P(YiImg)=P(ImgYi)P(Yi)P(Img) P(Y_i|Img) = \frac{P(Img|Y_i)P(Y_i)}{P(Img)}
在mnist數據集上的應用即爲求最大後驗概率問題
f=argmaxP(Y=iImg) f = argmax P(Y=i|Img)
進一步細化問題,又可以分爲 如何表示變量ImgImg 和 如何得到Y的參數模型.針對這兩個問題將在下文中一一講述

  1. 如何表示變量ImgImg
    在mnist的官網上可以查到,數據集中圖片是標準化處理的28X28灰度圖像,採用一維矩陣存儲.所以我們可以用這784個像素點作爲特徵值來描述一副圖片,也就是說每一副圖片都是由784個獨立且隨機變量構成.但是由於每一副圖像都經過標準化處理,像素點的取值可近似爲區間[0,1][0,1]上連續,爲避免過於複雜運算,這裏首先對圖片進行二值化處理,關於圖片二值化處理將在程序實現中說明,這裏不過多介紹
  2. 如何得到YY的參數模型
    依據大數定理,以頻率替代概率.通過統計訓練集中數據得出先驗概率及類條件概率

程序實現

完整程序見文末

圖片預處理

def preprocessing(images, labels):
    # 返回二值化像素矩陣 以及 解碼後labels
    len, num = images.shape
    index = np.zeros([len], dtype=np.int)
    # 二值化函數
    for i in range(len):
        images[i][images[i] > 0] = 1
        index[i] = np.nonzero(labels[i])[0]
    return np.array(images, dtype=np.int), index

這裏二值化操作較爲粗暴,將全部非零值判定爲1

介於水平有限,未能進一步探討二值化算法選擇對識別準確率的影響,這裏推薦Otsu算法,其閾值計算可使得類間方差最大,可能對準確率提升有所幫助

其次,由於mnist數據集讀入後,label爲熱獨碼,所以還需對其解碼,以獲得標籤信息

概率分佈模型獲取

def statics(images, labels):
    num, pixNum = images.shape
    
    numOnes, priP, condP = (np.count_nonzero(images),
                             np.array((np.bincount(labels, minlength=10) + 1) / (num + 10), dtype=np.float),
                             np.empty([10, pixNum], dtype=np.float))
    # laplace平滑處理
    for i in range(10):
        selected = np.where(labels == i)
        image_i = images[selected]
        condP[i] = np.array((np.count_nonzero(image_i, axis=0) + 1) / (image_i.shape[0] + 2))
    return numOnes / (pixNum * num + 2), priP, condP

由於圖像二值化後變爲二項分佈模型,這裏僅求取像素點爲1時的概率模型.

此外需要注意的是,當求解條件概率時,784個小數相乘使得最終結果爲NaN,爲避免這種情況發生,所以後期需要對數運算.但是實際統計結果中,可能存在某一類別中一像素點爲0的情況,此時類條件概率爲0,無法對數運算.爲解決該問題,這裏引入拉普拉斯平滑處理,通俗解釋爲
Ptimes+1total+kindsnum P \approx \frac{times + 1}{total+kindsnum}

numOnes用於計算P(pixel=1)P(pixel=1),用於求解P(Img)P(Img),但通過適當變形省去了對於P(Img)P(Img)的求解,所以該參數實際可以省略

圖片識別

def predict(image, priorProb, condProb):
    kind, num = condProb.shape
    afterProb = np.zeros(kind, dtype=np.float)
    for i in range(kind):
        condProbOfImg = np.log(condProb[i] * image + (1 - condProb[i]) * ((image + 1) % 2))
        afterProb[i] = sum(condProbOfImg) + np.log(priorProb[i])
    pos = np.argmax(afterProb)
    return pos

依據貝葉斯公式對圖片進行識別,計算式如下
P(YiImg)=j=0783P(pixjYi)P(Yi)P(Img) P(Y_i|Img) = \frac{\prod_{j=0}^{783} P(pix_j|Y_i)P(Y_i)}{P(Img)}
對於同一圖像,其出現概率不變,可以不做計算;再對上式求對數後,計算式可進一步簡化爲
P(YiImg)=logp(pixiyi)+logP(Yi) P(Y_i|Img) = \sum \log p(pix_i|y_i) + \log P(Y_i)
計算所有類別下後驗概率並取其中最大值,即爲貝葉斯分類結果

運行結果

.
.
.
.
We predict this is 2 the standard is 2
We predict this is 3 the standard is 3
We predict this is 9 the standard is 4
We predict this is 8 the standard is 5
We predict this is 6 the standard is 6

Accuracy is: 0.8413

完整程序

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


def preprocessing(images, labels):
    # 返回二值化像素矩陣 以及 解碼後labels
    len, num = images.shape
    index = np.zeros([len], dtype=np.int)
    # 二值化函數
    for i in range(len):
        images[i][images[i] > 0] = 1
        index[i] = np.nonzero(labels[i])[0]
    return np.array(images, dtype=np.int), index


def statics(images, labels):
    # 統計像素點爲 1 以及在各標籤下爲 1 的概率
    # 統計各標籤出現概率
    num, pixNum = images.shape
    # priP 標籤出現概率 即先驗概率
    # condP 在特定標籤條件下出現概率 即類條件概率
    numOnes, priP, condP = (np.count_nonzero(images),
                             np.array((np.bincount(labels, minlength=10) + 1) / (num + 10), dtype=np.float),
                             np.empty([10, pixNum], dtype=np.float))
    # laplace平滑處理
    for i in range(10):
        selected = np.where(labels == i)
        image_i = images[selected]
        condP[i] = np.array((np.count_nonzero(image_i, axis=0) + 1) / (image_i.shape[0] + 2))
    # 像素不做laplace平滑,像素點必不爲0
    return numOnes / (pixNum * num + 2), priP, condP


def predict(image, priorProb, condProb):
    kind, num = condProb.shape
    afterProb = np.zeros(kind, dtype=np.float)
    for i in range(kind):
        condProbOfImg = np.log(condProb[i] * image + (1 - condProb[i]) * ((image + 1) % 2))
        afterProb[i] = sum(condProbOfImg) + np.log(priorProb[i])
    # 測試用
    pos = np.argmax(afterProb)
    # print("max is :", afterProb[pos])
    return pos


if __name__ == '__main__':
    mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

    # 訓練集
    train_images, train_labels = preprocessing(mnist.train.images, mnist.train.labels)
    pix1, priorProb1, condProb1 = statics(train_images, train_labels)

    # 測試集
    test_images, test_labels = preprocessing(mnist.test.images, mnist.test.labels)
    num, acc = test_images.shape[0], 0
    for i in range(num):
        predictLabel = predict(test_images[i], priorProb1, condProb1)
        print("We predict this is ", predictLabel, " the standard is ", test_labels[i])
        acc += (predictLabel == test_labels[i])
    print("\nAccuracy is:",np.float(acc) / num)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章