From 3e78ac11fdbcad06d52e44953f90fc54d0c5d4b0 Mon Sep 17 00:00:00 2001 From: Viraj Date: Mon, 25 Dec 2017 13:35:00 -0800 Subject: [PATCH] initial version of GoDec algorithm --- .gitignore | 32 ++++++++++++++++++ README.md | 3 ++ include/godec.h | 8 +++++ src/godec.cc | 86 +++++++++++++++++++++++++++++++++++++++++++++++++ src/main.cc | 31 ++++++++++++++++++ 5 files changed, 160 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 include/godec.h create mode 100644 src/godec.cc create mode 100644 src/main.cc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..259148f --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app diff --git a/README.md b/README.md new file mode 100644 index 0000000..6e7d6b5 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +This repository contains a C++ implementation of the GoDec algorithm for decomposing a matrix into low-rank and sparse components. See [T. Zhou and D. Tao., _Godec: Randomized Low-Rank & Sparse Matrix Decomposition in Noisy Case_](http://www.icml-2011.org/papers/41_icmlpaper.pdf). The algorithm has been used for compression of deep neural networks, whose weight tensors can often be approximated well as sums of low-rank and sparse tensors. See [Yu et al., _On Compressing Deep Models by Low Rank and Sparse Decomposition_](https://pdfs.semanticscholar.org/7551/cc8e398b34cba3ec46569326273da3e9a3df.pdf). + +This code requires the [Eigen](eigen.tuxfamily.org/) linear algebra library. diff --git a/include/godec.h b/include/godec.h new file mode 100644 index 0000000..95b7af6 --- /dev/null +++ b/include/godec.h @@ -0,0 +1,8 @@ +#ifndef __GODEC_H_INCLUDED__ +#define __GODEC_H_INCLUDED__ + +#include + +Eigen::MatrixXd godec(const Eigen::MatrixXd &x, int r, int k, int num_iterations); + +#endif diff --git a/src/godec.cc b/src/godec.cc new file mode 100644 index 0000000..4f663ad --- /dev/null +++ b/src/godec.cc @@ -0,0 +1,86 @@ +#include "godec.h" + +#include +#include +#include +#include + +Eigen::MatrixXd reducerank(const Eigen::MatrixXd &m, int r) +{ + Eigen::BDCSVD decomposition(m, Eigen::ComputeThinU | Eigen::ComputeThinV); + Eigen::MatrixXd s = decomposition.singularValues().asDiagonal(); + Eigen::MatrixXd u = decomposition.matrixU(); + Eigen::MatrixXd v = decomposition.matrixV(); + Eigen::MatrixXd uslice = u.block(0, 0, u.rows(), r); + Eigen::MatrixXd vslice = v.block(0, 0, v.rows(), r); + Eigen::MatrixXd sslice = s.block(0, 0, r, r); + Eigen::MatrixXd approx = uslice*sslice*vslice.transpose(); + std::cout << "Original:" << std::endl << m << std::endl; + std::cout << "U:" << std::endl << u << std::endl; + std::cout << "V:" << std::endl << v << std::endl; + std::cout << "S:" << std::endl << s << std::endl; + std::cout << "recovered:" << std::endl << u*s*v.transpose() << std::endl; + std::cout << "U slice:" << std::endl << uslice << std::endl; + std::cout << "V slice:" << std::endl << vslice << std::endl; + std::cout << "S slice:" << std::endl << sslice << std::endl; + std::cout << "approximation:" << std::endl << approx << std::endl; + + return approx; +} + +class MatElt { +public: + std::pair index; + float val; + MatElt(std::pair p, float x) : index(p), val(x) { } +}; + +Eigen::MatrixXd thresh(const Eigen::MatrixXd &x, int k) +{ + auto cmp = [](MatElt left, MatElt right) { return (left.val < right.val);}; + std::priority_queue, decltype(cmp)> q(cmp); + for (int i = 0; i < x.rows(); i++) + { + for (int j = 0; j < x.cols(); j++) + { + q.push(MatElt(std::make_pair(i, j), x(i, j))); + } + } + + Eigen::MatrixXd a = Eigen::MatrixXd::Zero(x.rows(), x.cols()); + for (int i = 0; i < k; i++) + { + MatElt elt = q.top(); + q.pop(); + auto f = elt.index; + float s = elt.val; + a(f.first, f.second) = s; + } + + std::cout << "a:" << std::endl << a; + + return a; +} + +Eigen::MatrixXd godec(const Eigen::MatrixXd &x, int r, int k, int num_iterations) +{ + Eigen::MatrixXd l(x.rows(), x.cols()); + Eigen::MatrixXd s(x.rows(), x.cols()); + + for (int i = 0; i < x.rows(); i++) + for (int j = 0; j < x.cols(); j++) + { + { + l(i, j) = x(i, j); + s(i, j) = 0.0; + } + } + + for (int i = 0; i < num_iterations; i++) + { + l = reducerank(x - s, r); + s = thresh(x - l, k); + } + + return l + s; +} diff --git a/src/main.cc b/src/main.cc new file mode 100644 index 0000000..4442ee8 --- /dev/null +++ b/src/main.cc @@ -0,0 +1,31 @@ +#include "godec.h" + +#include +#include + +Eigen::MatrixXd testmatrix() { + Eigen::MatrixXd x(4, 3); + x(0, 0) = .5; + x(0, 1) = 0; + x(0, 2) = 0; + x(1, 0) = 0; + x(1, 1) = .8; + x(1, 2) = 0; + x(2, 0) = 0; + x(2, 1) = 0; + x(2, 2) = 0; + x(3, 0) = .2; + x(3, 1) = 0; + x(3, 2) = 0; + return x; +} + +int main() +{ + Eigen::MatrixXd x = testmatrix(); + int r = 1; + int k = 1; + int num_iterations = 20; + auto result = godec(x, r, k, num_iterations); + std::cout << "godec result is " << std::endl << result << std::endl; +}