【パターン認識】NN法で数字の画像から数値を識別する

フリーソフトでつくる音声認識システムという本の第一章のメモ。

学んだことと演習問題に沿って実際に識別するプログラムを書こうと思った。

Imageクラスを定義

まずは各imageをインスタンス化するためのImageクラスを作ってみる。

インスタンス化する際に5*5=25の要素を持つリストを渡す。これは1と0だけで構成されていて、縦5マス横5マスを0=白、1=黒で2値化してる画像(しょぼい)が渡されることを想定してる。

Imageクラスのメソッド

  • draw(): 画像を描画する
  • classify(): NN(Nearest Neighbor)法その画像が0~9のうちどの数字なのか識別する

という二つ。ちなみにNN法は与えられたN次元ベクトル x に対して1番距離が近いクラス(今回は単純に、プロトタイプのN次元ベクトル Pi のうちどれか)に分類するというシンプルな方法。

classify()クラスでは普通に2点間の距離を求めてます

ソースコードは以下。

import sys
import numpy as np

class Image:
  def __init__(self, image):
    self.image = image

  def draw(self):
    print("")
    print("Image:")
    print("")
    sys.stdout.write("     ")
    for i in range(len(self.image)):
      if (self.image[i]==1):
        sys.stdout.write("#")
      else:
        sys.stdout.write(" ")
      if ((i+1)%5==0):
        print("")
        sys.stdout.write("     ")
    print("")

  def classify(self):
    d0 = 0;
    for i in range(0,24):
      d0 += (p0[i]-self.image[i])**2
    d1 = 0;
    for i in range(0,24):
      d1 += (p1[i]-self.image[i])**2
    d2 = 0;
    for i in range(0,24):
      d2 += (p2[i]-self.image[i])**2
    d3 = 0;
    for i in range(0,24):
      d3 += (p3[i]-self.image[i])**2
    d4 = 0;
    for i in range(0,24):
      d4 += (p4[i]-self.image[i])**2
    x = np.array([d0, d1, d2, d3, d4])
    print("The number of image is %d" % np.argmin(x))

numpyのargmin()は最小値が複数あれば最初のインデックスを返すので、まぁ偏ってしまうけどそれはお許しください笑

そんでPythonオブジェクト指向慣れてなさすぎていろいろぎこちないし冗長すぎる気がする。特にclassify()メソッドはforで書けるじゃん...もうめんどい...

プロトタイプを用意

そして今度はプロトタイプを作成する。このプロトタイプをもとにパターンを識別する。画像データを25次元ベクトルで表す。

これはプログラムの冒頭で宣言しておく。

# Prototypes (Images of 0~4)
p0 = [0,1,1,1,0, 1,0,0,0,1, 1,0,0,0,1, 1,0,0,0,1, 0,1,1,1,0]
p1 = [0,0,1,0,0, 0,0,1,0,0, 0,0,1,0,0, 0,0,1,0,0, 0,0,1,0,0]
p2 = [0,1,1,1,1, 1,0,0,1,0, 0,0,1,0,0, 0,1,0,0,0, 1,1,1,1,1]
p3 = [0,1,1,1,0, 1,0,0,0,1, 0,0,1,1,0, 1,0,0,0,1, 0,1,1,1,0]
p4 = [0,0,1,0,0, 0,1,0,0,0, 1,0,0,1,0, 1,1,1,1,1, 0,0,0,1,0]

さっきのImageクラスのdraw()メソッドを使ってそれぞれ描画してみると...

>>> i = Image(p0)
>>> i.draw()

Image:

      ### 
     #   #
     #   #
     #   #
      ### 
    
 
>>> i = Image(p1)
>>> i.draw()

Image:

       #  
       #  
       #  
       #  
       #  
     

>>> i = Image(p2)
>>> i.draw()

Image:

      ####
     #  # 
       #  
      #   
     #####
     

>>> i = Image(p3)
>>> i.draw()

Image:

      ### 
     #   #
       ## 
     #   #
      ### 
     

>>> i = Image(p4)
>>> i.draw()

Image:

       #  
      #   
     #  # 
     #####
        # 
     

ちゃんと数字になってる!!!

実行してみる

ということ何種類か適当な画像を与えて実行してみます。

なんか4のなりそこないみたいなやつ。

>>> image1 = Image([0,1,1,0,0, 1,1,0,0,0, 1,0,0,1,0, 1,1,0,1,1, 0,0,0,0,1])
>>> image1.draw()

Image:

      ##  
     ##   
     #  # 
     ## ##
         #
     
>>> image1.classify()

The number of image is 4

すばらしい。

次は教科書の例題のやつ。1を右にひとマスずらしたやつ。

>>> image1 = Image([0,0,0,1,0, 0,0,0,1,0, 0,0,0,1,0, 0,0,0,1,0, 0,0,0,1,0])
>>> image1.draw()

Image:

        # 
        # 
        # 
        # 
        # 
    
 
>>> image1.classify()

The number of image is 4

ということでこれははずれ。人間が見たら明らかに1だけど...笑

特徴抽出(ここだと画像上における文字の位置や大きさに依存しないような特徴の抽出)をちゃんと行っていないとかが大きな要因になってるんだなー。

おわり

ということで第一章のパターン認識の基礎の基礎の部分でした。

Githubリポジトリにあげてるので、よかったら酷評してやってください...

totzYuta/book_speaking-system · GitHub

まだ若干内容が簡単だから楽しい、よし。笑