CustomMappingCatalog.CustomMapping<TSrc,TDst> 方法

定義

建立 CustomMappingEstimator<TSrc,TDst> ,它會將輸入資料行的自訂對應套用至輸出資料行。

public static Microsoft.ML.Transforms.CustomMappingEstimator<TSrc,TDst> CustomMapping<TSrc,TDst> (this Microsoft.ML.TransformsCatalog catalog, Action<TSrc,TDst> mapAction, string contractName, Microsoft.ML.Data.SchemaDefinition inputSchemaDefinition = default, Microsoft.ML.Data.SchemaDefinition outputSchemaDefinition = default) where TSrc : class, new() where TDst : class, new();
static member CustomMapping : Microsoft.ML.TransformsCatalog * Action<'Src, 'Dst (requires 'Src : null and 'Src : (new : unit -> 'Src) and 'Dst : null and 'Dst : (new : unit -> 'Dst))> * string * Microsoft.ML.Data.SchemaDefinition * Microsoft.ML.Data.SchemaDefinition -> Microsoft.ML.Transforms.CustomMappingEstimator<'Src, 'Dst (requires 'Src : null and 'Src : (new : unit -> 'Src) and 'Dst : null and 'Dst : (new : unit -> 'Dst))> (requires 'Src : null and 'Src : (new : unit -> 'Src) and 'Dst : null and 'Dst : (new : unit -> 'Dst))
<Extension()>
Public Function CustomMapping(Of TSrc As {Class, New}, TDst As {Class, New}) (catalog As TransformsCatalog, mapAction As Action(Of TSrc, TDst), contractName As String, Optional inputSchemaDefinition As SchemaDefinition = Nothing, Optional outputSchemaDefinition As SchemaDefinition = Nothing) As CustomMappingEstimator(Of TSrc, TDst)

類型參數

TSrc

類別,定義要從傳入資料取用的資料行。

TDst

類別,定義要新增至資料的新資料行。

參數

catalog
TransformsCatalog

轉換目錄

mapAction
Action<TSrc,TDst>

對應動作。 這必須是安全線程且不受副作用影響。 如果產生的轉換器必須能夠儲存,則定義 mapAction 類別應該實 CustomMappingFactory<TSrc,TDst> 作,且必須使用 CustomMappingFactoryAttributeAttribute 提供的 contractName 裝飾。 在 v1.5-preview2 和更早版本中,包含 類別的元件應該註冊于使用 RegisterAssembly(Assembly, Boolean) 載入回的環境中。

contractName
String

ML.NET 用來載入模型的合約名稱。 如果 null 已指定,產生的轉換器將無法儲存。

inputSchemaDefinition
SchemaDefinition

與輸入資料之間的 TSrc 架構對應的其他參數。 處理批註時很有用。

outputSchemaDefinition
SchemaDefinition

與輸出資料之間 TDst 架構對應的其他參數。 處理批註時很有用。

傳回

範例

using System;
using System.Collections.Generic;
using Microsoft.ML;

namespace Samples.Dynamic
{
    public static class CustomMapping
    {
        // This example shows how to define and apply a custom mapping of input
        // columns to output columns without defining a contract. Since a contract
        // is not defined, the pipeline containing this mapping cannot be saved and
        // loaded back.
        public static void Example()
        {
            // Create a new ML context, for ML.NET operations. It can be used for
            // exception tracking and logging, as well as the source of randomness.
            var mlContext = new MLContext();

            // Get a small dataset as an IEnumerable and convert it to an IDataView.
            var samples = new List<InputData>
            {
                new InputData { Age = 26 },
                new InputData { Age = 35 },
                new InputData { Age = 34 },
                new InputData { Age = 28 },
            };
            var data = mlContext.Data.LoadFromEnumerable(samples);

            // We define the custom mapping between input and output rows that will
            // be applied by the transformation.
            Action<InputData, CustomMappingOutput> mapping =
                (input, output) => output.IsUnderThirty = input.Age < 30;

            // Custom transformations can be used to transform data directly, or as
            // part of a pipeline of estimators. Note: If contractName is null in
            // the CustomMapping estimator, any pipeline of estimators containing
            // it, cannot be saved and loaded back. 
            var pipeline = mlContext.Transforms.CustomMapping(mapping, contractName:
                null);

            // Now we can transform the data and look at the output to confirm the
            // behavior of the estimator. This operation doesn't actually evaluate
            // data until we read the data below.
            var transformer = pipeline.Fit(data);
            var transformedData = transformer.Transform(data);

            var dataEnumerable = mlContext.Data.CreateEnumerable<TransformedData>(
                transformedData, reuseRowObject: true);

            Console.WriteLine("Age\t IsUnderThirty");
            foreach (var row in dataEnumerable)
                Console.WriteLine($"{row.Age}\t {row.IsUnderThirty}");

            // Expected output:
            // Age      IsUnderThirty
            // 26       True
            // 35       False
            // 34       False
            // 28       True
        }

        // Defines only the column to be generated by the custom mapping
        // transformation in addition to the columns already present.
        private class CustomMappingOutput
        {
            public bool IsUnderThirty { get; set; }
        }

        // Defines the schema of the input data.
        private class InputData
        {
            public float Age { get; set; }
        }

        // Defines the schema of the transformed data, which includes the new column
        // IsUnderThirty.
        private class TransformedData : InputData
        {
            public bool IsUnderThirty { get; set; }
        }
    }
}
using System;
using System.Collections.Generic;
using Microsoft.ML;
using Microsoft.ML.Transforms;

namespace Samples.Dynamic
{
    public static class CustomMappingSaveAndLoad
    {
        // This example shows how to define and apply a custom mapping of input
        // columns to output columns with a contract name. The contract name is
        // used in the CustomMappingFactoryAttribute that decorates the custom
        // mapping action. The pipeline containing the custom mapping can then be
        // saved to disk, and it can be loaded back after the assembly containing
        // the custom mapping action is registered.
        public static void Example()
        {
            // Create a new ML context, for ML.NET operations. It can be used for
            // exception tracking and logging, as well as the source of randomness.
            var mlContext = new MLContext();

            // Get a small dataset as an IEnumerable and convert it to an IDataView.
            var samples = new List<InputData>
            {
                new InputData { Age = 26 },
                new InputData { Age = 35 },
                new InputData { Age = 34 },
                new InputData { Age = 28 },
            };
            var data = mlContext.Data.LoadFromEnumerable(samples);

            // Custom transformations can be used to transform data directly, or as
            // part of a pipeline of estimators. The contractName must be provided
            // in order for a pipeline containing a CustomMapping estimator to be
            // saved and loaded back. The contractName must be the same as in the
            // CustomMappingFactoryAttribute used to decorate the custom action
            // defined by the user.
            var pipeline = mlContext.Transforms.CustomMapping(new
                IsUnderThirtyCustomAction().GetMapping(), contractName:
                "IsUnderThirty");

            var transformer = pipeline.Fit(data);

            // To save and load the CustomMapping estimator, the assembly in which
            // the custom action is defined needs to be registered in the
            // environment. The following registers the assembly where
            // IsUnderThirtyCustomAction is defined.    
            // This is necessary only in versions v1.5-preview2 and earlier
            mlContext.ComponentCatalog.RegisterAssembly(typeof(
                IsUnderThirtyCustomAction).Assembly);

            // Now the transform pipeline can be saved and loaded through the usual
            // MLContext method. 
            mlContext.Model.Save(transformer, data.Schema, "customTransform.zip");
            var loadedTransform = mlContext.Model.Load("customTransform.zip", out
                var inputSchema);

            // Now we can transform the data and look at the output to confirm the
            // behavior of the estimator. This operation doesn't actually evaluate
            // data until we read the data below.
            var transformedData = loadedTransform.Transform(data);

            var dataEnumerable = mlContext.Data.CreateEnumerable<TransformedData>(
                transformedData, reuseRowObject: true);

            Console.WriteLine("Age\tIsUnderThirty");
            foreach (var row in dataEnumerable)
                Console.WriteLine($"{row.Age}\t {row.IsUnderThirty}");

            // Expected output:
            // Age      IsUnderThirty
            // 26       True
            // 35       False
            // 34       False
            // 28       True
        }

        // The custom action needs to implement the abstract class
        // CustomMappingFactory, and needs to have attribute
        // CustomMappingFactoryAttribute with argument equal to the contractName
        // used to define the CustomMapping estimator which uses the action.
        [CustomMappingFactoryAttribute("IsUnderThirty")]
        private class IsUnderThirtyCustomAction : CustomMappingFactory<InputData,
            CustomMappingOutput>
        {
            // We define the custom mapping between input and output rows that will
            // be applied by the transformation.
            public static void CustomAction(InputData input, CustomMappingOutput
                output) => output.IsUnderThirty = input.Age < 30;

            public override Action<InputData, CustomMappingOutput> GetMapping()
                => CustomAction;
        }

        // Defines only the column to be generated by the custom mapping
        // transformation in addition to the columns already present.
        private class CustomMappingOutput
        {
            public bool IsUnderThirty { get; set; }
        }

        // Defines the schema of the input data.
        private class InputData
        {
            public float Age { get; set; }
        }

        // Defines the schema of the transformed data, which includes the new column
        // IsUnderThirty.
        private class TransformedData : InputData
        {
            public bool IsUnderThirty { get; set; }
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.ML;
using Microsoft.ML.Data;

namespace Samples.Dynamic
{
    class CustomMappingWithInMemoryCustomType
    {
        // This example shows how custom mapping actions can be performed on custom data
        // types that ML.NET doesn't know yet. The example tells a story of how two alien
        // bodies are merged to form a super alien with a single body.
        //
        // Here, the type AlienHero represents a single alien entity with a member "Name"
        // of type string and members "One" and "Two" of type AlienBody. It defines a custom
        // mapping action AlienFusionProcess that takes an AlienHero and "fuses" its two
        // AlienBody members to produce a SuperAlienHero entity with a "Name" member of type
        // string and a single "Merged" member of type AlienBody, where the merger is just
        // the addition of the various members of AlienBody.
        public static void Example()
        {
            var mlContext = new MLContext();
            // Build in-memory data.
            var tribe = new List<AlienHero>() { new AlienHero("ML.NET", 2, 1000,
                2000, 3000, 4000, 5000, 6000, 7000) };

            // Build a ML.NET pipeline and make prediction.
            var tribeDataView = mlContext.Data.LoadFromEnumerable(tribe);
            var pipeline = mlContext.Transforms.CustomMapping(AlienFusionProcess
                .GetMapping(), contractName: null);

            var model = pipeline.Fit(tribeDataView);
            var tribeTransformed = model.Transform(tribeDataView);

            // Print out prediction produced by the model.
            var firstAlien = mlContext.Data.CreateEnumerable<SuperAlienHero>(
                tribeTransformed, false).First();

            Console.WriteLine("We got a super alien with name " + firstAlien.Name +
                ", age " + firstAlien.Merged.Age + ", " + "height " + firstAlien
                .Merged.Height + ", weight  " + firstAlien.Merged.Weight + ", and "
                + firstAlien.Merged.HandCount + " hands.");

            // Expected output:
            //   We got a super alien with name Super ML.NET, age 4002, height 6000, weight 8000, and 10000 hands.

            // Create a prediction engine and print out its prediction.
            var engine = mlContext.Model.CreatePredictionEngine<AlienHero,
                SuperAlienHero>(model);

            var alien = new AlienHero("TEN.LM", 1, 2, 3, 4, 5, 6, 7, 8);
            var superAlien = engine.Predict(alien);
            Console.Write("We got a super alien with name " + superAlien.Name +
                ", age " + superAlien.Merged.Age + ", height " +
                superAlien.Merged.Height + ", weight " + superAlien.Merged.Weight +
                ", and " + superAlien.Merged.HandCount + " hands.");

            // Expected output:
            //   We got a super alien with name Super TEN.LM, age 6, height 8, weight 10, and 12 hands.
        }

        // A custom type which ML.NET doesn't know yet. Its value will be loaded as
        // a DataView column in this example.
        //
        // The type members represent the characteristics of an alien body that will
        // be merged in the AlienFusionProcess.
        private class AlienBody
        {
            public int Age { get; set; }
            public float Height { get; set; }
            public float Weight { get; set; }
            public int HandCount { get; set; }

            public AlienBody(int age, float height, float weight, int handCount)
            {
                Age = age;
                Height = height;
                Weight = weight;
                HandCount = handCount;
            }
        }

        // DataViewTypeAttribute applied to class AlienBody members. This attribute
        // defines how class AlienBody is registered in ML.NET's type system. In this
        // case, AlienBody is registered as DataViewAlienBodyType in ML.NET. The RaceId
        // property allows different members of type AlienBody to be registered with
        // different types in ML.NEt (see usage in class AlienHero).
        private sealed class AlienTypeAttributeAttribute : DataViewTypeAttribute
        {
            public int RaceId { get; }

            // Create an DataViewTypeAttribute> from raceId to a AlienBody.
            public AlienTypeAttributeAttribute(int raceId)
            {
                RaceId = raceId;
            }

            // A function implicitly invoked by ML.NET when processing a custom
            // type. It binds a DataViewType to a custom type plus its attributes.
            public override void Register()
            {
                DataViewTypeManager.Register(new DataViewAlienBodyType(RaceId),
                    typeof(AlienBody), this);
            }

            public override bool Equals(DataViewTypeAttribute other)
            {
                if (other is AlienTypeAttributeAttribute alienTypeAttributeAttribute)
                    return RaceId == alienTypeAttributeAttribute.RaceId;
                return false;
            }

            public override int GetHashCode() => RaceId.GetHashCode();
        }

        // A custom class with a type which ML.NET doesn't know yet. Its value will
        // be loaded as a DataView row in this example. It will be the input of
        // AlienFusionProcess.MergeBody(AlienHero, SuperAlienHero).
        //
        // The members One and Two would be mapped to different types inside
        // ML.NET type system because they have different 
        // AlienTypeAttributeAttribute's. For example, the column type of One would
        // be DataViewAlienBodyType with RaceId=100.
        //
        // This type represents a "Hero" Alien that is a single entity with two bodies.
        // The "Hero" undergoes a fusion process defined in AlienFusionProcess to
        // become a SuperAlienHero with a single body that is a merger of the two
        // bodies.
        private class AlienHero
        {
            public string Name { get; set; }

            [AlienTypeAttribute(100)]
            public AlienBody One { get; set; }

            [AlienTypeAttribute(200)]
            public AlienBody Two { get; set; }

            public AlienHero()
            {
                Name = "Unknown";
                One = new AlienBody(0, 0, 0, 0);
                Two = new AlienBody(0, 0, 0, 0);
            }

            public AlienHero(string name,
                int age, float height, float weight, int handCount,
                int anotherAge, float anotherHeight, float anotherWeight, int
                    anotherHandCount)
            {
                Name = name;
                One = new AlienBody(age, height, weight, handCount);
                Two = new AlienBody(anotherAge, anotherHeight, anotherWeight,
                    anotherHandCount);
            }
        }

        // Type of AlienBody in ML.NET's type system. This is the data view type that
        // will represent AlienBody in ML.NET's type system when it is registered as
        // such in AlienTypeAttributeAttribute.
        // It usually shows up as DataViewSchema.Column.Type among IDataView.Schema.
        private class DataViewAlienBodyType : StructuredDataViewType
        {
            public int RaceId { get; }

            public DataViewAlienBodyType(int id) : base(typeof(AlienBody))
            {
                RaceId = id;
            }

            public override bool Equals(DataViewType other)
            {
                if (other is DataViewAlienBodyType otherAlien)
                    return otherAlien.RaceId == RaceId;
                return false;
            }

            public override int GetHashCode()
            {
                return RaceId.GetHashCode();
            }
        }

        // The output type of processing AlienHero using AlienFusionProcess
        // .MergeBody(AlienHero, SuperAlienHero).
        // This is a "fused" alien whose body is a merger of the two bodies
        // of AlienHero.
        private class SuperAlienHero
        {
            public string Name { get; set; }

            [AlienTypeAttribute(007)]
            public AlienBody Merged { get; set; }

            public SuperAlienHero()
            {
                Name = "Unknown";
                Merged = new AlienBody(0, 0, 0, 0);
            }
        }

        // The implementation of custom mapping is MergeBody. It accepts AlienHero
        // and produces SuperAlienHero.
        private class AlienFusionProcess
        {
            public static void MergeBody(AlienHero input, SuperAlienHero output)
            {
                output.Name = "Super " + input.Name;
                output.Merged.Age = input.One.Age + input.Two.Age;
                output.Merged.Height = input.One.Height + input.Two.Height;
                output.Merged.Weight = input.One.Weight + input.Two.Weight;
                output.Merged.HandCount = input.One.HandCount + input.Two.HandCount;
            }

            public static Action<AlienHero, SuperAlienHero> GetMapping()
            {
                return MergeBody;
            }
        }
    }
}

適用於