-
Notifications
You must be signed in to change notification settings - Fork 122
Closed
Labels
Description
I was playing around with implementing a basic linear SVM in both Convex.jl and JuMP and noticed a pretty significant penalty for model generation in Convex.jl:
using JuMP
using Distributions
using Gurobi
import Convex # namespace conflicts with JuMP.Variable()
function gen_data(n)
pos = rand(MvNormal([1.0,2.0],1.0),n)
neg = rand(MvNormal([-1.0,1.0],1.0),n)
return pos,neg
end
const N = 2
const C = 10
function svm_jump(pos,neg, solver)
m = Model(solver=solver)
@defVar(m, w[1:N])
@defVar(m, b)
@defVar(m, ξpos[1:size(pos,2)] >= 0)
@defVar(m, ξneg[1:size(neg,2)] >= 0)
@setObjective(m, Min, sum{w[i]^2, i = 1:N} + C*sum(ξpos) + C*sum(ξneg))
@addConstraint(m, posconstr[j=1:size(pos,2)], dot(w,pos[:,j]) - b >= 1 - ξpos[j])
@addConstraint(m, negconstr[j=1:size(neg,2)], -1*(dot(w,neg[:,j]) - b) >= 1 - ξneg[j])
status = solve(m)
@assert status == :Optimal
return getValue(w[:]), getValue(b)
end
function svm_convex(pos,neg,solver)
w = Convex.Variable(N)
b = Convex.Variable()
ξpos = Convex.Variable(size(pos,2), Convex.Positive())
ξneg = Convex.Variable(size(neg,2), Convex.Positive())
problem = Convex.minimize(Convex.sum_squares(w) + C*sum(ξpos) + C*sum(ξneg))
for j in 1:size(pos,2)
push!(problem.constraints, dot(w,pos[:,j]) - b >= 1 - ξpos[j])
#problem.constraints += dot(w,pos[:,j]) - b >= 1 - ξpos[j]
end
for j in 1:size(neg,2)
push!(problem.constraints, -1*(dot(w,neg[:,j]) - b) >= 1-ξneg[j])
#problem.constraints += -1*(dot(w,neg[:,j]) - b) >= 1-ξneg[j]
end
Convex.solve!(problem, solver)
return Convex.evaluate(w), Convex.evaluate(b)
end
pos,neg = gen_data(10)
# initial compilation
svm_jump(pos,neg, GurobiSolver(OutputFlag=0))
svm_convex(pos,neg, GurobiSolver(OutputFlag=0))
pos,neg = gen_data(2000)
@time w, b = svm_jump(pos,neg, GurobiSolver())
@show w,b
@time w, b = svm_convex(pos,neg, GurobiSolver())
@show w,b
Both give approximately the same answer. For JuMP on my machine, Gurobi solves in 0.09 seconds and the whole thing is done in 0.10 seconds. For Convex.jl, Gurobi solves in 0.11 seconds but the total time is 6.5 seconds.
I know model generation time hasn't been as much of a priority as with JuMP, and Convex.jl has to do more work in principle since it's performing a lot of automatic transformations. Anyway I wanted to share this as a benchmark that could be used to speed up Convex.jl.