* F# mnist sample

* add F# mnist sample to main readme

* fix key ordering
This commit is contained in:
Kevin Malenfant 2019-04-23 11:22:51 -06:00 коммит произвёл prathyusha12345
Родитель b9f389cbdd
Коммит 1c3e4baa46
8 изменённых файлов: 5878 добавлений и 1 удалений

Просмотреть файл

@ -57,7 +57,7 @@ The official ML.NET samples are divided in multiple categories depending on the
<h4>Issues classification &nbsp;&nbsp;&nbsp;
<a href="samples/csharp/end-to-end-apps/MulticlassClassification-GitHubLabeler">C#</a> &nbsp;&nbsp;&nbsp;<a href="samples/fsharp/end-to-end-apps/MulticlassClassification-GitHubLabeler">F#</a> &nbsp;&nbsp;&nbsp;<img src="images/app-type-e2e.png" alt="End-to-end app icon"></h4>
<h4>Iris flowers classification &nbsp;&nbsp;&nbsp;<a href="samples/csharp/getting-started/MulticlassClassification_Iris">C#</a> &nbsp; &nbsp;<a href="samples/fsharp/getting-started/MulticlassClassification_Iris">F#</a> &nbsp;&nbsp;&nbsp;<img src="images/app-type-getting-started.png" alt="Getting started icon"></h4>
<h4>MNIST &nbsp;&nbsp;&nbsp;<a href="samples/csharp/getting-started/MulticlassClassification_mnist">C#</a> &nbsp; &nbsp;&nbsp;<img src="images/app-type-getting-started.png" alt="Getting started icon"></h4>
<h4>MNIST &nbsp;&nbsp;&nbsp;<a href="samples/csharp/getting-started/MulticlassClassification_mnist">C#</a> &nbsp;&nbsp;&nbsp;<a href="samples/fsharp/getting-started/MulticlassClassification_mnist">F#</a> &nbsp; &nbsp;&nbsp;<img src="images/app-type-getting-started.png" alt="Getting started icon"></h4>
</td>
</tr>
<tr>

Просмотреть файл

@ -0,0 +1,115 @@
# MNIST Classification
| ML.NET version | API type | Status | App Type | Data type | Scenario | ML Task | Algorithms |
|----------------|-------------------|-------------------------------|-------------|-----------|---------------------|---------------------------|-----------------------------|
| v1.0.0-preview | Dynamic API | Up-to-date | Console app | .csv files | MNIST classification | Multi-class classification | Sdca Multi-class |
In this introductory sample, you'll see how to use [ML.NET](https://www.microsoft.com/net/learn/apps/machine-learning-and-ai/ml-dotnet) to classify handwritten digits from 0 to 9 using the MNIST dataset. This is a **multiclass classification** problem that we will solve using SDCA (Stochastic Dual Coordinate Ascent) algorithm.
## Problem
The MNIST data set contains handwritten images of digits, ranging from 0 to 9.
The MNIST dataset we are using contains 65 columns of numbers. The first 64 columns in each row are integer values in the range from 0 to 16. These values are calculated by dividing 32 x 32 bitmaps into non-overlapping blocks of 4 x 4. The number of ON pixels is counted in each of these blocks, which generates an input matrix of 8 x 8. The last column in each row is the number that is represented by the values in the first 64 columns. These first 64 columns are our features and our ML model will use these features to classifiy the testing images. The last column in our training and validation datasets is the label - the actual number that we will predict using our ML model.
the ML model that we will build will return probabilities for a given image of being one of the numbers from 0 to 9 as explained above.
## ML task - Multiclass classification
The generalized problem of **multiclass classification** is to classify items into one of three or more classes. (Classifying items into one of the two classes is called **binary classification**).
## Solution
To solve this problem, first we will build an ML model. Then we will train the model on existing data, evaluate how good it is, and lastly we'll consume the model to predict a number the given image represents.
![Build -> Train -> Evaluate -> Consume](../shared_content/modelpipeline.png)
### 1. Build model
Building a model includes:
* Uploading data (`optdigits-train.csv`) with (`DataReader`)
* Create an Estimator and transform the data in the first 64 columns to one column so it can be used effectively by an ML algorithm (with `Concatenate`)
* Choosing a learning algorithm (`StochasticDualCoordinateAscent`).
The initial code is similar to the following:
```fsharp
// STEP 1: Common data loading configuration
let trainData = mlContext.Data.LoadFromTextFile<Input>(trainDataPath, separatorChar=',', hasHeader=false)
let testData = mlContext.Data.LoadFromTextFile<Input>(testDataPath, separatorChar=',', hasHeader=false)
// STEP 2: Common data process configuration with pipeline data transformations
// Use in-memory cache for small/medium datasets to lower training time. Do NOT use it (remove .AppendCacheCheckpoint()) when handling very large datasets.
let dataProcessPipeline =
EstimatorChain()
.Append(mlContext.Transforms.Conversion.MapValueToKey("Label", "Number"))
.Append(mlContext.Transforms.Concatenate("Features", "PixelValues"))
.AppendCacheCheckpoint(mlContext)
// STEP 3: Set the training algorithm, then create and config the modelBuilder
let trainer = mlContext.MulticlassClassification.Trainers.SdcaMaximumEntropy("Label", "Features")
let trainingPipeline =
dataProcessPipeline
.Append(trainer)
.Append(mlContext.Transforms.Conversion.MapKeyToValue("Number", "Label"))
```
### 2. Train model
Training the model is a process of running the chosen algorithm on a training data to tune the parameters of the model. Our training data consists of pixel values and the digit they represent. It is implemented in the `Fit()` method from the Estimator object.
To perform training we just call the method providing the training dataset (optdigits-train.csv file) in a DataView object.
```fsharp
// STEP 4: Train the model fitting to the DataSet
let watch = System.Diagnostics.Stopwatch.StartNew();
printfn "=============== Training the model ==============="
let trainedModel = trainingPipeline.Fit(trainData)
```
### 3. Evaluate model
We need this step to conclude how accurate our model operates on new data. To do so, the model from the previous step is run against another dataset that was not used in training (`optdigits-val.csv`). `MulticlassClassification.Evaluate` calculates the difference between known types and values predicted by the model in various metrics.
```fsharp
let predictions = trainedModel.Transform(testData)
let metrics = mlContext.MulticlassClassification.Evaluate(predictions, "Number", "Score")
Common.ConsoleHelper.printMultiClassClassificationMetrics (trainer.ToString()) metrics
```
>*To learn more on how to understand the metrics, check out the Machine Learning glossary from the [ML.NET Guide](https://docs.microsoft.com/en-us/dotnet/machine-learning/) or use any available materials on data science and machine learning*.
If you are not satisfied with the quality of the model, there are a variety of ways to improve it, which will be covered in the *examples* category.
### 4. Consume model
After the model is trained, we can use the `Predict()` API to predict the probability of being correct digit.
```fsharp
let loadedTrainedModel, modelInputSchema = mlContext.Model.Load modelPath
// Create prediction engine related to the loaded trained model
let predEngine = mlContext.Model.CreatePredictionEngine<Input, Output>(loadedTrainedModel)
sampleData
|> Array.iter
(fun (n,dat) ->
let p = predEngine.Predict dat
printfn "Actual: %d Predicted probability: zero: %.4f" n p.Score.[0]
["one:"; "two:"; "three:"; "four:"; "five:"; "six:"; "seven:"; "eight:"; "nine:"]
|> List.iteri
(fun i w ->
let i = i + 1
printfn " %-6s %.4f" w p.Score.[i]
)
printfn ""
)
```
Where `sampleData` stores the pixel values of the digit that want to predict using the ML model.
```fsharp
let sampleData =
[|
7, {
Number = 0.f
PixelValues = [|0.f;0.f;0.f;0.f;14.f;13.f;1.f;0.f;0.f;0.f;0.f;5.f;16.f;16.f;2.f;0.f;0.f;0.f;0.f;14.f;16.f;12.f;0.f;0.f;0.f;1.f;10.f;16.f;16.f;12.f;0.f;0.f;0.f;3.f;12.f;14.f;16.f;9.f;0.f;0.f;0.f;0.f;0.f;5.f;16.f;15.f;0.f;0.f;0.f;0.f;0.f;4.f;16.f;14.f;0.f;0.f;0.f;0.f;0.f;1.f;13.f;16.f;1.f;0.f|]
}
//...
|]
```

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,2 @@
This folder is empty until you run the training console app and create/train and save the models as .ZIP files.
Those model .ZIP files should appear in this folder.

Просмотреть файл

@ -0,0 +1,111 @@
open Microsoft.ML
open Microsoft.ML.Data
open System
open System.IO
open Microsoft.ML.Transforms
[<CLIMutable>]
type Input =
{
[<LoadColumn(0,63); VectorType(64)>]
PixelValues : float32 []
[<LoadColumn(64)>]
Number : float32
}
[<CLIMutable>]
type Output = {Score : float32 []}
let sampleData =
[|
1, {
Number = 0.f
PixelValues = [|0.f;0.f;0.f;0.f;14.f;13.f;1.f;0.f;0.f;0.f;0.f;5.f;16.f;16.f;2.f;0.f;0.f;0.f;0.f;14.f;16.f;12.f;0.f;0.f;0.f;1.f;10.f;16.f;16.f;12.f;0.f;0.f;0.f;3.f;12.f;14.f;16.f;9.f;0.f;0.f;0.f;0.f;0.f;5.f;16.f;15.f;0.f;0.f;0.f;0.f;0.f;4.f;16.f;14.f;0.f;0.f;0.f;0.f;0.f;1.f;13.f;16.f;1.f;0.f|]
}
7, {
Number = 0.f
PixelValues = [|0.f;0.f;1.f;8.f;15.f;10.f;0.f;0.f;0.f;3.f;13.f;15.f;14.f;14.f;0.f;0.f;0.f;5.f;10.f;0.f;10.f;12.f;0.f;0.f;0.f;0.f;3.f;5.f;15.f;10.f;2.f;0.f;0.f;0.f;16.f;16.f;16.f;16.f;12.f;0.f;0.f;1.f;8.f;12.f;14.f;8.f;3.f;0.f;0.f;0.f;0.f;10.f;13.f;0.f;0.f;0.f;0.f;0.f;0.f;11.f;9.f;0.f;0.f;0.f|]
}
9, {
Number = 0.f
PixelValues = [|0.f;0.f;6.f;14.f;4.f;0.f;0.f;0.f;0.f;0.f;11.f;16.f;10.f;0.f;0.f;0.f;0.f;0.f;8.f;14.f;16.f;2.f;0.f;0.f;0.f;0.f;1.f;12.f;12.f;11.f;0.f;0.f;0.f;0.f;0.f;0.f;0.f;11.f;3.f;0.f;0.f;0.f;0.f;0.f;0.f;5.f;11.f;0.f;0.f;0.f;1.f;4.f;4.f;7.f;16.f;2.f;0.f;0.f;7.f;16.f;16.f;13.f;11.f;1.f|]
}
|]
let assemblyFolderPath = Path.GetDirectoryName(Reflection.Assembly.GetExecutingAssembly().Location)
let baseDatasetsRelativePath = @"../../../Data"
let trianDataRealtivePath = Path.Combine(baseDatasetsRelativePath, "optdigits-train.csv")
let testDataRealtivePath = Path.Combine(baseDatasetsRelativePath, "optdigits-val.csv")
let trainDataPath = Path.Combine(assemblyFolderPath, trianDataRealtivePath)
let testDataPath = Path.Combine(assemblyFolderPath, testDataRealtivePath)
let baseModelsRelativePath = @"../../../MLModels";
let modelRelativePath = Path.Combine(baseModelsRelativePath, "Model.zip")
let modelPath = Path.Combine(assemblyFolderPath, modelRelativePath)
let mlContext = new MLContext()
// STEP 1: Common data loading configuration
let trainData = mlContext.Data.LoadFromTextFile<Input>(trainDataPath, separatorChar=',', hasHeader=false)
let testData = mlContext.Data.LoadFromTextFile<Input>(testDataPath, separatorChar=',', hasHeader=false)
// STEP 2: Common data process configuration with pipeline data transformations
// Use in-memory cache for small/medium datasets to lower training time. Do NOT use it (remove .AppendCacheCheckpoint()) when handling very large datasets.
let dataProcessPipeline =
EstimatorChain()
.Append(mlContext.Transforms.Conversion.MapValueToKey("Label", "Number", keyOrdinality=ValueToKeyMappingEstimator.KeyOrdinality.ByValue))
.Append(mlContext.Transforms.Concatenate("Features", "PixelValues"))
.AppendCacheCheckpoint(mlContext)
// STEP 3: Set the training algorithm, then create and config the modelBuilder
let trainer = mlContext.MulticlassClassification.Trainers.SdcaMaximumEntropy("Label", "Features")
let trainingPipeline =
dataProcessPipeline
.Append(trainer)
.Append(mlContext.Transforms.Conversion.MapKeyToValue("Number", "Label"))
// STEP 4: Train the model fitting to the DataSet
let watch = System.Diagnostics.Stopwatch.StartNew();
printfn "=============== Training the model ==============="
let trainedModel = trainingPipeline.Fit(trainData)
printfn "***** Training time: %d seconds *****" watch.Elapsed.Seconds
printfn "===== Evaluating Model's accuracy with Test data ====="
let predictions = trainedModel.Transform(testData)
let metrics = mlContext.MulticlassClassification.Evaluate(predictions, "Number", "Score")
Common.ConsoleHelper.printMultiClassClassificationMetrics (trainer.ToString()) metrics
mlContext.Model.Save(trainedModel, trainData.Schema, modelPath)
printfn "The model is saved to %s" modelPath
// Test some predicitions
let loadedTrainedModel, modelInputSchema = mlContext.Model.Load modelPath
// Create prediction engine related to the loaded trained model
let predEngine = mlContext.Model.CreatePredictionEngine<Input, Output>(loadedTrainedModel)
sampleData
|> Array.iter
(fun (n,dat) ->
let p = predEngine.Predict dat
printfn "Actual: %d Predicted probability: zero: %.4f" n p.Score.[0]
["one:"; "two:"; "three:"; "four:"; "five:"; "six:"; "seven:"; "eight:"; "nine:"]
|> List.iteri
(fun i w ->
let i = i + 1
printfn " %-6s %.4f" w p.Score.[i]
)
printfn ""
)
printfn "Hit any key to finish the app"
Console.ReadKey() |> ignore

Просмотреть файл

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\..\common\ConsoleHelper.fs" Link="Common\ConsoleHelper.fs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ML" Version="$(MicrosoftMLVersion)" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.fs" />
<Folder Include="Common\" />
</ItemGroup>
</Project>

Просмотреть файл

@ -51,6 +51,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GitHubIssuesLabeler.Solutio
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "GitHubLabeler", "end-to-end-apps\MulticlassClassification-GitHubLabeler\GitHubLabeler\GitHubLabelerConsoleApp\GitHubLabeler.fsproj", "{F1262B9E-1DBD-4219-BB01-A3F8226A0AF7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MNIST.Solution", "MNIST.Solution", "{8F35CF6E-5813-43D7-AE24-A493AB14A3C9}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "MNIST", "getting-started\MulticlassClassification_mnist\mnist\MNIST.fsproj", "{99E19BEE-2719-46EC-A146-D74FAB3260F1}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ProductRecommendation.Solution", "ProductRecommendation.Solution", "{D45A09B8-F6EA-4B2F-85A1-F1E6DB836DAE}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "ProductRecommender", "getting-started\MatrixFactorization_ProductRecommendation\ProductRecommender\ProductRecommender.fsproj", "{5FF1F5D5-CBE0-4083-95CA-B5228349DF4A}"
@ -168,6 +171,10 @@ Global
{F1262B9E-1DBD-4219-BB01-A3F8226A0AF7}.Debug|x64.Build.0 = Debug|Any CPU
{F1262B9E-1DBD-4219-BB01-A3F8226A0AF7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F1262B9E-1DBD-4219-BB01-A3F8226A0AF7}.Release|Any CPU.Build.0 = Release|Any CPU
{99E19BEE-2719-46EC-A146-D74FAB3260F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{99E19BEE-2719-46EC-A146-D74FAB3260F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{99E19BEE-2719-46EC-A146-D74FAB3260F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{99E19BEE-2719-46EC-A146-D74FAB3260F1}.Release|Any CPU.Build.0 = Release|Any CPU
{F1262B9E-1DBD-4219-BB01-A3F8226A0AF7}.Release|x64.ActiveCfg = Release|Any CPU
{F1262B9E-1DBD-4219-BB01-A3F8226A0AF7}.Release|x64.Build.0 = Release|Any CPU
{5FF1F5D5-CBE0-4083-95CA-B5228349DF4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@ -200,6 +207,7 @@ Global
{880A505E-177F-4E6D-A563-2C527F8CCADD} = {4BCB9F94-ACBA-4437-B592-2E08E5C58CC4}
{F2D39895-9C19-4468-A7BB-62207CC5BCD6} = {40328BCB-2F8E-4189-879C-697A6002C1E6}
{F1262B9E-1DBD-4219-BB01-A3F8226A0AF7} = {959E87F1-8A76-4B9F-9DE4-E4D115BC58AC}
{99E19BEE-2719-46EC-A146-D74FAB3260F1} = {8F35CF6E-5813-43D7-AE24-A493AB14A3C9}
{5FF1F5D5-CBE0-4083-95CA-B5228349DF4A} = {D45A09B8-F6EA-4B2F-85A1-F1E6DB836DAE}
{45A7CA79-4B9D-4855-A703-2559DC932EE6} = {A4E15AA2-F36A-49D4-A28A-8FCDD8BE5597}
EndGlobalSection