In a previous post, I was using Google’s prediction API to predict what game was streaming based on the color histogram of an image. The API worked pretty well and was fairly accurate. The main downside was that is was slow and inconsistent. Many of the requests would just time out and give a generic 503 error. This lead me to looking into alternatives, ideally one that is fast, free, and I could easily do myself.

With these issues I started looking for an alternative, possibly an existing library out there that I could run locally. Then I came across the liblinear library which is a linear classification library that supports a bunch of different classifiers and has bindings for pretty much every language. I ended up using the liblinear-ruby gem.

In the previous post, we have already put together our training set. Now we just need to train our new liblinear model.

require 'liblinear'

# reference
# games = {1 => "csgo",
#          2 => "dota2",
#          3 => "hearthstone",
#          4 => "minecraft",
#          5 => "starcraft"}

# Setting parameters
param = Liblinear::Parameter.new
param.solver_type = Liblinear::L2R_LR

label_ids = {}

labels = []
examples = []

id = 1

File.open("training_set.txt", "r").each_line do |line|
  split = line.split(",")
  game = split[0].gsub("\"", "")

  if label_ids[game].nil?
    label_ids[game] = id
    id += 1
  end

  labels << label_ids[game]
  examples << split[1..-1].map{|x| x.to_f}
end

bias = 0.5
prob = Liblinear::Problem.new(labels, examples, bias)
model = Liblinear::Model.new(prob, param)

model.save("games.model")

Now we have our trained model in the file games.model and can start querying it.

require 'liblinear'
require 'opencv'

games = {1 => "csgo", 2 => "dota2", 3 => "hearthstone", 4 => "minecraft", 5 => "starcraft"}

def hist(file)
  iplimg = OpenCV::IplImage.decode_image(open(file).read)
  b, g, r = iplimg.split

  dim = 3
  sizes = [8,8,8]
  ranges = [[0, 255],[0, 255],[0, 255]]
  hist = OpenCV::CvHistogram.new(dim, sizes, OpenCV::CV_HIST_ARRAY, ranges, true)
  hist.calc_hist([r, g, b])
end

model = Liblinear::Model.new("games.model")

h = hist(ARGV[0])
vals = []

(0..511).each do |i|
  vals << h[i]
end

puts "Guessing what game for #{ARGV[0]}"
puts "Prediction: #{games[model.predict(vals).to_i]}"

model.save("games.model")

So how does this compare with Google’s prediction API?

Liblinear

Game Correct Wrong Accuracy
CS:GO 4 1 80%
Dota 2 5 0 100%
Hearthstone 5 0 100%
Minecraft 3 2 60%
Starcraft 2 3 2 60%

Prediction API

Game Correct Wrong Accuracy
CS:GO 4 1 80%
Dota 2 3 2 60%
Hearthstone 4 1 80%
Minecraft 2 3 40%
Starcraft 2 4 1 80%

As you can see, aside from Starcraft 2, all games had either the same correctly predicted results or better. Combining the accuracy and speed of this model, we could next start predicting on screens from live video streams.

You can find the code for this in github: https://github.com/abronte/GamePredict