File: EvaluateTests.cs
Web Access
Project: ..\..\..\test\Microsoft.ML.Tests\Microsoft.ML.Tests.csproj (Microsoft.ML.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Collections.Generic;
using System.Linq;
using Microsoft.ML.Data;
using Microsoft.ML.Runtime;
using Microsoft.ML.TestFramework;
using Xunit;
using Xunit.Abstractions;
 
namespace Microsoft.ML.Tests
{
    public class EvaluateTests : BaseTestClass
    {
        public EvaluateTests(ITestOutputHelper output)
            : base(output)
        {
        }
 
        public class MulticlassEvaluatorInput
        {
            public float Label { get; set; }
 
            [VectorType(4)]
            public float[] Score { get; set; }
 
            public float PredictedLabel { get; set; }
        }
 
        private class RegressionEvaluatorInput
        {
            public float Label { get; set; }
 
            public float Score { get; set; }
        }
 
        [Fact]
        public void ShowSchemaWithEvaluatorTransformDoesNotThrowDuringCleanup()
        {
            bool transformCreated = false;
            var args = new ShowSchemaCommand.Arguments
            {
                Loader = ComponentFactoryUtils.CreateFromFunction<IMultiStreamSource, ILegacyDataLoader>(
                    (env, source) => TextLoader.Create(env, new TextLoader.Options
                    {
                        Columns = new[]
                        {
                            new TextLoader.Column(nameof(RegressionEvaluatorInput.Label), DataKind.Single, 0),
                            new TextLoader.Column(nameof(RegressionEvaluatorInput.Score), DataKind.Single, 1)
                        }
                    }, source)),
                Transforms = new[]
                {
                    new KeyValuePair<string, IComponentFactory<IDataView, IDataTransform>>(
                        null,
                        ComponentFactoryUtils.CreateFromFunction<IDataView, IDataTransform>((env, input) =>
                        {
                            transformCreated = true;
                            var roleMappedData = new RoleMappedData(
                                input,
                                opt: false,
                                RoleMappedSchema.ColumnRole.Label.Bind(nameof(RegressionEvaluatorInput.Label)),
                                new RoleMappedSchema.ColumnRole("Score").Bind(nameof(RegressionEvaluatorInput.Score)));
                            var evaluator = new RegressionEvaluator(env, new RegressionEvaluator.Arguments());
                            return ((IEvaluator)evaluator).GetPerInstanceMetrics(roleMappedData);
                        }))
                }
            };
 
            var env = new ConsoleEnvironment(42).AddStandardComponents();
            new ShowSchemaCommand(env, args).Run();
 
            Assert.True(transformCreated);
        }
 
        [Fact]
        public void MulticlassEvaluatorTopKArray()
        {
            var mlContext = new MLContext(seed: 1);
 
            // Notice that the probability assigned to the correct label (i.e. Score[0])
            // decreases on each row so as to get the expected TopK accuracy array hardcoded below.
            var inputArray = new[]
            {
                new MulticlassEvaluatorInput{Label = 0, Score = new[] {0.4f, 0.3f, 0.2f, 0.1f}, PredictedLabel = 0},
                new MulticlassEvaluatorInput{Label = 0, Score = new[] {0.3f, 0.4f, 0.2f, 0.1f}, PredictedLabel = 1},
                new MulticlassEvaluatorInput{Label = 0, Score = new[] {0.2f, 0.3f, 0.4f, 0.1f}, PredictedLabel = 2},
                new MulticlassEvaluatorInput{Label = 0, Score = new[] {0.1f, 0.3f, 0.2f, 0.4f}, PredictedLabel = 3},
            };
 
            var expectedTopKArray = new[] { 0.25d, 0.5d, 0.75d, 1.0d };
 
            var inputDV = mlContext.Data.LoadFromEnumerable(inputArray);
            var metrics = mlContext.MulticlassClassification.Evaluate(inputDV, topKPredictionCount: 4);
            Assert.Equal(expectedTopKArray, metrics.TopKAccuracyForAllK);
 
 
            // After introducing a sample whose label was unseen (i.e. the Score array doesn't assign it a probability)
            // then the Top K array changes, as its values are divided by the total number of instances
            // that were evaluated.
            var inputArray2 = inputArray.AppendElement(new MulticlassEvaluatorInput
            {
                Label = 5,
                Score = new[] { 0.1f, 0.3f, 0.2f, 0.4f },
                PredictedLabel = 3
            });
 
            var expectedTopKArray2 = new[] { 0.2d, 0.4d, 0.6d, 0.8d };
 
            var inputDV2 = mlContext.Data.LoadFromEnumerable(inputArray2);
            var metrics2 = mlContext.MulticlassClassification.Evaluate(inputDV2, topKPredictionCount: 4);
            var output2 = metrics2.TopKAccuracyForAllK.ToArray();
            for (int i = 0; i < expectedTopKArray2.Length; i++)
                Assert.Equal(expectedTopKArray2[i], output2[i], 0.0000001);
        }
    }
}