基於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