> dotnet --info
.NET Core SDK (reflecting any global.json):
Version: 2.1.400-preview-009063
Commit: dd0179a67c
Runtime Environment:
OS Name: Windows
OS Version: 10.0.17134
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\2.1.400-preview-009063\
Host (useful for support):
Version: 2.1.1
Commit: 6985b9f684
0.3.0-preview NuGet package, I tried using LightGBM in a .NET Core application. I did the walk through: https://www.microsoft.com/net/learn/apps/machine-learning-and-ai/ml-dotnet/get-started/windows, only changing:```C#
// STEP 4: Add learner
// Add a learning algorithm to the pipeline.
// This is a classification scenario (What type of iris is this?)
pipeline.Add(new LightGbmClassifier());
// pipeline.Add(new StochasticDualCoordinateAscentClassifier());
- **What happened?**
Unhandled Exception: System.InvalidOperationException: Entry point 'Trainers.LightGbmClassifier' not found
at Microsoft.ML.Runtime.EntryPoints.EntryPointNode..ctor(IHostEnvironment env, IChannel ch, ModuleCatalog moduleCatalog, RunContext context, String id, String entryPointName, JObject inputs, JObject outputs, Boolean checkpoint, String stageId, Single cost, String label, String group, String weight)
at Microsoft.ML.Runtime.EntryPoints.EntryPointNode.ValidateNodes(IHostEnvironment env, RunContext context, JArray nodes, ModuleCatalog moduleCatalog, String label, String group, String weight)
at Microsoft.ML.Runtime.EntryPoints.EntryPointGraph..ctor(IHostEnvironment env, ModuleCatalog moduleCatalog, JArray nodes)
at Microsoft.ML.Runtime.Experiment.Compile()
at Microsoft.ML.LearningPipeline.TrainTInput,TOutput
at MLLightGBMSmokeTest.Program.Main(String[] args) in C:\Users\eerhardt\source\repos\MLLightGBMSmokeTest\Program.cs:line 72
- **What did you expect?**
I expected the walk through app to run successfully.
### Notes
When F5 debugging a .NET Core app in VS, or using `dotnet run` on the command line, .NET Core doesn't have all the dependencies copied to the output directory. Instead, references that come from NuGet packages are executed from the NuGet package cache folder.
Since LightGBM comes from a separate NuGet package than the rest of the Microsoft.ML, it is loaded from a separate folder than the rest of the Microsoft.ML package.
I've looked through the [ComponentCatalog](https://github.com/dotnet/machinelearning/blob/c023727b76970ab913ec1ce38276508835c17bcf/src/Microsoft.ML.Core/ComponentModel/ComponentCatalog.cs#L393-L425) code, and it appears if I force the `Microsoft.ML.LightGBM.dll` to be loaded first, I can workaround the issue.
So I added
```C#
static void Main(string[] args)
{
// workaround to ensure LightGbm assembly is loaded
new LightGbmArguments();
And I am able to successfully use LightGBM on .NET Core during F5.
Any of these should allow you to workaround the issue:
new LightGbmArguments();dotnet publish your application and running it from the published folder (since all dependencies are copied during publish)/cc @ericstj @TomFinley @codemzs
Hi Eric, were you using LightGBM nuget?
Yes, here is my .csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ML.LightGBM" Version="0.3.0-preview-26703-11" />
</ItemGroup>
<ItemGroup>
<None Update="iris-data.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
I spoke with Eric offline and as a work around running dotnet publish places the dependencies in one folder.
There is another workaround (on the user end) as outlined in #618. It requires adding the following line to the .csproj file:
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
so that it becomes:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ML" Version="0.4.0" />
<PackageReference Include="Microsoft.ML.LightGBM" Version="0.4.0" />
</ItemGroup>
<ItemGroup>
<None Update="iris-data.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
This problem should be soon resolved by the change from the LearningPipelineAPI to the direct access API #371. Users will call directly into the LightGBM assembly, which will therefore be loaded.
@artidoro once #1020 is merged, please test and close this issue. Thanks.
The new direct access API and the changes coming with version 0.6.0 of ML.NET solved this issue.
After loading both the ML.NET nuget and the LightGBM nuget, the tutorial can be run without incurring in any errors. Note that we will update the tutorial to reflect the changes for the new API.
Using legacy APIs (even with workaround) when upgrading to ML.NET 0.6 seems to bring this issue back up.
@artidoro can you please verify this issue with 0.7?
Hello @bartczernicki! Sorry for the late reply.
As you noticed using the Legacy API will still has the issue that was pointed out in this post initially. However, I have tested again that with v0.7 the iris tutorial with LightGBM works fine. I know there have been a lot of significant changes to the API and renaming of namespaces and trainers recently, so I am going to post the updated code for the tutorial. I used the pre-release nugets (remember to install the LightGBM nuget for this code to work) but as soon as v0.7 is released you will be able to use those.
using Microsoft.ML;
using Microsoft.ML.Runtime.LightGBM;
using Microsoft.ML.Runtime.Api;
using Microsoft.ML.Runtime.Data;
using Microsoft.ML.Transforms;
using Microsoft.ML.Transforms.Categorical;
using Microsoft.ML.Transforms.Conversions;
using System;
namespace myApp
{
class Program
{
// STEP 1: Define your data structures
// IrisData is used to provide training data, and as
// input for prediction operations
// - First 4 properties are inputs/features used to predict the label
// - Label is what you are predicting, and is only set when training
public class IrisData
{
[Column("0")]
public float SepalLength;
[Column("1")]
public float SepalWidth;
[Column("2")]
public float PetalLength;
[Column("3")]
public float PetalWidth;
[Column("4")]
[ColumnName("Label")]
public string Label;
}
// IrisPrediction is the result returned from prediction operations
public class IrisPrediction
{
[ColumnName("PredictedLabel")]
public string PredictedLabel;
}
static void Main(string[] args)
{
// STEP 2: Create an evironment and load your data
var ctx = new MLContext();
// If working in Visual Studio, make sure the 'Copy to Output Directory'
// property of iris-data.txt is set to 'Copy always'
string dataPath = "iris-data.txt";
var reader = new TextLoader(ctx,
new TextLoader.Arguments()
{
Separator = ",",
HasHeader = true,
Column = new[]
{
new TextLoader.Column("SepalLength", DataKind.R4, 0),
new TextLoader.Column("SepalWidth", DataKind.R4, 1),
new TextLoader.Column("PetalLength", DataKind.R4, 2),
new TextLoader.Column("PetalWidth", DataKind.R4, 3),
new TextLoader.Column("Label", DataKind.Text, 4)
}
});
IDataView trainingDataView = reader.Read(new MultiFileSource(dataPath));
// STEP 3: Transform your data and add a learner
// Assign numeric values to text in the "Label" column, because only
// numbers can be processed during model training.
// Add a learning algorithm to the pipeline. e.g.(What type of iris is this?)
// Convert the Label back into original text (after converting to number in step 3)
var pipeline = new ValueToKeyMappingEstimator(ctx, "Label", "Label")
.Append(new ColumnConcatenatingEstimator(ctx, "Features", "SepalLength", "SepalWidth", "PetalLength", "PetalWidth"))
.Append(new LightGbmMulticlassTrainer(ctx, "Label", "Features"))
.Append(new KeyToValueEstimator(ctx, "PredictedLabel"));;
// STEP 4: Train your model based on the data set
var model = pipeline.Fit(trainingDataView);
// STEP 5: Use your model to make a prediction
// You can change these numbers to test different predictions
var prediction = model.MakePredictionFunction<IrisData, IrisPrediction>(ctx).Predict(
new IrisData()
{
SepalLength = 3.3f,
SepalWidth = 1.6f,
PetalLength = 0.2f,
PetalWidth = 5.1f,
});
Console.WriteLine($"Predicted flower type is: {prediction.PredictedLabel}");
Console.ReadLine();
}
}
}
Most helpful comment
This problem should be soon resolved by the change from the LearningPipelineAPI to the direct access API #371. Users will call directly into the LightGBM assembly, which will therefore be loaded.