{"id":12605,"date":"2019-06-05T11:36:50","date_gmt":"2019-06-05T18:36:50","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/cesardelatorre\/?p=12605"},"modified":"2019-06-05T12:12:49","modified_gmt":"2019-06-05T19:12:49","slug":"run-with-ml-net-c-code-a-tensorflow-model-exported-from-azure-cognitive-services-custom-vision","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cesardelatorre\/run-with-ml-net-c-code-a-tensorflow-model-exported-from-azure-cognitive-services-custom-vision\/","title":{"rendered":"Run with ML.NET C# code a TensorFlow model exported from Azure Cognitive Services Custom Vision"},"content":{"rendered":"<p><a target=\"_blank\" rel=\"noopener noreferrer\"><img decoding=\"async\" src=\"https:\/\/github.com\/CESARDELATORRE\/MLNET-Posts\/raw\/master\/Posts\/004-Run-with-ML.NET-TensorFlow-model-exported-from-Custom-Vision\/images\/header-image.png\" alt=\"alt text\" title=\"ML.NET logo plus other\" style=\"max-width:100%;\"><\/a><\/p>\n<p>With <strong><a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.ML\" rel=\"nofollow\">ML.NET<\/a><\/strong> and related <a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.ML.TensorFlow\/0.13.0\" rel=\"nofollow\">NuGet packages for TensorFlow<\/a> you can currently do the following:<\/p>\n<ul>\n<li>\n<p><strong>Run\/score a pre-trained TensorFlow model:<\/strong> In ML.NET you can load a frozen TensorFlow model .pb file (also called \u201cfrozen graph def\u201d which is essentially a serialized graph_def protocol buffer written to disk) and make predictions with it from C# for scenarios like image classification, object detection or any other. Here&#8217;s a <a href=\"https:\/\/github.com\/dotnet\/machinelearning-samples\/tree\/master\/samples\/csharp\/getting-started\/DeepLearning_ImageClassification_TensorFlow\">Getting started sample on scoring a TensorFlow model<\/a> which is using the <a href=\"https:\/\/storage.googleapis.com\/download.tensorflow.org\/models\/inception5h.zip\" rel=\"nofollow\">Inception pre-trained TensorFlow model<\/a>.<\/p>\n<\/li>\n<li>\n<p><strong>Transfer Learning on top of a pre-trained TensorFlow model:<\/strong> You can re-use part of an already pre-trained TensorFlow model (such as the <a href=\"https:\/\/storage.googleapis.com\/download.tensorflow.org\/models\/inception5h.zip\" rel=\"nofollow\">Inception pre-trained TensorFlow model<\/a> ) to build a new model trained with additional samples for the final layer, such as trained with new images. For instance, see this <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/machine-learning\/tutorials\/image-classification\" rel=\"nofollow\">Tutorial on how to use Transfer Learning with ML.NET<\/a> by using an already trained Image Classifier TensorFlow model to build a new custom model to classify images into different categories.<\/p>\n<\/li>\n<\/ul>\n<p>However, in the scenario where you want to train with your own images, the Transfer Learning approach can be a bit complex because even without taking into account the code implementation for transfer learning you&#8217;ll need to find a base TensorFlow model to train on top of it which was originally trained with similar image types to your new images. Here&#8217;s some specific examples to understand that statement:<\/p>\n<ul>\n<li>\n<p>For instance, the <a href=\"https:\/\/storage.googleapis.com\/download.tensorflow.org\/models\/inception5h.zip\" rel=\"nofollow\">TensorFlow Inception model<\/a> was trained with photos of may objects, animals, vegetables and people, so you could train the final layer, let&#8217;s say with photos of &#8216;super heroes&#8217;, and the model will clasify properly images of specific &#8216;super heroes&#8217;. In any case, the new images need to be of &#8220;similar type&#8221;, as mentioned.<\/p>\n<\/li>\n<li>\n<p>But if the new training &#8220;image type&#8221; is very different, it won&#8217;t work properly. For instance, if you try to do &#8216;transfer learning&#8217; with ML.NET 1.0 (trains only on the final layer) and the <a href=\"https:\/\/storage.googleapis.com\/download.tensorflow.org\/models\/inception5h.zip\" rel=\"nofollow\">TensorFlow Inception model<\/a> with completely different image types, let&#8217;s say <a href=\"https:\/\/en.wikipedia.org\/wiki\/MNIST_database\" rel=\"nofollow\">MINST images<\/a> (so a blank image with just a handwritten digits\/numbers), those images won&#8217;t be recognized properly if the base TF model was the &#8216;Inception model&#8217;. It might work right if you use a different TF pre-trained model that was trained with handwritten digits images, as the base model.<\/p>\n<\/li>\n<\/ul>\n<p>In any case, it can get tricky and you need to understand some complexity. For some custom scenarios might fit your needs since you have control of it but for other scenarios you might want a simpler approach.<\/p>\n<p>Therefore, is there any other approach for .NET developers if you just want to quickly get started and simply try to run a TensorFlow model on your .NET application while being able to use your own images? (Let&#8217;s say you want to train with very specific images from your industry or domain).<\/p>\n<p>The answer is: &#8220;Of course there are additional approaches!&#8221;<\/p>\n<p>You can use <strong>Azure Cognitive Services Custom Vision<\/strong> to train a TensorFlow model, then export it as a frozen TensorFlow model .pb file and finally run\/score that model with ML.NET code in your end-user .NET application.<\/p>\n<h2><a id=\"user-content-the-hypothetical-business-scenario-for-the-sample-app\" class=\"anchor\" aria-hidden=\"true\" href=\"#the-hypothetical-business-scenario-for-the-sample-app\"><svg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"><\/path><\/svg><\/a>The hypothetical business scenario for the sample app<\/h2>\n<p>The hypothetical business scenario for the sample app in this blog post is <em>pretty similar<\/em> to whay Snapchat and Amazon are testing and you can check out <a href=\"https:\/\/www.theverge.com\/2018\/9\/24\/17896788\/snapchat-amazon-shop-photos-partnership\" rel=\"nofollow\">here<\/a>.<\/p>\n<p>Basically, that feature would let users point their Snapchat camera at a physical product to then be redirected to an Amazon pop-up card for that product or something similar (so the user can easily buy what he just saw from a friend, etc.), as in the following image:<\/p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\"><img decoding=\"async\" src=\"https:\/\/github.com\/CESARDELATORRE\/MLNET-Posts\/raw\/master\/Posts\/004-Run-with-ML.NET-TensorFlow-model-exported-from-Custom-Vision\/images\/snapchat-amazon-scenario.png\" alt=\"Scenario architecture with web app and service\" style=\"max-width:100%;\"><\/a><\/p>\n<p>In my sample scenario I&#8217;ll create a simplified web app with a Web API service that could also be used from a mobile app like in the Snapchat\/Amazon scenario, but for simplicity&#8217;s sake everything will work in a single web app for testing the feature, like shown in the architecture diagram below.<\/p>\n<h2><a id=\"user-content-the-architecture\" class=\"anchor\" aria-hidden=\"true\" href=\"#the-architecture\"><svg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"><\/path><\/svg><\/a>The architecture<\/h2>\n<p>The advantage of using <strong>ML.NET<\/strong> to run a <strong>TensorFlow model<\/strong> exported from <strong>Azure Cognitive Services Custom Vision<\/strong> is that you don&#8217;t have any mandatory on-line dependency\/requirement with Azure. You can run\/score that model in offline or online scenarios, wherever you want within your apps as long as the app is running .NET code (C#\/F#\/VB).<\/p>\n<p>It can be a desktop app (.NET Framework, WinForms, WPF), a web app (ASP.NET Core, ASP.NET), a service (WebAPI, WCF), etc. on Windows or Windows\/Linux\/Mac if using .NET Core.<\/p>\n<ul>\n<li>If using services, those services can be deployed on-premises, on Azure or anywhere.<\/li>\n<li>If using offline applications with no conectivity to Internet, the model will also work locally!<\/li>\n<\/ul>\n<p>In this case, I&#8217;m running\/scoring the TensorFlow model on an ASP.NET Core Razor web that is also working as a WebAPI service at the same time (so the service could also be consumed by a remote mobile app). Something like the following simplified scenario architecture:<\/p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\"><img decoding=\"async\" src=\"https:\/\/github.com\/CESARDELATORRE\/MLNET-Posts\/raw\/master\/Posts\/004-Run-with-ML.NET-TensorFlow-model-exported-from-Custom-Vision\/images\/scenario-architecture.png\" alt=\"Scenario architecture with web app and service\" style=\"max-width:100%;\"><\/a><\/p>\n<p>That TensorFlow .pb model file that you see in the diagram (and the labels.txt codes\/Ids) is what you create\/train in Azure Cognitive Services Custom Vision then exporte as a frozen TensorFlow model file to be used by ML.NET C# code.<\/p>\n<h2><a id=\"user-content-train-a-model-in-azure-cognitive-services-custom-vision-and-exporting-it-as-a-frozen-tensorflow-model-file\" class=\"anchor\" aria-hidden=\"true\" href=\"#train-a-model-in-azure-cognitive-services-custom-vision-and-exporting-it-as-a-frozen-tensorflow-model-file\"><svg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"><\/path><\/svg><\/a>Train a model in Azure Cognitive Services Custom Vision and exporting it as a frozen TensorFlow model file<\/h2>\n<p>Below are the steps I took using Azure Cognitive Services. You can take similar steps but targeting your own images and probably using many more types\/objects, since I just used two different chair models.<\/p>\n<ul>\n<ol>\n<li>\n<p>I created two labels (kind of product codes), one per object\/furniture-type to be trained in the model:<\/p>\n<ul>\n<li><code>001-Green-Meeting-Chair-Redmond<\/code><\/li>\n<li><code>002-High-Metal-Chair-Redmond<\/code><\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<ol start=\"2\">\n<li>Per object, I trained with around 90 photos for one chair and around 40 photos for the other chair.<\/li>\n<\/ol>\n<\/li>\n<ol start=\"3\">\n<li>\n<p>Finally, export the TensorFlow .pb model file and the labels .txt<\/p>\n<ul>\n<li>Export from menu <em>Performance -&gt; Export -&gt; TensorFlow<\/em>. In that menu, &#8220;Android&#8221; just means that it is usually the format you need for Android apps<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<\/ul>\n<p>Those steps are visualized on the <a href=\"https:\/\/customvision.ai\/\" rel=\"nofollow\">https:\/\/customvision.ai\/<\/a> portal screenshot below.<\/p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\"><img decoding=\"async\" src=\"https:\/\/github.com\/CESARDELATORRE\/MLNET-Posts\/raw\/master\/Posts\/004-Run-with-ML.NET-TensorFlow-model-exported-from-Custom-Vision\/images\/cognitive-services-custom-vision-screenshot.png\" alt=\"Scenario architecture with web app and service\" style=\"max-width:100%;\"><\/a><\/p>\n<p>For a detailed walkthrough on how to train your model with your own images in Azure Cognitive Services Custom Vision check out this tutorial:<\/p>\n<ul>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/cognitive-services\/custom-vision-service\/getting-started-build-a-classifier\" rel=\"nofollow\">How to build an image classifier model with Custom Vision<\/a><\/li>\n<\/ul>\n<h2><a id=\"user-content-define-the-mlnet-pipeline-model-configuration\" class=\"anchor\" aria-hidden=\"true\" href=\"#define-the-mlnet-pipeline-model-configuration\"><svg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"><\/path><\/svg><\/a>Define the ML.NET pipeline model configuration<\/h2>\n<p>In order to run\/score a TensorFlow model in ML.NET you need to &#8220;wrap&#8221; it with an ML.NET model which in reality won&#8217;t need to train in ML.NET since it was already trained as a TensorFlow model, but you need to define the image transformations (such as image resize, how to load the image file into the model, etc.) in the ML.NET model&#8217;s pipeline.<\/p>\n<p>This is basically the code you need to write and run just once in order to create the ML.NET model (ITransformer) wrapping the TensorFlow model:<\/p>\n<pre class=\"lang:default decode:true\">\r\nprivate ITransformer SetupMlnetModel(string tensorFlowModelFilePath)\r\n{\r\n    var pipeline = _mlContext.Transforms.ResizeImages(outputColumnName: TensorFlowModelSettings.inputTensorName,\r\n                                                      imageWidth: ImageSettings.imageWidth, \r\n                                                      imageHeight: ImageSettings.imageHeight, \r\n                                                      inputColumnName: nameof(ImageInputData.Image))\r\n           .Append(_mlContext.Transforms.ExtractPixels(outputColumnName: TensorFlowModelSettings.inputTensorName,\r\n                                                      interleavePixelColors: ImageSettings.channelsLast,\r\n                                                      offsetImage: ImageSettings.mean))\r\n           .Append(_mlContext.Model.LoadTensorFlowModel(tensorFlowModelFilePath)\r\n                                               .ScoreTensorFlowModel(\r\n                                                      outputColumnNames: new[]{TensorFlowModelSettings.outputTensorName },\r\n                                                      inputColumnNames: new[] { TensorFlowModelSettings.inputTensorName },\r\n                                                      addBatchDimensionInput: false));\r\n\r\n    ITransformer mlModel = pipeline.Fit(CreateEmptyDataView());\r\n\r\n    return mlModel;\r\n}\r\n<\/pre>\n<p>As mentioned, this code has to be run just once so you define the ML.NET model and how it has to load the TensorFlow model plus what transformations need the images to process.<\/p>\n<p>The TensorFlow model pipeline above is defined based on the following settings:<\/p>\n<pre class=\"lang:default decode:true\">\r\npublic struct ImageSettings\r\n{\r\n    public const int imageHeight = 227;\r\n    public const int imageWidth = 227;\r\n    public const float mean = 117;         \/\/offsetImage\r\n    public const bool channelsLast = true; \/\/interleavePixelColors\r\n}\r\n\r\n\/\/ For checking tensor names, you can open the TF model .pb file with tools like Netron: https:\/\/github.com\/lutzroeder\/netron\r\npublic struct TensorFlowModelSettings\r\n{\r\n    \/\/ input tensor name\r\n    public const string inputTensorName = \"Placeholder\";\r\n\r\n    \/\/ output tensor name\r\n    public const string outputTensorName = \"loss\";\r\n}\r\n<\/pre>\n<p>You might think how could you know what size the images need to be re-sized and what are the TensorFlow model&#8217;s input\/output tensor names, right? &#8211; So for that you can explore the .pb file (frozen TensorFlow model) with a tool like <a href=\"https:\/\/github.com\/lutzroeder\/netron\">Netron<\/a> so you can see the names of the input and output tensors, like in the following screenshots:<\/p>\n<p><strong>Input Tensor Name:<\/strong><\/p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\"><img decoding=\"async\" src=\"https:\/\/github.com\/CESARDELATORRE\/MLNET-Posts\/raw\/master\/Posts\/004-Run-with-ML.NET-TensorFlow-model-exported-from-Custom-Vision\/images\/netron-model-input-tensor.png\" alt=\"Scenario architecture with web app and service\" style=\"max-width:100%;\"><\/a><\/p>\n<p>You can see there the name of the input tensor plus the size of the image (width=227, eight=227).<\/p>\n<p><strong>Output Tensor Name:<\/strong><\/p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\"><img decoding=\"async\" src=\"https:\/\/github.com\/CESARDELATORRE\/MLNET-Posts\/raw\/master\/Posts\/004-Run-with-ML.NET-TensorFlow-model-exported-from-Custom-Vision\/images\/netron-model-output-tensor.png\" alt=\"Scenario architecture with web app and service\" style=\"max-width:100%;\"><\/a><\/p>\n<h2><a id=\"user-content-working-with-in-memory-images-new-in-mlnet-v11\" class=\"anchor\" aria-hidden=\"true\" href=\"#working-with-in-memory-images-new-in-mlnet-v11\"><svg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"><\/path><\/svg><\/a>Working with in-memory images (NEW in ML.NET v1.1)<\/h2>\n<p>With ML.NET v1.0 whenever you were dealing with images and an ML.NET model you needed to work with files stored on a drive (or write a bunch of code hard to justify..). That was just a limitation of the API and IDataView supported types. However, we have fixed this feature in ML.NET 1.1 and there a new <code>ImageType<\/code> that can be used as the type for a column in a DataView, as in the following code:<\/p>\n<pre class=\"lang:default decode:true\">\r\npublic class ImageInputData\r\n{\r\n    [ImageType(227, 227)]\r\n    public Bitmap Image { get; set; }\r\n}\r\n<\/pre>\n<p>This is great because it allows you to work with in-memory images.\nIn the scenario for this blog post, the image is coming through HTTP into my WebAPI, so I already have it as an in-memory object. With ML.NET 1.0 I needed to create a temporal image file on the drive, then load the image in the model and predict. But that was just a workaround, not efficient at all.<\/p>\n<p>Now ,I can just take the image coming from HTTP into my WebAPI, convert to a BitMap type and process the image with the model and get my prediction (image classification returning its related &#8220;product code&#8221; in this case).<\/p>\n<p>Here you can see the simplified **WebAPI code**, very straight forward!:<\/p>\n<pre class=\"lang:default decode:true\">\r\n[HttpPost]\r\n[ProducesResponseType(200)]\r\n[ProducesResponseType(400)]\r\n[Route(\"classifyimage\")]\r\npublic async Task<IActionResult> ClassifyImage(IFormFile imageFile)\r\n{\r\n    MemoryStream imageMemoryStream = new MemoryStream();\r\n    await imageFile.CopyToAsync(imageMemoryStream);\r\n\r\n    \/\/Convert to Bitmap\r\n    Bitmap bitmapImage = (Bitmap)Image.FromStream(imageMemoryStream);\r\n\r\n    \/\/Set the specific image data into the ImageInputData type used in the DataView\r\n    ImageInputData imageInputData = new ImageInputData { Image = bitmapImage };\r\n\r\n    \/\/Predict code for provided image\r\n    ImageLabelPredictions imageLabelPredictions = _predictionEnginePool.Predict(imageInputData);\r\n\r\n    \/\/Predict the image's label (The one with highest probability)\r\n    ImagePredictedLabelWithProbability imageBestLabelPrediction\r\n                        = FindBestLabelWithProbability(imageLabelPredictions, imageInputData);\r\n\r\n    return Ok(imageBestLabelPrediction);\r\n}\r\n<\/pre>\n<p>Note that since this is an ASP.NET Core web app (that method is a WebAPI method), I&#8217;m using our optimized way (Microsoft&#8217;s recommended way) to run an ML.NET PredictionEngine in multithreaded ASP.NET Core apps, which is to use the <code>PredictionEnginePool<\/code> injected into the controller&#8217;s constructor using the <em>Dependency Injection<\/em> system in ASP.NET Core, as explained in this Tutorial:<\/p>\n<ul>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/machine-learning\/how-to-guides\/serve-model-web-api-ml-net\" rel=\"nofollow\">Deploy a model in an ASP.NET Core Web API<\/a><\/li>\n<\/ul>\n<p>For further detailed info about why the <code>PredictionEnginePool<\/code> is recommended for scalable and multithreaded applications check this blog post that I wrote:<\/p>\n<ul>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/cesardelatorre\/how-to-optimize-and-run-ml-net-models-on-scalable-asp-net-core-webapis-or-web-apps\/\" rel=\"nofollow\">How to optimize and run ML.NET models on scalable ASP.NET Core WebAPIs or web apps\n<\/a><\/li>\n<\/ul>\n<p>Here are a couple of screenshots on how the app identifies\/predicts the label (product code in this case) for the object in the provided photo. That action is called in machine learning as &#8220;Image classification&#8221;:<\/p>\n<p><strong>Select the image to identify:<\/strong><\/p>\n<p>Note that even when those chairs for the two test-pictures are the same chairs than the ones used when training the model in Custom Vision, these particular photos\/files in the &#8216;TestImages&#8217; folder where NOT used to train the model. Could be the same chair taken in a different angle, different place or room, etc. \ud83d\ude42<\/p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\"><img decoding=\"async\" src=\"https:\/\/github.com\/CESARDELATORRE\/MLNET-Posts\/raw\/master\/Posts\/004-Run-with-ML.NET-TensorFlow-model-exported-from-Custom-Vision\/images\/app-run-01.png\" alt=\"Get started icon\" style=\"max-width:100%;\"><\/a><\/p>\n<p><strong>The app shows you its related label (product code):<\/strong><\/p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\"><img decoding=\"async\" src=\"https:\/\/github.com\/CESARDELATORRE\/MLNET-Posts\/raw\/master\/Posts\/004-Run-with-ML.NET-TensorFlow-model-exported-from-Custom-Vision\/images\/app-run-02.png\" alt=\"Get started icon\" style=\"max-width:100%;\"><\/a><\/p>\n<h2><a id=\"user-content-show-me-the-code\" class=\"anchor\" aria-hidden=\"true\" href=\"#show-me-the-code\"><svg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"><\/path><\/svg><\/a>Show me the code!<\/h2>\n<p>Youcan get the code for this whole sample app this GitHub repo:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/CESARDELATORRE\/TensorFlowImageClassificationWebApp\/tree\/master\/WebAppUsingInMemoryImages\">https:\/\/github.com\/CESARDELATORRE\/TensorFlowImageClassificationWebApp\/tree\/master\/WebAppUsingInMemoryImages<\/a><\/li>\n<\/ul>\n<p>Eventually, we will probably publish this sample at the <a href=\"https:\/\/github.com\/dotnet\/machinelearning-samples\">ML.NET Samples GitHub repo<\/a>, as well.<\/p>\n<h2><a id=\"user-content-get-started-with-mlnet-10\" class=\"anchor\" aria-hidden=\"true\" href=\"#get-started-with-mlnet-10\"><svg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"><\/path><\/svg><\/a>Get started with ML.NET 1.0!<\/h2>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\"><img decoding=\"async\" src=\"https:\/\/github.com\/CESARDELATORRE\/MLNET-Posts\/raw\/master\/Posts\/004-Run-with-ML.NET-TensorFlow-model-exported-from-Custom-Vision\/images\/get-started-rocket.png\" alt=\"Get started icon\" style=\"max-width:100%;\"><\/a><\/p>\n<p>If you still don&#8217;t know ML.NET, get started by exploring the following resources:<\/p>\n<ul>\n<li><strong>Get started<\/strong> with <a href=\"https:\/\/www.microsoft.com\/net\/learn\/apps\/machine-learning-and-ai\/ml-dotnet\/get-started\" rel=\"nofollow\">ML.NET here<\/a>.<\/li>\n<li><strong>Tutorials<\/strong> and resources at the <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/machine-learning\/\" rel=\"nofollow\">Microsoft Docs ML.NET Guide<\/a><\/li>\n<li><strong>Sample apps<\/strong> using ML.NET at the <a href=\"https:\/\/github.com\/dotnet\/machinelearning-samples\">machinelearning-samples GitHub repo<\/a><\/li>\n<\/ul>\n<p>Thanks and happy coding with <a href=\"http:\/\/dot.net\/ml\" rel=\"nofollow\">ML.NET<\/a>!<\/p>\n<p><em>Cesar de la Torre<\/em><\/p>\n<p><em>Principal Program Manager<\/em><\/p>\n<p><em>.NET and ML.NET product group<\/em><\/p>\n<p><em>Microsoft Corp.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>With ML.NET and related NuGet packages for TensorFlow you can currently do the following: Run\/score a pre-trained TensorFlow model: In ML.NET you can load a frozen TensorFlow model .pb file (also called \u201cfrozen graph def\u201d which is essentially a serialized graph_def protocol buffer written to disk) and make predictions with it from C# for scenarios [&hellip;]<\/p>\n","protected":false},"author":362,"featured_media":12611,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[370,369,308,309,299,368],"class_list":["post-12605","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cesardelatorre","tag-ai","tag-azure-cognitive-services-custom-vision","tag-machine-learning","tag-ml","tag-ml-net","tag-tensorflow"],"acf":[],"blog_post_summary":"<p>With ML.NET and related NuGet packages for TensorFlow you can currently do the following: Run\/score a pre-trained TensorFlow model: In ML.NET you can load a frozen TensorFlow model .pb file (also called \u201cfrozen graph def\u201d which is essentially a serialized graph_def protocol buffer written to disk) and make predictions with it from C# for scenarios [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-json\/wp\/v2\/posts\/12605","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-json\/wp\/v2\/users\/362"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-json\/wp\/v2\/comments?post=12605"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-json\/wp\/v2\/posts\/12605\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-json\/wp\/v2\/media\/12611"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-json\/wp\/v2\/media?parent=12605"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-json\/wp\/v2\/categories?post=12605"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cesardelatorre\/wp-json\/wp\/v2\/tags?post=12605"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}