这几天看了Locality-constrained Linear Coding for Image Classification算法,里面涉及到coding与pooling过程,在此做一解析:
1)Feature Extract
在代码部分,作者用了Lazebnik's SIFT算法提取 Dense Sift特征
CalculateSiftDescriptor(rt_img_dir, rt_data_dir, gridSpacing, patchSize, maxImSize, nrml_threshold)
其中patchSize为提取Sift特征的patch大小,gridSpacing为patch移动的步长
2)coding
coding过程其实是LLE (Locally Linear Embedding) 局部线性嵌入算法(链接)的前两步
(1)寻找每个样本点的k个近邻点
% find k nearest neighbors % B -M x d codebook, M entries in a d-dim space % X -N x d matrix, N data points in a d-dim space XX = sum(X.*X, 2); BB = sum(B.*B, 2); D = repmat(XX, 1, nbase)-2*X*B'+repmat(BB', nframe, 1); IDX = zeros(nframe, knn); %(1)寻找每个样本点的k个近邻点 for i = 1:nframe, d = D(i,:); [dummy, idx] = sort(d, 'ascend'); IDX(i, :) = idx(1:knn); end
a) 距离方阵
首先注意到这样一个事实|Xi-Xj|^2=|Xi|^2+|Xj|^2-2<Xi, Xj>,其中< , >为内积。XX = sum(X.^2,1)是N行1列的矩阵,第j个元素为X第j行的平方和,也就是|Xj|^2。
repmat是平铺函数,repmat(XX,N,1)得到N×N方阵,每行都是XX,同理repmat(BB',nframe,1)每行都是BB','是转置的意思。X'*X得到N×N方阵,(i,j)位置元素为<Xi, Xj>。因此distance就是我们要的距离方阵的平方。
b) 省去开平凡
因为我们只需要K近邻,而不需要具体的距离值,而开平方是严格单调函数,保序,因此我们可以省去开平方,节省了计算量。
c) 反向索引
sort给矩阵每列排序,并返回置换前后下标的映射关系index:index(i,j)是distance第j列第i小的元素的下标。我们要每列前K小的下标,也就是每个Xi的K近邻。
任意两个点至少做一次内积O(D),共O(N^2)个点对,故复杂度:O(DN^2)
(2)由每个样本点的近邻点计算出该样本点的局部重建权值矩阵
II = eye(knn, knn); Coeff = zeros(nframe, nbase); for i=1:nframe idx = IDX(i,:); z = B(idx,:) - repmat(X(i,:), knn, 1); % shift ith pt to origin C = z*z'; % local covariance C = C + II*beta*trace(C); % regularlization (K>D)或脊回归,矩阵的对角线加上较小的数,防止C为奇异矩阵 w = C\ones(knn,1); w = w/sum(w); % enforce sum(w)=1 Coeff(i,idx) = w'; end
首先,因为对于任意i,Wij=0若j不属于Si,故W只需要存K行N列即可。
其次,易见E(W)极小当且仅当每一求和项极小,因此我们依次计算W的每一列。固定列i,记x=Xi,w=W第i列,ŋj=Xj,极小化|x-
∑{j=1..K}{wjηj}|^2,满足归一化约束∑{ j=1..k }{wj}=1。用矩阵语言描述:记B=( ŋ1-x,…, ηk-x)为D×K矩阵,G=B'B为K×K方阵(讲义中称之为Gram方阵,半正定,在摄动意义下总可以假设它非奇异),e=(1,…,1)'为K维单位列向量,则问题化为——
min |Bw|^2也就是min w'Gw(二次型) s.t. e'w=1
用拉格朗日乘数法求此条件极值:做辅助函数F(w,λ)= w'Gw-λ(e'w -1)
对每个wj求偏导数令为0得Gw=λe,反解出w=G^{-1}λe,代入到归一化约束得
λ=(e'G^{-1}e)^{-1},即最优解w=(e'G^{-1}e)^{-1} G^{-1}e
实际操作时,我们先解线性方程组Gw=e,然后再将解向量w归一化,易见得到的就是上述最优解。
3) pooling
作者采用max-pooliing方法,size(llc_codes)=[nBase,nFrame],每一行对应一个dictionary中的base,max(llc_codes(:, sidxBin), [], 2)取每一行的最大值。