dotnet / machinelearning

ML.NET is an open source and cross-platform machine learning framework for .NET.
https://dot.net/ml
MIT License
9.02k stars 1.88k forks source link

[Image Classification API] metricsCallback NullReferenceException when using custom function #4259

Closed luisquintanilla closed 5 years ago

luisquintanilla commented 5 years ago

System information

Issue

Tried to provide a custom function for the metricsCallback parameter. The documentation in IntelliSense says this method is only called during the Training phase. However, it does not appear to be the case. If the Bottleneck phase has to happen (training for first time or not using cached bottleneck values), a System.NullReferenceException is raised.

System.NullReferenceException: 'Object reference not set to an instance of an object.'

trainMetrics was null.

I suspect this is because the same callback is used for both the Bottleneck / Training phases. It would be good to either:

a) Have separate callbacks depending on whether it's Bottleneck / Training phase. b) Allow the user to check which phase is currently taking place so they can display the results accordingly in their metricsCallback method.

Note that once a model is trained and the Bottleneck phase no longer needs to happen since the cached values are being used, no Exceptions are raised and the application works as expected.

Source code / logs

Pipeline:

var trainingPipeline =
    mapLabelTransform
   .Append(mlContext.Model.ImageClassification(
       "ImagePath",
       "LabelAsKey",
       arch: ImageClassificationEstimator.Architecture.ResnetV2101,
       epoch: 100,
       batchSize: 20,
       metricsCallback: DisplayMetrics,
       validationSet: transformedTestData
       //reuseTrainSetBottleneckCachedValues: true,
       /*reuseValidationSetBottleneckCachedValues: true*/));

Metrics Callback Method:

public static void DisplayMetrics(ImageClassificationMetrics metrics)
{
    TrainMetrics trainMetrics = metrics.Train;
    Console.WriteLine($"Epoch: {trainMetrics.Epoch} | Accuracy {trainMetrics.Accuracy} | Loss: {trainMetrics.CrossEntropy}");
}
luisquintanilla commented 5 years ago

Here is a workaround for now to use a custom function.

public static void DisplayMetrics(ImageClassificationMetrics metrics)
{
    if(metrics.Train == null)
    {
        Console.WriteLine(metrics);
    } else
    {
        TrainMetrics trainMetrics = metrics.Train;
        Console.WriteLine($"Epoch: {trainMetrics.Epoch} | Accuracy {trainMetrics.Accuracy} | Loss: {trainMetrics.CrossEntropy}");
    }
}
harshithapv commented 5 years ago

metricsCallback parameter is called during training phase and bottleneck phase. I have fixed the documentation. Thanks.