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