dotnet / dotnet/machinelearning
Trivial estimators should also be ITransformer
- Dominant language
- C#
- Stars
- 9.4k
- Forks
- 2k
- Avg merge
- 2d 20h
- Merged PRs (30d)
- 11
Description
We are making constructors of transformers internal as part of issue #1798. This makes the creation of non trainable transformers somewhat clumsy. This problem is already reported in the following issue #2165 by an external user.
Here is an example:
```csharp
IDataView data = ...
var estimator = mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel");
var transformer = estimator.Fit(ANY DATA);
var transformedData = transformer.Transform(data);
```
The problem here is the step where the call to `Fit()` is completely useless and feels silly. However, we need estimators for non trainable transformers to use them in estimator pipelines, and the estimator interface cannot change.
One possible approach that we came up with @glebuk and @TomFinley is to make the 'trivial' estimators (estimators for non trainable transformers) `ITransformers` themselves. This is how the API would look like if we make this change, you can see that it is still possible to make the trivial estimators part of a pipeline:
```csharp
IDataView data = ...
var estimatorTransformer = mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel");
var transformedData = estimatorTransformer.Transform(data);
var pipeline = estimatorTransformer.Append(ml.Regression.Learners.FastTree(options);
var trainedPipeline = pipeline.Fit(data);
var transformedData2 = trainedPipeline.Transform(data);
```
The conversion would be very simple. The estimator will have a field `ITransformer Transformer` which is instantiated in the constructor using the arguments passed to the constructor of the estimator (this is already done in cases where the estimator derive from `TrivialEstimator` which should be the case for non trainable estimators). The methods of the interface `ITransformer` will be implemented by calling the respective methods of `Transformer`. A sample conversion should look like the following:
```csharp
public sealed class KeyToValueMappingEstimator : TrivialEstimator, ITransformer
{
public KeyToValueMappingEstimator(IHostEnvironment env, string columnName)
: base(Contracts.CheckRef(env, nameof(env)).Register(nameof(KeyToValueMappingEstimator)), new KeyToValueMappingTransformer(env, columnName))
{ }
public KeyToValueMappingEstimator(IHostEnvironment env, params (string outputColumnName, string inputColumnName)[] columns)
: base(Contracts.CheckRef(env, nameof(env)).Register(nameof(KeyToValueMappingEstimator)), new KeyToValueMappingTransformer(env, columns))
{ }
public override SchemaShape GetOutputSchema(SchemaShape inputSchema)
{ ... }
public bool IsRowToRowMapper => Transformer.IsRowToRowMapper;
public Schema GetOutputSchema(Schema inputSchema) => Transformer.GetOutputSchema(inputSchema);
public IRowToRowMapper GetRowToRowMapper(Schema inputSchema) => Transformer.GetRowToRowMapper(inputSchema);
public IDataView Transform(IDataView input) => Transformer.Transform(input);
}
}
```
/cc @Ivanidzo4ka
Contributor guide
Assessment
This issue has not been assessed yet.