Skip to content

example of slow model generation #49

@mlubin

Description

@mlubin

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.

CC @IainNZ @joehuchette

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions