Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Image classification using DNNs and Transfer Learning. #4057

Merged
merged 38 commits into from
Aug 6, 2019
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
1a219d1
Image classification using DNNs and Transfer Learning.
codemzs Aug 2, 2019
eb6fef9
Undo sample changes.
codemzs Aug 2, 2019
dce734a
Disable ONNX conversion test because of protobuf version conflict.
codemzs Aug 2, 2019
a6168fe
Disable ONNX conversion test because of protobuf version conflict.
codemzs Aug 2, 2019
13f3f58
Upgrade to latest TF.NEt and enable ONNX test.
codemzs Aug 2, 2019
71d0968
stop buffer resue. comment out buggy tests.
codemzs Aug 3, 2019
825fbdf
enable buggy tests.
codemzs Aug 3, 2019
735e354
enable buggy tests.
codemzs Aug 3, 2019
30e0713
pass string directly as tensor instead of converting to utf8.
codemzs Aug 3, 2019
0b84992
pass string directly as tensor instead of converting to utf8.
codemzs Aug 3, 2019
42f97da
fix session dispose call in DNNTransfomer.
codemzs Aug 3, 2019
1231587
fix session dispose call in DNNTransfomer.
codemzs Aug 3, 2019
8fe76a0
fix crash issue when tesing tf.net.
Oceania2018 Aug 3, 2019
3c3613b
Merge pull request #4 from Oceania2018/imageclassificationapi
codemzs Aug 3, 2019
a48da72
fix for premature deallocation by TF.NET.
codemzs Aug 3, 2019
9669cbc
fix for destructor.
codemzs Aug 3, 2019
28f5c72
fix for destructor.
codemzs Aug 3, 2019
6cf21f4
Upgrade to latest TF.NEt that contains fix for default graph.
codemzs Aug 3, 2019
67170a1
TDV-TF mapping.
codemzs Aug 4, 2019
0bcc228
Add test for transfer learning.
codemzs Aug 4, 2019
e28cd18
Add Inception V3 model.
codemzs Aug 4, 2019
0723aa4
Add Inception V3 model and unit-test
codemzs Aug 4, 2019
a1a6972
Add Inception V3 model and unit-test
codemzs Aug 4, 2019
d38ee21
Add Inception V3 model and unit-test
codemzs Aug 4, 2019
e0e326f
Add Inception V3 model and unit-test
codemzs Aug 4, 2019
e618eff
Add Inception V3 model and unit-test
codemzs Aug 4, 2019
981ef13
Update transfer learning test.
codemzs Aug 4, 2019
eb354a0
Remove hard coded paths from test.
codemzs Aug 4, 2019
72260cf
tsts
codemzs Aug 4, 2019
b614621
Add more samples and minor refactoring.
codemzs Aug 5, 2019
d7296ba
Take dependency of scisharp tensorflow redist.
codemzs Aug 5, 2019
bd6e2cb
Merge branch 'master' of https://github.com/dotnet/machinelearning in…
codemzs Aug 5, 2019
84c08e7
Merge branch 'master' of https://github.com/dotnet/machinelearning in…
codemzs Aug 5, 2019
11cc810
Merge branch 'master' of https://github.com/dotnet/machinelearning in…
codemzs Aug 6, 2019
95f8453
PR feedback.
codemzs Aug 6, 2019
6cb29c4
PR feedback.
codemzs Aug 6, 2019
d36e3db
Cleanup.
codemzs Aug 6, 2019
5e2eed7
Merge branch 'master' of https://github.com/dotnet/machinelearning in…
codemzs Aug 6, 2019
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
657 changes: 657 additions & 0 deletions Microsoft.ML.sln

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.ML;
using Microsoft.ML.Data;
using Microsoft.ML.Transforms;

namespace Samples.Dynamic
{
public static class InceptionV3TransferLearning
{
/// <summary>
/// Example use of Image classification API in a ML.NET pipeline.
/// </summary>
public static void Example()
{
var mlContext = new MLContext(seed: 1);

var imagesDataFile = Path.GetDirectoryName(
Microsoft.ML.SamplesUtils.DatasetUtils.DownloadImages());

var data = mlContext.Data.LoadFromEnumerable(
ImageNetData.LoadImagesFromDirectory(imagesDataFile, 4));

data = mlContext.Data.ShuffleRows(data, 5);
var pipeline = mlContext.Transforms.Conversion.MapValueToKey("Label")
.Append(mlContext.Transforms.LoadImages("ImageObject", null,
"ImagePath"))
.Append(mlContext.Transforms.ResizeImages("Image",
inputColumnName: "ImageObject", imageWidth: 299,
imageHeight: 299))
.Append(mlContext.Transforms.ExtractPixels("Image",
interleavePixelColors: true))
.Append(mlContext.Model.ImageClassification("Image",
"Label", arch: DnnEstimator.Architecture.InceptionV3, epoch: 4,
batchSize: 4));

var trainedModel = pipeline.Fit(data);
var predicted = trainedModel.Transform(data);
var metrics = mlContext.MulticlassClassification.Evaluate(predicted);

Console.WriteLine($"Micro-accuracy: {metrics.MicroAccuracy}," +
$"macro-accuracy = {metrics.MacroAccuracy}");

// Create prediction function and test prediction
var predictFunction = mlContext.Model
.CreatePredictionEngine<ImageNetData, ImagePrediction>(trainedModel);

var prediction = predictFunction
.Predict(ImageNetData.LoadImagesFromDirectory(imagesDataFile, 4)
.First());

Console.WriteLine($"Scores : [{string.Join(",", prediction.Score)}], " +
$"Predicted Label : {prediction.PredictedLabel}");

}
}

public class ImageNetData
{
[LoadColumn(0)]
public string ImagePath;

[LoadColumn(1)]
public string Label;

public static IEnumerable<ImageNetData> LoadImagesFromDirectory(
string folder, int repeat = 1, bool useFolderNameasLabel = false)
{
var files = Directory.GetFiles(folder, "*",
searchOption: SearchOption.AllDirectories);

foreach (var file in files)
{
if (Path.GetExtension(file) != ".jpg")
continue;

var label = Path.GetFileName(file);
if (useFolderNameasLabel)
label = Directory.GetParent(file).Name;
else
{
for (int index = 0; index < label.Length; index++)
{
if (!char.IsLetter(label[index]))
{
label = label.Substring(0, index);
break;
}
}
}

for (int index = 0; index < repeat; index++)
yield return new ImageNetData() {
ImagePath = file,Label = label };
}
}
}

public class ImagePrediction
{
[ColumnName("Score")]
public float[] Score;

[ColumnName("PredictedLabel")]
public Int64 PredictedLabel;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
using System;
using System.Diagnostics;
using System.Linq;
using Microsoft.ML;
using Microsoft.ML.Data;

namespace Samples.Dynamic
{
public static class ResnetV2101TransferLearning
{
/// <summary>
/// Example use of Image classification API in a ML.NET pipeline.
/// </summary>
public static void Example()
{
var sw = new Stopwatch();

var mlContext = new MLContext();
var data = GetTensorData();
var idv = mlContext.Data.LoadFromEnumerable(data);

// Create a ML pipeline.
var pipeline =
mlContext.Transforms.Conversion.MapValueToKey(
nameof(TensorData.Label))
.Append(mlContext.Model.ImageClassification(
nameof(TensorData.input),
nameof(TensorData.Label), batchSize: 2));

// Run the pipeline and get the transformed values.
var estimator = pipeline.Fit(idv);
var transformedValues = estimator.Transform(idv);

// Retrieve model scores.
var outScores = mlContext.Data.CreateEnumerable<OutputScores>(
transformedValues, reuseRowObject: false);

// Display scores. (for the sake of brevity we display scores of the
// first 3 classes)
foreach (var prediction in outScores)
{
int numClasses = 0;
foreach (var classScore in prediction.Scores.Take(2))
{
Console.WriteLine(
$"Class #{numClasses++} score = {classScore}");
}
Console.WriteLine(
$"Predicted Label: {prediction.PredictedLabel}");


Console.WriteLine(new string('-', 10));
}

Console.WriteLine(sw.Elapsed);
// Class #0 score = 0.03416626
// Class #1 score = 0.9658337
// Predicted Label: 1
// ----------
// Class #0 score = 0.02959618
// Class #1 score = 0.9704038
// Predicted Label: 1
// ----------
}

private const int imageHeight = 224;
private const int imageWidth = 224;
private const int numChannels = 3;
private const int inputSize = imageHeight * imageWidth * numChannels;

/// <summary>
/// A class to hold sample tensor data.
/// Member name should match the inputs that the model expects (in this
/// case, input).
/// </summary>
public class TensorData
{
[VectorType(imageHeight, imageWidth, numChannels)]
public float[] input { get; set; }

public Int64 Label { get; set; }
}

/// <summary>
/// Method to generate sample test data. Returns 2 sample rows.
/// </summary>
public static TensorData[] GetTensorData()
{
// This can be any numerical data. Assume image pixel values.
var image1 = Enumerable.Range(0, inputSize).Select(
x => (float)x / inputSize).ToArray();

var image2 = Enumerable.Range(0, inputSize).Select(
x => (float)(x + 10000) / inputSize).ToArray();
return new TensorData[] { new TensorData() { input = image1, Label = 0 },
new TensorData() { input = image2, Label = 1 } };
}

/// <summary>
/// Class to contain the output values from the transformation.
/// </summary>
class OutputScores
{
public float[] Scores { get; set; }
public Int64 PredictedLabel { get; set; }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\Microsoft.ML.Dnn\Microsoft.ML.Dnn.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.ML.LightGbm\Microsoft.ML.LightGbm.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.ML.Mkl.Components\Microsoft.ML.Mkl.Components.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.ML.KMeansClustering\Microsoft.ML.KMeansClustering.csproj" />
Expand Down Expand Up @@ -963,5 +964,10 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<Content Include="$(ObjDir)DnnImageModels\Resnet101V2Tensorflow\resnet_v2_101_299.meta">
<Link>DnnImageModels\Resnet101V2Tensorflow\resnet_v2_101_299.meta</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>
5 changes: 3 additions & 2 deletions docs/samples/Microsoft.ML.Samples/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public static class Program

internal static void RunAll()
{
int samples = 0;
/*int samples = 0;
foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
{
var sample = type.GetMethod("Example", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
Expand All @@ -23,7 +23,8 @@ internal static void RunAll()
}
}

Console.WriteLine("Number of samples that ran without any exception: " + samples);
Console.WriteLine("Number of samples that ran without any exception: " + samples);*/
InceptionV3TransferLearning.Example();
}
}
}
12 changes: 12 additions & 0 deletions pkg/Microsoft.ML.Dnn/Microsoft.ML.Dnn.nupkgproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk" DefaultTargets="Pack">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<PackageDescription>Microsoft.ML.Dnn contains APIs to do high level DNN training such as image classification.</PackageDescription>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="../Microsoft.ML/Microsoft.ML.nupkgproj" />
</ItemGroup>

</Project>
5 changes: 5 additions & 0 deletions pkg/Microsoft.ML.Dnn/Microsoft.ML.Dnn.symbols.nupkgproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Project DefaultTargets="Pack">

<Import Project="Microsoft.ML.Dnn.nupkgproj" />

</Project>
9 changes: 9 additions & 0 deletions pkg/common/Resnet101V2.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Content Include="$(MSBuildThisFileDirectory)..\..\tools\DnnImageModels\Resnet101V2Tensorflow\*.*">
<Link>DnnImageModels\%(RecursiveDir)%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>
1 change: 1 addition & 0 deletions src/Microsoft.ML.Core/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
[assembly: InternalsVisibleTo(assemblyName: "Microsoft.ML.StandardTrainers" + PublicKey.Value)]
[assembly: InternalsVisibleTo(assemblyName: "Microsoft.ML.Sweeper" + PublicKey.Value)]
[assembly: InternalsVisibleTo(assemblyName: "Microsoft.ML.TensorFlow" + PublicKey.Value)]
[assembly: InternalsVisibleTo(assemblyName: "Microsoft.ML.Dnn" + PublicKey.Value)]
[assembly: InternalsVisibleTo(assemblyName: "Microsoft.ML.TimeSeries" + PublicKey.Value)]
[assembly: InternalsVisibleTo(assemblyName: "Microsoft.ML.Transforms" + PublicKey.Value)]

Expand Down
1 change: 1 addition & 0 deletions src/Microsoft.ML.Data/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
[assembly: InternalsVisibleTo(assemblyName: "Microsoft.ML.StandardTrainers" + PublicKey.Value)]
[assembly: InternalsVisibleTo(assemblyName: "Microsoft.ML.Sweeper" + PublicKey.Value)]
[assembly: InternalsVisibleTo(assemblyName: "Microsoft.ML.TensorFlow" + PublicKey.Value)]
[assembly: InternalsVisibleTo(assemblyName: "Microsoft.ML.Dnn" + PublicKey.Value)]
[assembly: InternalsVisibleTo(assemblyName: "Microsoft.ML.TimeSeries" + PublicKey.Value)]
[assembly: InternalsVisibleTo(assemblyName: "Microsoft.ML.Transforms" + PublicKey.Value)]
[assembly: InternalsVisibleTo(assemblyName: "Microsoft.ML.DnnImageFeaturizer.AlexNet" + PublicKey.Value)]
Expand Down
9 changes: 9 additions & 0 deletions src/Microsoft.ML.Dnn/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Runtime.CompilerServices;
using Microsoft.ML;

[assembly: InternalsVisibleTo(assemblyName: "Microsoft.ML.Tests" + PublicKey.TestValue)]
[assembly: InternalsVisibleTo(assemblyName: "Microsoft.ML.Tensorflow" + PublicKey.Value)]
Loading