diff --git a/src/Microsoft.ML.CodeGenerator/CodeGenerator/CSharp/CodeGenerator.cs b/src/Microsoft.ML.CodeGenerator/CodeGenerator/CSharp/CodeGenerator.cs index cece240cf4..da4b68a225 100644 --- a/src/Microsoft.ML.CodeGenerator/CodeGenerator/CSharp/CodeGenerator.cs +++ b/src/Microsoft.ML.CodeGenerator/CodeGenerator/CSharp/CodeGenerator.cs @@ -329,18 +329,11 @@ private string GenerateConsumeModelCSFileContent(string namespaceValue) { if (_pipeline == null) throw new ArgumentNullException(nameof(_pipeline)); - try - { - var node = _pipeline.Nodes.Where(t => t.NodeType == PipelineNodeType.Trainer).First(); - ITrainerGenerator generator = TrainerGeneratorFactory.GetInstance(node); - var trainerString = generator.GenerateTrainer(); - var trainerUsings = generator.GenerateUsings(); - return (trainerString, trainerUsings); - } - catch (Exception) - { - return (string.Empty, new string[0]); - } + var node = _pipeline.Nodes.Where(t => t.NodeType == PipelineNodeType.Trainer).First(); + ITrainerGenerator generator = TrainerGeneratorFactory.GetInstance(node); + var trainerString = generator.GenerateTrainer(); + var trainerUsings = generator.GenerateUsings(); + return (trainerString, trainerUsings); } internal IList GenerateClassLabels(IDictionary columnMapping = default) diff --git a/src/Microsoft.ML.CodeGenerator/CodeGenerator/CSharp/TrainerGeneratorBase.cs b/src/Microsoft.ML.CodeGenerator/CodeGenerator/CSharp/TrainerGeneratorBase.cs index 53ebbb34a2..20761f95a6 100644 --- a/src/Microsoft.ML.CodeGenerator/CodeGenerator/CSharp/TrainerGeneratorBase.cs +++ b/src/Microsoft.ML.CodeGenerator/CodeGenerator/CSharp/TrainerGeneratorBase.cs @@ -97,6 +97,12 @@ private void Initialize(PipelineNode node) value = "\"" + val + "\""; } + if (type.IsEnum) + { + //example: "MatrixFactorizationTrainer.LossFunctionType.SquareLossRegression" + value = $"{type.ReflectedType.Name}.{type.Name}.{kv.Value.ToString()}"; + } + if (type == typeof(CustomProperty)) { value = kv.Value; diff --git a/test/Microsoft.ML.CodeGenerator.Tests/ApprovalTests/ConsoleCodeGeneratorTests.Recommendation_GenerateConsoleAppProjectContents_VerifyModelBuilder.approved.txt b/test/Microsoft.ML.CodeGenerator.Tests/ApprovalTests/ConsoleCodeGeneratorTests.Recommendation_GenerateConsoleAppProjectContents_VerifyModelBuilder.approved.txt index 0ca57a2ff5..66b5413c30 100644 --- a/test/Microsoft.ML.CodeGenerator.Tests/ApprovalTests/ConsoleCodeGeneratorTests.Recommendation_GenerateConsoleAppProjectContents_VerifyModelBuilder.approved.txt +++ b/test/Microsoft.ML.CodeGenerator.Tests/ApprovalTests/ConsoleCodeGeneratorTests.Recommendation_GenerateConsoleAppProjectContents_VerifyModelBuilder.approved.txt @@ -11,6 +11,7 @@ using System.Linq; using Microsoft.ML; using Microsoft.ML.Data; using TestNamespace.Model; +using Microsoft.ML.Trainers; namespace TestNamespace.ConsoleApp { @@ -55,9 +56,10 @@ namespace TestNamespace.ConsoleApp public static IEstimator BuildTrainingPipeline(MLContext mlContext) { // Data process configuration with pipeline data transformations - var dataProcessPipeline = mlContext.Transforms.Concatenate("Out", new[] { "In" }); + var dataProcessPipeline = mlContext.Transforms.Conversion.MapValueToKey("userId", "userId") + .Append(mlContext.Transforms.Conversion.MapValueToKey("movieId", "movieId")); // Set the training algorithm - var trainer = mlContext.Recommendation().Trainers.MatrixFactorization(labelColumnName: "Label", matrixColumnIndexColumnName: "userId", matrixRowIndexColumnName: "movieId"); + var trainer = mlContext.Recommendation().Trainers.MatrixFactorization(new MatrixFactorizationTrainer.Options() { MatrixColumnIndexColumnName = "userId", MatrixRowIndexColumnName = "movieId", LabelColumnName = "Label", NumberOfIterations = 10, LearningRate = 0.01f, ApproximationRank = 8, Lambda = 0.01f, LossFunction = MatrixFactorizationTrainer.LossFunctionType.SquareLossRegression, Alpha = 1f, C = 1E-05f }); var trainingPipeline = dataProcessPipeline.Append(trainer); diff --git a/test/Microsoft.ML.CodeGenerator.Tests/ApprovalTests/ConsoleCodeGeneratorTests.cs b/test/Microsoft.ML.CodeGenerator.Tests/ApprovalTests/ConsoleCodeGeneratorTests.cs index 297792fffc..d8e1799050 100644 --- a/test/Microsoft.ML.CodeGenerator.Tests/ApprovalTests/ConsoleCodeGeneratorTests.cs +++ b/test/Microsoft.ML.CodeGenerator.Tests/ApprovalTests/ConsoleCodeGeneratorTests.cs @@ -19,6 +19,7 @@ using Microsoft.ML.CodeGenerator.Templates.Console; using Microsoft.ML.CodeGenerator.Utilities; using Microsoft.ML.Data; +using Microsoft.ML.Trainers; using Xunit; using CodeGenerator = Microsoft.ML.CodeGenerator.CSharp.CodeGenerator; @@ -466,16 +467,30 @@ private CodeGenerator PrepareForRecommendationTask() if (mockedPipeline == null) { MLContext context = new MLContext(); + var hyperParam = new Dictionary() + { + {"MatrixColumnIndexColumnName","userId" }, + {"MatrixRowIndexColumnName","movieId" }, + {"LabelColumnName","Label" }, + {nameof(MatrixFactorizationTrainer.Options.NumberOfIterations), 10 }, + {nameof(MatrixFactorizationTrainer.Options.LearningRate), 0.01f }, + {nameof(MatrixFactorizationTrainer.Options.ApproximationRank), 8 }, + {nameof(MatrixFactorizationTrainer.Options.Lambda), 0.01f }, + {nameof(MatrixFactorizationTrainer.Options.LossFunction), MatrixFactorizationTrainer.LossFunctionType.SquareLossRegression }, + {nameof(MatrixFactorizationTrainer.Options.Alpha), 1f }, + {nameof(MatrixFactorizationTrainer.Options.C), 0.00001f }, + }; + var valueToKeyPipelineNode1 = new PipelineNode(nameof(EstimatorName.ValueToKeyMapping), PipelineNodeType.Transform, "userId", "userId"); + var valueToKeyPipelineNode2 = new PipelineNode(nameof(EstimatorName.ValueToKeyMapping), PipelineNodeType.Transform, "movieId", "movieId"); + var matrixPipelineNode = new PipelineNode(nameof(TrainerName.MatrixFactorization), PipelineNodeType.Trainer, "Features", "Score", hyperParam); + var pipeline = new Pipeline(new PipelineNode[] + { + valueToKeyPipelineNode1, + valueToKeyPipelineNode2, + matrixPipelineNode + }); - var trainer1 = new SuggestedTrainer(context, new MatrixFactorizationExtension(), new ColumnInformation() { - LabelColumnName = "Label", - UserIdColumnName = "userId", - ItemIdColumnName = "movieId", - }, hyperParamSet: null); - var transforms1 = new List() { ColumnConcatenatingExtension.CreateSuggestedTransform(context, new[] { "In" }, "Out") }; - var inferredPipeline1 = new SuggestedPipeline(transforms1, new List(), trainer1, context, false); - - mockedPipeline = inferredPipeline1.ToPipeline(); + mockedPipeline = pipeline; var textLoaderArgs = new TextLoader.Options() { Columns = new[] { diff --git a/test/Microsoft.ML.CodeGenerator.Tests/TrainerGeneratorTests.cs b/test/Microsoft.ML.CodeGenerator.Tests/TrainerGeneratorTests.cs index 0145d6e7f2..9a398d117d 100644 --- a/test/Microsoft.ML.CodeGenerator.Tests/TrainerGeneratorTests.cs +++ b/test/Microsoft.ML.CodeGenerator.Tests/TrainerGeneratorTests.cs @@ -8,6 +8,7 @@ using Microsoft.ML; using Microsoft.ML.AutoML; using Microsoft.ML.CodeGenerator.CSharp; +using Microsoft.ML.Trainers; using Xunit; namespace mlnet.Tests @@ -295,14 +296,21 @@ public void MatrixFactorizationAdvancedTest() {"MatrixColumnIndexColumnName","userId" }, {"MatrixRowIndexColumnName","movieId" }, {"LabelColumnName","rating" }, + {nameof(MatrixFactorizationTrainer.Options.NumberOfIterations), 10 }, + {nameof(MatrixFactorizationTrainer.Options.LearningRate), 0.01f }, + {nameof(MatrixFactorizationTrainer.Options.ApproximationRank), 8 }, + {nameof(MatrixFactorizationTrainer.Options.Lambda), 0.01f }, + {nameof(MatrixFactorizationTrainer.Options.LossFunction), MatrixFactorizationTrainer.LossFunctionType.SquareLossRegression }, + {nameof(MatrixFactorizationTrainer.Options.Alpha), 1f }, + {nameof(MatrixFactorizationTrainer.Options.C), 0.00001f }, }; PipelineNode node = new PipelineNode("MatrixFactorization", PipelineNodeType.Trainer, default(string[]), default(string), elementProperties); Pipeline pipeline = new Pipeline(new PipelineNode[] { node }); CodeGenerator codeGenerator = new CodeGenerator(pipeline, null, null); var actual = codeGenerator.GenerateTrainerAndUsings(); - string expectedTrainerString = "MatrixFactorization(matrixColumnIndexColumnName:\"userId\",matrixRowIndexColumnName:\"movieId\",labelColumnName:\"rating\")"; + string expectedTrainerString = "MatrixFactorization(new MatrixFactorizationTrainer.Options(){MatrixColumnIndexColumnName=\"userId\",MatrixRowIndexColumnName=\"movieId\",LabelColumnName=\"rating\",NumberOfIterations=10,LearningRate=0.01f,ApproximationRank=8,Lambda=0.01f,LossFunction=MatrixFactorizationTrainer.LossFunctionType.SquareLossRegression,Alpha=1f,C=1E-05f})"; Assert.Equal(expectedTrainerString, actual.Item1); - Assert.Null(actual.Item2); + Assert.Equal(new string[] { "using Microsoft.ML.Trainers;\r\n" },actual.Item2); } [Fact]