本次学习的是来自cvpr2015的《Person Re-identification by Local Maximal Occurrence Representation and Metric Learning》。
项目主页:http://www.cbsr.ia.ac.cn/users/scliao/projects/lomo_xqda/
QDA分类器也是假设每一类观测都服从一个高斯分布,把参数估计带入贝叶斯定理进行预测;
不同的是:每一类观测的协方差可以不同。
根据贝叶斯理论:
主要思想是将一副人脸看做两部分构成,一部分是人与人之间的差异,另一部分是个体自身的差异,比如表情变动。
然后我们假设这两部分分别服从高斯分布。人脸识别之联合贝叶斯注意到分布是零均值,所以在你所获得的人脸特征,一定要做零均值处理。
交叉视角的二次判别分析法 (XQDA)是在保持直接简单原则的度量 (KISSME)和贝叶斯人脸方法基础上提出的。该方法用高斯模型分别拟合类内和类间样本特征的差值分布。根据两个高斯分布的对数似然比推导出马氏距离。
上述两式取根号相除,得到对数似然比为:
则两个样本之间的距离为:
定义子空间w,则投影到子空间后的样本距离变为:
因此为了将样本分开,类间方差小,类外方差大,因此得到下面的优化公式:
等价于:
和LDA方法中的广义特征值分解相似,解为:
function [W, M, inCov, exCov] = XQDA(galX, probX, galLabels, probLabels, options)
%% function [W, M, inCov, exCov] = XQDA(galX, probX, galLabels, probLabels, options)
% Cross-view Quadratic Discriminant Analysis for subspace and metric
% learning
%
% Input:
% : features of gallery samples. Size: [n, d]
% : features of probe samples. Size: [m, d]
% : class labels of the gallery samples
% : class labels of the probe samples
% [options]: optional parameters. A structure containing any of the
% following fields:
% lambda: the regularizer. Default: 0.001
% qdaDims: the number of dimensions to be preserved in the learned
% subspace. Negative values indicate automatic dimension selection by
% perserving latent values larger than 1. Default: -1.
% verbose: whether to print the learning details. Default: false
%
% Output:
% W: the subspace projection matrix. Size: [d, r], where r is the
% subspace dimension.
% M: the learned metric kernel. Size: [r,r]
% inCov: covariance matrix of the intra-personal difference class. Size:
% [r,r]
% exCov: covriance matrix of the extra-personal difference class. Size:
% [r,r]
%
% With W, inCov, and exCov, we can quickly learn another metric of different dimensions:
% W2 = W(:, 1:r2);
% M2 = inv(inCov(1:r2, 1:r2)) - inv(exCov(1:r2, 1:r2));
%
% Example:
% Please see Demo_XQDA.m.
%
% Reference:
% Shengcai Liao, Yang Hu, Xiangyu Zhu, and Stan Z. Li. Person
% re-identification by local maximal occurrence representation and metric
% learning. In IEEE Conference on Computer Vision and Pattern Recognition, 2015.
%
% Version: 1.0
% Date: 2015-04-30
%
% Author: Shengcai Liao
% Institute: National Laboratory of Pattern Recognition,
% Institute of Automation, Chinese Academy of Sciences
% Email: [email protected]
lambda = 0.001;
qdaDims = -1;
verbose = false;
if nargin >= 5 && ~isempty(options)
if isfield(options,'lambda') && ~isempty(options.lambda) && isscalar(options.lambda) && isnumeric(options.lambda)
lambda = options.lambda;
end
if isfield(options,'qdaDims') && ~isempty(options.qdaDims) && isscalar(options.qdaDims) && isnumeric(options.qdaDims) && options.qdaDims > 0
qdaDims = options.qdaDims;
end
if isfield(options,'verbose') && ~isempty(options.verbose) && isscalar(options.verbose) && islogical(options.verbose)
verbose = options.verbose;
end
end
if verbose == true
fprintf('options.lambda = %g.\n', lambda);
fprintf('options.qdaDims = %d.\n', qdaDims);
fprintf('options.verbose = %d.\n', verbose);
end
[numGals, d] = size(galX); % n
numProbs = size(probX, 1); % m
% If d > numGals + numProbs, it is not necessary to apply XQDA on the high dimensional space.
% In this case we can apply XQDA on QR decomposed space, achieving the same performance but much faster.
if d > numGals + numProbs
if verbose == true
fprintf('\nStart to apply QR decomposition.\n');
end
t0 = tic;
[W, X] = qr([galX', probX'], 0); % [d, n]
galX = X(:, 1:numGals)';
probX = X(:, numGals+1:end)';
d = size(X,1);
clear X;
if verbose == true
fprintf('QR decomposition time: %.3g seconds.\n', toc(t0));
end
end
labels = unique([galLabels; probLabels]); %所有label
c = length(labels); %label个数
if verbose == true
fprintf('#Classes: %d\n', c);
fprintf('Compute intra/extra-class covariance matrix...');
end
t0 = tic;
galW = zeros(numGals, 1);
galClassSum = zeros(c, d);
probW = zeros(numProbs, 1);
probClassSum = zeros(c, d);
ni = 0;
%这一段对应论文实际中怎么求协方差矩阵的部分
for k = 1 : c
galIndex = find(galLabels == labels(k));%找到和第k个label相同的所有gallery
nk = length(galIndex);
galClassSum(k, :) = sum( galX(galIndex, :), 1 );
probIndex = find(probLabels == labels(k));
mk = length(probIndex);
probClassSum(k, :) = sum( probX(probIndex, :), 1 );
ni = ni + nk * mk;
galW(galIndex) = sqrt(mk);
probW(probIndex) = sqrt(nk);
end
galSum = sum(galClassSum, 1);
probSum = sum(probClassSum, 1);
galCov = galX' * galX;
probCov = probX' * probX;
galX = bsxfun( @times, galW, galX );
probX = bsxfun( @times, probW, probX );
inCov = galX' * galX + probX' * probX - galClassSum' * probClassSum - probClassSum' * galClassSum;
exCov = numProbs * galCov + numGals * probCov - galSum' * probSum - probSum' * galSum - inCov;
ne = numGals * numProbs - ni;
inCov = inCov / ni;
exCov = exCov / ne;
inCov = inCov + lambda * eye(d);
if verbose == true
fprintf(' %.3g seconds.\n', toc(t0));
fprintf('#Intra: %d, #Extra: %d\n', ni, ne);
fprintf('Compute eigen vectors...');
end
t0 = tic;
[V, S] = svd(inCov \ exCov);
if verbose == true
fprintf(' %.3g seconds.\n', toc(t0));
end
latent = diag(S);
[latent, index] = sort(latent, 'descend');
energy = sum(latent);
minv = latent(end);
r = sum(latent > 1);
energy = sum(latent(1:r)) / energy;
if qdaDims > r
qdaDims = r;
end
if qdaDims <= 0
qdaDims = max(1,r);
end
if verbose == true
fprintf('Energy remained: %f, max: %f, min: %f, all min: %f, #opt-dim: %d, qda-dim: %d.\n', energy, latent(1), latent(max(1,r)), minv, r, qdaDims);
end
V = V(:, index(1:qdaDims));
if ~exist('W', 'var');
W = V;
else
W = W * V;
end
if verbose == true
fprintf('Compute kernel matrix...');
end
t0 = tic;
inCov = V' * inCov * V;
exCov = V' * exCov * V;
M = inv(inCov) - inv(exCov);
if verbose == true
fprintf(' %.3g seconds.\n\n', toc(t0));
end