-
Notifications
You must be signed in to change notification settings - Fork 3
/
nrs_classifier.m
184 lines (167 loc) · 7.31 KB
/
nrs_classifier.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
function [assignments prox] = nrs_classifier(Train,Test,Train_labels,lambda,params)
% nrs_classifier(Train,Test,Train_labels,params)
% Use Nearest Regularized Subspace method to classify the provided test samples
% based upon the given training set.
%
% Inputs:
% [REQUIRED]
% * Train -- Training data matrix (d x NTrain)
% * Test -- Testing data matrix (d x NTest)
% * Train_labels -- Class labels of the training dataset (Classes x 1)
% * lambda -- Regularization parameter (scalar)
%
% [OPTIONAL]
% * params.bias -- Allows the user to specify how to calculate
% the biasing factors in the matrix \Gamma. Can take the
% form of a transform matrix (f x d) or function handle.
% > If chosen to be a function handle, the function must
% take two (1 x d) vector inputs and calculate a scalar
% value result.
% (Default: Euclidean distance in feature space)
% * params.bias_precal-- If set to "1", this variable indicates that
% the matrix contained in params.bias holds
% a set of preclaculated weights. This matrix
% should be of dimensionality (NTrain x
% NTest).
% > 1 : params.bias contains precalculated
% biasing coefficients.
% > 0 : params.bias tells how to calculate
% biasing coefficients.
%
% * params.features -- Specify the dimensionality (d) of the
% feature vectors used in Train and Test.
% Specify this parameter if you are unsure
% about the proper orientation of the data
% matrices.
% * params.ranking -- Specifies a
% function handle which takes two inputs, a
% class approximation and a test sample (both dx1),
% and outputs a scalar value which denotes the
% proximity of the class approximation to the
% test sample.
% (Default: Squared Euclidean Distance)
% * params.ranking_dir-- Specifies which direction the ranking of class
% approximations should be done in.
% > -1 : Minimization
% > 1 : Maximization
% (Default: Minimizatoin)
% * params.partition_mode -- String specifying what kind of partitioning to
% use, pre-partitioning (as in NRS paper)
% or post-partitioning (ala CRC/SRC).
% > "pre" : Pre-partitioning
% > "post" : Post-partitioning
% (Default: Pre-partitioning)
% Outputs:
% * assignments -- Class labels assigned to each of the test samples (Ntest x 1)
%
addpath('./subroutines');
[features NTrain] = size(Train);
[features2 NTest] = size(Test);
NClasses = length(Train_labels);
%% Check passed parameters
if isfield(params,'features')
if NTrain == params.features && features ~= params.features
% Training set rotated incorrectly
Train = Train';
[features NTrain] = size(Train);
end
if NTest == params.features && features2 ~= params.features
% Test set rotated incorrectly
Test = Test';
[features2 NTest] = size(Test);
end
if features ~= params.features
error('nrs_classifier:DimensionMismatch','Passed feature size does not match Training set.');
end
if features2 ~= params.features
error('nrs_classifier:DimensionMismatch','Passed feature size does not match Test set.');
end
end
ranking_direction = -1;
if isfield(params,'ranking_dir')
if params.ranking_dir > 0
ranking_direction = 1;
end
end
pre_part_mode = 1;
if isfield(params,'partition_mode')
switch params.partition_mode
case 'pre'
pre_part_mode = 1;
case 'post'
pre_part_mode = 0;
end
end
%% Data Check
if features ~= features2
error('nrs_classifier:DimensionMismatch','The feature dimensionality of the Training and Test sets are different!');
end
if ~isreal([Train Test])
error('nrs_classifier:ComplexData','Complex data types are currently unsupported.');
end
%% Bias Check
% Determine which kind of biasing the user wants to use when constructing
% the Tikhonov matrix, \Gamma.
bias_precalculated = 0;
if isfield(params,'bias_precal')
bias_precalculated = params.bias_precal;
end
if isfield(params,'bias')
if bias_precalculated
[biasRows biasCols] = size(params.bias);
if biasRows ~= NTrain || biasCols ~= NTest
error('nrs_classifier:DimensionMismatch','Biasing Coefficient matrix of improper size.');
end
biasing = @(A,B,l) l.*params.bias;
else
if isa(params.bias,'function_handle')
biasing = @(A,B,l) kernel_biasing(A,B,l,params.bias);
else
if ~isscalar(params.bias)
if ~iscell(params.bias)
biasing = @(A,B,l) matrix_biasing(A,B,l,params.bias);
else
error('nrs_classifier:UnsupportedBiasType','Bias input format is unsupported!');
end
else
error('nrs_classifier:UnsupportedBiasType','Bias input format is unsupported!');
end
end
end
else
biasing = @(A,B,l) default_biasing(A,B,l);
end
%% Ranking Check
% Determine how to score all of the approximations.
if isfield(params,'ranking')
if isa(params.ranking,'function_handle')
ranking = params.ranking;
else
error('nrs_classifier:UnsupportedRankingType','Ranking must be specified as a function handle.');
end
else
ranking = @(x,y) default_ranking(x,y);
end
%% Label Check
% Make sure that the training labels are in the expected format. The label
% vector should consist of C entries, where C is the number of classes and
% each entry specifies how many of the training samples belong to the class
% at that index.
if NClasses == NTrain
% In this case, there is a training label assigned to every sample.
% We will reorganize the training set according to the given labels.
[sorted_labels ordering] = sort(Train_labels,'ascend');
Train = Train(:,ordering);
Train_labels = hist(sorted_labels,unique(sorted_labels));
NClasses = length(Train_labels);
end
if pre_part_mode
approx_acc = main_loop_pre(Train,Test,Train_labels,lambda,biasing,ranking);
else
approx_acc = main_loop_post(Train,Test,Train_labels,lambda,biasing,ranking);
end
if ranking_direction < 0
[prox assignments] = min(approx_acc);
else
[prox assignments] = max(approx_acc);
end