13 namespace classification {
17 template<
class KERNEL,
size_t SOLVER,
class T>
18 template<
class... Args>
20 const arma::Row<size_t>& labels,
21 const size_t num_class,
23 const Args&... args) :
24 nclass_(num_class), C_(C), cov_(args...)
27 ulab_ = arma::unique(labels);
29 if (ulab_.n_elem == 1)
39 this->
Train(inputs,labels);
44 nclass_, size_t(2), C, args...);
49 template<
class KERNEL,
size_t SOLVER,
class T>
50 template<
class... Args>
52 const arma::Row<size_t>& labels,
53 const size_t num_class,
54 const Args&... args ) :
55 nclass_(num_class), C_(T(1.0)), cov_(args...)
57 ulab_ = arma::unique(labels);
59 if (ulab_.n_elem == 1)
67 this->
Train(inputs,labels);
70 nclass_, size_t(2),C_,args...);
74 template<
class KERNEL,
size_t SOLVER,
class T>
76 const arma::Row<size_t>& y )
78 if (solver_ ==
"fanSMO")
81 ERR(
"Not Implemented: Try fanSMO");
84 template<
class KERNEL,
size_t SOLVER,
class T>
86 const arma::Row<size_t>& y,
87 const size_t num_class )
89 this -> nclass_ = num_class;
93 template<
class KERNEL,
size_t SOLVER,
class T>
97 T inf = arma::datum::inf;
101 size_t len = y_.n_elem;
104 for (
size_t t=0; t<len; t++)
106 if ( (y_[t] == +1 && alphas_[t] < C_) || (y_[t] == -1 && alphas_[t] > 0.) )
108 if ( -y_[t]*G[t] >= G_max )
111 G_max = -y_[t] * G[t];
117 for (
size_t t=0; t<len; t++)
119 if ( (y_[t] == +1 && alphas_[t] > 0.) || (y_[t] == -1 && alphas_[t] < C_) )
121 T b = G_max + y_[t]*G[t];
122 if ( -y_[t]*G[t] <= G_max )
126 T a = Q(i,i) + Q(t,t) - 2.*y_[i]*y_[t]*Q(i,t);
129 if (-(b*b)/a <= obj_min)
139 if (G_max-G_min < eps_)
145 template<
class KERNEL,
size_t SOLVER,
class T>
146 void SVM<KERNEL,SOLVER,T>::_fanSMO (
const arma::Mat<T>& X,
147 const arma::Row<size_t>& y )
150 y_ = (arma::conv_to<arma::Row<int>>::from((y==ulab_(0)) * -2 + 1));
151 size_t N = y_.n_elem;
154 arma::Row<T> G(N); G.fill(-1.);
160 K = cov_.GetMatrix(X,X);
161 arma::Mat<T> Q = (y_.t() * y_) % K;
162 while (max_iter_>iter_++)
164 auto [i, j] = _selectset(G, Q);
168 T a = Q(i, i) + Q(j, j) - 2 * y_[i]*y_[j] * Q(i, j);
173 T b = -y_[i] * G[i] + y_[j] * G[j];
176 T oldAi = alphas_[i];
177 T oldAj = alphas_[j];
180 alphas_[i] += y_[i] * b / a;
181 alphas_[j] -= y_[j] * b / a;
184 T sum = y_[i] * oldAi + y_[j] * oldAj;
187 alphas_[i] = std::clamp(alphas_[i], T(0.0), C_);
190 alphas_[j] = y_[j] * (sum - y_[i] * alphas_[i]);
191 alphas_[j] = std::clamp(alphas_[j], T(0.0), C_);
194 alphas_[i] = y_[i] * (sum - y_[j] * alphas_[j]);
197 T deltaAi = alphas_[i] - oldAi;
198 T deltaAj = alphas_[j] - oldAj;
202 size_t len = y_.n_elem;
203 for (
size_t h=0; h<len; h++)
205 G[h] += Q(h,i)*deltaAi+Q(h,j)*deltaAj;
208 idx_ = arma::find(alphas_ > tau_);
211 template<
class KERNEL,
size_t SOLVER,
class T>
213 arma::Row<size_t>& preds )
const
220 Classify(inputs,preds,temp);
224 ova_.Classify(inputs,preds,temp);
229 preds.resize(inputs.n_cols);
230 preds.fill(ulab_[0]);
234 template<
class KERNEL,
size_t SOLVER,
class T>
236 arma::Row<size_t>& preds,
237 arma::Mat<T>& probs )
const
239 arma::Mat<T> dec_func;
247 probs.set_size(nclass_,inputs.n_cols);
248 preds.set_size(inputs.n_cols);
249 arma::Mat<T> svs = X_.cols(idx_);
250 arma::Mat<T> K = cov_.GetMatrix(svs,inputs);
251 arma::Mat<T> Ksv = cov_.GetMatrix(svs);
253 b = arma::accu(arma::conv_to<arma::Row<T>>::from(y_.cols(idx_))
254 - ((alphas_.cols(idx_) % y_.cols(idx_)) * Ksv)) /idx_.n_elem;
256 dec_func = (alphas_.cols(idx_) % y_.cols(idx_)) * K + b;
258 preds.elem( arma::find( dec_func <= 0.) ).fill(ulab_[0]);
259 preds.elem( arma::find( dec_func > 0.) ).fill(ulab_[1]);
260 probs.row(0) = 1. / (1. + arma::exp(dec_func));
261 probs.row(1) = 1 - probs.row(0);
265 ERR(
"No support vectors->No prediction");
270 ova_.Classify(inputs, preds, probs);
274 probs.resize(nclass_,inputs.n_cols);
275 probs.row(ulab_[0]).fill(1.);
276 preds.resize(inputs.n_cols);
277 preds.fill(ulab_[0]);
281 template<
class KERNEL,
size_t SOLVER,
class T>
283 const arma::Row<size_t>& responses )
285 arma::Row<size_t> predictions;
286 Classify(points,predictions);
287 arma::Row<size_t> temp = predictions - responses;
288 return (arma::accu(temp != 0))/T(predictions.n_elem);
291 template<
class KERNEL,
size_t SOLVER,
class T>
293 const arma::Row<size_t>& responses )
295 return (1. - ComputeError(points, responses));
void Train(const arma::Mat< T > &inputs, const arma::Row< size_t > &labels, const size_t num_class)
T ComputeAccuracy(const arma::Mat< T > &points, const arma::Row< size_t > &responses)
T ComputeError(const arma::Mat< T > &points, const arma::Row< size_t > &responses)
void Classify(const arma::Mat< T > &inputs, arma::Row< size_t > &labels) const