f# - 如何将 "Hello ML.NET World"示例翻译成 F#?

标签 f# ml.net

我正在尝试翻译 "Hello ML.NET World" example从 C# 到 F#(代码复制如下),但我收到有关不兼容类型的 F# 编译器错误。

我看过一些关于 ML.NET 和 F# 的博客文章,但它们都使用旧 API,其中涉及显式创建 LearningPipeline 对象。据我所知,此 API 已被删除。

C# 中有问题的行是训练管道的行:

var pipeline = mlContext.Transforms.Concatenate("Features", new[] { "Size" })
    .Append(mlContext.Regression.Trainers.Sdca(labelColumnName: "Price", maximumNumberOfIterations: 100));

我试图像这样翻译成 F#:

let pipeline (mlContext:MLContext) =
    mlContext.Transforms
        .Concatenate("Features", [| "Size" |])
        .Append(mlContext.Regression.Trainers.Sdca(labelColumnName = "Price", maximumNumberOfIterations = Nullable(100)))

但是,我遇到了编译器错误:Type constraint mismatch: The type 'Transforms.ColumnConcatenatingEstimator' is not compatible with the type IEstimator<ITransformer>' .

我还尝试将 ColumnConcatenatingEstimator 显式向下转换为 IEstimator:

let pipeline' (mlContext:MLContext) =
    let concat = mlContext.Transforms.Concatenate("Features", [| "Size" |])
    let scda = mlContext.Regression.Trainers.Sdca(labelColumnName = "Price", maximumNumberOfIterations = Nullable(100))

    let concatAsEstimator = concat :> IEstimator<_>
    concatAsEstimator.Append(scda)

这会稍微改变编译器错误中的类型。新消息表明 IEstimator<ColumnConcatenatingTransformer>IEstimator<ITransformer> 不兼容.

看起来我需要将泛型中的 ColumnConcatenatingTransformer 显式向下转换为 ITransformer,但我不确定如何在 F# 中执行此操作。这可能吗?

作为引用,这是我正在尝试改编的来自 Microsoft 的完整 C# 代码:

using System;
using Microsoft.ML;
using Microsoft.ML.Data;

class Program
{
   public class HouseData
   {
       public float Size { get; set; }
       public float Price { get; set; }
   }

   public class Prediction
   {
       [ColumnName("Score")]
       public float Price { get; set; }
   }

   static void Main(string[] args)
   {
       MLContext mlContext = new MLContext();

       // 1. Import or create training data
       HouseData[] houseData = {
           new HouseData() { Size = 1.1F, Price = 1.2F },
           new HouseData() { Size = 1.9F, Price = 2.3F },
           new HouseData() { Size = 2.8F, Price = 3.0F },
           new HouseData() { Size = 3.4F, Price = 3.7F } };
       IDataView trainingData = mlContext.Data.LoadFromEnumerable(houseData);

       // 2. Specify data preparation and model training pipeline
       var pipeline = mlContext.Transforms.Concatenate("Features", new[] { "Size" })
           .Append(mlContext.Regression.Trainers.Sdca(labelColumnName: "Price", maximumNumberOfIterations: 100));

       // 3. Train model
       var model = pipeline.Fit(trainingData);

       // 4. Make a prediction
       var size = new HouseData() { Size = 2.5F };
       var price = mlContext.Model.CreatePredictionEngine<HouseData, Prediction>(model).Predict(size);

       Console.WriteLine($"Predicted price for size: {size.Size*1000} sq ft= {price.Price*100:C}k");

       // Predicted price for size: 2500 sq ft= $261.98k
   }
}

(编辑:澄清一下,这与 How to translate the intro ML.NET demo to F# 不同。)这是一个不同的代码示例,它使用更新版本的 ML.NET。该答案中的 Microsoft 链接现在似乎也已损坏。

最佳答案

ML.NET 在构建时考虑了 C#,因此有时转换为 F# 需要在任何地方添加 Nullablefloat32。 这是我摆脱 PredictionEngine 的版本,我将 Sdca 作为训练器并使用 EstimatorChain() 附加并创建一个 IEstimator

open System
open Microsoft.ML
open Microsoft.ML.Data


type HouseData = 
    {
        Size  : float32
        Price : float32 
    }
let downcastPipeline (x : IEstimator<_>) = 
    match x with 
    | :? IEstimator<ITransformer> as y -> y
    | _ -> failwith "downcastPipeline: expecting a IEstimator<ITransformer>"

let mlContext = MLContext(Nullable 0)
let houseData = 
    [|
        { Size = 1.1F; Price = 1.2F }
        { Size = 1.1F; Price = 1.2F }
        { Size = 2.8F; Price = 3.0F }
        { Size = 3.4F; Price = 3.7F }
    |] |> mlContext.Data.LoadFromEnumerable 
let trainer = 
    mlContext.Regression.Trainers.Sdca(
        labelColumnName= "Label",
        featureColumnName = "Features",
        maximumNumberOfIterations = Nullable 100
        )
let pipeline = 
    EstimatorChain()
        .Append(mlContext.Transforms.Concatenate("Features", "Size"))
        .Append(mlContext.Transforms.CopyColumns("Label", "Price"))
        .Append(trainer)
    |> downcastPipeline 

let model = pipeline.Fit houseData

let newSize = [| {Size = 2.5f; Price = 0.f} |] 
let prediction = 
    newSize
    |> mlContext.Data.LoadFromEnumerable
    |> model.Transform
    |> fun x -> x.GetColumn<float32> "Score"
    |> Seq.toArray
printfn "Predicted price for size: %.0f sq ft= %.2fk" (newSize.[0].Size * 1000.f) (prediction.[0] * 100.f)

结果

Predicted price for size: 2500 sq ft= 270.69k

乔恩·伍德的视频 F# ML.Net也是开始在 F# 中使用 ML.Net 的好地方。

关于f# - 如何将 "Hello ML.NET World"示例翻译成 F#?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61663860/

相关文章:

f# - 如何在嵌套范围内引用同名类型

ml.net - 使用 ML.NET 训练模型时在空字符串上使用占位符

.net - 使用内部委托(delegate)类型编译 lambda 表达式

f# - 序列到字典

f# - 使用单例区分联合类型是否会对性能产生影响?

F# 更改列表中的元素并返回完整的新列表

c# - 无法使 ONNX 模型的输入列名称起作用

c# - ML.NET 无法在 uwp 上运行

ml.net - 动态类/对象 ML.net 的 PredictionMoadel<TInput, TOutput> Train()

ml.net - 有没有办法重新打开 ML.NET 模型生成器?