00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00044
#include "DivisiveNormalizationKernel.h"
00045
00046
namespace PLearn {
00047
using namespace std;
00048
00050
00052 DivisiveNormalizationKernel::DivisiveNormalizationKernel()
00053 : data_will_change(false),
00054 remove_bias(false)
00055 {}
00056
00057 DivisiveNormalizationKernel::DivisiveNormalizationKernel(
Ker the_source,
bool the_remove_bias)
00058 : data_will_change(false),
00059 remove_bias(the_remove_bias)
00060 {
00061 source_kernel = the_source;
00062
build();
00063 }
00064
00065
PLEARN_IMPLEMENT_OBJECT(
DivisiveNormalizationKernel,
00066
"Divisive normalization of an underlying kernel.",
00067
"From a positive kernel K, defines a new kernel K' such that:\n"
00068
" K'(x,y) = K(x,y) / sqrt(E[K(x,x_i)] . E[K(x_i,y)])\n"
00069
"where the expectation is performed on the data set.\n"
00070
"If the 'remove_bias' option is set, then the expectation will not\n"
00071
"take into account terms of the form K(x_i,x_i).\n"
00072 );
00073
00075
00077 void DivisiveNormalizationKernel::declareOptions(
OptionList& ol)
00078 {
00079
00080
00081
declareOption(ol,
"data_will_change", &DivisiveNormalizationKernel::data_will_change, OptionBase::buildoption,
00082
"If set to 1, then the Gram matrix will be always recomputed, even if\n"
00083
"it's not completely sure the data has changed.");
00084
00085
declareOption(ol,
"remove_bias", &DivisiveNormalizationKernel::remove_bias, OptionBase::buildoption,
00086
"If set to 1, then the bias induced by the K(x_i,x_i) will be removed.\n");
00087
00088
00089
00090
declareOption(ol,
"average_col", &DivisiveNormalizationKernel::average_col, OptionBase::learntoption,
00091
"The average of the underlying kernel over each column of the Gram matrix.");
00092
00093
declareOption(ol,
"average_row", &DivisiveNormalizationKernel::average_row, OptionBase::learntoption,
00094
"The average of the underlying kernel over each row of the Gram matrix.");
00095
00096
00097 inherited::declareOptions(ol);
00098 }
00099
00101
00103 void DivisiveNormalizationKernel::build()
00104 {
00105 inherited::build();
00106
build_();
00107 }
00108
00110
00112 void DivisiveNormalizationKernel::build_()
00113 {
00114
00115
00116
00117
00118
00119
00120
00121 }
00122
00124
00126 real DivisiveNormalizationKernel::computeAverage(
const Vec& x,
bool on_row,
real squared_norm_of_x)
const {
00127
all_k_x.
resize(n_examples);
00128
if (is_symmetric || !on_row) {
00129 source_kernel->evaluate_all_i_x(
x,
all_k_x, squared_norm_of_x);
00130 }
else {
00131 source_kernel->evaluate_all_x_i(
x,
all_k_x, squared_norm_of_x);
00132 }
00133
return sum(
all_k_x) /
real(n_examples);
00134 }
00135
00137
00139 void DivisiveNormalizationKernel::computeGramMatrix(
Mat K)
const {
00140
00141 Kernel::computeGramMatrix(K);
00142 }
00143
00145
00147 real DivisiveNormalizationKernel::evaluate(
const Vec& x1,
const Vec& x2)
const {
00148
real avg_1 =
computeAverage(x1,
true);
00149
real avg_2 = computeAverage(x2,
false);
00150
return source_kernel->evaluate(x1, x2) /
sqrt(avg_1 * avg_2);
00151 }
00152
00154
00156 real DivisiveNormalizationKernel::evaluate_i_j(
int i,
int j)
const {
00157
return source_kernel->evaluate_i_j(i,j) /
sqrt(
average_row[i] *
average_col[j]);
00158 }
00159
00161
00163 real DivisiveNormalizationKernel::evaluate_i_x(
int i,
const Vec& x,
real squared_norm_of_x)
const {
00164
return source_kernel->evaluate_i_x(i,
x, squared_norm_of_x)
00165 /
sqrt(
average_row[i] *
computeAverage(
x,
false, squared_norm_of_x));
00166 }
00167
00169
00171 real DivisiveNormalizationKernel::evaluate_i_x_again(
int i,
const Vec& x,
real squared_norm_of_x,
bool first_time)
const {
00172
if (first_time) {
00173
avg_evaluate_i_x_again =
computeAverage(
x,
false, squared_norm_of_x);
00174 }
00175
return source_kernel->evaluate_i_x_again(i,
x, squared_norm_of_x, first_time)
00176 /
sqrt(
average_row[i] *
avg_evaluate_i_x_again);
00177 }
00178
00180
00182 real DivisiveNormalizationKernel::evaluate_x_i(
const Vec& x,
int i,
real squared_norm_of_x)
const {
00183
return source_kernel->evaluate_x_i(
x, i, squared_norm_of_x)
00184 /
sqrt(
average_col[i] *
computeAverage(
x,
true, squared_norm_of_x));
00185 }
00186
00188
00190 real DivisiveNormalizationKernel::evaluate_x_i_again(
const Vec& x,
int i,
real squared_norm_of_x,
bool first_time)
const {
00191
if (first_time) {
00192
avg_evaluate_x_i_again =
computeAverage(
x,
true, squared_norm_of_x);
00193 }
00194
return source_kernel->evaluate_x_i_again(
x, i, squared_norm_of_x, first_time)
00195 /
sqrt(
average_col[i] *
avg_evaluate_x_i_again);
00196 }
00197
00199
00201 void DivisiveNormalizationKernel::makeDeepCopyFromShallowCopy(map<const void*, void*>& copies)
00202 {
00203 inherited::makeDeepCopyFromShallowCopy(copies);
00204
00205
00206
00207
00208
00209
00210
00211
00212
PLERROR(
"DivisiveNormalizationKernel::makeDeepCopyFromShallowCopy not fully (correctly) implemented yet!");
00213 }
00214
00216
00218 void DivisiveNormalizationKernel::setDataForKernelMatrix(
VMat the_data) {
00219
bool there_was_data_and_it_changed = data && !(data->looksTheSameAs(the_data));
00220
00221 inherited::setDataForKernelMatrix(the_data);
00222
00223
int n = the_data->
length();
00224
if (
data_will_change
00225 ||
average_row.
length() != n
00226 || there_was_data_and_it_changed) {
00227
00228
Mat gram(n, n);
00229 source_kernel->computeGramMatrix(gram);
00230
00231
average_row.
resize(n);
00232
average_row.
fill(0);
00233
if (is_symmetric) {
00234
average_col =
average_row;
00235 }
else {
00236
average_col.
resize(n);
00237
average_col.
fill(0);
00238 }
00239
real k_x_x;
00240
for (
int i = 0; i < n; i++) {
00241
if (is_symmetric) {
00242
real v;
00243 k_x_x = gram(i,i);
00244
if (!
remove_bias) {
00245
average_row[i] += k_x_x;
00246 }
00247
for (
int j = i + 1; j < n; j++) {
00248 v = gram(i,j);
00249
average_row[i] += v;
00250
average_row[j] += v;
00251 }
00252 }
else {
00253
for (
int j = 0; j < n; j++) {
00254
if (!
remove_bias || j != i) {
00255
average_row[i] += gram(i,j);
00256
average_col[i] += gram(j,i);
00257
if (j == i) {
00258 }
00259 }
00260 }
00261 }
00262 }
00263
real n_terms_in_sum;
00264
if (
remove_bias) {
00265
00266 n_terms_in_sum =
real(n - 1);
00267 }
else {
00268 n_terms_in_sum =
real(n);
00269 }
00270
average_row /= n_terms_in_sum;
00271
if (!is_symmetric) {
00272
average_col /= n_terms_in_sum;
00273 }
00274 }
00275 }
00276
00277 }
00278