LoginSignup
2
4

More than 5 years have passed since last update.

UnityとF#で機械学習④:k Nearest Neighbor (K近傍法)による画像分類

Last updated at Posted at 2016-05-16

はじめに

"F# for Machine Learning Essentials" (Sudipta Mukherjee 著 以下「原著」) の第3章 "Classification Techniques"(分類法)では、機械学習でよく用いられる分類法をF#で記述する方法について説明されています。最初に出てくるのが、以前にも紹介した k-nearest neighbour(k近傍法)を用いた分類法です。

今回は、Kaggleにある犬と猫の画像データを用いて、犬と猫の分類を行います。分類法は単純で、犬と猫では毛の色の感じが違うので、写真の色の分布をヒストグラムにして、その形から分類する、というものです。顔の形とかは全く考慮しません。

参考資料

残念ながら、今回は原著のコードがネットに見当たりませんでした。フルコードをご覧になりたい方は、原著をご覧ください。

ヒストグラム

原著では、以下の方法でヒストグラムを計算しています。

Library1.fs

    let getHist(values: float[]) = 
        values |> Seq.groupBy(fun color -> color)
               |> Map.ofSeq
               |> Map.map(fun t colors -> Seq.length colors)
               |> Map.toArray
               |> Array.map(fun colorCount -> float (snd colorCount))

Seq.groupBy(fun color -> color)において、funはラムダ式を定義するためのキーワードです。fun parameter-list -> expressionという形式をとります。Seq.groupByは、ラムダ式でつくられるkeyをもとに、配列をグループ化します。MSDNの例を挙げておくと。

    let sequence = seq { 1 .. 100 }
    let sequences3 = Seq.groupBy (fun index ->
                                    if (index % 3 = 0) then 0
                                      elif (index % 3 = 1) then 1
                                      else 2) sequence

この計算結果は、(1, seq [1; 4; 7; 10; ...]) (2, seq [2; 5; 8; 11; ...]) (0, seq [3; 6; 9; 12; ...])になります。

Seq.groupByのあとは、Map.ofSeqで配列からmapを生成し、Map.map...でmapのcolorsに対して配列の長さの計算を適用し、Map.toArrayで配列に戻したあと、snd でタプルの二番目の要素を取り出しています。

Unityでの実行

UnityでF#を実行する際の基本的な手順に従ってください。このサンプルでは、System.Drawingという名前空間を使うので、そちらもSolution ExplorerのReferenceフォルダを右クリックし、
image

Add Referenceを選んで、下図の通り、Assemblies/FrameworkタブのSystem.Drawingを選んでOK。

image

これで、Imageクラスなどが使えるようになります。

そして、いつも通り、namespaceとmoduleを指定します。

Library1.fs

  namespace kNNDogCat

  open System
  open System.IO
  open System.Drawing
  module kNNDogCatEntry = 
    type Entry = {Label:string;Values:float[]}

  \\ 以下略

あと、UnityでつかえるF#3.0ではList.itemが使えないので、List.nthで代用します。具体的には

Library1.fs
 \\ 

  let guess1 = fst (List.nth labels1 0)

 \\ 

のようになります。

また、原著では計算結果の表示はprintfnを使ってますが、ここでは、Unity側に出力しましょう。Unity C#のコードは以下の通りです

ReadFSharp.cs
using UnityEngine;
using kNNDogCat;

public class ReadFSharp : MonoBehaviour
{
    void Start()
    {
        Debug.Log(kNNDogCatEntry.labels1);
        Debug.Log("The known dog is identified as a "+kNNDogCatEntry.guess1);
        Debug.Log(kNNDogCatEntry.labels2);
        Debug.Log("The known dog is identified as a "+kNNDogCatEntry.guess2);
    }
}
2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4