K-SVD算法

来源:互联网 发布:什么是自动编程系统 编辑:程序博客网 时间:2024/05/22 04:41

转自:http://blog.csdn.net/hjxzb/article/details/39433905

K-SVD算法的基本思想:


Y为训练样本,D为字典,X为稀疏系数。一般分为Sparse CodingDictionaryUpdate两个步骤:

1Sparse Coding:固定字典D通过下面的目标函数采用一种追踪算法找到样本的最佳稀疏矩阵。

2Dictionary Update:按列更新字典,一句可使MSE减少的准则,通过SVD(奇异值分解)循序的更新每一列和该列对应的稀疏矩阵的值。


EK为字典的第k列的残差,物理意义:没有dk时表示的误差,也就是字典的第k列在表示Y的过程中究竟起到了多大的作用。

根据上面的EK的解释可以知道,我们的目的就是找到一个合适的dk来最大化减小EK

为了得到dk就需要对E进行SVD(奇异值分解),Ek=UΔVT令矩阵U的第一列作为字典第K列更新后的dk,同时令Δ(1,1)乘以V的第一列作为更新后的稀疏系数。


下面是一个简单的利用KSVD和OMP算法的演示代码

代码流程:

Step1:读入的一张lena图片img

Step2: 随机生成一个测量矩阵phi

Step3:y=phi*img得到观测值

Step4:利用[Dictionary,]=KSVD[img,para]得到dictionary

Step5:利用A=OMP[phi*Dictionary,y,L]得到稀疏系数矩阵

Step6:img_rec=Dictionary*A得到重建的图像。


Demo_Code_1.m

[plain] view plain copy
  1. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
  2. % the K-SVD basis is selected as the sparse representation dictionary  
  3. % the OMP  algorithm is used to recover the image  
  4. % Author: zhang ben, ncuzhangben@qq.com  
  5. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
  6. %***************************** read in the image **************************  
  7. img=imread('lena.bmp');     % read in the image "lena.bmp"  
  8. img=double(img);  
  9. [N,n]=size(img);   
  10. img0 = img;  % keep an original copy of the input signal  
  11. %****************form the measurement matrix and Dictionary ***************  
  12. %form the measurement matrix Phi  
  13. Phi=randn(N,n);     
  14. Phi = Phi./repmat(sqrt(sum(Phi.^2,1)),[N,1]); % normalize each column  
  15. %fix the parameters  
  16. param.L =20;   % number of elements in each linear combination.  
  17. param.K =150; %number of dictionary elements  
  18. param.numIteration = 50; % number of iteration to execute the K-SVD algorithm.  
  19. param.errorFlag = 0; % decompose signals until a certain error is reached.   
  20.                      %do not use fix number of coefficients.   
  21. %param.errorGoal = sigma;  
  22. param.preserveDCAtom = 0;  
  23. param.InitializationMethod ='DataElements';%initialization by the signals themselves  
  24. param.displayProgress = 1; % progress information is displyed.  
  25. [Dictionary,output]= KSVD(img,param);%Dictionary is N*param.K   
  26. %************************ projection **************************************  
  27. y=Phi*img;          % treat each column as a independent signal  
  28. y0=y;  % keep an original copy of the measurements  
  29. %********************* recover using OMP *********************************  
  30. D=Phi*Dictionary;  
  31. A=OMP(D,y,20);  
  32. imgr=Dictionary*A;    
  33. %***********************  show the results  ********************************   
  34. figure(1)  
  35. subplot(2,2,1),imagesc(img0),title('original image')  
  36. subplot(2,2,2),imagesc(y0),title('measurement image')  
  37. subplot(2,2,3),imagesc(Dictionary),title('Dictionary')  
  38. psnr=20*log10(255/sqrt(mean((img(:)-imgr(:)).^2)));  
  39. subplot(2,2,4),imagesc(imgr),title(strcat('recover image (',num2str(psnr),'dB)'))  
  40. disp('over')  

OMP.m(这是网友写好的代码)

[plain] view plain copy
  1. function [A]=OMP(D,X,L);   
  2. %=============================================  
  3. % Sparse coding of a group of signals based on a given   
  4. % dictionary and specified number of atoms to use.   
  5. % input arguments:   
  6. %       D - the dictionary (its columns MUST be normalized).  
  7. %       X - the signals to represent  
  8. %       L - the max. number of coefficients for each signal.  
  9. % output arguments:   
  10. %       A - sparse coefficient matrix.  
  11. %=============================================  
  12. [n,K]=size(D);  
  13. [n,P]=size(X);  
  14. for k=1:1:P,  
  15.     a=[];  
  16.     x=X(:,k);%令向量x等于矩阵X的第K列的元素长度为n*1  
  17.     residual=x;%n*1  
  18.     indx=zeros(L,1);%L*1的0矩阵  
  19.     for j=1:1:L,  
  20.         proj=D'*residual;%K*n n*1 变成K*1  
  21.         [maxVal,pos]=max(abs(proj));%  最大投影系数对应的位置  
  22.         pos=pos(1);  
  23.         indx(j)=pos;   
  24.         a=pinv(D(:,indx(1:j)))*x;  
  25.         residual=x-D(:,indx(1:j))*a;  
  26.         if sum(residual.^2) < 1e-6  
  27.             break;  
  28.         end  
  29.     end;  
  30.     temp=zeros(K,1);  
  31.     temp(indx(1:j))=a;  
  32.     A(:,k)=sparse(temp);%A为返回为K*P的矩阵  
  33. end;  
  34. return;  

KSVD算法实现代码:

[plain] view plain copy
  1. function [Dictionary,output] = KSVD(...  
  2.     Data,... % an nXN matrix that contins N signals (Y), each of dimension n.  
  3.     param)  
  4. % =========================================================================  
  5. %                          K-SVD algorithm  
  6. % =========================================================================  
  7. % The K-SVD algorithm finds a dictionary for linear representation of  
  8. % signals. Given a set of signals, it searches for the best dictionary that  
  9. % can sparsely represent each signal. Detailed discussion on the algorithm  
  10. % and possible applications can be found in "The K-SVD: An Algorithm for   
  11. % Designing of Overcomplete Dictionaries for Sparse Representation", written  
  12. % by M. Aharon, M. Elad, and A.M. Bruckstein and appeared in the IEEE Trans.   
  13. % On Signal Processing, Vol. 54, no. 11, pp. 4311-4322, November 2006.   
  14. % =========================================================================  
  15. % INPUT ARGUMENTS:  
  16. % Data                         an nXN matrix that contins N signals (Y), each of dimension n.   
  17. % param                        structure that includes all required  
  18. %                                 parameters for the K-SVD execution.  
  19. %                                 Required fields are:  
  20. %    K, ...                    the number of dictionary elements to train  
  21. %    numIteration,...          number of iterations to perform.  
  22. %    errorFlag...              if =0, a fix number of coefficients is  
  23. %                                 used for representation of each signal. If so, param.L must be  
  24. %                                 specified as the number of representing atom. if =1, arbitrary number  
  25. %                                 of atoms represent each signal, until a specific representation error  
  26. %                                 is reached. If so, param.errorGoal must be specified as the allowed  
  27. %                                 error.  
  28. %    preserveDCAtom...         if =1 then the first atom in the dictionary  
  29. %                                 is set to be constant, and does not ever change. This  
  30. %                                 might be useful for working with natural  
  31. %                                 images (in this case, only param.K-1  
  32. %                                 atoms are trained).  
  33. %    (optional, see errorFlag) L,...                 % maximum coefficients to use in OMP coefficient calculations.  
  34. %    (optional, see errorFlag) errorGoal, ...        % allowed representation error in representing each signal.  
  35. %    InitializationMethod,...  mehtod to initialize the dictionary, can  
  36. %                                 be one of the following arguments:   
  37. %                                 * 'DataElements' (initialization by the signals themselves), or:   
  38. %                                 * 'GivenMatrix' (initialization by a given matrix param.initialDictionary).  
  39. %    (optional, see InitializationMethod) initialDictionary,...      % if the initialization method   
  40. %                                 is 'GivenMatrix', this is the matrix that will be used.  
  41. %    (optional) TrueDictionary, ...        % if specified, in each  
  42. %                                 iteration the difference between this dictionary and the trained one  
  43. %                                 is measured and displayed.  
  44. %    displayProgress, ...      if =1 progress information is displyed. If param.errorFlag==0,   
  45. %                                 the average repersentation error (RMSE) is displayed, while if   
  46. %                                 param.errorFlag==1, the average number of required coefficients for   
  47. %                                 representation of each signal is displayed.  
  48. % =========================================================================  
  49. % OUTPUT ARGUMENTS:  
  50. %  Dictionary                  The extracted dictionary of size nX(param.K).  
  51. %  output                      Struct that contains information about the current run. It may include the following fields:  
  52. %    CoefMatrix                  The final coefficients matrix (it should hold that Data equals approximately Dictionary*output.CoefMatrix.  
  53. %    ratio                       If the true dictionary was defined (in  
  54. %                                synthetic experiments), this parameter holds a vector of length  
  55. %                                param.numIteration that includes the detection ratios in each  
  56. %                                iteration).  
  57. %    totalerr                    The total representation error after each  
  58. %                                iteration (defined only if  
  59. %                                param.displayProgress=1 and  
  60. %                                param.errorFlag = 0)  
  61. %    numCoef                     A vector of length param.numIteration that  
  62. %                                include the average number of coefficients required for representation  
  63. %                                of each signal (in each iteration) (defined only if  
  64. %                                param.displayProgress=1 and  
  65. %                                param.errorFlag = 1)  
  66. % =========================================================================  
  67.   
  68. if (~isfield(param,'displayProgress'))  
  69.     param.displayProgress = 0;  
  70. end  
  71. totalerr(1) = 99999;  
  72. if (isfield(param,'errorFlag')==0)  
  73.     param.errorFlag = 0;  
  74. end  
  75.   
  76. if (isfield(param,'TrueDictionary'))  
  77.     displayErrorWithTrueDictionary = 1;  
  78.     ErrorBetweenDictionaries = zeros(param.numIteration+1,1); %产生零矩阵  
  79.     ratio = zeros(param.numIteration+1,1);  
  80. else  
  81.     displayErrorWithTrueDictionary = 0;  
  82.     ratio = 0;  
  83. end  
  84. if (param.preserveDCAtom>0)  
  85.     FixedDictionaryElement(1:size(Data,1),1) = 1/sqrt(size(Data,1));  
  86. else  
  87.     FixedDictionaryElement = [];  
  88. end  
  89. % coefficient calculation method is OMP with fixed number of coefficients  
  90.   
  91. if (size(Data,2) < param.K)  
  92.     disp('Size of data is smaller than the dictionary size. Trivial solution...');  
  93.     Dictionary = Data(:,1:size(Data,2));  
  94.     return;  
  95. elseif (strcmp(param.InitializationMethod,'DataElements'))  
  96.     Dictionary(:,1:param.K-param.preserveDCAtom) = Data(:,1:param.K-param.preserveDCAtom);  
  97. elseif (strcmp(param.InitializationMethod,'GivenMatrix'))  
  98.     Dictionary(:,1:param.K-param.preserveDCAtom) = param.initialDictionary(:,1:param.K-param.preserveDCAtom);  
  99. end  
  100. % reduce the components in Dictionary that are spanned by the fixed  
  101. % elements  
  102. if (param.preserveDCAtom)  
  103.     tmpMat = FixedDictionaryElement \ Dictionary;  
  104.     Dictionary = Dictionary - FixedDictionaryElement*tmpMat;  
  105. end  
  106. %normalize the dictionary.  
  107. Dictionary = Dictionary*diag(1./sqrt(sum(Dictionary.*Dictionary)));  
  108. Dictionary = Dictionary.*repmat(sign(Dictionary(1,:)),size(Dictionary,1),1); % multiply in the sign of the first element.  
  109. totalErr = zeros(1,param.numIteration);  
  110.   
  111. % the K-SVD algorithm starts here.  
  112.   
  113. for iterNum = 1:param.numIteration  
  114.     % find the coefficients  
  115.     if (param.errorFlag==0)  
  116.         %CoefMatrix = mexOMPIterative2(Data, [FixedDictionaryElement,Dictionary],param.L);  
  117.         CoefMatrix = OMP([FixedDictionaryElement,Dictionary],Data, param.L);  
  118.     else   
  119.         %CoefMatrix = mexOMPerrIterative(Data, [FixedDictionaryElement,Dictionary],param.errorGoal);  
  120.         CoefMatrix = OMPerr([FixedDictionaryElement,Dictionary],Data, param.errorGoal);  
  121.         param.L = 1;  
  122.     end  
  123.       
  124.     replacedVectorCounter = 0;  
  125.     rPerm = randperm(size(Dictionary,2));  
  126.     for j = rPerm  
  127.         [betterDictionaryElement,CoefMatrix,addedNewVector] = I_findBetterDictionaryElement(Data,...  
  128.             [FixedDictionaryElement,Dictionary],j+size(FixedDictionaryElement,2),...  
  129.             CoefMatrix ,param.L);  
  130.         Dictionary(:,j) = betterDictionaryElement;  
  131.         if (param.preserveDCAtom)  
  132.             tmpCoef = FixedDictionaryElement\betterDictionaryElement;  
  133.             Dictionary(:,j) = betterDictionaryElement - FixedDictionaryElement*tmpCoef;  
  134.             Dictionary(:,j) = Dictionary(:,j)./sqrt(Dictionary(:,j)'*Dictionary(:,j));  
  135.         end  
  136.         replacedVectorCounter = replacedVectorCounter+addedNewVector;  
  137.     end  
  138.   
  139.     if (iterNum>1 & param.displayProgress)  
  140.         if (param.errorFlag==0)  
  141.             output.totalerr(iterNum-1) = sqrt(sum(sum((Data-[FixedDictionaryElement,Dictionary]*CoefMatrix).^2))/prod(size(Data)));  
  142.             disp(['Iteration   ',num2str(iterNum),'   Total error is: ',num2str(output.totalerr(iterNum-1))]);  
  143.         else  
  144.             output.numCoef(iterNum-1) = length(find(CoefMatrix))/size(Data,2);  
  145.             disp(['Iteration   ',num2str(iterNum),'   Average number of coefficients: ',num2str(output.numCoef(iterNum-1))]);  
  146.         end  
  147.     end  
  148.     if (displayErrorWithTrueDictionary )   
  149.         [ratio(iterNum+1),ErrorBetweenDictionaries(iterNum+1)] = I_findDistanseBetweenDictionaries(param.TrueDictionary,Dictionary);  
  150.         disp(strcat(['Iteration  ', num2str(iterNum),' ratio of restored elements: ',num2str(ratio(iterNum+1))]));  
  151.         output.ratio = ratio;  
  152.     end  
  153.     Dictionary = I_clearDictionary(Dictionary,CoefMatrix(size(FixedDictionaryElement,2)+1:end,:),Data);  
  154.       
  155.     if (isfield(param,'waitBarHandle'))  
  156.         waitbar(iterNum/param.counterForWaitBar);  
  157.     end  
  158. end  
  159.   
  160. output.CoefMatrix = CoefMatrix;  
  161. Dictionary = [FixedDictionaryElement,Dictionary];  
  162. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
  163. %  findBetterDictionaryElement  
  164. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
  165.   
  166. function [betterDictionaryElement,CoefMatrix,NewVectorAdded] = I_findBetterDictionaryElement(Data,Dictionary,j,CoefMatrix,numCoefUsed)  
  167. if (length(who('numCoefUsed'))==0)  
  168.     numCoefUsed = 1;  
  169. end  
  170. relevantDataIndices = find(CoefMatrix(j,:)); % the data indices that uses the j'th dictionary element.  
  171. if (length(relevantDataIndices)<1) %(length(relevantDataIndices)==0)  
  172.     ErrorMat = Data-Dictionary*CoefMatrix;  
  173.     ErrorNormVec = sum(ErrorMat.^2);  
  174.     [d,i] = max(ErrorNormVec);  
  175.     betterDictionaryElement = Data(:,i);%ErrorMat(:,i); %  
  176.     betterDictionaryElement = betterDictionaryElement./sqrt(betterDictionaryElement'*betterDictionaryElement);  
  177.     betterDictionaryElement = betterDictionaryElement.*sign(betterDictionaryElement(1));  
  178.     CoefMatrix(j,:) = 0;  
  179.     NewVectorAdded = 1;  
  180.     return;  
  181. end  
  182.   
  183. NewVectorAdded = 0;  
  184. tmpCoefMatrix = CoefMatrix(:,relevantDataIndices);   
  185. tmpCoefMatrix(j,:) = 0;% the coeffitients of the element we now improve are not relevant.  
  186. errors =(Data(:,relevantDataIndices) - Dictionary*tmpCoefMatrix); % vector of errors that we want to minimize with the new element  
  187. % % the better dictionary element and the values of beta are found using svd.  
  188. % % This is because we would like to minimize || errors - beta*element ||_F^2.   
  189. % % that is, to approximate the matrix 'errors' with a one-rank matrix. This  
  190. % % is done using the largest singular value.  
  191. [betterDictionaryElement,singularValue,betaVector] = svds(errors,1);  
  192. CoefMatrix(j,relevantDataIndices) = singularValue*betaVector';% *signOfFirstElem  
  193.   
  194. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
  195. %  findDistanseBetweenDictionaries  
  196. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
  197. function [ratio,totalDistances] = I_findDistanseBetweenDictionaries(original,new)  
  198. % first, all the column in oiginal starts with positive values.  
  199. catchCounter = 0;  
  200. totalDistances = 0;  
  201. for i = 1:size(new,2)  
  202.     new(:,i) = sign(new(1,i))*new(:,i);  
  203. end  
  204. for i = 1:size(original,2)  
  205.     d = sign(original(1,i))*original(:,i);  
  206.     distances =sum ( (new-repmat(d,1,size(new,2))).^2);  
  207.     [minValue,index] = min(distances);  
  208.     errorOfElement = 1-abs(new(:,index)'*d);  
  209.     totalDistances = totalDistances+errorOfElement;  
  210.     catchCounter = catchCounter+(errorOfElement<0.01);  
  211. end  
  212. ratio = 100*catchCounter/size(original,2);  
  213.   
  214. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
  215. %  I_clearDictionary  
  216. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
  217. function Dictionary = I_clearDictionary(Dictionary,CoefMatrix,Data)  
  218. T2 = 0.99;  
  219. T1 = 3;  
  220. K=size(Dictionary,2);  
  221. Er=sum((Data-Dictionary*CoefMatrix).^2,1); % remove identical atoms  
  222. G=Dictionary'*Dictionary; G = G-diag(diag(G));  
  223. for jj=1:1:K,  
  224.     if max(G(jj,:))>T2 | length(find(abs(CoefMatrix(jj,:))>1e-7))<=T1 ,  
  225.         [val,pos]=max(Er);  
  226.         Er(pos(1))=0;  
  227.         Dictionary(:,jj)=Data(:,pos(1))/norm(Data(:,pos(1)));  
  228.         G=Dictionary'*Dictionary; G = G-diag(diag(G));  
  229.     end;  
  230. end;  
这是运行代码之后的结果:
原创粉丝点击