1. 程式人生 > >基於MNIST資料集通過樸素貝葉斯學習生成隨機手寫體數字影象

基於MNIST資料集通過樸素貝葉斯學習生成隨機手寫體數字影象

        好久沒寫部落格了,話不多說,進入主題。

1、貝葉斯方法

2、訓練資料集

3、具體實現過程

        3.1 匯入資料集

        上面提到的資料由於編碼問題,需要自己寫匯入方法,如果你也是用python的話,有現成的模板可以使用。推薦一個GitHub的下載地址

        3.2 學習並生成圖片

        對於一張影象,例如資料集中28*28的影象,每個畫素點畫素值為0~255。這樣一來,經過抽象,一張影象可以分為影象本身資料資訊images和它所表示的意義label。其中,images是一個28*28=784維的特徵集,且每個維度的特徵有256個取值(0~255的畫素值)label表示這個特徵集的分類,為0~9分為10類。

        根據貝葉斯方法,我們需要得到類別label的先驗概率P(c) = {P(c_i)} (i=0~9)。這個過程可以通過簡單的統計計算即可。然後在特定類別c的情況下,我們需要去統計計算出每個維度的特徵值的後驗概率P(x_j | c) = {P(x_j = k | c)} (j = 0~784, k = 0~255)。學習過程即可結束。

        根據學習到的類別label的先驗概率和特徵向量的後驗概率,在生成影象時,我們只需要根據相應的概率隨機生成影象資訊矩陣即可。首先是生成隨機生成0~9的隨機數,作為類別label的取值;然後在特定label的情況下,根據P(x_j | c)生成每個維度的隨機概率取值,組成影象矩陣。

       根據生成的影象矩陣,生成影象。

4、注意

        關於根據分佈概率生成隨機數的方法,我採用的是將概率對映到0~1000的範圍。比如概率分佈是0.2,0.5, 0.3,那麼生成0~1000範圍的隨機數,如果隨機數是在在0~199範圍的話,就對映為P=0.2的值,以此類推。

5、生成圖片效果

6、Python實現程式碼

# -*- coding: utf-8 -*-
print(__doc__)

import math
import pylab as pl
import numpy as np
from mnist import MNIST
import random
from collections import Counter

# 按照分佈概率取樣,生成class隨機數
def prob_choice_class(probs):
    rnd = random.random() * sum(probs)
    for i, w in enumerate(probs):
        rnd -= w
        if rnd < 0:
            return i

# 按照分佈概率取樣,生成feature隨機數
# 按照概率分佈進行對映到0~1000區間
def prob_choice_feature(probs):
    rnd = random.random() * 1000
    prob_section = []
    for i in range(0, len(probs)):
        if rnd >= sum(prob_section):
            prob_section.append(int(probs[i]*1000))
            if rnd < sum(prob_section) or i == len(probs)-1:
                return i
    

# 開源資料集
mndata = MNIST('data')
mndata.load_training()

# 平滑資料,轉化為(samples, feature)的矩陣
n_samples = len(mndata.train_images)
data = np.array(mndata.train_images).reshape(n_samples, -1)

# 統計資料
count_class = Counter()
count_feature = {}
# 構建3維陣列
for x in range(0, 10):
    ycount = {}
    for y in range(0, 784):
        zcount = {}
        for z in range(0, 256):
            zcount[z] = 0
        ycount[y] = zcount
    count_feature[x] = ycount
# 分別統計class和feature
for i in range(0, len(data)):
    count_class[mndata.train_labels[i]] += 1
    for j in range(0, len(data[i])):
        count_feature[mndata.train_labels[i]][j][int(data[i][j])] += 1

# 計算class的概率分佈
count_class_prob = []
count_class_sum = sum(count_class.values())
for key, value in count_class.iteritems():
    count_class_prob.append(float(value)/count_class_sum)

# 計算每個畫素維度的分佈概率
count_feature_prob = {}
# 構建3維陣列
for x in range(0, 10):
    ycount = {}
    for y in range(0, 784):
        zcount = {}
        for z in range(0, 256):
            zcount[z] = 0
        ycount[y] = zcount
    count_feature_prob[x] = ycount
# 具體計算
for i in range(0, 10):
    for j in range(0, 784):
        count_feature_sum = sum(count_feature[i][j].values())
        for k in range(0, 256):
            count_feature_prob[i][j][k] = float(count_feature[i][j][k])/count_feature_sum
##file_class = open('model/classprob', 'w')
##file_feature = open('model/featureprob', 'w')
##file_class.write(str(count_class_prob))
##file_feature.write(str(count_feature_prob))
##file_class.close()
##file_feature.close()
# 根據模型構建圖片
# 指定構建圖片數量
nr_target = 10
# 圖片的畫素維度(28*28=784)
nr_feature = 784
# 開始生成圖片畫素矩陣
class_ = []
feature = []
for x in xrange(nr_target):
    target = prob_choice_class(count_class_prob)
    class_.append(target)
    for y in xrange(nr_feature):
        feature.append(float(prob_choice_feature(count_feature_prob[target][y])))
features = np.array(feature).reshape((nr_target, 28, 28))

# 根據矩陣儲存為相應圖片
# 圖片命名規則:編號_類別(num_class)
num = 0
for index, (image, prediction) in enumerate(zip(features, class_)):
    pl.subplot(1, 1, 1)
    pl.axis('off')
    pl.imshow(image, cmap=pl.cm.gray_r, interpolation='nearest')
    pl.savefig('pic/'+repr(num)+'_%i' % prediction)
##    pl.title('Create: %i' % prediction)
    num += 1

##pl.show()


#END ICTwangbiao