Skip to content
Closed
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
88 changes: 88 additions & 0 deletions src/Microsoft.ML.AutoML/AutoPipeline/AutoEstimatorChain.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.ML.Data;
using Microsoft.ML.Internal.Utilities;
using Microsoft.ML.Runtime;
using Tensorflow;

namespace Microsoft.ML.AutoPipeline
{
internal class AutoEstimatorChain<TLastTransformer> : IEstimator<TransformerChain<TLastTransformer>>
where TLastTransformer : class, ITransformer
{
private readonly TransformerScope[] _scopes;
private readonly IEstimator<ITransformer>[] _estimators;
public readonly IEstimator<TLastTransformer> LastEstimator;

public AutoEstimatorChain(IEstimator<ITransformer>[] estimators, TransformerScope[] scopes)
{
Contracts.AssertValueOrNull(estimators);
Contracts.AssertValueOrNull(scopes);
Contracts.Assert(Utils.Size(estimators) == Utils.Size(scopes));
_estimators = estimators ?? new IEstimator<ITransformer>[0];
_scopes = scopes ?? new TransformerScope[0];
LastEstimator = estimators.LastOrDefault() as IEstimator<TLastTransformer>;
}

public AutoEstimatorChain()
{
_estimators = new IEstimator<ITransformer>[0];
_scopes = new TransformerScope[0];
LastEstimator = null;
}

public TransformerChain<TLastTransformer> Fit(IDataView input)
{
GetOutputSchema(SchemaShape.Create(input.Schema));

while (true)
{

}
}

public IEnumerable<(TransformerChain<TLastTransformer>, ISweeper)> Fits(IDataView input)
{
GetOutputSchema(SchemaShape.Create(input.Schema));

// index of autoEstimator
var autoEstimator = _estimators.Where(_est => _est is IAutoEstimator).FirstOrDefault() as IAutoEstimator;
while (true)
{
// check sweeper
if (autoEstimator.Sweeper.MoveNext() == false)
{
yield break;
}

IDataView current = input;
var xfs = new ITransformer[_estimators.Length];
for (int i = 0; i < _estimators.Length; i++)
{
var est = _estimators[i];
xfs[i] = est.Fit(current);
current = xfs[i].Transform(current);
}

yield return (new TransformerChain<TLastTransformer>(xfs, _scopes), autoEstimator.Sweeper);
}
}

public SchemaShape GetOutputSchema(SchemaShape inputSchema)
{
var s = inputSchema;
foreach (var est in _estimators)
s = est.GetOutputSchema(s);
return s;
}

public AutoEstimatorChain<TNewTrans> Append<TNewTrans>(IEstimator<TNewTrans> estimator, TransformerScope scope = TransformerScope.Everything)
where TNewTrans: class, ITransformer
{
Contracts.CheckValue(estimator, nameof(estimator));
return new AutoEstimatorChain<TNewTrans>(_estimators.AppendElement(estimator), _scopes.AppendElement(scope));
}
}
}
27 changes: 27 additions & 0 deletions src/Microsoft.ML.AutoML/AutoPipeline/AutoEstimatorExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
using Microsoft.ML.Data;

namespace Microsoft.ML.AutoPipeline
{
internal static class AutoEstimatorExtension
{
public static AutoEstimatorChain<TNewTrain>
Append<TLastTrain, TNewTrain, TOption>(this EstimatorChain<TLastTrain> estimatorChain,
Func<TOption, IEstimator<TNewTrain>> estimatorBuilder,
OptionBuilder<TOption> parameters,
ISweeper sweeper,
TransformerScope scope = TransformerScope.Everything)
where TLastTrain: class, ITransformer
where TNewTrain: class, ITransformer
where TOption: class
{
var autoEstimator = new AutoEstimator<TNewTrain, TOption>(estimatorBuilder, parameters, sweeper);

return new AutoEstimatorChain<TLastTrain>(estimatorChain.GetEstimators, estimatorChain.GetScopes)
.Append(autoEstimator, scope);
}
}
}
71 changes: 71 additions & 0 deletions src/Microsoft.ML.AutoML/AutoPipeline/IAutoEstimator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Microsoft.ML.AutoPipeline
{
internal interface IAutoEstimator
{
ISweeper Sweeper { get; }
}

internal interface IAutoEstimator<out TTransformer>: IEstimator<TTransformer>, IAutoEstimator
where TTransformer: ITransformer
{
IEstimator<TTransformer> ToEstimator();
}

internal class AutoEstimator<TTransformer, TOption> : IAutoEstimator<TTransformer>
where TTransformer : ITransformer
where TOption: class
{
private readonly ISweeper _sweeper;
private readonly OptionBuilder<TOption> _optionBuilder;
private readonly Func<TOption, IEstimator<TTransformer>> _estimatorFactory;
private IEstimator<TTransformer> _current;

public AutoEstimator(Func<TOption, IEstimator<TTransformer>> estimatorFactory, OptionBuilder<TOption> optionBuilder, ISweeper sweeper)
{
this._estimatorFactory = estimatorFactory;
this._optionBuilder = optionBuilder;
this._sweeper = sweeper;
}

public ISweeper Sweeper => this._sweeper;

public TTransformer Fit(IDataView input)
{
var sweepOutput = this._sweeper.Current;
var option = this._optionBuilder.BuildOption(sweepOutput);
this._current = this._estimatorFactory(option);
return this._current.Fit(input);
}

public void AddRunHistory(IEnumerable<IRunResult> input, SweeperInput Y)
{
this._sweeper.AddRunHistory(input, Y);
}

public SchemaShape GetOutputSchema(SchemaShape inputSchema)
{
var defaultOption = this._optionBuilder.CreateDefaultOption();
var defaultEstimator = this._estimatorFactory(defaultOption);
return defaultEstimator.GetOutputSchema(inputSchema);
}

public bool MoveNext()
{
return this._sweeper?.MoveNext() ?? false;
}

public void Reset()
{
this._sweeper?.Reset();
}

public IEstimator<TTransformer> ToEstimator()
{
return this._current;
}
}
}
65 changes: 65 additions & 0 deletions src/Microsoft.ML.AutoML/AutoPipeline/Sweeper/GridSearchSweeper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.ML.Sweeper;

namespace Microsoft.ML.AutoPipeline
{
internal class GridSearchSweeper : ISweeper
{
private ParameterSet _next;
private ParameterSet[] _results;
private readonly RandomGridSweeper _gridSweeper;
private int _maximum;

public GridSearchSweeper(MLContext context, IValueGenerator[] valueGenerators, int maximum = 10000)
{
var option = new RandomGridSweeper.Options();
_maximum = maximum;
_gridSweeper = new RandomGridSweeper(context, option, valueGenerators);
_results = _gridSweeper.ProposeSweeps(maximum);
}

public ParameterSet Current => _next;

object IEnumerator.Current => _next;

public void Dispose()
{
return;
}

public IEnumerator<ParameterSet> GetEnumerator()
{
return this;
}

public bool MoveNext()
{
if(_maximum <= 0)
{
return false;
}
_next = _results[_maximum-1];
_maximum -= 1;
return true;
}

public void Reset()
{
return;
}

IEnumerator IEnumerable.GetEnumerator()
{
return this;
}

public void AddRunHistory(IEnumerable<IRunResult> input, SweeperInput Y)
{
throw new NotImplementedException();
}
}
}
22 changes: 22 additions & 0 deletions src/Microsoft.ML.AutoML/AutoPipeline/Sweeper/ISweeper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Microsoft.ML.AutoPipeline
{
internal interface ISweeper: IEnumerable<ParameterSet>, IEnumerator<ParameterSet>
{
/// <summary>
/// For trainable Sweeper.
/// </summary>
/// <param name="input">Output of Sweeper.</param>
/// <param name="Y">Score from model</param>
void AddRunHistory(IEnumerable<IRunResult> input, SweeperInput Y);
}

internal class SweeperInput
{
public double Score { get; set; }
}

}
55 changes: 55 additions & 0 deletions src/Microsoft.ML.AutoML/AutoPipeline/Sweeper/OptionBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Microsoft.ML.AutoPipeline
{
internal abstract class OptionBuilder<TOption>
where TOption: class
{
public IValueGenerator[] ValueGenerators { get => this.GetParameterAttributes().Select(kv => kv.Value.ValueGenerator).ToArray(); }

public TOption CreateDefaultOption()
{
var assem = typeof(TOption).Assembly;
var option = assem.CreateInstance(typeof(TOption).FullName) as TOption;

// set up fields
var fields = this.GetType().GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
foreach(var field in fields)
{
var value = field.GetValue(this);
option.GetType().GetField(field.Name)?.SetValue(option, value);
}

return option;
}

public TOption BuildOption(Microsoft.ML.ParameterSet parameters)
{
var option = CreateDefaultOption();
foreach(var param in parameters)
{
var value = param.RawValue;
typeof(TOption).GetField(param.Name)?.SetValue(option, value);
}

return option;
}

private Dictionary<string, ParameterAttribute> GetParameterAttributes()
{
var paramaters = this.GetType().GetFields()
.Where(x => Attribute.GetCustomAttribute(x, typeof(ParameterAttribute)) != null);

var paramatersDictionary = new Dictionary<string, ParameterAttribute>();
foreach (var param in paramaters)
{
paramatersDictionary.Add(param.Name, Attribute.GetCustomAttribute(param, typeof(ParameterAttribute)) as ParameterAttribute);
}

return paramatersDictionary;
}
}
}
Loading