貝葉斯方法在mnist手寫數據集上應用
理論基礎
記爲待識別的照片,爲種類集合,那麼根據貝葉斯公式可知
在mnist數據集上的應用即爲求最大後驗概率問題
進一步細化問題,又可以分爲 如何表示變量 和 如何得到Y的參數模型.針對這兩個問題將在下文中一一講述
- 如何表示變量
在mnist的官網上可以查到,數據集中圖片是標準化處理的28X28灰度圖像,採用一維矩陣存儲.所以我們可以用這784個像素點作爲特徵值來描述一副圖片,也就是說每一副圖片都是由784個獨立且隨機變量構成.但是由於每一副圖像都經過標準化處理,像素點的取值可近似爲區間上連續,爲避免過於複雜運算,這裏首先對圖片進行二值化處理,關於圖片二值化處理將在程序實現中說明,這裏不過多介紹 - 如何得到的參數模型
依據大數定理,以頻率替代概率.通過統計訓練集中數據得出先驗概率及類條件概率
程序實現
完整程序見文末
圖片預處理
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,無法對數運算.爲解決該問題,這裏引入拉普拉斯平滑處理,通俗解釋爲
numOnes用於計算,用於求解,但通過適當變形省去了對於的求解,所以該參數實際可以省略
圖片識別
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
依據貝葉斯公式對圖片進行識別,計算式如下
對於同一圖像,其出現概率不變,可以不做計算;再對上式求對數後,計算式可進一步簡化爲
計算所有類別下後驗概率並取其中最大值,即爲貝葉斯分類結果
運行結果
.
.
.
.
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)