/// <inheritdoc /> /// <exception cref="ArgumentNullException"> /// <paramref name="features"/> is <b>null</b>. /// </exception> public override Answer Classify(PointsOfInterestFeatures features, CancellationToken cancellationToken) { if (features == null) { throw new ArgumentNullException(nameof(features)); } if (!this.isLearned) { throw new InvalidOperationException(Properties.Resources.E_Classifier_NotLearned); } if (features.Features.Count > 0) { // build a feature vector float[] featureVector = PointsOfInterestClassifier.PrepareVector(this.kmeans, features.Features, cancellationToken); // classify feature vector float[] w = this.svm.Classify(featureVector, null, cancellationToken); Vectors.SoftMax(w.Length, w, 0); // find best class int[] indices = Arrays.Indexes(w.Length); Vectors.Sort(w.Length, w, 0, indices, 0, false); /*float confidence = w[0]; * float diff = w[0] - w[1]; * if (diff < 0.15f) * { * // penalize first answer which score is close to second's * confidence *= 1.0f - (1.0f / (float)Math.Exp(100.0 * diff / Math.PI)); * }*/ float confidence = (float)(-Math.Log(w[1] / w[0], 2.0)); return(new Answer( features.Id, this.classes[indices[0]], confidence.Clip(0, 1), w.Take(5).Select((x, i) => (this.classes[indices[i]], w[i])))); } else { return(new Answer(features.Id)); } }
public (List <string> classes, KMeans kmeans, OneVsAllSupportVectorMachine svm) FinishLearning( int vectorLength, CancellationToken cancellationToken) { // count classes List <string> classes = new List <string>(this.features.Select(x => x.truth).ToLookup(x => x).Select(x => x.Key)); if (classes.Count < 2) { throw new ArgumentException(); } classes.Sort(); // count vectors int numberOfVectors = this.features.Sum(x => x.features.Count); // copy vectors Dictionary <IVector <float>, float> vectors = new Dictionary <IVector <float>, float>(numberOfVectors); for (int i = 0, ii = this.features.Count; i < ii; i++) { FeatureDetectors.Features f = this.features[i].features; for (int j = 0, jj = f.Count, len = f.Length, off = 0; j < jj; j++, off += len) { ////DenseVectorF vector = new DenseVectorF(len, f.X, off); SparseVectorF vector = SparseVectorF.FromDense(len, f.X, off); vectors[vector] = vectors.TryGetValue(vector, out float weight) ? weight + 1.0f : 1.0f; } } cancellationToken.ThrowIfCancellationRequested(); // learn k-means KMeans kmeans = KMeans.Learn( vectorLength, KMeansSeeding.Random, 2, default(EuclideanDistance), vectors.Keys.ToList(), vectors.Values.ToList(), cancellationToken); cancellationToken.ThrowIfCancellationRequested(); // learn svm Dictionary <string, int> classesLookup = classes.ToDictionary((x, i) => x, (x, i) => i); SequentualMinimalOptimization smo = new SequentualMinimalOptimization(new ChiSquare()) { Algorithm = SMOAlgorithm.LibSVM, Tolerance = 0.01f, }; List <float[]> svmx = new List <float[]>(this.features.Count); List <int> svmy = new List <int>(this.features.Count); for (int i = 0, ii = this.features.Count; i < ii; i++) { (FeatureDetectors.Features features, string truth) = this.features[i]; svmx.Add(PointsOfInterestClassifier.PrepareVector(kmeans, features, cancellationToken)); svmy.Add(classesLookup[truth]); } cancellationToken.ThrowIfCancellationRequested(); OneVsAllSupportVectorMachine svm = OneVsAllSupportVectorMachine.Learn( smo, classes.Count, svmx, svmy, null, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); return(classes, kmeans, svm); }