最近打算在研究中尝试稀疏编码。稀疏表示的理论知识这里不具体补充,有兴趣的可以查看下面这篇用稀疏表示做人脸识别的文章,讲得很清楚。
http://blog.csdn.net/xiaoshengforever/article/details/14002843
稀疏表示中的关键是求解L2范数或者L1范数。L2范数的求解很简单,一个公式就搞定了; L1范数的求解就要复杂多了,求解的方式也有很多种。笔者做了实验后发现用L1求解出的结果确实比用L2求解出的结果稀疏多了。
通常求解L1范数都要借助第三方包。网上求解L1的MATLAB包比较多,但是C++包却相对很少,搜索后发现了KL1p这个好东西。
kl1p是一个压缩感知方面的C++库,里面封装了很多压缩感知方法,在稀疏表(SRC)示中主要是借助它来求取l1范数最小化问题。它的官方:http://kl1p.sourceforge.net/home.html 目前的版本是0.4.2
说明:从KL1p的配置可以看到,在KL1p在求解矩阵时实际上是通过Armadillo库来实现的,关于Armadillo库的矩阵操作手册可在这个网站查询:
http://arma.sourceforge.net/docs.html
最后给一个完整Demo程序
//KL1p Demo
#include"armadillo"
#include <KL1pInclude.h>
#include <KL1p.h>
using namespace std;
using namespace kl1p;
using namespace arma;
int main()
{
arma::mat featureMat; //839*156
featureMat.load("LBPPCANorFeatures.csv",csv_ascii);
arma::mat x0; //1*156
x0.load("test.csv",csv_ascii);
//在读取的两个csv文件中,一个样本的特征占一行,所以需要取转置
arma::mat A1 = featureMat.t();
arma::mat y = x0.t();
std::cout<<"Start of KL1p compressed-sensing example."<<std::endl;
std::cout<<"Try to determine a sparse vector x "<<std::endl;
std::cout<<"from an underdetermined set of linear measurements y=A*x, "<<std::endl;
std::cout<<"where A is a random gaussian i.i.d sensing matrix."<<std::endl;
klab::UInt32 n = A1.n_rows; // Size of the original signal x0.
klab::DoubleReal alpha = 0.5; // Ratio of the cs-measurements.
klab::DoubleReal rho = 0.1; // Ratio of the sparsity of the signal x0.
klab::UInt32 m = klab::UInt32(alpha*n); // Number of cs-measurements.
klab::UInt32 k = klab::UInt32(rho*n); // Sparsity of the signal x0 (number of non-zero elements).
klab::UInt64 seed = 0; // Seed used for random number generation (0 if regenerate random numbers on each launch).
bool bWrite = true; // Write signals to files ?
// Display signal informations.
std::cout<<"=============================="<<std::endl;
std::cout<<"N="<<n<<" (signal size)"<<std::endl;
std::cout<<"M="<<m<<"="<<std::setprecision(5)<<(alpha*100.0)<<"% (number of measurements)"<<std::endl;
std::cout<<"K="<<k<<"="<<std::setprecision(5)<<(rho*100.0)<<"% (signal sparsity)"<<std::endl;
std::cout<<"=============================="<<std::endl;
kl1p::TMatrixOperator<klab::DoubleReal> * matrix = new kl1p::TMatrixOperator<klab::DoubleReal>(A1);
klab::TSmartPointer<kl1p::TOperator<klab::DoubleReal, klab::DoubleReal> > * A2 =new klab::TSmartPointer<kl1p::TOperator<klab::DoubleReal, klab::DoubleReal> >(matrix);
klab::TSmartPointer<kl1p::TOperator<klab::DoubleReal, klab::DoubleReal> > A = *A2;
klab::DoubleReal tolerance = 1e-3; // Tolerance of the solution.
arma::Col<klab::DoubleReal> x; // Will contain the solution of the reconstruction.
klab::KTimer timer;
// Compute Basis-Pursuit.
std::cout<<"[BasisPursuit] Start."<<std::endl;
timer.start();
kl1p::TBasisPursuitSolver<klab::DoubleReal> bp(tolerance);
bp.solve(y, A, x);
timer.stop();
std::cout<<"[BasisPursuit] Done - SNR="<<std::setprecision(5)<<klab::SNR(x, x0)<<" - "
<<"Time="<<klab::UInt32(timer.durationInMilliseconds())<<"ms"<<" - "
<<"Iterations="<<bp.iterations()<<std::endl;
if(bWrite)
x.save("BasisPursuit-Signal.csv",csv_ascii); // Write solution to a file.
// Compute OMP.
std::cout<<"------------------------------"<<std::endl;
std::cout<<"[OMP] Start."<<std::endl;
timer.start();
kl1p::TOMPSolver<klab::DoubleReal> omp(tolerance);
omp.solve(y, A, k, x);
timer.stop();
std::cout<<"[OMP] Done - SNR="<<std::setprecision(5)<<klab::SNR(x, x0)<<" - "
<<"Time="<<klab::UInt32(timer.durationInMilliseconds())<<"ms"<<" - "
<<"Iterations="<<omp.iterations()<<std::endl;
if(bWrite)
x.save("OMP-Signal.csv",csv_ascii); // Write solution to a file.
// Compute ROMP.
std::cout<<"------------------------------"<<std::endl;
std::cout<<"[ROMP] Start."<<std::endl;
timer.start();
kl1p::TROMPSolver<klab::DoubleReal> romp(tolerance);
romp.solve(y, A, k, x);
timer.stop();
std::cout<<"[ROMP] Done - SNR="<<std::setprecision(5)<<klab::SNR(x, x0)<<" - "
<<"Time="<<klab::UInt32(timer.durationInMilliseconds())<<"ms"<<" - "
<<"Iterations="<<romp.iterations()<<std::endl;
if(bWrite)
x.save("ROMP-Signal.csv",csv_ascii); // Write solution to a file.
// Compute CoSaMP.
std::cout<<"------------------------------"<<std::endl;
std::cout<<"[CoSaMP] Start."<<std::endl;
timer.start();
kl1p::TCoSaMPSolver<klab::DoubleReal> cosamp(tolerance);
cosamp.solve(y, A, k, x);
timer.stop();
std::cout<<"[CoSaMP] Done - SNR="<<std::setprecision(5)<<klab::SNR(x, x0)<<" - "
<<"Time="<<klab::UInt32(timer.durationInMilliseconds())<<"ms"<<" - "
<<"Iterations="<<cosamp.iterations()<<std::endl;
if(bWrite)
x.save("CoSaMP-Signal.csv",csv_ascii); // Write solution to a file.
// Compute Subspace-Pursuit.
std::cout<<"------------------------------"<<std::endl;
std::cout<<"[SubspacePursuit] Start."<<std::endl;
timer.start();
kl1p::TSubspacePursuitSolver<klab::DoubleReal> sp(tolerance);
sp.solve(y, A, k, x);
timer.stop();
std::cout<<"[SubspacePursuit] Done - SNR="<<std::setprecision(5)<<klab::SNR(x, x0)<<" - "
<<"Time="<<klab::UInt32(timer.durationInMilliseconds())<<"ms"<<" - "
<<"Iterations="<<sp.iterations()<<std::endl;
if(bWrite)
x.save("SubspacePursuit-Signal.csv",csv_ascii); // Write solution to a file.
// Compute SL0.
std::cout<<"------------------------------"<<std::endl;
std::cout<<"[SL0] Start."<<std::endl;
timer.start();
kl1p::TSL0Solver<klab::DoubleReal> sl0(tolerance);
sl0.solve(y, A, x);
timer.stop();
std::cout<<"[SL0] Done - SNR="<<std::setprecision(5)<<klab::SNR(x, x0)<<" - "
<<"Time="<<klab::UInt32(timer.durationInMilliseconds())<<"ms"<<" - "
<<"Iterations="<<sl0.iterations()<<std::endl;
if(bWrite)
x.save("SL0-Signal.csv",csv_ascii); // Write solution to a file.
// Compute AMP.
std::cout<<"------------------------------"<<std::endl;
std::cout<<"[AMP] Start."<<std::endl;
timer.start();
kl1p::TAMPSolver<klab::DoubleReal> amp(tolerance);
amp.solve(y, A, x);
timer.stop();
std::cout<<"[AMP] Done - SNR="<<std::setprecision(5)<<klab::SNR(x, x0)<<" - "
<<"Time="<<klab::UInt32(timer.durationInMilliseconds())<<"ms"<<" - "
<<"Iterations="<<amp.iterations()<<std::endl;
if(bWrite)
x.save("AMP-Signal.csv",csv_ascii); // Write solution to a file
system("pause");
return 0;
}
程序的执行结果如下:
从结果可以看到,不同的算法所需的求解时间不同。
下面详细看看不同算法求解出的结果。
BasicPursuit的计算结果:
OMP的求解结果:
ROMP的求解结果:
CoSaMP的求解结果:
SubspacePursuit的求解结果:
SL0的求解结果:
AMP的求解结果:
从以上结果可以看到,不同的算法求解出的结果稀疏度有较大的差别。
完成Demo程序及数据下载地址:
http://download.csdn.net/detail/computerme/9309285
Reference:
http://blog.csdn.net/jianjian1992/article/details/49387477 例子讲解
http://blog.csdn.net/u013088062/article/details/44566667 配置过程
http://blog.csdn.net/xiaoshengforever/article/details/14002843 人脸识别