Skip to content
/ KSVD.jl Public

Highly optimized K-SVD implementation in Julia, with several parallelization techniques available.

License

Notifications You must be signed in to change notification settings

RomeoV/KSVD.jl

Repository files navigation

KSVD.jl

K-SVD is an algorithm for creating overcomplete dictionaries for sparse representations.

This package implements:

In particular, substantial effort has been put in speeding up this implementation. This includes:

  • Custom parallel dense-sparse matrix multiplication via ThreadedDenseSparseMul.jl
  • Custom pipelined GPU offloading for matching pursuit (CUDAAcceleratedMatchingPursuit)
  • Threaded matching pursuit (ParallelMatchingPursuit) (mostly "embarassingly parallel")
  • Threaded ksvd implementation (ParallelKSVD) (not "embarassingly parallel")
  • Threaded and batched ksvd implementation (BatchedParallelKSVD) (not "embarassingly parallel")
  • Extensive efforts removing allocations by preallocating buffers
  • Extensive benchmark-driven optimizations utilizing ProfileView.jl
  • Many other modification experiments.

Usage

Assume that each column of Y represents a feature vector (or an input signal from some system).
D is a dictionary. Each column of D represents an atom.
K-SVD derives D and X such that DX ≈ Y from only Y.

(; D, X) = ksvd(Y, 256)

# we can control the matching pursuit stage and ksvd stage through method structs
ksvd_update_method = BatchedParallelKSVD{false, Float64}(shuffle_indices=true, batch_size_per_thread=1)
sparse_coding_method = ParallelMatchingPursuit(max_nnz=25, rtol=5e-2)
result = ksvd(Y, 256;
              ksvd_update_method,
              sparse_coding_method,
              maxiters=100,
              abstol=1e-6,
              reltol=1e-6,
              show_trace=true)

# Access additional information
println("Termination condition: ", result.termination_condition)
println("Norm results: ", result.norm_results)
println("NNZ per column results: ", result.nnz_per_col_results)
println("Timing information: ", result.timer)

Of course we can also just run one step of matching pursuit/sparse coding, or one step of the ksvd update:

basis = KSVD.init_dictionary(size(Y, 1), 2*size(Y,2))
X = sparse_coding(OrthogonalMatchingPursuit(max_nnz=25), Y, basis)

(; D, X) = ksvd_update(ksvd_update_method, Y, basis, X)

Matching Pursuit derives X from D and Y such that DX = Y in constraint that X be as sparse as possible.

Performance improvements

Here is an overview of the performance improvements in the ksvd_update provided in this package, broken down by computation type. The data is computed using different commits on the experiments branch. More details will be added later.

benchmark results

About

Highly optimized K-SVD implementation in Julia, with several parallelization techniques available.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages