Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions src/Microsoft.ML.FastTree/TreeEnsembleFeaturizer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -703,10 +703,12 @@ public static IDataTransform CreateForEntryPoint(IHostEnvironment env, Arguments
using (var ch = host.Start("Create Tree Ensemble Scorer"))
{
var scorerArgs = new TreeEnsembleFeaturizerBindableMapper.Arguments() { Suffix = args.Suffix };
var predictor = args.PredictorModel?.Predictor;
var predictor = args.PredictorModel.Predictor;
ch.Trace("Prepare data");
RoleMappedData data = null;
args.PredictorModel?.PrepareData(env, input, out data, out var predictor2);
args.PredictorModel.PrepareData(env, input, out data, out var predictor2);
ch.AssertValue(data);
ch.Assert(predictor == predictor2);

// Make sure that the given predictor has the correct number of input features.
if (predictor is CalibratedPredictorBase)
Expand All@@ -715,16 +717,16 @@ public static IDataTransform CreateForEntryPoint(IHostEnvironment env, Arguments
// be non-null.
var vm = predictor as IValueMapper;
ch.CheckUserArg(vm != null, nameof(args.PredictorModel), "Predictor does not have compatible type");
if (data != null && vm?.InputType.VectorSize != data.Schema.Feature.Type.VectorSize)
if (data != null && vm.InputType.VectorSize != data.Schema.Feature.Type.VectorSize)

@TomFinleyTomFinleyMay 11, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (data != null && vm.InputType.VectorSize != data.Schema.Feature.Type.VectorSize) [](start = 16, length = 83)

If someone were to fit in a predictor that did implement IValueMapper (which most do), but that is nevertheless not a tree, what do we expect would happen? From my reading of the code it would just apply a generic scorer. Should we at least verify, in some fashion, that it is the type of predictor we expect beyond being merely a IValueMapper?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though mayhap, even if I'm right about that it should be addressed as a separate issue.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Tom, thanks for reviewing this change. If the predictor is an IValueMapper but is not a tree, then the constructor of TreeEnsembleFeaturizerBindableMapper below will fail.


In reply to: 187707032 [](ancestors = 187707032)

{
throw ch.ExceptUserArg(nameof(args.PredictorModel),
"Predictor expects {0} features, but data has {1} features",
vm?.InputType.VectorSize, data.Schema.Feature.Type.VectorSize);
vm.InputType.VectorSize, data.Schema.Feature.Type.VectorSize);
}

var bindable = new TreeEnsembleFeaturizerBindableMapper(env, scorerArgs, predictor);
var bound = bindable.Bind(env, data?.Schema);
xf = new GenericScorer(env, scorerArgs, input, bound, data?.Schema);
var bound = bindable.Bind(env, data.Schema);
xf = new GenericScorer(env, scorerArgs, data.Data, bound, data.Schema);
ch.Done();
}
return xf;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,6 +18,7 @@

<ItemGroup>
<NativeAssemblyReference Include="CpuMathNative" />
<NativeAssemblyReference Include="FastTreeNative" />
</ItemGroup>

</Project>
67 changes: 66 additions & 1 deletion test/Microsoft.ML.Core.Tests/UnitTests/TestEntryPoints.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,13 +6,13 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.ML.Runtime;
using Microsoft.ML.Runtime.Api;
using Microsoft.ML.Runtime.Core.Tests.UnitTests;
using Microsoft.ML.Runtime.Data;
using Microsoft.ML.Runtime.Data.IO;
using Microsoft.ML.Runtime.EntryPoints;
using Microsoft.ML.Runtime.EntryPoints.JsonUtils;
using Microsoft.ML.Runtime.FastTree;
using Microsoft.ML.Runtime.Internal.Utilities;
using Microsoft.ML.Runtime.Learners;
using Newtonsoft.Json;
Expand DownExpand Up@@ -2521,5 +2521,70 @@ public void EntryPointPrepareLabelConvertPredictedLabel()
}
}
}

[Fact]
public void EntryPointTreeLeafFeaturizer()
{
var dataPath = GetDataPath(@"adult.tiny.with-schema.txt");
var inputFile = new SimpleFileHandle(Env, dataPath, false, false);
var dataView = ImportTextData.ImportText(Env, new ImportTextData.Input { InputFile = inputFile }).Data;
var cat = Categorical.CatTransformDict(Env, new CategoricalTransform.Arguments()

@glebukglebukMay 15, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CatTransformDict [](start = 34, length = 16)

Would it be easier to use the LearningPipeline for the test here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file contains tests for entrypoints. Learning pipeline has its own file with its own test cases. I would not create a learning pipeline test here for this scenario, instead I would create this scenario in learning pipeline test file.

I believe this pipeline can be created using learning pipeline with much fewer lines. We should try to add this scenario using learning pipeline under "Scenario" folder in the test folder. This way the users will see how tree leaf featurizer is used.


In reply to: 188444049 [](ancestors = 188444049)

{
Data = dataView,
Column = new[] { new CategoricalTransform.Column { Name = "Categories", Source = "Categories" } }
});
var concat = SchemaManipulation.ConcatColumns(Env, new ConcatTransform.Arguments()
{
Data = cat.OutputData,
Column = new[] { new ConcatTransform.Column { Name = "Features", Source = new[] { "Categories", "NumericFeatures" } } }
});

var fastTree = FastTree.FastTree.TrainBinary(Env, new FastTreeBinaryClassificationTrainer.Arguments
{
FeatureColumn = "Features",
NumTrees = 5,
NumLeaves = 4,
LabelColumn = DefaultColumnNames.Label,
TrainingData = concat.OutputData
});

var combine = ModelOperations.CombineModels(Env, new ModelOperations.PredictorModelInput()
{
PredictorModel = fastTree.PredictorModel,
TransformModels = new[] { cat.Model, concat.Model }
});

var treeLeaf = TreeFeaturize.Featurizer(Env, new TreeEnsembleFeaturizerTransform.ArgumentsForEntryPoint
{
Data = dataView,
PredictorModel = combine.PredictorModel
});

var view = treeLeaf.OutputData;
Assert.True(view.Schema.TryGetColumnIndex("Trees", out int treesCol));
Assert.True(view.Schema.TryGetColumnIndex("Leaves", out int leavesCol));
Assert.True(view.Schema.TryGetColumnIndex("Paths", out int pathsCol));
VBuffer<float> treeValues = default(VBuffer<float>);
VBuffer<float> leafIndicators = default(VBuffer<float>);
VBuffer<float> pathIndicators = default(VBuffer<float>);
using (var curs = view.GetRowCursor(c => c == treesCol || c == leavesCol || c == pathsCol))
{
var treesGetter = curs.GetGetter<VBuffer<float>>(treesCol);
var leavesGetter = curs.GetGetter<VBuffer<float>>(leavesCol);
var pathsGetter = curs.GetGetter<VBuffer<float>>(pathsCol);
while (curs.MoveNext())
{
treesGetter(ref treeValues);
leavesGetter(ref leafIndicators);
pathsGetter(ref pathIndicators);

Assert.Equal(5, treeValues.Length);
Assert.Equal(5, treeValues.Count);
Assert.Equal(20, leafIndicators.Length);
Assert.Equal(5, leafIndicators.Count);
Assert.Equal(15, pathIndicators.Length);
}
}
}
}
}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions src/Microsoft.ML.FastTree/TreeEnsembleFeaturizer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -703,10 +703,12 @@ public static IDataTransform CreateForEntryPoint(IHostEnvironment env, Arguments
using (var ch = host.Start("Create Tree Ensemble Scorer"))
{
var scorerArgs = new TreeEnsembleFeaturizerBindableMapper.Arguments() { Suffix = args.Suffix };
var predictor = args.PredictorModel?.Predictor;
var predictor = args.PredictorModel.Predictor;
ch.Trace("Prepare data");
RoleMappedData data = null;
args.PredictorModel?.PrepareData(env, input, out data, out var predictor2);
args.PredictorModel.PrepareData(env, input, out data, out var predictor2);
ch.AssertValue(data);
ch.Assert(predictor == predictor2);

// Make sure that the given predictor has the correct number of input features.
if (predictor is CalibratedPredictorBase)
Expand All@@ -715,16 +717,16 @@ public static IDataTransform CreateForEntryPoint(IHostEnvironment env, Arguments
// be non-null.
var vm = predictor as IValueMapper;
ch.CheckUserArg(vm != null, nameof(args.PredictorModel), "Predictor does not have compatible type");
if (data != null && vm?.InputType.VectorSize != data.Schema.Feature.Type.VectorSize)
if (data != null && vm.InputType.VectorSize != data.Schema.Feature.Type.VectorSize)

@TomFinleyTomFinleyMay 11, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (data != null && vm.InputType.VectorSize != data.Schema.Feature.Type.VectorSize) [](start = 16, length = 83)

If someone were to fit in a predictor that did implement IValueMapper (which most do), but that is nevertheless not a tree, what do we expect would happen? From my reading of the code it would just apply a generic scorer. Should we at least verify, in some fashion, that it is the type of predictor we expect beyond being merely a IValueMapper?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though mayhap, even if I'm right about that it should be addressed as a separate issue.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Tom, thanks for reviewing this change. If the predictor is an IValueMapper but is not a tree, then the constructor of TreeEnsembleFeaturizerBindableMapper below will fail.


In reply to: 187707032 [](ancestors = 187707032)

{
throw ch.ExceptUserArg(nameof(args.PredictorModel),
"Predictor expects {0} features, but data has {1} features",
vm?.InputType.VectorSize, data.Schema.Feature.Type.VectorSize);
vm.InputType.VectorSize, data.Schema.Feature.Type.VectorSize);
}

var bindable = new TreeEnsembleFeaturizerBindableMapper(env, scorerArgs, predictor);
var bound = bindable.Bind(env, data?.Schema);
xf = new GenericScorer(env, scorerArgs, input, bound, data?.Schema);
var bound = bindable.Bind(env, data.Schema);
xf = new GenericScorer(env, scorerArgs, data.Data, bound, data.Schema);
ch.Done();
}
return xf;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,6 +18,7 @@

<ItemGroup>
<NativeAssemblyReference Include="CpuMathNative" />
<NativeAssemblyReference Include="FastTreeNative" />
</ItemGroup>

</Project>
67 changes: 66 additions & 1 deletion test/Microsoft.ML.Core.Tests/UnitTests/TestEntryPoints.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,13 +6,13 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.ML.Runtime;
using Microsoft.ML.Runtime.Api;
using Microsoft.ML.Runtime.Core.Tests.UnitTests;
using Microsoft.ML.Runtime.Data;
using Microsoft.ML.Runtime.Data.IO;
using Microsoft.ML.Runtime.EntryPoints;
using Microsoft.ML.Runtime.EntryPoints.JsonUtils;
using Microsoft.ML.Runtime.FastTree;
using Microsoft.ML.Runtime.Internal.Utilities;
using Microsoft.ML.Runtime.Learners;
using Newtonsoft.Json;
Expand DownExpand Up@@ -2521,5 +2521,70 @@ public void EntryPointPrepareLabelConvertPredictedLabel()
}
}
}

[Fact]
public void EntryPointTreeLeafFeaturizer()
{
var dataPath = GetDataPath(@"adult.tiny.with-schema.txt");
var inputFile = new SimpleFileHandle(Env, dataPath, false, false);
var dataView = ImportTextData.ImportText(Env, new ImportTextData.Input { InputFile = inputFile }).Data;
var cat = Categorical.CatTransformDict(Env, new CategoricalTransform.Arguments()

@glebukglebukMay 15, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CatTransformDict [](start = 34, length = 16)

Would it be easier to use the LearningPipeline for the test here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file contains tests for entrypoints. Learning pipeline has its own file with its own test cases. I would not create a learning pipeline test here for this scenario, instead I would create this scenario in learning pipeline test file.

I believe this pipeline can be created using learning pipeline with much fewer lines. We should try to add this scenario using learning pipeline under "Scenario" folder in the test folder. This way the users will see how tree leaf featurizer is used.


In reply to: 188444049 [](ancestors = 188444049)

{
Data = dataView,
Column = new[] { new CategoricalTransform.Column { Name = "Categories", Source = "Categories" } }
});
var concat = SchemaManipulation.ConcatColumns(Env, new ConcatTransform.Arguments()
{
Data = cat.OutputData,
Column = new[] { new ConcatTransform.Column { Name = "Features", Source = new[] { "Categories", "NumericFeatures" } } }
});

var fastTree = FastTree.FastTree.TrainBinary(Env, new FastTreeBinaryClassificationTrainer.Arguments
{
FeatureColumn = "Features",
NumTrees = 5,
NumLeaves = 4,
LabelColumn = DefaultColumnNames.Label,
TrainingData = concat.OutputData
});

var combine = ModelOperations.CombineModels(Env, new ModelOperations.PredictorModelInput()
{
PredictorModel = fastTree.PredictorModel,
TransformModels = new[] { cat.Model, concat.Model }
});

var treeLeaf = TreeFeaturize.Featurizer(Env, new TreeEnsembleFeaturizerTransform.ArgumentsForEntryPoint
{
Data = dataView,
PredictorModel = combine.PredictorModel
});

var view = treeLeaf.OutputData;
Assert.True(view.Schema.TryGetColumnIndex("Trees", out int treesCol));
Assert.True(view.Schema.TryGetColumnIndex("Leaves", out int leavesCol));
Assert.True(view.Schema.TryGetColumnIndex("Paths", out int pathsCol));
VBuffer<float> treeValues = default(VBuffer<float>);
VBuffer<float> leafIndicators = default(VBuffer<float>);
VBuffer<float> pathIndicators = default(VBuffer<float>);
using (var curs = view.GetRowCursor(c => c == treesCol || c == leavesCol || c == pathsCol))
{
var treesGetter = curs.GetGetter<VBuffer<float>>(treesCol);
var leavesGetter = curs.GetGetter<VBuffer<float>>(leavesCol);
var pathsGetter = curs.GetGetter<VBuffer<float>>(pathsCol);
while (curs.MoveNext())
{
treesGetter(ref treeValues);
leavesGetter(ref leafIndicators);
pathsGetter(ref pathIndicators);

Assert.Equal(5, treeValues.Length);
Assert.Equal(5, treeValues.Count);
Assert.Equal(20, leafIndicators.Length);
Assert.Equal(5, leafIndicators.Count);
Assert.Equal(15, pathIndicators.Length);
}
}
}
}
}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions src/Microsoft.ML.FastTree/TreeEnsembleFeaturizer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -703,10 +703,12 @@ public static IDataTransform CreateForEntryPoint(IHostEnvironment env, Arguments
using (var ch = host.Start("Create Tree Ensemble Scorer"))
{
var scorerArgs = new TreeEnsembleFeaturizerBindableMapper.Arguments() { Suffix = args.Suffix };
var predictor = args.PredictorModel?.Predictor;
var predictor = args.PredictorModel.Predictor;
ch.Trace("Prepare data");
RoleMappedData data = null;
args.PredictorModel?.PrepareData(env, input, out data, out var predictor2);
args.PredictorModel.PrepareData(env, input, out data, out var predictor2);
ch.AssertValue(data);
ch.Assert(predictor == predictor2);

// Make sure that the given predictor has the correct number of input features.
if (predictor is CalibratedPredictorBase)
Expand All@@ -715,16 +717,16 @@ public static IDataTransform CreateForEntryPoint(IHostEnvironment env, Arguments
// be non-null.
var vm = predictor as IValueMapper;
ch.CheckUserArg(vm != null, nameof(args.PredictorModel), "Predictor does not have compatible type");
if (data != null && vm?.InputType.VectorSize != data.Schema.Feature.Type.VectorSize)
if (data != null && vm.InputType.VectorSize != data.Schema.Feature.Type.VectorSize)

@TomFinleyTomFinleyMay 11, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (data != null && vm.InputType.VectorSize != data.Schema.Feature.Type.VectorSize) [](start = 16, length = 83)

If someone were to fit in a predictor that did implement IValueMapper (which most do), but that is nevertheless not a tree, what do we expect would happen? From my reading of the code it would just apply a generic scorer. Should we at least verify, in some fashion, that it is the type of predictor we expect beyond being merely a IValueMapper?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though mayhap, even if I'm right about that it should be addressed as a separate issue.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Tom, thanks for reviewing this change. If the predictor is an IValueMapper but is not a tree, then the constructor of TreeEnsembleFeaturizerBindableMapper below will fail.


In reply to: 187707032 [](ancestors = 187707032)

{
throw ch.ExceptUserArg(nameof(args.PredictorModel),
"Predictor expects {0} features, but data has {1} features",
vm?.InputType.VectorSize, data.Schema.Feature.Type.VectorSize);
vm.InputType.VectorSize, data.Schema.Feature.Type.VectorSize);
}

var bindable = new TreeEnsembleFeaturizerBindableMapper(env, scorerArgs, predictor);
var bound = bindable.Bind(env, data?.Schema);
xf = new GenericScorer(env, scorerArgs, input, bound, data?.Schema);
var bound = bindable.Bind(env, data.Schema);
xf = new GenericScorer(env, scorerArgs, data.Data, bound, data.Schema);
ch.Done();
}
return xf;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,6 +18,7 @@

<ItemGroup>
<NativeAssemblyReference Include="CpuMathNative" />
<NativeAssemblyReference Include="FastTreeNative" />
</ItemGroup>

</Project>
67 changes: 66 additions & 1 deletion test/Microsoft.ML.Core.Tests/UnitTests/TestEntryPoints.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,13 +6,13 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.ML.Runtime;
using Microsoft.ML.Runtime.Api;
using Microsoft.ML.Runtime.Core.Tests.UnitTests;
using Microsoft.ML.Runtime.Data;
using Microsoft.ML.Runtime.Data.IO;
using Microsoft.ML.Runtime.EntryPoints;
using Microsoft.ML.Runtime.EntryPoints.JsonUtils;
using Microsoft.ML.Runtime.FastTree;
using Microsoft.ML.Runtime.Internal.Utilities;
using Microsoft.ML.Runtime.Learners;
using Newtonsoft.Json;
Expand DownExpand Up@@ -2521,5 +2521,70 @@ public void EntryPointPrepareLabelConvertPredictedLabel()
}
}
}

[Fact]
public void EntryPointTreeLeafFeaturizer()
{
var dataPath = GetDataPath(@"adult.tiny.with-schema.txt");
var inputFile = new SimpleFileHandle(Env, dataPath, false, false);
var dataView = ImportTextData.ImportText(Env, new ImportTextData.Input { InputFile = inputFile }).Data;
var cat = Categorical.CatTransformDict(Env, new CategoricalTransform.Arguments()

@glebukglebukMay 15, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CatTransformDict [](start = 34, length = 16)

Would it be easier to use the LearningPipeline for the test here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file contains tests for entrypoints. Learning pipeline has its own file with its own test cases. I would not create a learning pipeline test here for this scenario, instead I would create this scenario in learning pipeline test file.

I believe this pipeline can be created using learning pipeline with much fewer lines. We should try to add this scenario using learning pipeline under "Scenario" folder in the test folder. This way the users will see how tree leaf featurizer is used.


In reply to: 188444049 [](ancestors = 188444049)

{
Data = dataView,
Column = new[] { new CategoricalTransform.Column { Name = "Categories", Source = "Categories" } }
});
var concat = SchemaManipulation.ConcatColumns(Env, new ConcatTransform.Arguments()
{
Data = cat.OutputData,
Column = new[] { new ConcatTransform.Column { Name = "Features", Source = new[] { "Categories", "NumericFeatures" } } }
});

var fastTree = FastTree.FastTree.TrainBinary(Env, new FastTreeBinaryClassificationTrainer.Arguments
{
FeatureColumn = "Features",
NumTrees = 5,
NumLeaves = 4,
LabelColumn = DefaultColumnNames.Label,
TrainingData = concat.OutputData
});

var combine = ModelOperations.CombineModels(Env, new ModelOperations.PredictorModelInput()
{
PredictorModel = fastTree.PredictorModel,
TransformModels = new[] { cat.Model, concat.Model }
});

var treeLeaf = TreeFeaturize.Featurizer(Env, new TreeEnsembleFeaturizerTransform.ArgumentsForEntryPoint
{
Data = dataView,
PredictorModel = combine.PredictorModel
});

var view = treeLeaf.OutputData;
Assert.True(view.Schema.TryGetColumnIndex("Trees", out int treesCol));
Assert.True(view.Schema.TryGetColumnIndex("Leaves", out int leavesCol));
Assert.True(view.Schema.TryGetColumnIndex("Paths", out int pathsCol));
VBuffer<float> treeValues = default(VBuffer<float>);
VBuffer<float> leafIndicators = default(VBuffer<float>);
VBuffer<float> pathIndicators = default(VBuffer<float>);
using (var curs = view.GetRowCursor(c => c == treesCol || c == leavesCol || c == pathsCol))
{
var treesGetter = curs.GetGetter<VBuffer<float>>(treesCol);
var leavesGetter = curs.GetGetter<VBuffer<float>>(leavesCol);
var pathsGetter = curs.GetGetter<VBuffer<float>>(pathsCol);
while (curs.MoveNext())
{
treesGetter(ref treeValues);
leavesGetter(ref leafIndicators);
pathsGetter(ref pathIndicators);

Assert.Equal(5, treeValues.Length);
Assert.Equal(5, treeValues.Count);
Assert.Equal(20, leafIndicators.Length);
Assert.Equal(5, leafIndicators.Count);
Assert.Equal(15, pathIndicators.Length);
}
}
}
}
}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions src/Microsoft.ML.FastTree/TreeEnsembleFeaturizer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -703,10 +703,12 @@ public static IDataTransform CreateForEntryPoint(IHostEnvironment env, Arguments
using (var ch = host.Start("Create Tree Ensemble Scorer"))
{
var scorerArgs = new TreeEnsembleFeaturizerBindableMapper.Arguments() { Suffix = args.Suffix };
var predictor = args.PredictorModel?.Predictor;
var predictor = args.PredictorModel.Predictor;
ch.Trace("Prepare data");
RoleMappedData data = null;
args.PredictorModel?.PrepareData(env, input, out data, out var predictor2);
args.PredictorModel.PrepareData(env, input, out data, out var predictor2);
ch.AssertValue(data);
ch.Assert(predictor == predictor2);

// Make sure that the given predictor has the correct number of input features.
if (predictor is CalibratedPredictorBase)
Expand All@@ -715,16 +717,16 @@ public static IDataTransform CreateForEntryPoint(IHostEnvironment env, Arguments
// be non-null.
var vm = predictor as IValueMapper;
ch.CheckUserArg(vm != null, nameof(args.PredictorModel), "Predictor does not have compatible type");
if (data != null && vm?.InputType.VectorSize != data.Schema.Feature.Type.VectorSize)
if (data != null && vm.InputType.VectorSize != data.Schema.Feature.Type.VectorSize)

@TomFinleyTomFinleyMay 11, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (data != null && vm.InputType.VectorSize != data.Schema.Feature.Type.VectorSize) [](start = 16, length = 83)

If someone were to fit in a predictor that did implement IValueMapper (which most do), but that is nevertheless not a tree, what do we expect would happen? From my reading of the code it would just apply a generic scorer. Should we at least verify, in some fashion, that it is the type of predictor we expect beyond being merely a IValueMapper?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though mayhap, even if I'm right about that it should be addressed as a separate issue.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Tom, thanks for reviewing this change. If the predictor is an IValueMapper but is not a tree, then the constructor of TreeEnsembleFeaturizerBindableMapper below will fail.


In reply to: 187707032 [](ancestors = 187707032)

{
throw ch.ExceptUserArg(nameof(args.PredictorModel),
"Predictor expects {0} features, but data has {1} features",
vm?.InputType.VectorSize, data.Schema.Feature.Type.VectorSize);
vm.InputType.VectorSize, data.Schema.Feature.Type.VectorSize);
}

var bindable = new TreeEnsembleFeaturizerBindableMapper(env, scorerArgs, predictor);
var bound = bindable.Bind(env, data?.Schema);
xf = new GenericScorer(env, scorerArgs, input, bound, data?.Schema);
var bound = bindable.Bind(env, data.Schema);
xf = new GenericScorer(env, scorerArgs, data.Data, bound, data.Schema);
ch.Done();
}
return xf;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,6 +18,7 @@

<ItemGroup>
<NativeAssemblyReference Include="CpuMathNative" />
<NativeAssemblyReference Include="FastTreeNative" />
</ItemGroup>

</Project>
67 changes: 66 additions & 1 deletion test/Microsoft.ML.Core.Tests/UnitTests/TestEntryPoints.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,13 +6,13 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.ML.Runtime;
using Microsoft.ML.Runtime.Api;
using Microsoft.ML.Runtime.Core.Tests.UnitTests;
using Microsoft.ML.Runtime.Data;
using Microsoft.ML.Runtime.Data.IO;
using Microsoft.ML.Runtime.EntryPoints;
using Microsoft.ML.Runtime.EntryPoints.JsonUtils;
using Microsoft.ML.Runtime.FastTree;
using Microsoft.ML.Runtime.Internal.Utilities;
using Microsoft.ML.Runtime.Learners;
using Newtonsoft.Json;
Expand DownExpand Up@@ -2521,5 +2521,70 @@ public void EntryPointPrepareLabelConvertPredictedLabel()
}
}
}

[Fact]
public void EntryPointTreeLeafFeaturizer()
{
var dataPath = GetDataPath(@"adult.tiny.with-schema.txt");
var inputFile = new SimpleFileHandle(Env, dataPath, false, false);
var dataView = ImportTextData.ImportText(Env, new ImportTextData.Input { InputFile = inputFile }).Data;
var cat = Categorical.CatTransformDict(Env, new CategoricalTransform.Arguments()

@glebukglebukMay 15, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CatTransformDict [](start = 34, length = 16)

Would it be easier to use the LearningPipeline for the test here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file contains tests for entrypoints. Learning pipeline has its own file with its own test cases. I would not create a learning pipeline test here for this scenario, instead I would create this scenario in learning pipeline test file.

I believe this pipeline can be created using learning pipeline with much fewer lines. We should try to add this scenario using learning pipeline under "Scenario" folder in the test folder. This way the users will see how tree leaf featurizer is used.


In reply to: 188444049 [](ancestors = 188444049)

{
Data = dataView,
Column = new[] { new CategoricalTransform.Column { Name = "Categories", Source = "Categories" } }
});
var concat = SchemaManipulation.ConcatColumns(Env, new ConcatTransform.Arguments()
{
Data = cat.OutputData,
Column = new[] { new ConcatTransform.Column { Name = "Features", Source = new[] { "Categories", "NumericFeatures" } } }
});

var fastTree = FastTree.FastTree.TrainBinary(Env, new FastTreeBinaryClassificationTrainer.Arguments
{
FeatureColumn = "Features",
NumTrees = 5,
NumLeaves = 4,
LabelColumn = DefaultColumnNames.Label,
TrainingData = concat.OutputData
});

var combine = ModelOperations.CombineModels(Env, new ModelOperations.PredictorModelInput()
{
PredictorModel = fastTree.PredictorModel,
TransformModels = new[] { cat.Model, concat.Model }
});

var treeLeaf = TreeFeaturize.Featurizer(Env, new TreeEnsembleFeaturizerTransform.ArgumentsForEntryPoint
{
Data = dataView,
PredictorModel = combine.PredictorModel
});

var view = treeLeaf.OutputData;
Assert.True(view.Schema.TryGetColumnIndex("Trees", out int treesCol));
Assert.True(view.Schema.TryGetColumnIndex("Leaves", out int leavesCol));
Assert.True(view.Schema.TryGetColumnIndex("Paths", out int pathsCol));
VBuffer<float> treeValues = default(VBuffer<float>);
VBuffer<float> leafIndicators = default(VBuffer<float>);
VBuffer<float> pathIndicators = default(VBuffer<float>);
using (var curs = view.GetRowCursor(c => c == treesCol || c == leavesCol || c == pathsCol))
{
var treesGetter = curs.GetGetter<VBuffer<float>>(treesCol);
var leavesGetter = curs.GetGetter<VBuffer<float>>(leavesCol);
var pathsGetter = curs.GetGetter<VBuffer<float>>(pathsCol);
while (curs.MoveNext())
{
treesGetter(ref treeValues);
leavesGetter(ref leafIndicators);
pathsGetter(ref pathIndicators);

Assert.Equal(5, treeValues.Length);
Assert.Equal(5, treeValues.Count);
Assert.Equal(20, leafIndicators.Length);
Assert.Equal(5, leafIndicators.Count);
Assert.Equal(15, pathIndicators.Length);
}
}
}
}
}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions src/Microsoft.ML.FastTree/TreeEnsembleFeaturizer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -703,10 +703,12 @@ public static IDataTransform CreateForEntryPoint(IHostEnvironment env, Arguments
using (var ch = host.Start("Create Tree Ensemble Scorer"))
{
var scorerArgs = new TreeEnsembleFeaturizerBindableMapper.Arguments() { Suffix = args.Suffix };
var predictor = args.PredictorModel?.Predictor;
var predictor = args.PredictorModel.Predictor;
ch.Trace("Prepare data");
RoleMappedData data = null;
args.PredictorModel?.PrepareData(env, input, out data, out var predictor2);
args.PredictorModel.PrepareData(env, input, out data, out var predictor2);
ch.AssertValue(data);
ch.Assert(predictor == predictor2);

// Make sure that the given predictor has the correct number of input features.
if (predictor is CalibratedPredictorBase)
Expand All@@ -715,16 +717,16 @@ public static IDataTransform CreateForEntryPoint(IHostEnvironment env, Arguments
// be non-null.
var vm = predictor as IValueMapper;
ch.CheckUserArg(vm != null, nameof(args.PredictorModel), "Predictor does not have compatible type");
if (data != null && vm?.InputType.VectorSize != data.Schema.Feature.Type.VectorSize)
if (data != null && vm.InputType.VectorSize != data.Schema.Feature.Type.VectorSize)

@TomFinleyTomFinleyMay 11, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (data != null && vm.InputType.VectorSize != data.Schema.Feature.Type.VectorSize) [](start = 16, length = 83)

If someone were to fit in a predictor that did implement IValueMapper (which most do), but that is nevertheless not a tree, what do we expect would happen? From my reading of the code it would just apply a generic scorer. Should we at least verify, in some fashion, that it is the type of predictor we expect beyond being merely a IValueMapper?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though mayhap, even if I'm right about that it should be addressed as a separate issue.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Tom, thanks for reviewing this change. If the predictor is an IValueMapper but is not a tree, then the constructor of TreeEnsembleFeaturizerBindableMapper below will fail.


In reply to: 187707032 [](ancestors = 187707032)

{
throw ch.ExceptUserArg(nameof(args.PredictorModel),
"Predictor expects {0} features, but data has {1} features",
vm?.InputType.VectorSize, data.Schema.Feature.Type.VectorSize);
vm.InputType.VectorSize, data.Schema.Feature.Type.VectorSize);
}

var bindable = new TreeEnsembleFeaturizerBindableMapper(env, scorerArgs, predictor);
var bound = bindable.Bind(env, data?.Schema);
xf = new GenericScorer(env, scorerArgs, input, bound, data?.Schema);
var bound = bindable.Bind(env, data.Schema);
xf = new GenericScorer(env, scorerArgs, data.Data, bound, data.Schema);
ch.Done();
}
return xf;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,6 +18,7 @@

<ItemGroup>
<NativeAssemblyReference Include="CpuMathNative" />
<NativeAssemblyReference Include="FastTreeNative" />
</ItemGroup>

</Project>
67 changes: 66 additions & 1 deletion test/Microsoft.ML.Core.Tests/UnitTests/TestEntryPoints.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,13 +6,13 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.ML.Runtime;
using Microsoft.ML.Runtime.Api;
using Microsoft.ML.Runtime.Core.Tests.UnitTests;
using Microsoft.ML.Runtime.Data;
using Microsoft.ML.Runtime.Data.IO;
using Microsoft.ML.Runtime.EntryPoints;
using Microsoft.ML.Runtime.EntryPoints.JsonUtils;
using Microsoft.ML.Runtime.FastTree;
using Microsoft.ML.Runtime.Internal.Utilities;
using Microsoft.ML.Runtime.Learners;
using Newtonsoft.Json;
Expand DownExpand Up@@ -2521,5 +2521,70 @@ public void EntryPointPrepareLabelConvertPredictedLabel()
}
}
}

[Fact]
public void EntryPointTreeLeafFeaturizer()
{
var dataPath = GetDataPath(@"adult.tiny.with-schema.txt");
var inputFile = new SimpleFileHandle(Env, dataPath, false, false);
var dataView = ImportTextData.ImportText(Env, new ImportTextData.Input { InputFile = inputFile }).Data;
var cat = Categorical.CatTransformDict(Env, new CategoricalTransform.Arguments()

@glebukglebukMay 15, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CatTransformDict [](start = 34, length = 16)

Would it be easier to use the LearningPipeline for the test here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file contains tests for entrypoints. Learning pipeline has its own file with its own test cases. I would not create a learning pipeline test here for this scenario, instead I would create this scenario in learning pipeline test file.

I believe this pipeline can be created using learning pipeline with much fewer lines. We should try to add this scenario using learning pipeline under "Scenario" folder in the test folder. This way the users will see how tree leaf featurizer is used.


In reply to: 188444049 [](ancestors = 188444049)

{
Data = dataView,
Column = new[] { new CategoricalTransform.Column { Name = "Categories", Source = "Categories" } }
});
var concat = SchemaManipulation.ConcatColumns(Env, new ConcatTransform.Arguments()
{
Data = cat.OutputData,
Column = new[] { new ConcatTransform.Column { Name = "Features", Source = new[] { "Categories", "NumericFeatures" } } }
});

var fastTree = FastTree.FastTree.TrainBinary(Env, new FastTreeBinaryClassificationTrainer.Arguments
{
FeatureColumn = "Features",
NumTrees = 5,
NumLeaves = 4,
LabelColumn = DefaultColumnNames.Label,
TrainingData = concat.OutputData
});

var combine = ModelOperations.CombineModels(Env, new ModelOperations.PredictorModelInput()
{
PredictorModel = fastTree.PredictorModel,
TransformModels = new[] { cat.Model, concat.Model }
});

var treeLeaf = TreeFeaturize.Featurizer(Env, new TreeEnsembleFeaturizerTransform.ArgumentsForEntryPoint
{
Data = dataView,
PredictorModel = combine.PredictorModel
});

var view = treeLeaf.OutputData;
Assert.True(view.Schema.TryGetColumnIndex("Trees", out int treesCol));
Assert.True(view.Schema.TryGetColumnIndex("Leaves", out int leavesCol));
Assert.True(view.Schema.TryGetColumnIndex("Paths", out int pathsCol));
VBuffer<float> treeValues = default(VBuffer<float>);
VBuffer<float> leafIndicators = default(VBuffer<float>);
VBuffer<float> pathIndicators = default(VBuffer<float>);
using (var curs = view.GetRowCursor(c => c == treesCol || c == leavesCol || c == pathsCol))
{
var treesGetter = curs.GetGetter<VBuffer<float>>(treesCol);
var leavesGetter = curs.GetGetter<VBuffer<float>>(leavesCol);
var pathsGetter = curs.GetGetter<VBuffer<float>>(pathsCol);
while (curs.MoveNext())
{
treesGetter(ref treeValues);
leavesGetter(ref leafIndicators);
pathsGetter(ref pathIndicators);

Assert.Equal(5, treeValues.Length);
Assert.Equal(5, treeValues.Count);
Assert.Equal(20, leafIndicators.Length);
Assert.Equal(5, leafIndicators.Count);
Assert.Equal(15, pathIndicators.Length);
}
}
}
}
}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions src/Microsoft.ML.FastTree/TreeEnsembleFeaturizer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -703,10 +703,12 @@ public static IDataTransform CreateForEntryPoint(IHostEnvironment env, Arguments
using (var ch = host.Start("Create Tree Ensemble Scorer"))
{
var scorerArgs = new TreeEnsembleFeaturizerBindableMapper.Arguments() { Suffix = args.Suffix };
var predictor = args.PredictorModel?.Predictor;
var predictor = args.PredictorModel.Predictor;
ch.Trace("Prepare data");
RoleMappedData data = null;
args.PredictorModel?.PrepareData(env, input, out data, out var predictor2);
args.PredictorModel.PrepareData(env, input, out data, out var predictor2);
ch.AssertValue(data);
ch.Assert(predictor == predictor2);

// Make sure that the given predictor has the correct number of input features.
if (predictor is CalibratedPredictorBase)
Expand All@@ -715,16 +717,16 @@ public static IDataTransform CreateForEntryPoint(IHostEnvironment env, Arguments
// be non-null.
var vm = predictor as IValueMapper;
ch.CheckUserArg(vm != null, nameof(args.PredictorModel), "Predictor does not have compatible type");
if (data != null && vm?.InputType.VectorSize != data.Schema.Feature.Type.VectorSize)
if (data != null && vm.InputType.VectorSize != data.Schema.Feature.Type.VectorSize)

@TomFinleyTomFinleyMay 11, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (data != null && vm.InputType.VectorSize != data.Schema.Feature.Type.VectorSize) [](start = 16, length = 83)

If someone were to fit in a predictor that did implement IValueMapper (which most do), but that is nevertheless not a tree, what do we expect would happen? From my reading of the code it would just apply a generic scorer. Should we at least verify, in some fashion, that it is the type of predictor we expect beyond being merely a IValueMapper?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though mayhap, even if I'm right about that it should be addressed as a separate issue.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Tom, thanks for reviewing this change. If the predictor is an IValueMapper but is not a tree, then the constructor of TreeEnsembleFeaturizerBindableMapper below will fail.


In reply to: 187707032 [](ancestors = 187707032)

{
throw ch.ExceptUserArg(nameof(args.PredictorModel),
"Predictor expects {0} features, but data has {1} features",
vm?.InputType.VectorSize, data.Schema.Feature.Type.VectorSize);
vm.InputType.VectorSize, data.Schema.Feature.Type.VectorSize);
}

var bindable = new TreeEnsembleFeaturizerBindableMapper(env, scorerArgs, predictor);
var bound = bindable.Bind(env, data?.Schema);
xf = new GenericScorer(env, scorerArgs, input, bound, data?.Schema);
var bound = bindable.Bind(env, data.Schema);
xf = new GenericScorer(env, scorerArgs, data.Data, bound, data.Schema);
ch.Done();
}
return xf;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,6 +18,7 @@

<ItemGroup>
<NativeAssemblyReference Include="CpuMathNative" />
<NativeAssemblyReference Include="FastTreeNative" />
</ItemGroup>

</Project>
67 changes: 66 additions & 1 deletion test/Microsoft.ML.Core.Tests/UnitTests/TestEntryPoints.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,13 +6,13 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.ML.Runtime;
using Microsoft.ML.Runtime.Api;
using Microsoft.ML.Runtime.Core.Tests.UnitTests;
using Microsoft.ML.Runtime.Data;
using Microsoft.ML.Runtime.Data.IO;
using Microsoft.ML.Runtime.EntryPoints;
using Microsoft.ML.Runtime.EntryPoints.JsonUtils;
using Microsoft.ML.Runtime.FastTree;
using Microsoft.ML.Runtime.Internal.Utilities;
using Microsoft.ML.Runtime.Learners;
using Newtonsoft.Json;
Expand DownExpand Up@@ -2521,5 +2521,70 @@ public void EntryPointPrepareLabelConvertPredictedLabel()
}
}
}

[Fact]
public void EntryPointTreeLeafFeaturizer()
{
var dataPath = GetDataPath(@"adult.tiny.with-schema.txt");
var inputFile = new SimpleFileHandle(Env, dataPath, false, false);
var dataView = ImportTextData.ImportText(Env, new ImportTextData.Input { InputFile = inputFile }).Data;
var cat = Categorical.CatTransformDict(Env, new CategoricalTransform.Arguments()

@glebukglebukMay 15, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CatTransformDict [](start = 34, length = 16)

Would it be easier to use the LearningPipeline for the test here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file contains tests for entrypoints. Learning pipeline has its own file with its own test cases. I would not create a learning pipeline test here for this scenario, instead I would create this scenario in learning pipeline test file.

I believe this pipeline can be created using learning pipeline with much fewer lines. We should try to add this scenario using learning pipeline under "Scenario" folder in the test folder. This way the users will see how tree leaf featurizer is used.


In reply to: 188444049 [](ancestors = 188444049)

{
Data = dataView,
Column = new[] { new CategoricalTransform.Column { Name = "Categories", Source = "Categories" } }
});
var concat = SchemaManipulation.ConcatColumns(Env, new ConcatTransform.Arguments()
{
Data = cat.OutputData,
Column = new[] { new ConcatTransform.Column { Name = "Features", Source = new[] { "Categories", "NumericFeatures" } } }
});

var fastTree = FastTree.FastTree.TrainBinary(Env, new FastTreeBinaryClassificationTrainer.Arguments
{
FeatureColumn = "Features",
NumTrees = 5,
NumLeaves = 4,
LabelColumn = DefaultColumnNames.Label,
TrainingData = concat.OutputData
});

var combine = ModelOperations.CombineModels(Env, new ModelOperations.PredictorModelInput()
{
PredictorModel = fastTree.PredictorModel,
TransformModels = new[] { cat.Model, concat.Model }
});

var treeLeaf = TreeFeaturize.Featurizer(Env, new TreeEnsembleFeaturizerTransform.ArgumentsForEntryPoint
{
Data = dataView,
PredictorModel = combine.PredictorModel
});

var view = treeLeaf.OutputData;
Assert.True(view.Schema.TryGetColumnIndex("Trees", out int treesCol));
Assert.True(view.Schema.TryGetColumnIndex("Leaves", out int leavesCol));
Assert.True(view.Schema.TryGetColumnIndex("Paths", out int pathsCol));
VBuffer<float> treeValues = default(VBuffer<float>);
VBuffer<float> leafIndicators = default(VBuffer<float>);
VBuffer<float> pathIndicators = default(VBuffer<float>);
using (var curs = view.GetRowCursor(c => c == treesCol || c == leavesCol || c == pathsCol))
{
var treesGetter = curs.GetGetter<VBuffer<float>>(treesCol);
var leavesGetter = curs.GetGetter<VBuffer<float>>(leavesCol);
var pathsGetter = curs.GetGetter<VBuffer<float>>(pathsCol);
while (curs.MoveNext())
{
treesGetter(ref treeValues);
leavesGetter(ref leafIndicators);
pathsGetter(ref pathIndicators);

Assert.Equal(5, treeValues.Length);
Assert.Equal(5, treeValues.Count);
Assert.Equal(20, leafIndicators.Length);
Assert.Equal(5, leafIndicators.Count);
Assert.Equal(15, pathIndicators.Length);
}
}
}
}
}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions src/Microsoft.ML.FastTree/TreeEnsembleFeaturizer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -703,10 +703,12 @@ public static IDataTransform CreateForEntryPoint(IHostEnvironment env, Arguments
using (var ch = host.Start("Create Tree Ensemble Scorer"))
{
var scorerArgs = new TreeEnsembleFeaturizerBindableMapper.Arguments() { Suffix = args.Suffix };
var predictor = args.PredictorModel?.Predictor;
var predictor = args.PredictorModel.Predictor;
ch.Trace("Prepare data");
RoleMappedData data = null;
args.PredictorModel?.PrepareData(env, input, out data, out var predictor2);
args.PredictorModel.PrepareData(env, input, out data, out var predictor2);
ch.AssertValue(data);
ch.Assert(predictor == predictor2);

// Make sure that the given predictor has the correct number of input features.
if (predictor is CalibratedPredictorBase)
Expand All@@ -715,16 +717,16 @@ public static IDataTransform CreateForEntryPoint(IHostEnvironment env, Arguments
// be non-null.
var vm = predictor as IValueMapper;
ch.CheckUserArg(vm != null, nameof(args.PredictorModel), "Predictor does not have compatible type");
if (data != null && vm?.InputType.VectorSize != data.Schema.Feature.Type.VectorSize)
if (data != null && vm.InputType.VectorSize != data.Schema.Feature.Type.VectorSize)

@TomFinleyTomFinleyMay 11, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (data != null && vm.InputType.VectorSize != data.Schema.Feature.Type.VectorSize) [](start = 16, length = 83)

If someone were to fit in a predictor that did implement IValueMapper (which most do), but that is nevertheless not a tree, what do we expect would happen? From my reading of the code it would just apply a generic scorer. Should we at least verify, in some fashion, that it is the type of predictor we expect beyond being merely a IValueMapper?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though mayhap, even if I'm right about that it should be addressed as a separate issue.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Tom, thanks for reviewing this change. If the predictor is an IValueMapper but is not a tree, then the constructor of TreeEnsembleFeaturizerBindableMapper below will fail.


In reply to: 187707032 [](ancestors = 187707032)

{
throw ch.ExceptUserArg(nameof(args.PredictorModel),
"Predictor expects {0} features, but data has {1} features",
vm?.InputType.VectorSize, data.Schema.Feature.Type.VectorSize);
vm.InputType.VectorSize, data.Schema.Feature.Type.VectorSize);
}

var bindable = new TreeEnsembleFeaturizerBindableMapper(env, scorerArgs, predictor);
var bound = bindable.Bind(env, data?.Schema);
xf = new GenericScorer(env, scorerArgs, input, bound, data?.Schema);
var bound = bindable.Bind(env, data.Schema);
xf = new GenericScorer(env, scorerArgs, data.Data, bound, data.Schema);
ch.Done();
}
return xf;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,6 +18,7 @@

<ItemGroup>
<NativeAssemblyReference Include="CpuMathNative" />
<NativeAssemblyReference Include="FastTreeNative" />
</ItemGroup>

</Project>
67 changes: 66 additions & 1 deletion test/Microsoft.ML.Core.Tests/UnitTests/TestEntryPoints.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,13 +6,13 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.ML.Runtime;
using Microsoft.ML.Runtime.Api;
using Microsoft.ML.Runtime.Core.Tests.UnitTests;
using Microsoft.ML.Runtime.Data;
using Microsoft.ML.Runtime.Data.IO;
using Microsoft.ML.Runtime.EntryPoints;
using Microsoft.ML.Runtime.EntryPoints.JsonUtils;
using Microsoft.ML.Runtime.FastTree;
using Microsoft.ML.Runtime.Internal.Utilities;
using Microsoft.ML.Runtime.Learners;
using Newtonsoft.Json;
Expand DownExpand Up@@ -2521,5 +2521,70 @@ public void EntryPointPrepareLabelConvertPredictedLabel()
}
}
}

[Fact]
public void EntryPointTreeLeafFeaturizer()
{
var dataPath = GetDataPath(@"adult.tiny.with-schema.txt");
var inputFile = new SimpleFileHandle(Env, dataPath, false, false);
var dataView = ImportTextData.ImportText(Env, new ImportTextData.Input { InputFile = inputFile }).Data;
var cat = Categorical.CatTransformDict(Env, new CategoricalTransform.Arguments()

@glebukglebukMay 15, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CatTransformDict [](start = 34, length = 16)

Would it be easier to use the LearningPipeline for the test here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file contains tests for entrypoints. Learning pipeline has its own file with its own test cases. I would not create a learning pipeline test here for this scenario, instead I would create this scenario in learning pipeline test file.

I believe this pipeline can be created using learning pipeline with much fewer lines. We should try to add this scenario using learning pipeline under "Scenario" folder in the test folder. This way the users will see how tree leaf featurizer is used.


In reply to: 188444049 [](ancestors = 188444049)

{
Data = dataView,
Column = new[] { new CategoricalTransform.Column { Name = "Categories", Source = "Categories" } }
});
var concat = SchemaManipulation.ConcatColumns(Env, new ConcatTransform.Arguments()
{
Data = cat.OutputData,
Column = new[] { new ConcatTransform.Column { Name = "Features", Source = new[] { "Categories", "NumericFeatures" } } }
});

var fastTree = FastTree.FastTree.TrainBinary(Env, new FastTreeBinaryClassificationTrainer.Arguments
{
FeatureColumn = "Features",
NumTrees = 5,
NumLeaves = 4,
LabelColumn = DefaultColumnNames.Label,
TrainingData = concat.OutputData
});

var combine = ModelOperations.CombineModels(Env, new ModelOperations.PredictorModelInput()
{
PredictorModel = fastTree.PredictorModel,
TransformModels = new[] { cat.Model, concat.Model }
});

var treeLeaf = TreeFeaturize.Featurizer(Env, new TreeEnsembleFeaturizerTransform.ArgumentsForEntryPoint
{
Data = dataView,
PredictorModel = combine.PredictorModel
});

var view = treeLeaf.OutputData;
Assert.True(view.Schema.TryGetColumnIndex("Trees", out int treesCol));
Assert.True(view.Schema.TryGetColumnIndex("Leaves", out int leavesCol));
Assert.True(view.Schema.TryGetColumnIndex("Paths", out int pathsCol));
VBuffer<float> treeValues = default(VBuffer<float>);
VBuffer<float> leafIndicators = default(VBuffer<float>);
VBuffer<float> pathIndicators = default(VBuffer<float>);
using (var curs = view.GetRowCursor(c => c == treesCol || c == leavesCol || c == pathsCol))
{
var treesGetter = curs.GetGetter<VBuffer<float>>(treesCol);
var leavesGetter = curs.GetGetter<VBuffer<float>>(leavesCol);
var pathsGetter = curs.GetGetter<VBuffer<float>>(pathsCol);
while (curs.MoveNext())
{
treesGetter(ref treeValues);
leavesGetter(ref leafIndicators);
pathsGetter(ref pathIndicators);

Assert.Equal(5, treeValues.Length);
Assert.Equal(5, treeValues.Count);
Assert.Equal(20, leafIndicators.Length);
Assert.Equal(5, leafIndicators.Count);
Assert.Equal(15, pathIndicators.Length);
}
}
}
}
}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions src/Microsoft.ML.FastTree/TreeEnsembleFeaturizer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -703,10 +703,12 @@ public static IDataTransform CreateForEntryPoint(IHostEnvironment env, Arguments
using (var ch = host.Start("Create Tree Ensemble Scorer"))
{
var scorerArgs = new TreeEnsembleFeaturizerBindableMapper.Arguments() { Suffix = args.Suffix };
var predictor = args.PredictorModel?.Predictor;
var predictor = args.PredictorModel.Predictor;
ch.Trace("Prepare data");
RoleMappedData data = null;
args.PredictorModel?.PrepareData(env, input, out data, out var predictor2);
args.PredictorModel.PrepareData(env, input, out data, out var predictor2);
ch.AssertValue(data);
ch.Assert(predictor == predictor2);

// Make sure that the given predictor has the correct number of input features.
if (predictor is CalibratedPredictorBase)
Expand All@@ -715,16 +717,16 @@ public static IDataTransform CreateForEntryPoint(IHostEnvironment env, Arguments
// be non-null.
var vm = predictor as IValueMapper;
ch.CheckUserArg(vm != null, nameof(args.PredictorModel), "Predictor does not have compatible type");
if (data != null && vm?.InputType.VectorSize != data.Schema.Feature.Type.VectorSize)
if (data != null && vm.InputType.VectorSize != data.Schema.Feature.Type.VectorSize)

@TomFinleyTomFinleyMay 11, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (data != null && vm.InputType.VectorSize != data.Schema.Feature.Type.VectorSize) [](start = 16, length = 83)

If someone were to fit in a predictor that did implement IValueMapper (which most do), but that is nevertheless not a tree, what do we expect would happen? From my reading of the code it would just apply a generic scorer. Should we at least verify, in some fashion, that it is the type of predictor we expect beyond being merely a IValueMapper?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though mayhap, even if I'm right about that it should be addressed as a separate issue.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Tom, thanks for reviewing this change. If the predictor is an IValueMapper but is not a tree, then the constructor of TreeEnsembleFeaturizerBindableMapper below will fail.


In reply to: 187707032 [](ancestors = 187707032)

{
throw ch.ExceptUserArg(nameof(args.PredictorModel),
"Predictor expects {0} features, but data has {1} features",
vm?.InputType.VectorSize, data.Schema.Feature.Type.VectorSize);
vm.InputType.VectorSize, data.Schema.Feature.Type.VectorSize);
}

var bindable = new TreeEnsembleFeaturizerBindableMapper(env, scorerArgs, predictor);
var bound = bindable.Bind(env, data?.Schema);
xf = new GenericScorer(env, scorerArgs, input, bound, data?.Schema);
var bound = bindable.Bind(env, data.Schema);
xf = new GenericScorer(env, scorerArgs, data.Data, bound, data.Schema);
ch.Done();
}
return xf;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,6 +18,7 @@

<ItemGroup>
<NativeAssemblyReference Include="CpuMathNative" />
<NativeAssemblyReference Include="FastTreeNative" />
</ItemGroup>

</Project>
67 changes: 66 additions & 1 deletion test/Microsoft.ML.Core.Tests/UnitTests/TestEntryPoints.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,13 +6,13 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.ML.Runtime;
using Microsoft.ML.Runtime.Api;
using Microsoft.ML.Runtime.Core.Tests.UnitTests;
using Microsoft.ML.Runtime.Data;
using Microsoft.ML.Runtime.Data.IO;
using Microsoft.ML.Runtime.EntryPoints;
using Microsoft.ML.Runtime.EntryPoints.JsonUtils;
using Microsoft.ML.Runtime.FastTree;
using Microsoft.ML.Runtime.Internal.Utilities;
using Microsoft.ML.Runtime.Learners;
using Newtonsoft.Json;
Expand DownExpand Up@@ -2521,5 +2521,70 @@ public void EntryPointPrepareLabelConvertPredictedLabel()
}
}
}

[Fact]
public void EntryPointTreeLeafFeaturizer()
{
var dataPath = GetDataPath(@"adult.tiny.with-schema.txt");
var inputFile = new SimpleFileHandle(Env, dataPath, false, false);
var dataView = ImportTextData.ImportText(Env, new ImportTextData.Input { InputFile = inputFile }).Data;
var cat = Categorical.CatTransformDict(Env, new CategoricalTransform.Arguments()

@glebukglebukMay 15, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CatTransformDict [](start = 34, length = 16)

Would it be easier to use the LearningPipeline for the test here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file contains tests for entrypoints. Learning pipeline has its own file with its own test cases. I would not create a learning pipeline test here for this scenario, instead I would create this scenario in learning pipeline test file.

I believe this pipeline can be created using learning pipeline with much fewer lines. We should try to add this scenario using learning pipeline under "Scenario" folder in the test folder. This way the users will see how tree leaf featurizer is used.


In reply to: 188444049 [](ancestors = 188444049)

{
Data = dataView,
Column = new[] { new CategoricalTransform.Column { Name = "Categories", Source = "Categories" } }
});
var concat = SchemaManipulation.ConcatColumns(Env, new ConcatTransform.Arguments()
{
Data = cat.OutputData,
Column = new[] { new ConcatTransform.Column { Name = "Features", Source = new[] { "Categories", "NumericFeatures" } } }
});

var fastTree = FastTree.FastTree.TrainBinary(Env, new FastTreeBinaryClassificationTrainer.Arguments
{
FeatureColumn = "Features",
NumTrees = 5,
NumLeaves = 4,
LabelColumn = DefaultColumnNames.Label,
TrainingData = concat.OutputData
});

var combine = ModelOperations.CombineModels(Env, new ModelOperations.PredictorModelInput()
{
PredictorModel = fastTree.PredictorModel,
TransformModels = new[] { cat.Model, concat.Model }
});

var treeLeaf = TreeFeaturize.Featurizer(Env, new TreeEnsembleFeaturizerTransform.ArgumentsForEntryPoint
{
Data = dataView,
PredictorModel = combine.PredictorModel
});

var view = treeLeaf.OutputData;
Assert.True(view.Schema.TryGetColumnIndex("Trees", out int treesCol));
Assert.True(view.Schema.TryGetColumnIndex("Leaves", out int leavesCol));
Assert.True(view.Schema.TryGetColumnIndex("Paths", out int pathsCol));
VBuffer<float> treeValues = default(VBuffer<float>);
VBuffer<float> leafIndicators = default(VBuffer<float>);
VBuffer<float> pathIndicators = default(VBuffer<float>);
using (var curs = view.GetRowCursor(c => c == treesCol || c == leavesCol || c == pathsCol))
{
var treesGetter = curs.GetGetter<VBuffer<float>>(treesCol);
var leavesGetter = curs.GetGetter<VBuffer<float>>(leavesCol);
var pathsGetter = curs.GetGetter<VBuffer<float>>(pathsCol);
while (curs.MoveNext())
{
treesGetter(ref treeValues);
leavesGetter(ref leafIndicators);
pathsGetter(ref pathIndicators);

Assert.Equal(5, treeValues.Length);
Assert.Equal(5, treeValues.Count);
Assert.Equal(20, leafIndicators.Length);
Assert.Equal(5, leafIndicators.Count);
Assert.Equal(15, pathIndicators.Length);
}
}
}
}
}