Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
comik/computeConformedMultiInstanceKernel.m
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
262 lines (244 sloc)
10.9 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function [conformedMultiInstanceKernel, rawConformedMultiInstanceKernel, instancesTransformationKernel, clusterCentres] = computeConformedMultiInstanceKernel(instanceStarts, instanceEnds, instanceWideKernel, trainIndices, allSeqsAsBags, nClusters, sig, Y, computationVersion, debugLevel, debugMsgLocation) | |
% COMPUTECONFORMEDMULTIINSTANCEKERNEL | |
% Computes the conformally transformed multi-instance kernel | |
% INPUT PARAMS | |
% Param 'instanceStarts' (vector) | |
% Indices where instances (segments) of any sequence begin | |
% | |
% Param 'instanceEnds' (vector) | |
% Indices where instances (segments) of any sequence end | |
% | |
% Param 'instanceWideKernel' (matrix) | |
% The instance-wide kernel matrix of dimension #Instances x #Instances | |
% | |
% Param 'trainIndices' (vector) | |
% Indices of the training sequences | |
% | |
% Param 'allSeqsAsBags' (cell array) | |
% Collection of all segments per sequence | |
% | |
% Param 'nClusters' | |
% number of clusters for k-means | |
% | |
% Param 'sig' | |
% Gaussian bandwidth (sigma) value for the Gaussian transformation | |
% | |
% Param 'Y' (vector) | |
% Vector of labels | |
% | |
% Param 'computationVersion' ('AccumArray'/'Looping') | |
% Flag specifying what approach to use for computing the kernel | |
% | |
% Param 'debugLevel' (0/1/2) | |
% | |
% Param 'debugMsgLocation' (1/fileID) | |
% | |
% | |
% OUTPUT PARAMS | |
% Param 'conformedMultiInstanceKernel' (matrix) | |
% Normalized conformally transformed MI kernel | |
% | |
% Param 'rawConformedMultiInstanceKernel' (matrix) | |
% Unnormalized conformally transformed MI kernel | |
% | |
% Param 'instancesTransformationKernel' (matrix) | |
% Transformation of the training instances | |
% | |
% Param 'clusterCentres' (matrix) | |
% Cluster centres obtained upon k-means | |
% | |
% ADDITIONAL NOTES | |
% -- Stratification | |
% . If stratification is required, see below, set stratified = 1 | |
% -- Replicates for k-means | |
% . currently set to 1 | |
% . can be increased | |
% | |
% Author: snikumbh@mpi-inf.mpg.de | |
% 1.1 Obtain expansion points | |
% | |
% -- Convert allSeqsAsBags in to a matrix X of dimensions nInstances x FVlength | |
% | |
% -- spread out the instances, get the nInstances | |
% -- trainIndices are trainingIndices | |
% Edit: We earlier expected trainIndices to be a row vector. Now it can be either | |
% a row or a column vector. | |
if nargin < 10 | |
% default | |
computationVersion = 'Looping'; | |
end | |
nBags = length(allSeqsAsBags); | |
% nBags, only as many bags as training examples | |
idxInstances = zeros(1,nBags); | |
stratified = 0; | |
% The following two lines also used for stratified representation. | |
if stratified | |
posInd = size(find(Y > 0),2); | |
negInd = size(find(Y < 0),2); | |
end | |
if strcmp(computationVersion, 'AccumArray') | |
instanceIDVector = zeros(1,instanceEnds(end)); | |
end | |
% Maintain a count of the instances arising from training indices/bags | |
% This is used later to define the number of rows for XtoPassFrom | |
currentTotal = 0; | |
for i=1:nBags | |
% #instances at each index/bag | |
idxInstances(i) = size(allSeqsAsBags{i}, 2); | |
if strcmp(computationVersion, 'AccumArray') | |
instanceIDVector(instanceStarts(i):instanceEnds(i)) = repmat(i, [1 size(allSeqsAsBags{i}, 2)]); | |
end | |
% The following is useful to have stratified repressentation, | |
% we don't need this now. | |
if stratified | |
if i <= posInd | |
nInstancesPos = nInstancesPos + size(allSeqsAsBags{i}, 2); | |
end | |
end | |
if any(i==trainIndices) == 1 %check, if a trainingIndex, get instances | |
currentTotal = currentTotal+idxInstances(i); | |
end | |
% useful to count instances only in training bags | |
end | |
forIndicesInX = cumsum(idxInstances); | |
nInstances = sum(idxInstances); | |
if strcmp(computationVersion, 'AccumArray') | |
assert(size(instanceIDVector,2) == nInstances); | |
end | |
logMessages(debugMsgLocation, sprintf('\n--- currentTotal for setting a zeros XtoPassFrom: %d\n', currentTotal), debugLevel); | |
XtoPassFrom = zeros( currentTotal, size(allSeqsAsBags{1},1) ); | |
% Make sure that only instances from training bags are taken | |
% trainIndices store the right set of indices as passed to it | |
currentTotal = 0; | |
for i=1:length(trainIndices)%indices of relevant bags/ training bags | |
XtoPassFrom( currentTotal+1 : currentTotal + idxInstances(trainIndices(i)) , : ) = transpose(allSeqsAsBags{ trainIndices(i) }); | |
currentTotal = currentTotal + idxInstances( trainIndices(i) ); | |
end | |
logMessages(debugMsgLocation, sprintf('--- allSeqsAsBags is now n x p matrix, ready for kmeans\n'), debugLevel); | |
% | |
% 1.2. Apply kmeans | |
% -- we are using Matlab's algorithm for kmeans. | |
% -- using the buckshot hueristic means: | |
% - randomly sample sqrt(nClusters * nInstances) | |
% data points from nInstances | |
% - this will give nClusters | |
% If sending complete XtoPassFrom for k-means clustering set XtoPass = XtoPassFrom; | |
% Replicates | |
nofRep = 1; | |
% Randomly sample without replacement | |
% XtoPassFrom contains only the relevant instances, hence freely select any instances from it | |
nSampled = round(sqrt(nClusters * currentTotal)); | |
logMessages(debugMsgLocation, sprintf('--- for kmeans, Total: %d, nSampled: %d, nClusters: %d\n', currentTotal, nSampled, nClusters), debugLevel); | |
XtoPass = XtoPassFrom( transpose(randsample( currentTotal, round(sqrt(nClusters * currentTotal)) )), :); | |
%% Without the buckshot heuristic, use | |
% XtoPass = XtoPassFram | |
clear('XtoPassFrom'); | |
[clusterCentres, matrixOfDistancesFromCentresForPassedVectors] = getExpansionPoints(XtoPass, nClusters, nofRep, debugLevel, debugMsgLocation); | |
clear('XtoPass'); | |
% clusterCentres is a k-by-p matrix | |
% matrixOfDistancesFromCentresForPassedVectors is n-by-k matrix | |
% | |
% 2. As many kernels as expansion points | |
% | |
% Use the fact that only comparisons with the clusterCentre | |
% are to be computed anew. Other values can be fetched from the instance-wide kernel. | |
% transformationKernel stores all products of the instances with the cluster centers | |
% transformationKernel is Gaussian RBF | |
tic; | |
logMessages(debugMsgLocation, sprintf('--- applying transformation...'), debugLevel); | |
[instancesTransformationKernel] = applyTransformation(allSeqsAsBags, clusterCentres, sig, debugLevel, debugMsgLocation); | |
logMessages(debugMsgLocation, sprintf('done in %.3f seconds\n', toc), debugLevel); | |
% instancesTransformationKernel is cell array for number of bags | |
% instancesTransformationKernel{eachBag} is nInstanceInBag-by-nClusters | |
% Initialize kernels | |
for i=1:nClusters | |
conformedMultiInstanceKernel{i} = zeros(nBags); | |
rawConformedMultiInstanceKernel{i} = zeros(nBags); | |
end | |
logMessages(debugMsgLocation, sprintf('--- computing the conformedKernel...'), debugLevel); | |
if strcmp(computationVersion, 'AccumArray') | |
logMessages(debugMsgLocation, sprintf('\nAccumarray version---\n'), debugLevel);tic; | |
instanceSubs = combvec(instanceIDVector, instanceIDVector)'; | |
% instanceSubs = tempInstanceSubs(tempInstanceSubs(:,1) <= tempInstanceSubs(:,2),:); | |
% instanceSubs are only the upper-triangular indices including the diagonal | |
% clear('tempInstanceSubs'); | |
instanceWideKernelRepeated = repmat(instanceWideKernel, 1, 1, nClusters); | |
allInstancesTransformations = cat(1,instancesTransformationKernel{:}); | |
for i=1:nClusters | |
KernelAsVector = (allInstancesTransformations(:,i) * allInstancesTransformations(:,i)') .* instanceWideKernelRepeated(:,:,i); | |
tempKernel = accumarray(instanceSubs, KernelAsVector(:)); | |
assert(size(tempKernel,1) == size(zeros(nBags),1)); | |
% tempKernel = triu(tempKernel, 1) + tempKernel'; %because instanceSubs stored indices for only the upper-triangular part of the matrix | |
conformedMultiInstanceKernel{i} = normalizeKernel(tempKernel); | |
end | |
clear('instanceWideKernelRepeated'); | |
clear('instanceIDVector'); | |
clear('instanceSubs'); | |
clear('allInstancesTransformations'); | |
logMessages(debugMsgLocation, sprintf('done in %.3f seconds', toc), debugLevel); | |
end | |
if strcmp(computationVersion, 'Looping') | |
% One can convert the transformationKernels into 3D matrices | |
logMessages(debugMsgLocation, sprintf('\n--- Looping-over-bags version...'), debugLevel); | |
% Performing the reshaped version | |
if issparse(allSeqsAsBags{1}) | |
logMessages(debugMsgLocation, sprintf('Doing the reshaped version..\n'), debugLevel); | |
% Pre-allocate memory, doesn't help in speed | |
% for i=1:nClusters | |
% rawConformedMultiInstanceKernel{i} = zeros(nBags); | |
% conformedMultiInstanceKernel{i} = zeros(nBags); | |
% end | |
tic; | |
tempKernelCollection = zeros(nBags, nBags, nClusters); | |
for b1=1:nBags | |
b1r = reshape(instancesTransformationKernel{b1}, idxInstances(b1) , [], nClusters); | |
for b2=b1:nBags | |
b2r = reshape(instancesTransformationKernel{b2}, idxInstances(b2) , [], nClusters); | |
b2rt = permute(b2r,[2,1,3]); | |
b1b2_transformationProducts = bsxfun(@times, b1r , b2rt); | |
tempToBeSummed = bsxfun(@times, b1b2_transformationProducts, instanceWideKernel(instanceStarts(b1):instanceEnds(b1), instanceStarts(b2):instanceEnds(b2)) ); | |
term = 1/(idxInstances(b1) * idxInstances(b2)); | |
tempKernelCollection(b1, b2, :) = sum(sum(tempToBeSummed,1)); | |
end | |
end | |
logMessages(debugMsgLocation, sprintf('Bag-wise kernel done in %.3f seconds\n', toc), debugLevel); | |
tic; | |
for i=1:nClusters | |
tempKernel = zeros(nBags); | |
tempKernel = triu(tempKernelCollection(:,:,i), 1) + tempKernelCollection(:,:,i)'; | |
rawConformedMultiInstanceKernel{i} = tempKernel; | |
conformedMultiInstanceKernel{i} = normalizeKernel(tempKernel); | |
end | |
logMessages(debugMsgLocation, sprintf('done in %.3f seconds\n', toc), debugLevel); | |
else % when not sparse | |
% not tested either for correctness or efficiency. We recommend only using sparse vectors, thus the approach above. | |
tic; | |
for i=1:size(clusterCentres,1) | |
tempKernel = zeros(nBags); | |
for b1=1:nBags | |
tempb1 = instancesTransformationKernel{b1}(:,i); | |
for b2=b1:nBags | |
tempKernel(b1,b2) = sum(sum((tempb1 * instancesTransformationKernel{b2}(:, i)') .* instanceWideKernel(instanceStarts(b1):instanceEnds(b1), instanceStarts(b2):instanceEnds(b2)) )); | |
end | |
end | |
tempKernel = triu(tempKernel, 1) + tempKernel'; | |
rawConformedMultiInstanceKernel{i} = tempKernel; | |
conformedMultiInstanceKernel{i} = normalizeKernel(tempKernel); | |
end | |
logMessages(debugMsgLocation, sprintf('done in %.3f seconds\n', toc)); | |
end | |
end | |
%%%%% | |
% check psd | |
for i=1:size(clusterCentres,1) | |
[~,p] = chol(conformedMultiInstanceKernel{i}); | |
if p==0 | |
else | |
logMessages(debugMsgLocation,sprintf('cluster %d Cholesky p: %.4f\n', i, p), debugLevel); | |
% p~=0 means there is an eigen value < 0 | |
% print the min(eigen values) in the log | |
logMessages(debugMsgLocation, sprintf('%e,', min(eig(conformedMultiInstanceKernel{i}))), debugLevel); | |
logMessages(debugMsgLocation, sprintf('Check kernel w.r.t. clusterCentre %d out of %d, may be not psd!\n', i, size(clusterCentres, 1)), debugLevel); | |
end | |
end | |
end % function ends | |