plot_sparsity (generic function with 1 method)
Block-Coordinate Frank-Wolfe and Block-Vectors
In this example, we demonstrate the usage of the FrankWolfe.block_coordinate_frank_wolfe
and FrankWolfe.BlockVector
. We consider the problem of minimizing the squared Euclidean distance between two sets. We compare different update orders and different update steps.
Import and setup
We first import the necessary packages and include the code for plotting the results.
using FrankWolfe
using LinearAlgebra
include("plot_utils.jl")
plot_sparsity (generic function with 1 method)
Next, we define the objective function and its gradient. The iterates x
are instances of the FrankWolfe.BlockVector
type. The different blocks of the vector can be accessed via the blocks
field.
f(x) = dot(x.blocks[1] - x.blocks[2], x.blocks[1] - x.blocks[2])
function grad!(storage, x)
@. storage.blocks = [x.blocks[1] - x.blocks[2], x.blocks[2] - x.blocks[1]]
end
grad! (generic function with 1 method)
In our example we consider the probability simplex and an L-infinity norm ball as the feasible sets.
n = 100
lmo1 = FrankWolfe.ScaledBoundLInfNormBall(-ones(n), zeros(n))
lmo2 = FrankWolfe.ProbabilitySimplexOracle(1.0)
prod_lmo = FrankWolfe.ProductLMO((lmo1, lmo2))
FrankWolfe.ProductLMO{2, Tuple{FrankWolfe.ScaledBoundLInfNormBall{Float64, 1, Vector{Float64}, Vector{Float64}}, FrankWolfe.ProbabilitySimplexOracle{Float64}}}((FrankWolfe.ScaledBoundLInfNormBall{Float64, 1, Vector{Float64}, Vector{Float64}}([-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0 … -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 … 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), FrankWolfe.ProbabilitySimplexOracle{Float64}(1.0)))
We initialize the starting point x0
as a FrankWolfe.BlockVector
with two blocks. The two other arguments are the block sizes and the overall number of entries.
x0 = FrankWolfe.BlockVector([-ones(n), [i == 1 ? 1 : 0 for i in 1:n]], [(n,), (n,)], 2 * n);
Running block-coordinate Frank-Wolfe with different update-orders
In a first step, we compare different update orders. There are three different update orders implemented, FrankWolfe.FullUpdate
, CyclicUpdate
and Stochasticupdate
. For creating a custome FrankWolfe.BlockCoordinateUpdateOrder
, one needs to implement the function select_update_indices
.
struct CustomOrder <: FrankWolfe.BlockCoordinateUpdateOrder end
function FrankWolfe.select_update_indices(::CustomOrder, state::FrankWolfe.CallbackState, dual_gaps)
return [rand() < 1 / n ? 1 : 2 for _ in 1:length(state.lmo.lmos)]
end
We run the block-coordinate Frank-Wolfe method with the different update orders and store the trajectories.
trajectories = []
for order in [
FrankWolfe.FullUpdate(),
FrankWolfe.CyclicUpdate(),
FrankWolfe.StochasticUpdate(),
CustomOrder(),
]
_, _, _, _, traj_data = FrankWolfe.block_coordinate_frank_wolfe(
f,
grad!,
prod_lmo,
x0;
verbose=true,
trajectory=true,
update_order=order,
)
push!(trajectories, traj_data)
end
Block coordinate Frank-Wolfe (BCFW).
MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: DataType[FrankWolfe.Adaptive{Float64, Int64}, FrankWolfe.Adaptive{Float64, Int64}] EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64
MOMENTUM: nothing GRADIENTTYPE: FrankWolfe.BlockVector{Float64, Vector{Float64}, Tuple{Int64}} UPDATE_ORDER: FrankWolfe.FullUpdate() UPDATE_STEP: DataType[FrankWolfe.FrankWolfeStep, FrankWolfe.FrankWolfeStep]
[ Info: In memory_mode memory iterates are written back into x0!
-------------------------------------------------------------------------------------------------
Type Iteration Primal Dual Dual Gap Time It/sec
-------------------------------------------------------------------------------------------------
I 1 5.732358e-01 -1.014268e+02 1.020000e+02 0.000000e+00 Inf
FW 1000 1.006522e-02 9.790473e-03 2.747434e-04 3.945157e-01 2.534753e+03
FW 2000 1.002905e-02 9.883695e-03 1.453591e-04 4.177063e-01 4.788054e+03
FW 3000 1.001690e-02 9.923899e-03 9.300514e-05 4.410217e-01 6.802386e+03
FW 4000 1.001088e-02 9.940501e-03 7.037823e-05 4.562200e-01 8.767700e+03
FW 5000 1.000730e-02 9.952154e-03 5.515099e-05 4.760016e-01 1.050417e+04
FW 6000 1.000507e-02 9.960902e-03 4.416633e-05 4.988345e-01 1.202804e+04
FW 7000 1.000360e-02 9.967424e-03 3.617261e-05 5.215289e-01 1.342207e+04
FW 8000 1.000260e-02 9.972504e-03 3.009367e-05 6.091148e-01 1.313381e+04
FW 9000 1.000190e-02 9.976620e-03 2.528359e-05 6.341737e-01 1.419170e+04
FW 10000 1.000141e-02 9.979993e-03 2.141696e-05 6.568415e-01 1.522437e+04
Last 10001 1.000141e-02 9.979981e-03 2.142870e-05 7.582650e-01 1.318932e+04
-------------------------------------------------------------------------------------------------
Block coordinate Frank-Wolfe (BCFW).
MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: DataType[FrankWolfe.Adaptive{Float64, Int64}, FrankWolfe.Adaptive{Float64, Int64}] EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64
MOMENTUM: nothing GRADIENTTYPE: FrankWolfe.BlockVector{Float64, Vector{Float64}, Tuple{Int64}} UPDATE_ORDER: FrankWolfe.CyclicUpdate(-1) UPDATE_STEP: DataType[FrankWolfe.FrankWolfeStep, FrankWolfe.FrankWolfeStep]
[ Info: In memory_mode memory iterates are written back into x0!
-------------------------------------------------------------------------------------------------
Type Iteration Primal Dual Dual Gap Time It/sec
-------------------------------------------------------------------------------------------------
I 1 5.732358e-01 -1.014268e+02 1.020000e+02 0.000000e+00 Inf
FW 1000 1.006522e-02 9.790473e-03 2.747434e-04 1.257483e-01 7.952392e+03
FW 2000 1.002905e-02 9.883695e-03 1.453591e-04 2.150809e-01 9.298827e+03
FW 3000 1.001690e-02 9.923899e-03 9.300514e-05 2.464568e-01 1.217252e+04
FW 4000 1.001088e-02 9.940501e-03 7.037823e-05 2.762288e-01 1.448075e+04
FW 5000 1.000730e-02 9.952154e-03 5.515099e-05 3.058596e-01 1.634737e+04
FW 6000 1.000507e-02 9.960902e-03 4.416633e-05 3.350088e-01 1.790997e+04
FW 7000 1.000360e-02 9.967424e-03 3.617261e-05 3.644264e-01 1.920827e+04
FW 8000 1.000260e-02 9.972504e-03 3.009367e-05 3.938649e-01 2.031153e+04
FW 9000 1.000190e-02 9.976620e-03 2.528359e-05 4.228602e-01 2.128363e+04
FW 10000 1.000141e-02 9.979993e-03 2.141696e-05 5.145945e-01 1.943278e+04
Last 10001 1.000141e-02 9.979981e-03 2.142870e-05 5.149724e-01 1.942046e+04
-------------------------------------------------------------------------------------------------
Block coordinate Frank-Wolfe (BCFW).
MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: DataType[FrankWolfe.Adaptive{Float64, Int64}, FrankWolfe.Adaptive{Float64, Int64}] EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64
MOMENTUM: nothing GRADIENTTYPE: FrankWolfe.BlockVector{Float64, Vector{Float64}, Tuple{Int64}} UPDATE_ORDER: FrankWolfe.StochasticUpdate(-1) UPDATE_STEP: DataType[FrankWolfe.FrankWolfeStep, FrankWolfe.FrankWolfeStep]
[ Info: In memory_mode memory iterates are written back into x0!
-------------------------------------------------------------------------------------------------
Type Iteration Primal Dual Dual Gap Time It/sec
-------------------------------------------------------------------------------------------------
I 1 5.732358e-01 -1.014268e+02 1.020000e+02 0.000000e+00 Inf
FW 1000 1.006649e-02 9.797679e-03 2.688115e-04 6.458421e-02 1.548366e+04
FW 2000 1.003282e-02 9.887544e-03 1.452767e-04 9.357221e-02 2.137387e+04
FW 3000 1.001920e-02 9.919860e-03 9.934003e-05 1.232392e-01 2.434291e+04
FW 4000 1.001224e-02 9.935454e-03 7.678946e-05 2.100172e-01 1.904606e+04
FW 5000 1.000812e-02 9.949492e-03 5.863302e-05 2.420344e-01 2.065822e+04
FW 6000 1.000561e-02 9.958403e-03 4.720724e-05 2.711276e-01 2.212980e+04
FW 7000 1.000400e-02 9.964922e-03 3.907771e-05 2.999578e-01 2.333662e+04
FW 8000 1.000288e-02 9.971244e-03 3.163293e-05 3.290759e-01 2.431050e+04
FW 9000 1.000209e-02 9.975610e-03 2.647559e-05 3.591794e-01 2.505712e+04
FW 10000 1.000153e-02 9.979405e-03 2.212997e-05 3.889933e-01 2.570739e+04
Last 10001 1.000153e-02 9.979008e-03 2.252590e-05 3.893947e-01 2.568345e+04
-------------------------------------------------------------------------------------------------
Block coordinate Frank-Wolfe (BCFW).
MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: DataType[FrankWolfe.Adaptive{Float64, Int64}, FrankWolfe.Adaptive{Float64, Int64}] EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64
MOMENTUM: nothing GRADIENTTYPE: FrankWolfe.BlockVector{Float64, Vector{Float64}, Tuple{Int64}} UPDATE_ORDER: Main.CustomOrder() UPDATE_STEP: DataType[FrankWolfe.FrankWolfeStep, FrankWolfe.FrankWolfeStep]
[ Info: In memory_mode memory iterates are written back into x0!
-------------------------------------------------------------------------------------------------
Type Iteration Primal Dual Dual Gap Time It/sec
-------------------------------------------------------------------------------------------------
I 1 1.024074e+02 -Inf Inf 0.000000e+00 Inf
FW 1000 1.003847e-02 9.875995e-03 1.624779e-04 7.549151e-02 1.324652e+04
FW 2000 1.001380e-02 9.931922e-03 8.188221e-05 1.158516e-01 1.726346e+04
FW 3000 1.000624e-02 9.955789e-03 5.044741e-05 1.559439e-01 1.923769e+04
FW 4000 1.000315e-02 9.969360e-03 3.378772e-05 1.956911e-01 2.044038e+04
FW 5000 1.000169e-02 9.978459e-03 2.323352e-05 2.956151e-01 1.691389e+04
FW 6000 1.000095e-02 9.983540e-03 1.740806e-05 3.351845e-01 1.790059e+04
FW 7000 1.000055e-02 9.987713e-03 1.283319e-05 3.744192e-01 1.869562e+04
FW 8000 1.000032e-02 9.990836e-03 9.486923e-06 4.140539e-01 1.932116e+04
FW 9000 1.000019e-02 9.992954e-03 7.238509e-06 4.542240e-01 1.981401e+04
FW 10000 1.000012e-02 9.994356e-03 5.760023e-06 5.574325e-01 1.793939e+04
Last 10001 1.000012e-02 9.994357e-03 5.759399e-06 5.578700e-01 1.792712e+04
-------------------------------------------------------------------------------------------------
Plotting the results
labels = ["Full update", "Cyclic order", "Stochstic order", "Custom order"]
plot_trajectories(trajectories, labels, xscalelog=true)
Running BCFW with different update methods
As a second step, we compare different update steps. We consider the FrankWolfe.BPCGStep
and the FrankWolfe.FrankWolfeStep
. One can either pass a tuple of FrankWolfe.UpdateStep
to define for each block the update procedure or pass a single update step so that each block uses the same procedure.
trajectories = []
for us in [(FrankWolfe.BPCGStep(), FrankWolfe.FrankWolfeStep()), (FrankWolfe.FrankWolfeStep(), FrankWolfe.BPCGStep()), FrankWolfe.BPCGStep(), FrankWolfe.FrankWolfeStep()]
_, _, _, _, traj_data = FrankWolfe.block_coordinate_frank_wolfe(
f,
grad!,
prod_lmo,
x0;
verbose=true,
trajectory=true,
update_step=us,
)
push!(trajectories, traj_data)
end
Block coordinate Frank-Wolfe (BCFW).
MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: DataType[FrankWolfe.Adaptive{Float64, Int64}, FrankWolfe.Adaptive{Float64, Int64}] EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64
MOMENTUM: nothing GRADIENTTYPE: FrankWolfe.BlockVector{Float64, Vector{Float64}, Tuple{Int64}} UPDATE_ORDER: FrankWolfe.CyclicUpdate(-1) UPDATE_STEP: DataType[FrankWolfe.BPCGStep, FrankWolfe.FrankWolfeStep]
[ Info: In memory_mode memory iterates are written back into x0!
-------------------------------------------------------------------------------------------------
Type Iteration Primal Dual Dual Gap Time It/sec
-------------------------------------------------------------------------------------------------
I 1 5.732358e-01 -1.014268e+02 1.020000e+02 0.000000e+00 Inf
FW 1000 1.006522e-02 9.790473e-03 2.747434e-04 5.146518e-01 1.943061e+03
FW 2000 1.002905e-02 9.883695e-03 1.453591e-04 5.533604e-01 3.614281e+03
FW 3000 1.001690e-02 9.923899e-03 9.300514e-05 6.496491e-01 4.617878e+03
FW 4000 1.001088e-02 9.940501e-03 7.037823e-05 6.879497e-01 5.814379e+03
FW 5000 1.000730e-02 9.952154e-03 5.515099e-05 7.272088e-01 6.875605e+03
FW 6000 1.000507e-02 9.960902e-03 4.416633e-05 7.653944e-01 7.839096e+03
FW 7000 1.000360e-02 9.967424e-03 3.617261e-05 8.040460e-01 8.705970e+03
FW 8000 1.000260e-02 9.972504e-03 3.009367e-05 8.426696e-01 9.493638e+03
FW 9000 1.000190e-02 9.976620e-03 2.528359e-05 9.462730e-01 9.510997e+03
FW 10000 1.000141e-02 9.979993e-03 2.141696e-05 9.844744e-01 1.015770e+04
Last 10001 1.000141e-02 9.979981e-03 2.142870e-05 9.868643e-01 1.013412e+04
-------------------------------------------------------------------------------------------------
Block coordinate Frank-Wolfe (BCFW).
MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: DataType[FrankWolfe.Adaptive{Float64, Int64}, FrankWolfe.Adaptive{Float64, Int64}] EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64
MOMENTUM: nothing GRADIENTTYPE: FrankWolfe.BlockVector{Float64, Vector{Float64}, Tuple{Int64}} UPDATE_ORDER: FrankWolfe.CyclicUpdate(-1) UPDATE_STEP: DataType[FrankWolfe.FrankWolfeStep, FrankWolfe.BPCGStep]
[ Info: In memory_mode memory iterates are written back into x0!
-------------------------------------------------------------------------------------------------
Type Iteration Primal Dual Dual Gap Time It/sec
-------------------------------------------------------------------------------------------------
I 1 5.732358e-01 -1.014268e+02 1.020000e+02 0.000000e+00 Inf
Last 474 1.000000e-02 9.999910e-03 8.999181e-08 2.033088e-01 2.331429e+03
-------------------------------------------------------------------------------------------------
Block coordinate Frank-Wolfe (BCFW).
MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: DataType[FrankWolfe.Adaptive{Float64, Int64}, FrankWolfe.Adaptive{Float64, Int64}] EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64
MOMENTUM: nothing GRADIENTTYPE: FrankWolfe.BlockVector{Float64, Vector{Float64}, Tuple{Int64}} UPDATE_ORDER: FrankWolfe.CyclicUpdate(-1) UPDATE_STEP: DataType[FrankWolfe.BPCGStep, FrankWolfe.BPCGStep]
[ Info: In memory_mode memory iterates are written back into x0!
-------------------------------------------------------------------------------------------------
Type Iteration Primal Dual Dual Gap Time It/sec
-------------------------------------------------------------------------------------------------
I 1 5.732358e-01 -1.014268e+02 1.020000e+02 0.000000e+00 Inf
Last 474 1.000000e-02 9.999910e-03 8.999181e-08 8.511164e-02 5.569156e+03
-------------------------------------------------------------------------------------------------
Block coordinate Frank-Wolfe (BCFW).
MEMORY_MODE: FrankWolfe.InplaceEmphasis() STEPSIZE: DataType[FrankWolfe.Adaptive{Float64, Int64}, FrankWolfe.Adaptive{Float64, Int64}] EPSILON: 1.0e-7 MAXITERATION: 10000 TYPE: Float64
MOMENTUM: nothing GRADIENTTYPE: FrankWolfe.BlockVector{Float64, Vector{Float64}, Tuple{Int64}} UPDATE_ORDER: FrankWolfe.CyclicUpdate(-1) UPDATE_STEP: DataType[FrankWolfe.FrankWolfeStep, FrankWolfe.FrankWolfeStep]
[ Info: In memory_mode memory iterates are written back into x0!
-------------------------------------------------------------------------------------------------
Type Iteration Primal Dual Dual Gap Time It/sec
-------------------------------------------------------------------------------------------------
I 1 5.732358e-01 -1.014268e+02 1.020000e+02 0.000000e+00 Inf
FW 1000 1.006522e-02 9.790473e-03 2.747434e-04 3.071012e-02 3.256256e+04
FW 2000 1.002905e-02 9.883695e-03 1.453591e-04 5.962156e-02 3.354491e+04
FW 3000 1.001690e-02 9.923899e-03 9.300514e-05 8.864506e-02 3.384283e+04
FW 4000 1.001088e-02 9.940501e-03 7.037823e-05 1.180024e-01 3.389761e+04
FW 5000 1.000730e-02 9.952154e-03 5.515099e-05 1.475915e-01 3.387728e+04
FW 6000 1.000507e-02 9.960902e-03 4.416633e-05 1.769491e-01 3.390806e+04
FW 7000 1.000360e-02 9.967424e-03 3.617261e-05 2.061035e-01 3.396352e+04
FW 8000 1.000260e-02 9.972504e-03 3.009367e-05 2.987627e-01 2.677710e+04
FW 9000 1.000190e-02 9.976620e-03 2.528359e-05 3.303867e-01 2.724081e+04
FW 10000 1.000141e-02 9.979993e-03 2.141696e-05 3.594485e-01 2.782039e+04
Last 10001 1.000141e-02 9.979981e-03 2.142870e-05 3.597772e-01 2.779776e+04
-------------------------------------------------------------------------------------------------
Plotting the results
labels = ["BPCG FW", "FW BPCG", "BPCG", "FW"]
plot_trajectories(trajectories, labels, xscalelog=true)
This page was generated using Literate.jl.