Skip to content
Permalink
a056a1c421
Switch branches/tags

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?
Go to file
 
 
Cannot retrieve contributors at this time
262 lines (244 sloc) 10.9 KB
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