先日は、k近傍による 画像認識を行いましたが、今回は、ナイーブベイズを使用。
HOG特徴量 + KNN(k近傍) による ジェスチャー(手話)画像認識 - end0tknr's kipple - 新web写経開発
以下は、更に以前の主成分分析に関するエントリ
固有値、固有ベクトルからの主成分分析 オレオレ入門 (PCA: Principal Component Analysis) - end0tknr's kipple - 新web写経開発
ただし、単純にベイズ分類器を使用せず、主成分分析(PCA)により次元数を 50に削減し、実行。
まっ、いつもの
の写経です
#!/usr/local/bin/python # -*- coding: utf-8 -*- from PIL import Image import numpy import os import bayes import math def main(): # 訓練データとtestデータのload features, labels = read_gesture_features_labels('train/') test_features, test_labels = read_gesture_features_labels('test/') classnames = numpy.unique(labels) print "CATEGORIES:", print classnames # 主成分分析 - 返り値:写像行列(次元の重要度順), 分散, 平均 V, S, m = my_pca(features) # 重要な次元を50コ残す V = V[:50] # numpy.dot():内積 features = numpy.array([numpy.dot(V, f - m) for f in features]) test_features = numpy.array([numpy.dot(V, f - m) for f in test_features]) # ベイズ分類器 bc = BayesClassifier() blist = [features[numpy.where(labels == c)[0]] for c in classnames] bc.train(blist, classnames) res = bc.classify(test_features)[0] acc = sum(1.0 * (res == test_labels)) / len(test_labels) print 'Accuracy:', acc print_confusion(res, test_labels, classnames) def read_gesture_features_labels(path): # *.dsift のfile名list featlist = [ os.path.join(path, f) for f in os.listdir(path) if f.endswith('.dsift') ] # 特徴量をload features = [] for featfile in featlist: l, d = read_features_from_file(featfile) features.append(d.flatten()) features = numpy.array(features) # ラベルを生成する labels = [featfile.split('/')[-1][0] for featfile in featlist] return features, numpy.array(labels) def print_confusion(res, test_labels, classnames): n = len(classnames) # 混同行列 class_ind = dict([(classnames[i], i) for i in range(n)]) confuse = numpy.zeros((n, n)) for i in range(len(test_labels)): confuse[class_ind[res[i]], class_ind[test_labels[i]]] += 1 print 'Confusion matrix for' print classnames print confuse # 特徴量を読込み行列形式で返す def read_features_from_file(filename): f = numpy.loadtxt(filename) return f[:, :4], f[:, 4:] # 特徴点の配置と記述子 # 主成分分析 # 入力:X, 訓練データを平板化した配列を行として格納した行列 # 出力:写像行列(次元の重要度順), 分散, 平均 def my_pca(X): # 次元数を取得 num_data, dim = X.shape # データをセンタリング mean_X = X.mean(axis=0) X = X - mean_X if dim > num_data: # PCA - 高次元のときはコンパクトな裏技を用いる M = numpy.dot(X, X.T) # 共分散行列 e, EV = numpy.linalg.eigh(M) # 固有値と固有ベクトル tmp = numpy.dot(X.T, EV).T # ここがコンパクトな裏技 V = tmp[::-1] # 末尾の固有ベクトルほど重要なので、反転する S = numpy.sqrt(e)[::-1] # 固有値の並びも反転する for i in range(V.shape[1]): V[:, i] /= S else: # PCA - 低次元なら特異値分解を用いる U, S, V = numpy.linalg.svd(X) V = V[:num_data] # 最初のnum_dataの分だけが有用 # 写像行列と、分散、平均を返す return V, S, mean_X class BayesClassifier(object): def __init__(self): self.labels = [] # クラスのラベル self.mean = [] # クラスの平均 self.var = [] # クラスの分散 self.n = 0 # クラスの数 # data (n*dimの配列のリスト)で学習。 # labelsはオプションで、デフォルトは 0...n-1 def train(self, data, labels=None): if labels == None: labels = range(len(data)) self.labels = labels self.n = len(labels) for c in data: self.mean.append(numpy.mean(c, axis=0)) self.var.append(numpy.var(c, axis=0)) # var():分散 # 各クラスの確率を計算し確率の高いラベルを返すことでpointsを分類 def classify(self, points): # 各クラスの確率を計算する est_prob = numpy.array( [gauss(m, v, points) for m, v in zip(self.mean, self.var)]) # 最も確率の高いindex noを求め、クラスのラベルを返す ndx = est_prob.argmax(axis=0) est_labels = numpy.array([self.labels[n] for n in ndx]) return est_labels, est_prob # 独立した平均m分散vの点を、xの行として持つ d次元ガウス分布を評価 def gauss(m, v, x): if len(x.shape) == 1: n, d = 1, x.shape[0] else: n, d = x.shape # 共分散行列を求め、xから平均を引く S = numpy.diag(1 / v) # diag():行列の対角成分 x = x - m # 確率の積, exp():ネイピア数(e)の?乗, dot():内積 y = numpy.exp(-0.5 * numpy.diag(numpy.dot(x, numpy.dot(S, x.T)))) # 正規化して返す, prod():配列の積 return y * (2 * numpy.pi)**(-d / 2.0) / (numpy.sqrt(numpy.prod(v)) + 1e-6) if __name__ == '__main__': main()
↑こう書くと↓こう表示されます
$ python 0_8.2.1.bayes_g.py CATEGORIES: ['A' 'B' 'C' 'F' 'P' 'V'] 0_8.2.1.bayes_g.py:87: RuntimeWarning: invalid value encountered in sqrt S = numpy.sqrt(e)[::-1] # 固有値の並びも反転する 0_8.2.1.bayes_g.py:109: FutureWarning: comparison to `None` will result in an elementwise object comparison in the future. if labels == None: Accuracy: 0.744680851064 Confusion matrix for ['A' 'B' 'C' 'F' 'P' 'V'] [[ 23. 1. 3. 2. 0. 0.] [ 0. 22. 0. 3. 2. 1.] [ 0. 1. 28. 1. 1. 1.] [ 1. 0. 0. 22. 0. 0.] [ 0. 5. 2. 0. 23. 5.] [ 5. 0. 3. 1. 10. 22.]]