diff --git a/Microsoft.ML.sln b/Microsoft.ML.sln index e491a54d2f..8f75429645 100644 --- a/Microsoft.ML.sln +++ b/Microsoft.ML.sln @@ -153,6 +153,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ML.SearchSpace", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ML.SearchSpace.Tests", "test\Microsoft.ML.SearchSpace.Tests\Microsoft.ML.SearchSpace.Tests.csproj", "{A3E9F25F-2718-4FF9-A35A-54C232A847AB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.ML.AutoML.SourceGenerator", "tools-local\Microsoft.ML.AutoML.SourceGenerator\Microsoft.ML.AutoML.SourceGenerator.csproj", "{C804B990-390E-41D7-8FF1-6774495D70E2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -717,6 +719,14 @@ Global {A3E9F25F-2718-4FF9-A35A-54C232A847AB}.Release|Any CPU.Build.0 = Release|Any CPU {A3E9F25F-2718-4FF9-A35A-54C232A847AB}.Release|x64.ActiveCfg = Release|Any CPU {A3E9F25F-2718-4FF9-A35A-54C232A847AB}.Release|x64.Build.0 = Release|Any CPU + {C804B990-390E-41D7-8FF1-6774495D70E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C804B990-390E-41D7-8FF1-6774495D70E2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C804B990-390E-41D7-8FF1-6774495D70E2}.Debug|x64.ActiveCfg = Debug|Any CPU + {C804B990-390E-41D7-8FF1-6774495D70E2}.Debug|x64.Build.0 = Debug|Any CPU + {C804B990-390E-41D7-8FF1-6774495D70E2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C804B990-390E-41D7-8FF1-6774495D70E2}.Release|Any CPU.Build.0 = Release|Any CPU + {C804B990-390E-41D7-8FF1-6774495D70E2}.Release|x64.ActiveCfg = Release|Any CPU + {C804B990-390E-41D7-8FF1-6774495D70E2}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -792,6 +802,7 @@ Global {8AFB8CC3-DA0B-4364-BFB3-296A7C54CC25} = {AED9C836-31E3-4F3F-8ABC-929555D3F3C4} {A8F4F08F-1F9D-4AAE-8C8D-502CDBBDE7D3} = {09EADF06-BE25-4228-AB53-95AE3E15B530} {A3E9F25F-2718-4FF9-A35A-54C232A847AB} = {AED9C836-31E3-4F3F-8ABC-929555D3F3C4} + {C804B990-390E-41D7-8FF1-6774495D70E2} = {7F13E156-3EBA-4021-84A5-CD56BA72F99E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {41165AF1-35BB-4832-A189-73060F82B01D} diff --git a/src/Microsoft.ML.AutoML/API/ExperimentSettings.cs b/src/Microsoft.ML.AutoML/API/ExperimentSettings.cs index 4ff9df0bae..8b54f697c4 100644 --- a/src/Microsoft.ML.AutoML/API/ExperimentSettings.cs +++ b/src/Microsoft.ML.AutoML/API/ExperimentSettings.cs @@ -2,7 +2,6 @@ // 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.IO; using System.Threading; namespace Microsoft.ML.AutoML diff --git a/src/Microsoft.ML.AutoML/CodeGen/apply_onnx_search_space.json b/src/Microsoft.ML.AutoML/CodeGen/apply_onnx_search_space.json new file mode 100644 index 0000000000..8cddde3c64 --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/apply_onnx_search_space.json @@ -0,0 +1,27 @@ +{ + "$schema": "./search-space-schema.json#", + "name": "apply_onnx_model_option", + "search_space": [ + { + "name": "ModelFile", + "type": "string" + }, + { + "name": "GpuDeviceId", + "type": "integer" + }, + { + "name": "FallbackToCpu", + "type": "boolean", + "default": false + }, + { + "name": "OutputColumnName", + "type": "string" + }, + { + "name": "InputColumnName", + "type": "string" + } + ] +} diff --git a/src/Microsoft.ML.AutoML/CodeGen/code_gen_flag.json b/src/Microsoft.ML.AutoML/CodeGen/code_gen_flag.json new file mode 100644 index 0000000000..477ae9aa07 --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/code_gen_flag.json @@ -0,0 +1,7 @@ +{ + "EstimatorFactoryGenerator": false, + "CodeGenCatalogGenerator": false, + "EstimatorTypeGenerator": false, + "SearchSpaceGenerator": true, + "SweepableEstimatorGenerator": false +} diff --git a/src/Microsoft.ML.AutoML/CodeGen/concat_search_space.json b/src/Microsoft.ML.AutoML/CodeGen/concat_search_space.json new file mode 100644 index 0000000000..6f98a3069c --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/concat_search_space.json @@ -0,0 +1,14 @@ +{ + "$schema": "./search-space-schema.json#", + "name": "concat_option", + "search_space": [ + { + "name": "InputColumnNames", + "type": "strings" + }, + { + "name": "OutputColumnName", + "type": "string" + } + ] +} diff --git a/src/Microsoft.ML.AutoML/CodeGen/extra_pixels_search_space.json b/src/Microsoft.ML.AutoML/CodeGen/extra_pixels_search_space.json new file mode 100644 index 0000000000..bad9158a0f --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/extra_pixels_search_space.json @@ -0,0 +1,30 @@ +{ + "$schema": "./search-space-schema.json#", + "name": "extract_pixels_option", + "search_space": [ + { + "name": "OutputColumnName", + "type": "string", + "default": "Output" + }, + { + "name": "InputColumnName", + "type": "string" + }, + { + "name": "ColorsToExtract", + "type": "colorBits", + "default": "ColorBits.Rgb" + }, + { + "name": "OrderOfExtraction", + "type": "colorsOrder", + "default": "ColorsOrder.ARGB" + }, + { + "name": "OutputAsFloatArray", + "type": "boolean", + "default": true + } + ] +} diff --git a/src/Microsoft.ML.AutoML/CodeGen/fast_forest_search_space.json b/src/Microsoft.ML.AutoML/CodeGen/fast_forest_search_space.json new file mode 100644 index 0000000000..4e5cf1536b --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/fast_forest_search_space.json @@ -0,0 +1,50 @@ +{ + "$schema": "./search-space-schema.json#", + "name": "fast_forest_option", + "search_space": [ + { + "name": "NumberOfTrees", + "type": "integer", + "default": 4, + "search_space": { + "min": 4, + "max": 32768, + "log_base": true + } + }, + { + "name": "NumberOfLeaves", + "type": "integer", + "default": 4, + "search_space": { + "min": 4, + "max": 32768, + "log_base": true + } + }, + { + "name": "FeatureFraction", + "type": "float", + "default": 1, + "search_space": { + "min": 2e-10, + "max": 1, + "log_base": false + } + }, + { + "name": "LabelColumnName", + "type": "string", + "default": "Label" + }, + { + "name": "FeatureColumnName", + "type": "string", + "default": "Feature" + }, + { + "name": "ExampleWeightColumnName", + "type": "string" + } + ] +} diff --git a/src/Microsoft.ML.AutoML/CodeGen/fast_tree_search_space.json b/src/Microsoft.ML.AutoML/CodeGen/fast_tree_search_space.json new file mode 100644 index 0000000000..0a3af2790e --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/fast_tree_search_space.json @@ -0,0 +1,80 @@ +{ + "$schema": "./search-space-schema.json#", + "name": "fast_tree_option", + "search_space": [ + { + "name": "NumberOfLeaves", + "type": "integer", + "default": 4, + "search_space": { + "log_base": true, + "min": 4, + "max": 32768 + } + }, + { + "name": "MinimumExampleCountPerLeaf", + "type": "integer", + "default": 20, + "search_space": { + "log_base": true, + "min": 2, + "max": 128 + } + }, + { + "name": "NumberOfTrees", + "type": "integer", + "default": 4, + "search_space": { + "min": 4, + "max": 32768, + "log_base": true + } + }, + { + "name": "MaximumBinCountPerFeature", + "type": "integer", + "default": 256, + "search_space": { + "min": 8, + "max": 1024, + "log_base": true + } + }, + { + "name": "FeatureFraction", + "type": "double", + "default": 1, + "search_space": { + "min": 2e-10, + "max": 1, + "log_base": false + } + }, + { + "name": "LearningRate", + "type": "double", + "default": 0.1, + "search_space": { + "min": 2e-10, + "max": 1, + "log_base": true + } + }, + { + "name": "LabelColumnName", + "type": "string", + "default": "Label" + }, + { + "name": "FeatureColumnName", + "type": "string", + "default": "Feature" + }, + { + "name": "ExampleWeightColumnName", + "type": "string" + } + ] +} diff --git a/src/Microsoft.ML.AutoML/CodeGen/featurize_text_search_space.json b/src/Microsoft.ML.AutoML/CodeGen/featurize_text_search_space.json new file mode 100644 index 0000000000..aaca712c65 --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/featurize_text_search_space.json @@ -0,0 +1,14 @@ +{ + "$schema": "./search-space-schema.json#", + "name": "featurize_text_option", + "search_space": [ + { + "name": "InputColumnName", + "type": "string" + }, + { + "name": "OutputColumnName", + "type": "string" + } + ] +} diff --git a/src/Microsoft.ML.AutoML/CodeGen/image_classification_search_space.json b/src/Microsoft.ML.AutoML/CodeGen/image_classification_search_space.json new file mode 100644 index 0000000000..0359ff78d0 --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/image_classification_search_space.json @@ -0,0 +1,21 @@ +{ + "$schema": "./search-space-schema.json#", + "name": "image_classification_option", + "search_space": [ + { + "name": "LabelColumnName", + "type": "string", + "default": "Label" + }, + { + "name": "ScoreColumnName", + "type": "string", + "default": "Score" + }, + { + "name": "FeatureColumnName", + "type": "string", + "default": "Feature" + } + ] +} diff --git a/src/Microsoft.ML.AutoML/CodeGen/lbfgs_search_space.json b/src/Microsoft.ML.AutoML/CodeGen/lbfgs_search_space.json new file mode 100644 index 0000000000..1aa3702448 --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/lbfgs_search_space.json @@ -0,0 +1,40 @@ +{ + "$schema": "./search-space-schema.json#", + "name": "lbfgs_option", + "search_space": [ + { + "name": "L1Regularization", + "type": "float", + "default": 1, + "search_space": { + "min": 0.03125, + "max": 32768, + "log_base": true + } + }, + { + "name": "L2Regularization", + "type": "float", + "default": 1, + "search_space": { + "min": 0.03125, + "max": 32768, + "log_base": true + } + }, + { + "name": "LabelColumnName", + "type": "string", + "default": "Label" + }, + { + "name": "FeatureColumnName", + "type": "string", + "default": "Feature" + }, + { + "name": "ExampleWeightColumnName", + "type": "string" + } + ] +} diff --git a/src/Microsoft.ML.AutoML/CodeGen/lgbm_search_space.json b/src/Microsoft.ML.AutoML/CodeGen/lgbm_search_space.json new file mode 100644 index 0000000000..2794e3c961 --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/lgbm_search_space.json @@ -0,0 +1,110 @@ +{ + "$schema": "./search-space-schema.json#", + "name": "lgbm_option", + "search_space": [ + { + "name": "NumberOfLeaves", + "type": "integer", + "default": 4, + "search_space": { + "log_base": true, + "max": 32768, + "min": 4 + } + }, + { + "name": "MinimumExampleCountPerLeaf", + "type": "integer", + "default": 20, + "search_space": { + "min": 20, + "max": 1024, + "log_base": true + } + }, + { + "name": "LearningRate", + "type": "double", + "default": 1, + "search_space": { + "min": 2e-10, + "max": 1, + "log_base": true + } + }, + { + "name": "NumberOfTrees", + "type": "integer", + "default": 4, + "search_space": { + "min": 4, + "max": 32768, + "log_base": true + } + }, + { + "name": "SubsampleFraction", + "type": "double", + "default": 1, + "search_space": { + "min": 2e-10, + "max": 1, + "log_base": true + } + }, + { + "name": "MaximumBinCountPerFeature", + "type": "integer", + "default": 256, + "search_space": { + "min": 8, + "max": 1024, + "log_base": true + } + }, + { + "name": "FeatureFraction", + "type": "double", + "default": 1, + "search_space": { + "min": 2e-10, + "max": 1, + "log_base": false + } + }, + { + "name": "L1Regularization", + "type": "double", + "default": 2e-10, + "search_space": { + "min": 2e-10, + "max": 1, + "log_base": true + } + }, + { + "name": "L2Regularization", + "type": "double", + "default": 1, + "search_space": { + "min": 2e-10, + "max": 1, + "log_base": true + } + }, + { + "name": "LabelColumnName", + "type": "string", + "default": "Label" + }, + { + "name": "FeatureColumnName", + "type": "string", + "default": "Feature" + }, + { + "name": "ExampleWeightColumnName", + "type": "string" + } + ] +} diff --git a/src/Microsoft.ML.AutoML/CodeGen/load_image_search_space.json b/src/Microsoft.ML.AutoML/CodeGen/load_image_search_space.json new file mode 100644 index 0000000000..2ef8ba27af --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/load_image_search_space.json @@ -0,0 +1,19 @@ +{ + "$schema": "./search-space-schema.json#", + "name": "load_image_option", + "search_space": [ + { + "name": "OutputColumnName", + "type": "string", + "default": "Output" + }, + { + "name": "ImageFolder", + "type": "string" + }, + { + "name": "InputColumnName", + "type": "string" + } + ] +} diff --git a/src/Microsoft.ML.AutoML/CodeGen/map_key_to_value_search_space.json b/src/Microsoft.ML.AutoML/CodeGen/map_key_to_value_search_space.json new file mode 100644 index 0000000000..2c1b988a3b --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/map_key_to_value_search_space.json @@ -0,0 +1,14 @@ +{ + "$schema": "./search-space-schema.json#", + "name": "map_key_to_value_option", + "search_space": [ + { + "name": "OutputColumnName", + "type": "string" + }, + { + "name": "InputColumnName", + "type": "string" + } + ] +} diff --git a/src/Microsoft.ML.AutoML/CodeGen/map_value_to_key_search_space.json b/src/Microsoft.ML.AutoML/CodeGen/map_value_to_key_search_space.json new file mode 100644 index 0000000000..6b52fa5bb4 --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/map_value_to_key_search_space.json @@ -0,0 +1,14 @@ +{ + "$schema": "./search-space-schema.json#", + "name": "map_value_to_key_option", + "search_space": [ + { + "name": "OutputColumnName", + "type": "string" + }, + { + "name": "InputColumnName", + "type": "string" + } + ] +} diff --git a/src/Microsoft.ML.AutoML/CodeGen/matrix_factorization_search_space.json b/src/Microsoft.ML.AutoML/CodeGen/matrix_factorization_search_space.json new file mode 100644 index 0000000000..af2302d06b --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/matrix_factorization_search_space.json @@ -0,0 +1,54 @@ +{ + "$schema": "./search-space-schema.json#", + "name": "matrix_factorization_option", + "search_space": [ + { + "name": "LabelColumnName", + "type": "string", + "default": "Label" + }, + { + "name": "MatrixColumnIndexColumnName", + "type": "string" + }, + { + "name": "MatrixRowIndexColumnName", + "type": "string" + }, + { + "name": "ApproximationRank", + "type": "integer", + "default": 20, + "search_space": { + "min": 10, + "max": 32768, + "log_base": true + } + }, + { + "name": "LearningRate", + "type": "double", + "default": 1, + "search_space": { + "min": 2e-10, + "max": 1, + "log_base": true + } + }, + { + "name": "NumberOfIterations", + "type": "integer", + "default": 128, + "search_space": { + "min": 4, + "max": 32768, + "log_base": true + } + }, + { + "name": "Quiet", + "type": "boolean", + "default": true + } + ] +} diff --git a/src/Microsoft.ML.AutoML/CodeGen/naive_search_space.json b/src/Microsoft.ML.AutoML/CodeGen/naive_search_space.json new file mode 100644 index 0000000000..34faad6b26 --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/naive_search_space.json @@ -0,0 +1,16 @@ +{ + "$schema": "./search-space-schema.json#", + "name": "naive_option", + "search_space": [ + { + "name": "LabelColumnName", + "type": "string", + "default": "Label" + }, + { + "name": "ScoreColumnName", + "type": "string", + "default": "Score" + } + ] +} diff --git a/src/Microsoft.ML.AutoML/CodeGen/normalize_min_max_search_space.json b/src/Microsoft.ML.AutoML/CodeGen/normalize_min_max_search_space.json new file mode 100644 index 0000000000..980d01a534 --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/normalize_min_max_search_space.json @@ -0,0 +1,14 @@ +{ + "$schema": "./search-space-schema.json#", + "name": "normalize_min_max_option", + "search_space": [ + { + "name": "OutputColumnNames", + "type": "strings" + }, + { + "name": "InputColumnNames", + "type": "strings" + } + ] +} diff --git a/src/Microsoft.ML.AutoML/CodeGen/onehot_encoding_search_space.json b/src/Microsoft.ML.AutoML/CodeGen/onehot_encoding_search_space.json new file mode 100644 index 0000000000..e018023484 --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/onehot_encoding_search_space.json @@ -0,0 +1,14 @@ +{ + "$schema": "./search-space-schema.json#", + "name": "one_hot_option", + "search_space": [ + { + "name": "OutputColumnNames", + "type": "strings" + }, + { + "name": "InputColumnNames", + "type": "strings" + } + ] +} diff --git a/src/Microsoft.ML.AutoML/CodeGen/replace_missing_value_search_space.json b/src/Microsoft.ML.AutoML/CodeGen/replace_missing_value_search_space.json new file mode 100644 index 0000000000..a633061160 --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/replace_missing_value_search_space.json @@ -0,0 +1,14 @@ +{ + "$schema": "./search-space-schema.json#", + "name": "replace_missing_value_option", + "search_space": [ + { + "name": "OutputColumnNames", + "type": "strings" + }, + { + "name": "InputColumnNames", + "type": "strings" + } + ] +} diff --git a/src/Microsoft.ML.AutoML/CodeGen/resize_image_search_space.json b/src/Microsoft.ML.AutoML/CodeGen/resize_image_search_space.json new file mode 100644 index 0000000000..128fdbab3e --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/resize_image_search_space.json @@ -0,0 +1,35 @@ +{ + "$schema": "./search-space-schema.json#", + "name": "resize_image_option", + "search_space": [ + { + "name": "OutputColumnName", + "type": "string", + "default": "Output" + }, + { + "name": "InputColumnName", + "type": "string" + }, + { + "name": "ImageHeight", + "type": "integer", + "default": 225 + }, + { + "name": "ImageWidth", + "type": "integer", + "default": 225 + }, + { + "name": "CropAnchor", + "type": "anchor", + "default": "Anchor.Center" + }, + { + "name": "Resizing", + "type": "resizingKind", + "default": "ResizingKind.Fill" + } + ] +} diff --git a/src/Microsoft.ML.AutoML/CodeGen/sdca_search_space.json b/src/Microsoft.ML.AutoML/CodeGen/sdca_search_space.json new file mode 100644 index 0000000000..a87bd47193 --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/sdca_search_space.json @@ -0,0 +1,40 @@ +{ + "$schema": "./search-space-schema.json#", + "name": "sdca_option", + "search_space": [ + { + "name": "L1Regularization", + "type": "float", + "default": 1, + "search_space": { + "min": 0.03125, + "max": 32768, + "log_base": true + } + }, + { + "name": "L2Regularization", + "type": "float", + "default": 0.1, + "search_space": { + "min": 0.03125, + "max": 32768, + "log_base": true + } + }, + { + "name": "LabelColumnName", + "type": "string", + "default": "Label" + }, + { + "name": "FeatureColumnName", + "type": "string", + "default": "Feature" + }, + { + "name": "ExampleWeightColumnName", + "type": "string" + } + ] +} diff --git a/src/Microsoft.ML.AutoML/CodeGen/search-space-schema.json b/src/Microsoft.ML.AutoML/CodeGen/search-space-schema.json new file mode 100644 index 0000000000..224ea9a375 --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/search-space-schema.json @@ -0,0 +1,163 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema", + "title": "Search Space", + "definitions": { + "range": { + "type": "object", + "properties": { + "min": { "type": "number" }, + "max": { "type": "number" }, + "log_base": { "type": "boolean" } + }, + "required": [ "min", "max" ] + }, + "choice": { + "type": "object", + "properties": { + "value": { + "oneOf": [ + { "type": "string" }, + { "type": "number" }, + { "type": "integer" }, + { "type": "boolean" } + ] + } + }, + "required": [ "value" ] + }, + "option": { + "type": "object", + "properties": { + "name": { + "$ref": "#/definitions/option_name" + }, + "type": { + "$ref": "#/definitions/option_type" + }, + "default": { + "oneOf": [ + { "type": "string" }, + { "type": "number" }, + { "type": "boolean" } + ] + }, + "search_space": { + "oneOf": [ + { "$ref": "#/definitions/range" }, + { "$ref": "#/definitions/choice" }, + { "$ref": "#/definitions/nest_search_space" } + ] + } + }, + "required": [ "name", "type" ] + }, + "nest_search_space": { + "type": "array", + "items": { + "$ref": "#/definitions/option" + }, + "minItems": 1 + }, + "search_space_name": { + "type": "string", + "enum": [ + "lgbm_option", + "fast_tree_option", + "fast_forest_option", + "lbfgs_option", + "sdca_option", + "ssa_option", + "concat_option", + "naive_option", + "one_hot_option", + "one_hot_hash_option", + "load_raw_image_byte_option", + "copy_columns_option", + "hash_option", + "map_key_to_value_option", + "indicate_missing_value_option", + "replace_missing_value_option", + "normalize_min_max_option", + "featurize_text_option", + "convert_type_option", + "map_value_to_key_option", + "apply_onnx_model_option", + "resize_image_option", + "extract_pixels_option", + "load_image_option", + "image_classification_option", + "matrix_factorization_option" + ] + }, + "option_name": { + "type": "string", + "enum": [ + "NumberOfLeaves", + "MinimumExampleCountPerLeaf", + "LearningRate", + "NumberOfTrees", + "SubsampleFraction", + "MaximumBinCountPerFeature", + "FeatureFraction", + "L1Regularization", + "L2Regularization", + "LabelColumnName", + "FeatureColumnName", + "ExampleWeightColumnName", + "WindowSize", + "SeriesLength", + "TrainSize", + "Horizon", + "OutputColumnName", + "OutputColumnNames", + "InputColumnName", + "ConfidenceLowerBoundColumn", + "ConfidenceUpperBoundColumn", + "InputColumnNames", + "ModelFile", + "GpuDeviceId", + "FallbackToCpu", + "ScoreColumnName", + "ImageFolder", + "ImageWidth", + "ImageHeight", + "CropAnchor", + "Resizing", + "ColorsToExtract", + "OrderOfExtraction", + "MatrixColumnIndexColumnName", + "MatrixRowIndexColumnName", + "ApproximationRank", + "NumberOfIterations", + "Quiet", + "OutputAsFloatArray" + ] + }, + "option_type": { + "type": "string", + "enum": [ + "integer", + "float", + "double", + "string", + "strings", + "boolean", + "resizingKind", + "colorBits", + "colorsOrder", + "anchor" + ] + } + }, + + "type": "object", + "properties": { + "name": { + "$ref": "#/definitions/search_space_name" + }, + "search_space": { + "$ref": "#/definitions/nest_search_space" + } + }, + "required": [ "name", "search_space" ] +} diff --git a/src/Microsoft.ML.AutoML/CodeGen/ssa_search_space.json b/src/Microsoft.ML.AutoML/CodeGen/ssa_search_space.json new file mode 100644 index 0000000000..05e6c97ffb --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/ssa_search_space.json @@ -0,0 +1,52 @@ +{ + "$schema": "./search-space-schema.json#", + "name": "ssa_option", + "search_space": [ + { + "name": "WindowSize", + "type": "integer", + "default": 2, + "search_space": { + "min": 2, + "max": 32768, + "log_base": false + } + }, + { + "name": "SeriesLength", + "type": "integer", + "default": 10, + "search_space": { + "min": 2, + "max": 32768, + "log_base": false + } + }, + { + "name": "TrainSize", + "type": "integer", + "default": 100 + }, + { + "name": "Horizon", + "type": "integer", + "default": 10 + }, + { + "name": "OutputColumnName", + "type": "string" + }, + { + "name": "InputColumnName", + "type": "string" + }, + { + "name": "ConfidenceLowerBoundColumn", + "type": "string" + }, + { + "name": "ConfidenceUpperBoundColumn", + "type": "string" + } + ] +} diff --git a/src/Microsoft.ML.AutoML/CodeGen/type_converter_search_space.json b/src/Microsoft.ML.AutoML/CodeGen/type_converter_search_space.json new file mode 100644 index 0000000000..d91293b857 --- /dev/null +++ b/src/Microsoft.ML.AutoML/CodeGen/type_converter_search_space.json @@ -0,0 +1,14 @@ +{ + "$schema": "./search-space-schema.json#", + "name": "convert_type_option", + "search_space": [ + { + "name": "OutputColumnNames", + "type": "strings" + }, + { + "name": "InputColumnNames", + "type": "strings" + } + ] +} diff --git a/src/Microsoft.ML.AutoML/ColumnInference/ColumnGroupingInference.cs b/src/Microsoft.ML.AutoML/ColumnInference/ColumnGroupingInference.cs index 0f6b6e3c2d..a7c89f7875 100644 --- a/src/Microsoft.ML.AutoML/ColumnInference/ColumnGroupingInference.cs +++ b/src/Microsoft.ML.AutoML/ColumnInference/ColumnGroupingInference.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using Microsoft.ML.Data; using static Microsoft.ML.Data.TextLoader; diff --git a/src/Microsoft.ML.AutoML/EstimatorExtensions/EstimatorExtensions.cs b/src/Microsoft.ML.AutoML/EstimatorExtensions/EstimatorExtensions.cs index ff8fac6766..394336e6c1 100644 --- a/src/Microsoft.ML.AutoML/EstimatorExtensions/EstimatorExtensions.cs +++ b/src/Microsoft.ML.AutoML/EstimatorExtensions/EstimatorExtensions.cs @@ -3,8 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using Microsoft.ML.Data; -using Microsoft.ML.Transforms; namespace Microsoft.ML.AutoML { diff --git a/src/Microsoft.ML.AutoML/Experiment/Runners/CrossValRunner.cs b/src/Microsoft.ML.AutoML/Experiment/Runners/CrossValRunner.cs index 84ca684bb5..402a6dd974 100644 --- a/src/Microsoft.ML.AutoML/Experiment/Runners/CrossValRunner.cs +++ b/src/Microsoft.ML.AutoML/Experiment/Runners/CrossValRunner.cs @@ -2,7 +2,6 @@ // 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; using System.Collections.Generic; using System.IO; using System.Linq; diff --git a/src/Microsoft.ML.AutoML/Experiment/SuggestedTrainer.cs b/src/Microsoft.ML.AutoML/Experiment/SuggestedTrainer.cs index 08a48c7ae2..ae1c98b242 100644 --- a/src/Microsoft.ML.AutoML/Experiment/SuggestedTrainer.cs +++ b/src/Microsoft.ML.AutoML/Experiment/SuggestedTrainer.cs @@ -2,7 +2,6 @@ // 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; using System.Collections.Generic; using System.Linq; using Microsoft.ML.Trainers; diff --git a/src/Microsoft.ML.AutoML/Microsoft.ML.AutoML.csproj b/src/Microsoft.ML.AutoML/Microsoft.ML.AutoML.csproj index 83d749800c..7a87c44ac7 100644 --- a/src/Microsoft.ML.AutoML/Microsoft.ML.AutoML.csproj +++ b/src/Microsoft.ML.AutoML/Microsoft.ML.AutoML.csproj @@ -5,25 +5,49 @@ netstandard2.0 Microsoft.ML.AutoML ML.NET AutoML: Optimizes an ML pipeline for your dataset, by automatically locating the best feature engineering, model, and hyperparameters + $(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage - + + all + + all + true + - + all - + all + + + + + + + + + + + + + + + + + + diff --git a/src/Microsoft.ML.AutoML/PipelineSuggesters/PipelineSuggester.cs b/src/Microsoft.ML.AutoML/PipelineSuggesters/PipelineSuggester.cs index fece093026..ccdcdbec7b 100644 --- a/src/Microsoft.ML.AutoML/PipelineSuggesters/PipelineSuggester.cs +++ b/src/Microsoft.ML.AutoML/PipelineSuggesters/PipelineSuggester.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Microsoft.ML.Data; using Microsoft.ML.Internal.Utilities; using Microsoft.ML.Runtime; diff --git a/src/Microsoft.ML.AutoML/TrainerExtensions/MultiTrainerExtensions.cs b/src/Microsoft.ML.AutoML/TrainerExtensions/MultiTrainerExtensions.cs index d5643f79ff..8a18ce2e0b 100644 --- a/src/Microsoft.ML.AutoML/TrainerExtensions/MultiTrainerExtensions.cs +++ b/src/Microsoft.ML.AutoML/TrainerExtensions/MultiTrainerExtensions.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using Microsoft.ML.Data; -using Microsoft.ML.Runtime; using Microsoft.ML.Trainers; using Microsoft.ML.Trainers.FastTree; using Microsoft.ML.Trainers.LightGbm; diff --git a/src/Microsoft.ML.AutoML/TransformInference/TransformInference.cs b/src/Microsoft.ML.AutoML/TransformInference/TransformInference.cs index 1d3384dd54..8a9bbbc728 100644 --- a/src/Microsoft.ML.AutoML/TransformInference/TransformInference.cs +++ b/src/Microsoft.ML.AutoML/TransformInference/TransformInference.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Text; using Microsoft.ML.Data; -using Microsoft.ML.Transforms; namespace Microsoft.ML.AutoML { diff --git a/src/Microsoft.ML.AutoML/TransformInference/TransformInferenceApi.cs b/src/Microsoft.ML.AutoML/TransformInference/TransformInferenceApi.cs index 4843f6ef7e..7fadcded71 100644 --- a/src/Microsoft.ML.AutoML/TransformInference/TransformInferenceApi.cs +++ b/src/Microsoft.ML.AutoML/TransformInference/TransformInferenceApi.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using Microsoft.ML.Data; namespace Microsoft.ML.AutoML { diff --git a/src/Microsoft.ML.SearchSpace/Microsoft.ML.SearchSpace.csproj b/src/Microsoft.ML.SearchSpace/Microsoft.ML.SearchSpace.csproj index 022510e78a..0eb3260f6b 100644 --- a/src/Microsoft.ML.SearchSpace/Microsoft.ML.SearchSpace.csproj +++ b/src/Microsoft.ML.SearchSpace/Microsoft.ML.SearchSpace.csproj @@ -2,6 +2,7 @@ netstandard2.0 + Microsoft.ML.AutoML true MSML_ContractsCheckMessageNotLiteralOrIdentifier 9.0 diff --git a/tools-local/Microsoft.ML.AutoML.SourceGenerator/Constant.cs b/tools-local/Microsoft.ML.AutoML.SourceGenerator/Constant.cs new file mode 100644 index 0000000000..055eda2500 --- /dev/null +++ b/tools-local/Microsoft.ML.AutoML.SourceGenerator/Constant.cs @@ -0,0 +1,11 @@ +// 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. + +namespace Microsoft.ML.AutoML.SourceGenerator +{ + internal class Constant + { + public const string CodeGeneratorNameSpace = "Microsoft.ML.AutoML.CodeGen"; + } +} diff --git a/tools-local/Microsoft.ML.AutoML.SourceGenerator/Microsoft.ML.AutoML.SourceGenerator.csproj b/tools-local/Microsoft.ML.AutoML.SourceGenerator/Microsoft.ML.AutoML.SourceGenerator.csproj new file mode 100644 index 0000000000..2c1c9cb675 --- /dev/null +++ b/tools-local/Microsoft.ML.AutoML.SourceGenerator/Microsoft.ML.AutoML.SourceGenerator.csproj @@ -0,0 +1,44 @@ + + + + netstandard2.0 + 9.0 + $(GetTargetPathDependsOn);GetDependencyTargetPaths + false + + + + + + + + + + + + + + + + + + + + + + + + True + True + SearchSpace.tt + + + + + + TextTemplatingFilePreprocessor + SearchSpace.cs + + + + diff --git a/tools-local/Microsoft.ML.AutoML.SourceGenerator/SearchSpaceGenerator.cs b/tools-local/Microsoft.ML.AutoML.SourceGenerator/SearchSpaceGenerator.cs new file mode 100644 index 0000000000..b36702c074 --- /dev/null +++ b/tools-local/Microsoft.ML.AutoML.SourceGenerator/SearchSpaceGenerator.cs @@ -0,0 +1,137 @@ +// 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; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Nodes; +using Microsoft.CodeAnalysis; +using Microsoft.ML.AutoML.SourceGenerator.Template; + +namespace Microsoft.ML.AutoML.SourceGenerator +{ + [Generator] + public class SearchSpaceGenerator : ISourceGenerator + { + public void Execute(GeneratorExecutionContext context) + { + if (context.AdditionalFiles.Where(f => f.Path.Contains("code_gen_flag.json")).First() is AdditionalText text) + { + var json = text.GetText().ToString(); + var flags = JsonSerializer.Deserialize>(json); + if (flags.TryGetValue(nameof(SearchSpaceGenerator), out var res) && res == false) + { + return; + } + } + + var searchSpacesJson = context.AdditionalFiles.Where(f => f.Path.Contains("search_space.json")) + .Select(f => f.GetText().ToString()) + .ToArray(); + var searchSpacesJNodes = searchSpacesJson.Select(x => JsonNode.Parse(x)); + + foreach (var jNode in searchSpacesJNodes) + { + var className = Utils.ToTitleCase(jNode["name"].GetValue()); + var searchSpaceJArray = jNode["search_space"].AsArray(); + var options = searchSpaceJArray.Select(t => + { + var optionName = Utils.ToTitleCase(t["name"].GetValue()); + string optionTypeName = t["type"].GetValue() switch + { + "integer" => "int", + "float" => "float", + "double" => "double", + "string" => "string", + "boolean" => "bool", + "strings" => "string[]", + "resizingKind" => "ResizingKind", + "anchor" => "Anchor", + "colorBits" => "ColorBits", + "colorsOrder" => "ColorsOrder", + _ => throw new ArgumentException("unknown type"), + }; + + var defaultToken = t.AsObject().ContainsKey("default") ? t["default"] : null; + string optionDefaultValue = (defaultToken, optionTypeName) switch + { + (null, _) => string.Empty, + (_, "string") => $"\"{defaultToken.GetValue()}\"", + (_, "int") => $"{defaultToken.GetValue().ToString(CultureInfo.InvariantCulture)}", + (_, "double") => $"{defaultToken.GetValue().ToString(CultureInfo.InvariantCulture)}", + (_, "float") => $"{defaultToken.GetValue().ToString(CultureInfo.InvariantCulture)}F", + (_, "bool") => defaultToken.GetValue() ? "true" : "false", + (_, "Anchor") => defaultToken.GetValue(), + (_, "ResizingKind") => defaultToken.GetValue(), + (_, "ColorBits") => defaultToken.GetValue(), + (_, "ColorsOrder") => defaultToken.GetValue(), + (_, _) => throw new ArgumentException("unknown"), + }; + + var searchSpaceNode = t.AsObject().ContainsKey("search_space") ? t["search_space"] : null; + string optionAttribution = null; + if (searchSpaceNode is null) + { + // default option + optionAttribution = string.Empty; + } + else + { + var searchSpaceObject = searchSpaceNode.AsObject(); + if (searchSpaceObject.ContainsKey("min")) + { + // range option + var minToken = searchSpaceNode["min"]; + var minValue = searchSpaceNode["min"].GetValue(); + var maxValue = searchSpaceNode["max"].GetValue(); + var logBase = searchSpaceObject.ContainsKey("log_base") is false ? "false" : searchSpaceNode["log_base"].GetValue() ? "true" : "false"; + optionAttribution = (optionTypeName, minValue, maxValue, logBase, optionDefaultValue) switch + { + ("int", _, _, _, null) => $"Range((int){Convert.ToInt32(minValue).ToString(CultureInfo.InvariantCulture)}, (int){Convert.ToInt32(maxValue).ToString(CultureInfo.InvariantCulture)}, logBase: {logBase.ToString(CultureInfo.InvariantCulture)})", + ("float", _, _, _, null) => $"Range((float){Convert.ToSingle(minValue).ToString(CultureInfo.InvariantCulture)}, (float){Convert.ToSingle(maxValue).ToString(CultureInfo.InvariantCulture)}, logBase: {logBase.ToString(CultureInfo.InvariantCulture)})", + ("double", _, _, _, null) => $"Range((double){minValue.ToString(CultureInfo.InvariantCulture)}, (double){maxValue.ToString(CultureInfo.InvariantCulture)}, logBase: {logBase.ToString(CultureInfo.InvariantCulture)})", + ("int", _, _, _, _) => $"Range((int){Convert.ToInt32(minValue).ToString(CultureInfo.InvariantCulture)}, (int){Convert.ToInt32(maxValue).ToString(CultureInfo.InvariantCulture)}, init: (int){optionDefaultValue.ToString(CultureInfo.InvariantCulture)}, logBase: {logBase.ToString(CultureInfo.InvariantCulture)})", + ("float", _, _, _, _) => $"Range((float){Convert.ToSingle(minValue).ToString(CultureInfo.InvariantCulture)}, (float){Convert.ToSingle(maxValue).ToString(CultureInfo.InvariantCulture)}, init: (float){optionDefaultValue.ToString(CultureInfo.InvariantCulture)}, logBase: {logBase.ToString(CultureInfo.InvariantCulture)})", + ("double", _, _, _, _) => $"Range((double){minValue.ToString(CultureInfo.InvariantCulture)}, (double){maxValue.ToString(CultureInfo.InvariantCulture)}, init: (double){optionDefaultValue.ToString(CultureInfo.InvariantCulture)}, logBase: {logBase.ToString(CultureInfo.InvariantCulture)})", + _ => throw new NotImplementedException(), + }; + optionAttribution = $"[{optionAttribution}]"; + } + else + { + // choice option + var values = searchSpaceNode["value"].GetValue(); + var valuesParam = optionTypeName switch + { + "int" => $"new object[]{{ {string.Join(",", values)} }}", + "boolean" => $"new object[]{{ {string.Join(",", values)} }}", + "string" => $"new object[]{{ {string.Join(",", values.Select(x => $"\"{x}\""))} }}", + _ => throw new NotImplementedException("only support int|boolean|string"), + }; + + optionAttribution = optionDefaultValue == null ? $"[Choice({valuesParam})]" : $"[Choice({valuesParam}, {optionDefaultValue})]"; + } + } + + return (optionTypeName, optionName, optionAttribution, optionDefaultValue); + }); + + var code = new SearchSpace() + { + NameSpace = Constant.CodeGeneratorNameSpace, + ClassName = className, + Properties = options, + }.TransformText(); + + context.AddSource($"{className}.cs", code); + } + } + + public void Initialize(GeneratorInitializationContext context) + { + } + } +} diff --git a/tools-local/Microsoft.ML.AutoML.SourceGenerator/Template/SearchSpace.cs b/tools-local/Microsoft.ML.AutoML.SourceGenerator/Template/SearchSpace.cs new file mode 100644 index 0000000000..141ffeff1e --- /dev/null +++ b/tools-local/Microsoft.ML.AutoML.SourceGenerator/Template/SearchSpace.cs @@ -0,0 +1,347 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version: 17.0.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ +namespace Microsoft.ML.AutoML.SourceGenerator.Template +{ + using System.Linq; + using System.Text; + using System.Collections.Generic; + using System; + + /// + /// Class to produce the template output + /// + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")] + internal partial class SearchSpace : SearchSpaceBase + { + /// + /// Create the template output + /// + public virtual string TransformText() + { + this.Write(@" +using Microsoft.ML.SearchSpace; +using OptionAttribute = Microsoft.ML.SearchSpace.OptionAttribute; +using ColorsOrder = Microsoft.ML.Transforms.Image.ImagePixelExtractingEstimator.ColorsOrder; +using ColorBits = Microsoft.ML.Transforms.Image.ImagePixelExtractingEstimator.ColorBits; +using ResizingKind = Microsoft.ML.Transforms.Image.ImageResizingEstimator.ResizingKind; +using Anchor = Microsoft.ML.Transforms.Image.ImageResizingEstimator.Anchor; + +#nullable enable + +namespace "); + this.Write(this.ToStringHelper.ToStringWithCulture(NameSpace)); + this.Write("\r\n{\r\n public class "); + this.Write(this.ToStringHelper.ToStringWithCulture(ClassName)); + this.Write("\r\n {\r\n"); +foreach((var optionType, var optionName, var optionAttribution, var defaultValue) in Properties){ + this.Write(" "); + this.Write(this.ToStringHelper.ToStringWithCulture(optionAttribution)); + this.Write("\r\n"); +if(defaultValue == string.Empty){ + this.Write(" public "); + this.Write(this.ToStringHelper.ToStringWithCulture(optionType)); + this.Write("? "); + this.Write(this.ToStringHelper.ToStringWithCulture(optionName)); + this.Write(" {get; set;}\r\n"); +}else{ + this.Write(" [System.Diagnostics.CodeAnalysis.SuppressMessage(\"Declaration\", \"MSML_NoI" + + "nstanceInitializers:No initializers on instance fields or properties\")]\r\n " + + " public "); + this.Write(this.ToStringHelper.ToStringWithCulture(optionType)); + this.Write(" "); + this.Write(this.ToStringHelper.ToStringWithCulture(optionName)); + this.Write(" {get; set;} = "); + this.Write(this.ToStringHelper.ToStringWithCulture(defaultValue)); + this.Write(";\r\n"); +} + this.Write("\r\n"); +} + this.Write("\r\n }\r\n}\r\n\r\n"); + return this.GenerationEnvironment.ToString(); + } + +public string NameSpace {get;set;} +public string ClassName {get;set;} +public IEnumerable<(string, string, string, string)> Properties {get; set;} + + } + #region Base class + /// + /// Base class for this transformation + /// + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TextTemplating", "17.0.0.0")] + internal class SearchSpaceBase + { + #region Fields + private global::System.Text.StringBuilder generationEnvironmentField; + private global::System.CodeDom.Compiler.CompilerErrorCollection errorsField; + private global::System.Collections.Generic.List indentLengthsField; + private string currentIndentField = ""; + private bool endsWithNewline; + private global::System.Collections.Generic.IDictionary sessionField; + #endregion + #region Properties + /// + /// The string builder that generation-time code is using to assemble generated output + /// + protected System.Text.StringBuilder GenerationEnvironment + { + get + { + if ((this.generationEnvironmentField == null)) + { + this.generationEnvironmentField = new global::System.Text.StringBuilder(); + } + return this.generationEnvironmentField; + } + set + { + this.generationEnvironmentField = value; + } + } + /// + /// The error collection for the generation process + /// + public System.CodeDom.Compiler.CompilerErrorCollection Errors + { + get + { + if ((this.errorsField == null)) + { + this.errorsField = new global::System.CodeDom.Compiler.CompilerErrorCollection(); + } + return this.errorsField; + } + } + /// + /// A list of the lengths of each indent that was added with PushIndent + /// + private System.Collections.Generic.List indentLengths + { + get + { + if ((this.indentLengthsField == null)) + { + this.indentLengthsField = new global::System.Collections.Generic.List(); + } + return this.indentLengthsField; + } + } + /// + /// Gets the current indent we use when adding lines to the output + /// + public string CurrentIndent + { + get + { + return this.currentIndentField; + } + } + /// + /// Current transformation session + /// + public virtual global::System.Collections.Generic.IDictionary Session + { + get + { + return this.sessionField; + } + set + { + this.sessionField = value; + } + } + #endregion + #region Transform-time helpers + /// + /// Write text directly into the generated output + /// + public void Write(string textToAppend) + { + if (string.IsNullOrEmpty(textToAppend)) + { + return; + } + // If we're starting off, or if the previous text ended with a newline, + // we have to append the current indent first. + if (((this.GenerationEnvironment.Length == 0) + || this.endsWithNewline)) + { + this.GenerationEnvironment.Append(this.currentIndentField); + this.endsWithNewline = false; + } + // Check if the current text ends with a newline + if (textToAppend.EndsWith(global::System.Environment.NewLine, global::System.StringComparison.CurrentCulture)) + { + this.endsWithNewline = true; + } + // This is an optimization. If the current indent is "", then we don't have to do any + // of the more complex stuff further down. + if ((this.currentIndentField.Length == 0)) + { + this.GenerationEnvironment.Append(textToAppend); + return; + } + // Everywhere there is a newline in the text, add an indent after it + textToAppend = textToAppend.Replace(global::System.Environment.NewLine, (global::System.Environment.NewLine + this.currentIndentField)); + // If the text ends with a newline, then we should strip off the indent added at the very end + // because the appropriate indent will be added when the next time Write() is called + if (this.endsWithNewline) + { + this.GenerationEnvironment.Append(textToAppend, 0, (textToAppend.Length - this.currentIndentField.Length)); + } + else + { + this.GenerationEnvironment.Append(textToAppend); + } + } + /// + /// Write text directly into the generated output + /// + public void WriteLine(string textToAppend) + { + this.Write(textToAppend); + this.GenerationEnvironment.AppendLine(); + this.endsWithNewline = true; + } + /// + /// Write formatted text directly into the generated output + /// + public void Write(string format, params object[] args) + { + this.Write(string.Format(global::System.Globalization.CultureInfo.CurrentCulture, format, args)); + } + /// + /// Write formatted text directly into the generated output + /// + public void WriteLine(string format, params object[] args) + { + this.WriteLine(string.Format(global::System.Globalization.CultureInfo.CurrentCulture, format, args)); + } + /// + /// Raise an error + /// + public void Error(string message) + { + System.CodeDom.Compiler.CompilerError error = new global::System.CodeDom.Compiler.CompilerError(); + error.ErrorText = message; + this.Errors.Add(error); + } + /// + /// Raise a warning + /// + public void Warning(string message) + { + System.CodeDom.Compiler.CompilerError error = new global::System.CodeDom.Compiler.CompilerError(); + error.ErrorText = message; + error.IsWarning = true; + this.Errors.Add(error); + } + /// + /// Increase the indent + /// + public void PushIndent(string indent) + { + if ((indent == null)) + { + throw new global::System.ArgumentNullException("indent"); + } + this.currentIndentField = (this.currentIndentField + indent); + this.indentLengths.Add(indent.Length); + } + /// + /// Remove the last indent that was added with PushIndent + /// + public string PopIndent() + { + string returnValue = ""; + if ((this.indentLengths.Count > 0)) + { + int indentLength = this.indentLengths[(this.indentLengths.Count - 1)]; + this.indentLengths.RemoveAt((this.indentLengths.Count - 1)); + if ((indentLength > 0)) + { + returnValue = this.currentIndentField.Substring((this.currentIndentField.Length - indentLength)); + this.currentIndentField = this.currentIndentField.Remove((this.currentIndentField.Length - indentLength)); + } + } + return returnValue; + } + /// + /// Remove any indentation + /// + public void ClearIndent() + { + this.indentLengths.Clear(); + this.currentIndentField = ""; + } + #endregion + #region ToString Helpers + /// + /// Utility class to produce culture-oriented representation of an object as a string. + /// + public class ToStringInstanceHelper + { + private System.IFormatProvider formatProviderField = global::System.Globalization.CultureInfo.InvariantCulture; + /// + /// Gets or sets format provider to be used by ToStringWithCulture method. + /// + public System.IFormatProvider FormatProvider + { + get + { + return this.formatProviderField ; + } + set + { + if ((value != null)) + { + this.formatProviderField = value; + } + } + } + /// + /// This is called from the compile/run appdomain to convert objects within an expression block to a string + /// + public string ToStringWithCulture(object objectToConvert) + { + if ((objectToConvert == null)) + { + throw new global::System.ArgumentNullException("objectToConvert"); + } + System.Type t = objectToConvert.GetType(); + System.Reflection.MethodInfo method = t.GetMethod("ToString", new System.Type[] { + typeof(System.IFormatProvider)}); + if ((method == null)) + { + return objectToConvert.ToString(); + } + else + { + return ((string)(method.Invoke(objectToConvert, new object[] { + this.formatProviderField }))); + } + } + } + private ToStringInstanceHelper toStringHelperField = new ToStringInstanceHelper(); + /// + /// Helper to produce culture-oriented representation of an object as a string + /// + public ToStringInstanceHelper ToStringHelper + { + get + { + return this.toStringHelperField; + } + } + #endregion + } + #endregion +} diff --git a/tools-local/Microsoft.ML.AutoML.SourceGenerator/Template/SearchSpace.tt b/tools-local/Microsoft.ML.AutoML.SourceGenerator/Template/SearchSpace.tt new file mode 100644 index 0000000000..8bf28cc1b0 --- /dev/null +++ b/tools-local/Microsoft.ML.AutoML.SourceGenerator/Template/SearchSpace.tt @@ -0,0 +1,38 @@ +<#@ template language="C#" linePragmas="false" visibility = "internal" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> + +using Microsoft.ML.SearchSpace; +using OptionAttribute = Microsoft.ML.SearchSpace.OptionAttribute; +using ColorsOrder = Microsoft.ML.Transforms.Image.ImagePixelExtractingEstimator.ColorsOrder; +using ColorBits = Microsoft.ML.Transforms.Image.ImagePixelExtractingEstimator.ColorBits; +using ResizingKind = Microsoft.ML.Transforms.Image.ImageResizingEstimator.ResizingKind; +using Anchor = Microsoft.ML.Transforms.Image.ImageResizingEstimator.Anchor; + +#nullable enable + +namespace <#=NameSpace#> +{ + public class <#=ClassName#> + { +<#foreach((var optionType, var optionName, var optionAttribution, var defaultValue) in Properties){#> + <#=optionAttribution#> +<#if(defaultValue == string.Empty){#> + public <#=optionType#>? <#=optionName#> {get; set;} +<#}else{#> + [System.Diagnostics.CodeAnalysis.SuppressMessage("Declaration", "MSML_NoInstanceInitializers:No initializers on instance fields or properties")] + public <#=optionType#> <#=optionName#> {get; set;} = <#=defaultValue#>; +<#}#> + +<#}#> + + } +} + +<#+ +public string NameSpace {get;set;} +public string ClassName {get;set;} +public IEnumerable<(string, string, string, string)> Properties {get; set;} +#> \ No newline at end of file diff --git a/tools-local/Microsoft.ML.AutoML.SourceGenerator/Utils.cs b/tools-local/Microsoft.ML.AutoML.SourceGenerator/Utils.cs new file mode 100644 index 0000000000..ab77f56e97 --- /dev/null +++ b/tools-local/Microsoft.ML.AutoML.SourceGenerator/Utils.cs @@ -0,0 +1,42 @@ +// 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 System.Text; + +namespace Microsoft.ML.AutoML.SourceGenerator +{ + internal class Utils + { + public static string CapitalFirstLetter(string str) + { + if (str == null) + return null; + + if (str.Length > 1) + return char.ToUpper(str[0]) + str.Substring(1); + + return str.ToUpper(); + } + + public static string PrettyPrintListOfString(IEnumerable strs) + { + // ["str1", "str2", "str3"] => "\"str1\", \"str2\", \"str3\"" + var sb = new StringBuilder(); + foreach (var str in strs) + { + sb.Append($"\"{str}\""); + sb.Append(", "); + } + + return sb.ToString(); + } + + public static string ToTitleCase(string str) + { + return string.Join(string.Empty, str.Split('_', ' ', '-').Select(x => CapitalFirstLetter(x))); + } + } +}