Using F# and R Provider with Kaggle’s Facial Keypoints Detection

Lately, I have been trying to learn more about Data Science and Machine Learning. Following a coursera’s machine learning class and reading some books like, Data Science for Business and Mining the Social Web is very useful. However, you may want to get your hands dirty and learn the topics by solving the real-world problems. Fortunately, there is a site called Kaggle which provides data and problems for you to solve.

Basically, Kaggle is a platform allowing companies and researchers to post their data, so that people like data scientist, statisticians, data miners, and so on can compete to produce the best predictive models. Most competitions are real-world problems that big companies are trying to solve, and if you come up with the best model, you could win some prizes or even get a job!  For a newbie like me, Kaggle also has 101-type competitions that could help you learn the basic while having fun solving the real-world problem. One of the problem that I am looking at is Facial Keypoints Detection which should also help me learn computer vision in addition to data science and machine learning.

Many languages and environments like R, MATLAB, Octave, and Python are generally used in Data Science and Machine Learning fields. However, F# is also a great language for data-oriented problem-solving, data science, and machine learning tasks as well. REPL and succinctness of F# allows you to explore and manipulate the data in both functional and imperative styles. With type providers, acquiring data from various sources like CSV, XML, JSON, and databases as well as interoperability with R can be done within F#. In addition, there are libraries like Deedle and FSharp.Charting that will be very useful. And as F# is a .NET languages, you can use .NET libraries like Math.NET and numl to help as well.

To get start quickly, we can just install the FsLab NuGet package that put together useful F# libraries for Data Science task.

image

NOTE: As of 4/26/2014, FsLab is still beta, so you have to select “Include Prerelease” option.

This post, I will show how we can use F# and R Provider with the Facial Keypoints Detection. I won’t try to solve the problem yet :-), but I will follow the R tutorial that let me learn R as well as getting familiar with the data.

The first step is to download the training data from here. The training file is in csv format with 7049 rows and has 31 columns, 30 of those columns keep 15 (x,y) keypoints such as nose tip, left eye, etc. The last column is a list of pixels representing a 96×96 image.

I want to use my own type, so I just create a Face type and write a simple parser in F#.

type Face =
    {
        LeftEyeCenter:Option<decimal*decimal>
        RightEyeCenter:Option<decimal*decimal>
        LeftEyeInnerCorner:Option<decimal*decimal>
        LeftEyeOuterCorner:Option<decimal*decimal>
        RightEyeInnerCorner:Option<decimal*decimal>
        RightEyeOuterCorner:Option<decimal*decimal>
        LeftEyeBrowInnerEnd:Option<decimal*decimal>
        LeftEyeBrowOuterEnd:Option<decimal*decimal>
        RightEyeBrowInnerEnd:Option<decimal*decimal>
        RighttEyeBrowOuterEnd:Option<decimal*decimal>
        NoseTip:Option<decimal*decimal>
        MouthLeftCorner:Option<decimal*decimal>
        MouthRightCorner:Option<decimal*decimal>
        MouthCenterTopLip:Option<decimal*decimal>
        MouthCenterBottomLip:Option<decimal*decimal>
        Image:int[]
    }

let lines = File.ReadAllLines("D:/kaggle/facial-keypoints-detection/training.csv")

let faces =      
    let d = Decimal.TryParse
    let toXy v1 v2 =         
        match d v1 with
        | false, _ -> None
        | true, x ->
            match d v2 with
            | false, _ -> None
            | true,y -> Some(x,y)        

    lines
    |> Seq.skip 1
    |> Seq.map (fun (row:string) -> 
            let r = row.Split(',')
            {
               LeftEyeCenter = toXy r.[0] r.[1]
               RightEyeCenter = toXy r.[2] r.[3]
               LeftEyeInnerCorner = toXy r.[4] r.[5]
               LeftEyeOuterCorner = toXy r.[6] r.[7]
               RightEyeInnerCorner = toXy r.[8] r.[9]
               RightEyeOuterCorner = toXy r.[10] r.[11]
               LeftEyeBrowInnerEnd = toXy r.[12] r.[13]
               LeftEyeBrowOuterEnd = toXy r.[14] r.[15]
               RightEyeBrowInnerEnd = toXy r.[16] r.[17]
               RighttEyeBrowOuterEnd = toXy r.[18] r.[19]
               NoseTip = toXy r.[20] r.[21]
               MouthLeftCorner = toXy r.[22] r.[23]
               MouthRightCorner = toXy r.[24] r.[25]
               MouthCenterTopLip = toXy r.[26] r.[27]
               MouthCenterBottomLip = toXy r.[28] r.[29]
               Image = (r.[30].Split(' ') |> Array.map (Int32.Parse))
            }
        )

If you want you can use CSV Type Provider, but you should specify the InferRows to be zero to check the whole file and set PreferOptionals to be true to use Options type.

type FaceCsv = CsvProvider<"D:/kaggle/facial-keypoints-detection/training.csv", InferRows=0, PreferOptionals = true>
let faces = new FaceCsv()

After we get all training data, the first thing is to visualize the face data. R already has nice graphics library that we can use to display the image, so we can use R Provider to call those functions from F#.

Let’s get values from the first face data.

// R Stuff
open RProvider
open RProvider.``base``
open RProvider.graphics
open RProvider.grDevices

// helper functions
let o x = x :> obj
let imXy p = match p with Some(x,y) -> (96m-x),(96m-y) | _ -> (0m,0m)     
let face i = faces |> Seq.nth i
let imPointParams (x,y) color = ["x",o x;"y",o y;"col",o color] |> namedParams

// get values from face
let im = R.matrix(nrow=96,ncol=96,data=Array.rev((face 0).Image))
let noseTipXy = imXy (face 0).NoseTip
let leftEyeCenterXy = imXy (face 0).LeftEyeCenter
let rightEyeCenterXy = imXy (face 0).RightEyeCenter

NOTE: To use R.NET and R Provider, you still have to download and install R,

Now we have all values, we can put them in a format that R expects and call the R functions.

// Visualize image using R
// image(1:96, 1:96, im, col=gray((0:255)/255))
let imageParams = 
    [
        "x",R.c([|1..96|])
        "y",R.c([|1..96|])
        "z",im
        "col",R.gray(["level",R.c(seq { for i in 0. .. 255. -> i/255.})]|>namedParams)
    ] |> namedParams
R.image(imageParams)

// add points for nose tip, left eye, right eye
// points(96-d.train$nose_tip_x[1], 96-d.train$nose_tip_y[1], col="red")
R.points(imPointParams noseTipXy "red")
R.points(imPointParams leftEyeCenterXy "blue")
R.points(imPointParams rightEyeCenterXy "green")

And you should see the sample image.

image

Although, you should be able to call R functions directly from F#, sometimes trying to figure out R format can be cumbersome. What we can do is to use REngine.Evaluate like this as well.

im.Engine.SetSymbol("im", im)
im.Engine.Evaluate("image(1:96, 1:96, im, col=gray((0:255)/255))")

Now since I know how to use R to display gray-scale image, I can use the same trick to display the image for Digit-Recognizer data :-).

image

You should see the power of F# which allows us to process and manipulate data with F# and utilize R for statistical computing and graphics!

In the future post, I plan to share more about my journey with Data Science and Machine Learning in F#. Happy data mining!