https://github.com/Microsoft/CNTK
Tip revision: 7ca2590f62e86085031906382f00ac861da13c26 authored by Bowen Bao on 02 July 2018, 07:26:17 UTC
adding profiling for seq conv v2
adding profiling for seq conv v2
Tip revision: 7ca2590
CNTKLibraryCSEvalExamples.cs
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
//
// CNTKLibraryCSEvalExamples.cs -- Examples for using CNTK Library C# Eval API.
//
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CNTK;
using CNTKExtension;
using CNTKImageProcessing;
namespace CNTKLibraryCSEvalExamples
{
public class CNTKLibraryManagedExamples
{
/// <summary>
/// The example shows
/// - how to load model.
/// - how to prepare input data for a single sample.
/// - how to prepare input and output data map.
/// - how to evaluate a model.
/// - how to retrieve evaluation result and retrieve output data in dense format.
/// </summary>
/// <param name="device">Specify on which device to run the evaluation.</param>
public static void EvaluationSingleImage(DeviceDescriptor device)
{
try
{
Console.WriteLine("\n===== Evaluate single image =====");
// Load the model.
// The model resnet20.dnn is trained by <CNTK>/Examples/Image/Classification/ResNet/Python/TrainResNet_CIFAR10.py
// Please see README.md in <CNTK>/Examples/Image/Classification/ResNet about how to train the model.
string modelFilePath = "resnet20.dnn";
ThrowIfFileNotExist(modelFilePath, string.Format("Error: The model '{0}' does not exist. Please follow instructions in README.md in <CNTK>/Examples/Image/Classification/ResNet to create the model.", modelFilePath));
Function modelFunc = Function.Load(modelFilePath, device);
// Get input variable. The model has only one single input.
// The same way described above for output variable can be used here to get input variable by name.
Variable inputVar = modelFunc.Arguments.Single();
// Get shape data for the input variable
NDShape inputShape = inputVar.Shape;
int imageWidth = inputShape[0];
int imageHeight = inputShape[1];
// Image preprocessing to match input requirements of the model.
// This program uses images from the CIFAR-10 dataset for evaluation.
// Please see README.md in <CNTK>/Examples/Image/DataSets/CIFAR-10 about how to download the CIFAR-10 dataset.
string sampleImage = "00000.png";
ThrowIfFileNotExist(sampleImage, string.Format("Error: The sample image '{0}' does not exist. Please see README.md in <CNTK>/Examples/Image/DataSets/CIFAR-10 about how to download the CIFAR-10 dataset.", sampleImage));
Bitmap bmp = new Bitmap(Bitmap.FromFile(sampleImage));
var resized = bmp.Resize(imageWidth, imageHeight, true);
List<float> resizedCHW = resized.ParallelExtractCHW();
// Create input data map
var inputDataMap = new Dictionary<Variable, Value>();
var inputVal = Value.CreateBatch(inputShape, resizedCHW, device);
inputDataMap.Add(inputVar, inputVal);
// The model has only one output.
// You can also use the following way to get output variable by name:
// Variable outputVar = modelFunc.Outputs.Where(variable => string.Equals(variable.Name, outputName)).Single();
Variable outputVar = modelFunc.Output;
// Create output data map. Using null as Value to indicate using system allocated memory.
// Alternatively, create a Value object and add it to the data map.
var outputDataMap = new Dictionary<Variable, Value>();
outputDataMap.Add(outputVar, null);
// Start evaluation on the device
modelFunc.Evaluate(inputDataMap, outputDataMap, device);
// Get evaluate result as dense output
var outputVal = outputDataMap[outputVar];
var outputData = outputVal.GetDenseData<float>(outputVar);
Console.WriteLine("Evaluation result for image " + sampleImage);
PrintOutput(outputVar.Shape.TotalSize, outputData);
}
catch (Exception ex)
{
Console.WriteLine("Error: {0}\nCallStack: {1}\n Inner Exception: {2}", ex.Message, ex.StackTrace, ex.InnerException != null ? ex.InnerException.Message : "No Inner Exception");
throw ex;
}
}
/// <summary>
/// The example shows
/// - how to load model.
/// - how to prepare input data for a batch of samples.
/// - how to prepare input and output data map.
/// - how to evaluate a model.
/// - how to retrieve evaluation result and retrieve output data in dense format.
/// </summary>
/// <param name="device">Specify on which device to run the evaluation.</param>
public static void EvaluationBatchOfImages(DeviceDescriptor device)
{
try
{
Console.WriteLine("\n===== Evaluate batch of images =====");
string modelFilePath = "resnet20.dnn";
// This program uses images from the CIFAR-10 dataset for evaluation.
// Please see README.md in <CNTK>/Examples/Image/DataSets/CIFAR-10 about how to download the CIFAR-10 dataset.
var imageList = new List<string>() { "00000.png", "00001.png", "00002.png" };
foreach (var image in imageList)
{
ThrowIfFileNotExist(image, string.Format("Error: The sample image '{0}' does not exist. Please see README.md in <CNTK>/Examples/Image/DataSets/CIFAR-10 about how to download the CIFAR-10 dataset.", image));
}
ThrowIfFileNotExist(modelFilePath, string.Format("Error: The model '{0}' does not exist. Please follow instructions in README.md in <CNTK>/Examples/Image/Classification/ResNet to create the model.", modelFilePath));
// Load the model.
// The model resnet20.dnn is trained by <CNTK>/Examples/Image/Classification/ResNet/Python/TrainResNet_CIFAR10.py
// Please see README.md in <CNTK>/Examples/Image/Classification/ResNet about how to train the model.
Function modelFunc = Function.Load(modelFilePath, device);
// Get input variable. The model has only one single input.
// The same way described above for output variable can be used here to get input variable by name.
Variable inputVar = modelFunc.Arguments.Single();
// Get shape data for the input variable
NDShape inputShape = inputVar.Shape;
int imageWidth = inputShape[0];
int imageHeight = inputShape[1];
Bitmap bmp, resized;
List<float> resizedCHW;
var seqData = new List<float>();
for (int sampleIndex = 0; sampleIndex < imageList.Count; sampleIndex++)
{
bmp = new Bitmap(Bitmap.FromFile(imageList[sampleIndex]));
resized = bmp.Resize(imageWidth, imageHeight, true);
resizedCHW = resized.ParallelExtractCHW();
// Add this sample to the data buffer.
seqData.AddRange(resizedCHW);
}
// Create Value for the batch data.
var inputVal = Value.CreateBatch(inputVar.Shape, seqData, device);
// Create input data map.
var inputDataMap = new Dictionary<Variable, Value>();
inputDataMap.Add(inputVar, inputVal);
// The model has only one output.
// You can also use the following way to get output variable by name:
// Variable outputVar = modelFunc.Outputs.Where(variable => string.Equals(variable.Name, outputName)).Single();
Variable outputVar = modelFunc.Output;
// Create output data map. Using null as Value to indicate using system allocated memory.
// Alternatively, create a Value object and add it to the data map.
var outputDataMap = new Dictionary<Variable, Value>();
outputDataMap.Add(outputVar, null);
// Evaluate the model against the batch input
modelFunc.Evaluate(inputDataMap, outputDataMap, device);
// Retrieve the evaluation result.
var outputVal = outputDataMap[outputVar];
var outputData = outputVal.GetDenseData<float>(outputVar);
// Output result
Console.Write("Evaluation result for batch of images: ");
for (int index = 0; index < imageList.Count; index++)
{
Console.Write(imageList[index]);
if (index < imageList.Count - 1)
Console.Write(", ");
else
Console.WriteLine();
}
PrintOutput(outputVar.Shape.TotalSize, outputData);
}
catch (Exception ex)
{
Console.WriteLine("Error: {0}\nCallStack: {1}\n Inner Exception: {2}", ex.Message, ex.StackTrace, ex.InnerException != null ? ex.InnerException.Message : "No Inner Exception");
throw ex;
}
}
/// <summary>
/// The example shows
/// - how to evaluate multiple sample requests in parallel.
/// </summary>
/// <param name="device">Specify on which device to run the evaluation.</param>
public static async Task EvaluateMultipleImagesInParallelAsync(DeviceDescriptor device)
{
Console.WriteLine("\n===== Evaluate multiple images in parallel =====");
string modelFilePath = "resnet20.dnn";
ThrowIfFileNotExist(modelFilePath, string.Format("Error: The model '{0}' does not exist. Please follow instructions in README.md in <CNTK>/Examples/Image/Classification/ResNet to create the model.", modelFilePath));
// This program uses images from the CIFAR-10 dataset for evaluation.
// Please see README.md in <CNTK>/Examples/Image/DataSets/CIFAR-10 about how to download the CIFAR-10 dataset.
var imageFiles = new string[] { "00000.png", "00001.png", "00002.png", "00003.png", "00004.png" };
var imageList = new BlockingCollection<string>();
foreach (var file in imageFiles)
{
ThrowIfFileNotExist(file, string.Format("Error: The sample image '{0}' does not exist. Please see README.md in <CNTK>/Examples/Image/DataSets/CIFAR-10 about how to download the CIFAR-10 dataset.", file));
// For simplicity, we add all images to the BlockingCollection in advance. It is also possible to add new images dynamically.
imageList.Add(file);
}
// Load and clone the model.
// The model resnet20.dnn is trained by <CNTK>/Examples/Image/Classification/ResNet/Python/TrainResNet_CIFAR10.py
// Please see README.md in <CNTK>/Examples/Image/Classification/ResNet about how to train the model.
var modelFunc = Function.Load(modelFilePath, device);
// It is not thread-safe to perform concurrent evaluation requests using the same model function.
// Use clone() to create copies of model function for parallel evaluation.
// ParameterCloningMethod.Share specifies that model parameters are shared between cloned model functions, while
// each model function instance has its own private state for evaluation.
int numOfModelInstances = 3;
List<Function> modelPool = new List<Function>();
modelPool.Add(modelFunc);
for (int i = 1; i < numOfModelInstances; i++)
{
modelPool.Add(modelFunc.Clone(ParameterCloningMethod.Share));
}
// Start to evaluate samples in parallel.
Console.WriteLine(string.Format("Evaluate {0} images in parallel using {1} model instances.", imageList.Count, numOfModelInstances));
var taskList = new List<Task>();
var results = new ConcurrentDictionary<string, IList<IList<float>>>();
foreach (var evalFunc in modelPool)
{
taskList.Add(Task.Factory.StartNew(() =>
{
// Get input and output variables
Variable inputVar = evalFunc.Arguments.Single();
NDShape inputShape = inputVar.Shape;
int imageWidth = inputShape[0];
int imageHeight = inputShape[1];
Variable outputVar = evalFunc.Output;
string image;
// The task exits when no image is available for evaluation.
while (imageList.TryTake(out image) == true)
{
Console.WriteLine(string.Format("Evaluating image {0} using thread {1}.", image, Thread.CurrentThread.ManagedThreadId));
Bitmap bmp = new Bitmap(Bitmap.FromFile(image));
var resized = bmp.Resize(imageWidth, imageHeight, true);
List<float> resizedCHW = resized.ParallelExtractCHW();
// Create input data map.
var inputDataMap = new Dictionary<Variable, Value>();
var inputVal = Value.CreateBatch(inputShape, resizedCHW, device);
inputDataMap.Add(inputVar, inputVal);
// Create output data map.
var outputDataMap = new Dictionary<Variable, Value>();
outputDataMap.Add(outputVar, null);
// Start evaluation on the device
evalFunc.Evaluate(inputDataMap, outputDataMap, device);
// Get evaluate result as dense output
var outputVal = outputDataMap[outputVar];
var outputData = outputVal.GetDenseData<float>(outputVar);
// Add result to the buffer for output at a later time.
if (results.TryAdd(image, outputData) == false)
throw new ArgumentException(string.Format("The image {0} has already been evaluated.", image));
}
}));
}
// Await until all images have been evaluated.
await Task.WhenAll(taskList);
var sampleSize = modelFunc.Output.Shape.TotalSize;
foreach (var file in imageFiles)
{
if (!results.ContainsKey(file))
throw new KeyNotFoundException(string.Format("Error: the image {0} has not been evaluated.", file));
var evalResult = results[file];
Console.WriteLine("Evaluation result for image " + file);
PrintOutput(sampleSize, evalResult);
}
}
/// <summary>
/// The example shows
/// - how to load model from a memory buffer.
/// </summary>
/// <param name="device">Specify on which device to run the evaluation.</param>
public static void LoadModelFromMemory(DeviceDescriptor device)
{
try
{
Console.WriteLine("\n===== Load model from memory buffer =====");
// For demo purpose, we first read the model into memory
// The model resnet20.dnn is trained by <CNTK>/Examples/Image/Classification/ResNet/Python/TrainResNet_CIFAR10.py
// Please see README.md in <CNTK>/Examples/Image/Classification/ResNet about how to train the model.
string modelFilePath = "resnet20.dnn";
ThrowIfFileNotExist(modelFilePath, string.Format("Error: The model '{0}' does not exist. Please follow instructions in README.md in <CNTK>/Examples/Image/Classification/ResNet to create the model.", modelFilePath));
var modelBuffer = File.ReadAllBytes(modelFilePath);
// Load model from memory buffer
Function modelFunc = Function.Load(modelBuffer, device);
// Get shape data for the input variable
Variable inputVar = modelFunc.Arguments.Single();
NDShape inputShape = inputVar.Shape;
int imageWidth = inputShape[0];
int imageHeight = inputShape[1];
// Image preprocessing to match input requirements of the model.
// This program uses images from the CIFAR-10 dataset for evaluation.
// Please see README.md in <CNTK>/Examples/Image/DataSets/CIFAR-10 about how to download the CIFAR-10 dataset.
string sampleImage = "00000.png";
ThrowIfFileNotExist(sampleImage, string.Format("Error: The sample image '{0}' does not exist. Please see README.md in <CNTK>/Examples/Image/DataSets/CIFAR-10 about how to download the CIFAR-10 dataset.", sampleImage));
Bitmap bmp = new Bitmap(Bitmap.FromFile(sampleImage));
var resized = bmp.Resize(imageWidth, imageHeight, true);
List<float> resizedCHW = resized.ParallelExtractCHW();
// Create input data map.
var inputDataMap = new Dictionary<Variable, Value>();
var inputVal = Value.CreateBatch(inputVar.Shape, resizedCHW, device);
inputDataMap.Add(inputVar, inputVal);
// Get output variable.
Variable outputVar = modelFunc.Output;
// Create output data map. Using null as Value to indicate using system allocated memory.
// Alternatively, create a Value object and add it to the data map.
var outputDataMap = new Dictionary<Variable, Value>();
outputDataMap.Add(outputVar, null);
// Start evaluation on the device.
modelFunc.Evaluate(inputDataMap, outputDataMap, device);
// Get evaluate result as dense output.
var outputVal = outputDataMap[outputVar];
var outputData = outputVal.GetDenseData<float>(outputVar);
PrintOutput(outputVar.Shape.TotalSize, outputData);
}
catch (Exception ex)
{
Console.WriteLine("Error: {0}\nCallStack: {1}\n Inner Exception: {2}", ex.Message, ex.StackTrace, ex.InnerException != null ? ex.InnerException.Message : "No Inner Exception");
throw ex;
}
}
/// <summary>
/// The example shows
/// - how to evaluate model using asynchronous task. This is useful when offloading is needed to achieve better responsiveness.
/// The asynchronous evaluation is implemented as an extension method in CNTKExtensions.cs, which provides an asynchronous facade for the synchronous Evaluation().
/// </summary>
/// <param name="device">Specify on which device to run the evaluation.</param>
public static async Task EvaluationSingleImageAsync(DeviceDescriptor device)
{
try
{
Console.WriteLine("\n===== Evaluate image asynchronously =====");
// Load the model.
// The model resnet20.dnn is trained by <CNTK>/Examples/Image/Classification/ResNet/Python/Models/TrainResNet_CIFAR10.py
// Please see README.md in <CNTK>/Examples/Image/Classification/ResNet about how to train the model.
string modelFilePath = "resnet20.dnn";
ThrowIfFileNotExist(modelFilePath, string.Format("Error: The model '{0}' does not exist. Please follow instructions in README.md in <CNTK>/Examples/Image/Classification/ResNet to create the model.", modelFilePath));
Function modelFunc = Function.Load(modelFilePath, device);
// Get input variable.
Variable inputVar = modelFunc.Arguments.Single();
// Get shape data for the input variable.
NDShape inputShape = inputVar.Shape;
int imageWidth = inputShape[0];
int imageHeight = inputShape[1];
// Image preprocessing to match input requirements of the model.
// This program uses images from the CIFAR-10 dataset for evaluation.
// Please see README.md in <CNTK>/Examples/Image/DataSets/CIFAR-10 about how to download the CIFAR-10 dataset.
string sampleImage = "00000.png";
ThrowIfFileNotExist(sampleImage, string.Format("Error: The sample image '{0}' does not exist. Please see README.md in <CNTK>/Examples/Image/DataSets/CIFAR-10 about how to download the CIFAR-10 dataset.", sampleImage));
Bitmap bmp = new Bitmap(Bitmap.FromFile(sampleImage));
var resized = bmp.Resize(imageWidth, imageHeight, true);
List<float> resizedCHW = resized.ParallelExtractCHW();
// Create input data map.
var inputDataMap = new Dictionary<Variable, Value>();
var inputVal = Value.CreateBatch(inputShape, resizedCHW, device);
inputDataMap.Add(inputVar, inputVal);
// Get output variable.
Variable outputVar = modelFunc.Output;
// Create output data map. Using null as Value to indicate using system allocated memory.
// Alternatively, create a Value object and add it to the data map.
var outputDataMap = new Dictionary<Variable, Value>();
outputDataMap.Add(outputVar, null);
// Start evaluation, await on the result.
await modelFunc.EvaluateAsync(inputDataMap, outputDataMap, device);
// Get evaluate result as dense output.
var outputVal = outputDataMap[outputVar];
var outputData = outputVal.GetDenseData<float>(outputVar);
PrintOutput(outputVar.Shape.TotalSize, outputData);
}
catch (Exception ex)
{
Console.WriteLine("Error: {0}\nCallStack: {1}\n Inner Exception: {2}", ex.Message, ex.StackTrace, ex.InnerException != null ? ex.InnerException.Message : "No Inner Exception");
throw ex;
}
}
/// <summary>
/// Print out the evaluation results.
/// </summary>
/// <typeparam name="T">The data value type</typeparam>
/// <param name="sampleSize">The size of each sample.</param>
/// <param name="outputBuffer">The evaluation result data.</param>
internal static void PrintOutput<T>(int sampleSize, IList<IList<T>> outputBuffer)
{
Console.WriteLine("The number of sequences in the batch: " + outputBuffer.Count);
int seqNo = 0;
int outputSampleSize = sampleSize;
foreach (var seq in outputBuffer)
{
if (seq.Count % outputSampleSize != 0)
{
throw new ApplicationException("The number of elements in the sequence is not a multiple of sample size");
}
Console.WriteLine(String.Format("Sequence {0} contains {1} samples.", seqNo++, seq.Count / outputSampleSize));
int i = 0;
int sampleNo = 0;
foreach (var element in seq)
{
if (i++ % outputSampleSize == 0)
{
Console.Write(String.Format(" sample {0}: ", sampleNo));
}
Console.Write(element);
if (i % outputSampleSize == 0)
{
Console.WriteLine(".");
sampleNo++;
}
else
{
Console.Write(",");
}
}
}
}
/// <summary>
/// The example shows
/// - how to load model.
/// - how to prepare input data as sequence using one-hot vector.
/// - how to prepare input and output data map.
/// - how to evaluate a model.
/// - how to retrieve evaluation result.
/// </summary>
/// <param name="device">Specify on which device to run the evaluation</param>
public static void EvaluationSingleSequenceUsingOneHot(DeviceDescriptor device)
{
try
{
Console.WriteLine("\n===== Evaluate single sequence using one-hot vector =====");
// The model atis.dnn is trained by <CNTK>/Examples/LanguageUnderstanding/ATIS/Python/LanguageUnderstanding.py
// Please see README.md in <CNTK>/Examples/LanguageUnderstanding/ATIS about how to train the model.
string modelFilePath = "atis.dnn";
ThrowIfFileNotExist(modelFilePath, string.Format("Error: The model '{0}' does not exist. Please follow instructions in README.md in <CNTK>/Examples/LanguageUnderstanding/ATIS to create the model.", modelFilePath));
Function modelFunc = Function.Load(modelFilePath, device);
// Read word and slot index files.
string vocabFile = "query.wl";
string labelFile = "slots.wl";
ThrowIfFileNotExist(vocabFile, string.Format("Error: The file '{0}' does not exist. Please copy it from <CNTK>/Examples/LanguageUnderstanding/ATIS/BrainScript/ to the output directory.", vocabFile));
ThrowIfFileNotExist(labelFile, string.Format("Error: The file '{0}' does not exist. Please copy it from <CNTK>/Examples/LanguageUnderstanding/ATIS/BrainScript/ to the output directory.", labelFile));
var vocabToIndex = buildVocabIndex(vocabFile);
var indexToSlots = buildSlotIndex(labelFile);
// Get input variable
var inputVar = modelFunc.Arguments.Single();
int vocabSize = inputVar.Shape.TotalSize;
var inputSentence = "BOS i would like to find a flight from charlotte to las vegas that makes a stop in st. louis EOS";
var seqData = new List<int>();
// SeqStartFlag is used to indicate whether this sequence is a new sequence (true) or concatenating the previous sequence (false).
var seqStartFlag = true;
// Get the index of each word in the sentence.
string[] inputWords = inputSentence.Split(' ');
foreach (var str in inputWords)
{
// Get the index of the word
var index = vocabToIndex[str];
// Add the sample to the sequence
seqData.Add(index);
}
// Create input value using OneHot vector data.
var inputValue = Value.CreateSequence<float>(vocabSize, seqData, seqStartFlag, device);
// Build input data map.
var inputDataMap = new Dictionary<Variable, Value>();
inputDataMap.Add(inputVar, inputValue);
// Prepare output.
Variable outputVar = modelFunc.Output;
// Create output data map. Using null as Value to indicate using system allocated memory.
var outputDataMap = new Dictionary<Variable, Value>();
outputDataMap.Add(outputVar, null);
// Evaluate the model.
modelFunc.Evaluate(inputDataMap, outputDataMap, device);
// Get output result.
var outputVal = outputDataMap[outputVar];
var outputData = outputVal.GetDenseData<float>(outputVar);
// output the result.
var outputSampleSize = outputVar.Shape.TotalSize;
if (outputData.Count != 1)
{
throw new ApplicationException("Only one sequence of slots is expected as output.");
}
var slotSeq = outputData[0];
if (slotSeq.Count % outputSampleSize != 0)
{
throw new ApplicationException("The number of elements in the slot sequence is not a multiple of sample size");
}
var numOfSlotsInOutput = slotSeq.Count / outputSampleSize;
if (inputWords.Count() != numOfSlotsInOutput)
{
throw new ApplicationException("The number of input words and the number of output slots do not match");
}
for (int i = 0; i < numOfSlotsInOutput; i++)
{
var max = slotSeq[i * outputSampleSize];
var maxIndex = 0;
for (int j = 1; j < outputSampleSize; j++)
{
if (slotSeq[i * outputSampleSize + j] > max)
{
max = slotSeq[i * outputSampleSize + j];
maxIndex = j;
}
}
Console.WriteLine(String.Format(" {0, 10} ---- {1}", inputWords[i], indexToSlots[maxIndex]));
}
Console.WriteLine();
}
catch (Exception ex)
{
Console.WriteLine("Error: {0}\nCallStack: {1}\n Inner Exception: {2}", ex.Message, ex.StackTrace, ex.InnerException != null ? ex.InnerException.Message : "No Inner Exception");
throw ex;
}
}
/// <summary>
/// The example shows
/// - how to load model.
/// - how to prepare input data as batch of sequences with variable length.
/// how to prepare data using one-hot vector format.
/// - how to prepare input and output data map.
/// - how to evaluate a model.
/// </summary>
/// <param name="device">Specify on which device to run the evaluation.</param>
public static void EvaluationBatchOfSequencesUsingOneHot(DeviceDescriptor device)
{
try
{
Console.WriteLine("\n===== Evaluate batch of sequences with variable length using one-hot vector =====");
// The model atis.dnn is trained by <CNTK>/Examples/LanguageUnderstanding/ATIS/Python/LanguageUnderstanding.py
// Please see README.md in <CNTK>/Examples/LanguageUnderstanding/ATIS about how to train the model.
string modelFilePath = "atis.dnn";
ThrowIfFileNotExist(modelFilePath, string.Format("Error: The model '{0}' does not exist. Please follow instructions in README.md in <CNTK>/Examples/LanguageUnderstanding/ATIS to create the model.", modelFilePath));
Function modelFunc = Function.Load(modelFilePath, device);
// Read word and slot index files.
string vocabFile = "query.wl";
string labelFile = "slots.wl";
ThrowIfFileNotExist(vocabFile, string.Format("Error: The file '{0}' does not exist. Please copy it from <CNTK>/Examples/LanguageUnderstanding/ATIS/BrainScript/ to the output directory.", vocabFile));
ThrowIfFileNotExist(labelFile, string.Format("Error: The file '{0}' does not exist. Please copy it from <CNTK>/Examples/LanguageUnderstanding/ATIS/BrainScript/ to the output directory.", labelFile));
var vocabToIndex = buildVocabIndex(vocabFile);
var indexToSlots = buildSlotIndex(labelFile);
// Get input variable.
var inputVar = modelFunc.Arguments.Single();
int vocabSize = inputVar.Shape.TotalSize;
// Prepare input data.
// Each sample is represented by an index to the onehot vector, so the index of the non-zero value of each sample is saved in the inner list.
// The outer list represents sequences contained in the batch.
var inputBatch = new List<List<int>>();
// SeqStartFlagBatch is used to indicate whether this sequence is a new sequence (true) or concatenating the previous sequence (false).
var seqStartFlagBatch = new List<bool>();
var inputSentences = new List<string>() {
"BOS i would like to find a flight from charlotte to las vegas that makes a stop in st. louis EOS",
"BOS flights from new york to seattle EOS"
};
var inputWords = new List<string[]>(2);
int numOfSequences = inputSentences.Count;
for (int seqIndex = 0; seqIndex < numOfSequences; seqIndex++)
{
// The input for one sequence
// Get the index of each word in the sentence.
var substring = inputSentences[seqIndex].Split(' ');
inputWords.Add(substring);
var seqData = new List<int>();
foreach (var str in substring)
{
var index = vocabToIndex[str];
seqData.Add(index);
}
inputBatch.Add(seqData);
seqStartFlagBatch.Add(true);
}
// Create the Value representing the batch data.
var inputValue = Value.CreateBatchOfSequences<float>(vocabSize, inputBatch, seqStartFlagBatch, device);
// Build input data map.
var inputDataMap = new Dictionary<Variable, Value>();
inputDataMap.Add(inputVar, inputValue);
// Prepare output.
Variable outputVar = modelFunc.Output;
// Create output data map. Using null as Value to indicate using system allocated memory.
var outputDataMap = new Dictionary<Variable, Value>();
outputDataMap.Add(outputVar, null);
// Evaluate the model
modelFunc.Evaluate(inputDataMap, outputDataMap, device);
// Get evaluation result.
var outputVal = outputDataMap[outputVar];
var outputData = outputVal.GetDenseData<float>(outputVar);
// output the result
var outputSampleSize = outputVar.Shape.TotalSize;
if (outputData.Count != inputBatch.Count)
{
throw new ApplicationException("The number of sequence in output does not match that in input.");
}
Console.WriteLine("The number of sequences in the batch: " + outputData.Count);
for (int seqno = 0; seqno < outputData.Count; seqno++)
{
var slotSeq = outputData[seqno];
Console.WriteLine("Sequence {0}: ", seqno);
if (slotSeq.Count % outputSampleSize != 0)
{
throw new ApplicationException("The number of elements in the slot sequence is not a multiple of sample size");
}
var numOfSlotsInOutput = slotSeq.Count / outputSampleSize;
if (inputWords[seqno].Count() != numOfSlotsInOutput)
{
throw new ApplicationException("The number of input words and the number of output slots do not match.");
}
for (int i = 0; i < numOfSlotsInOutput; i++)
{
var max = slotSeq[i * outputSampleSize];
var maxIndex = 0;
for (int j = 1; j < outputSampleSize; j++)
{
if (slotSeq[i * outputSampleSize + j] > max)
{
max = slotSeq[i * outputSampleSize + j];
maxIndex = j;
}
}
Console.WriteLine(String.Format(" {0, 10} ---- {1}", inputWords[seqno][i], indexToSlots[maxIndex]));
}
Console.WriteLine();
}
}
catch (Exception ex)
{
Console.WriteLine("Error: {0}\nCallStack: {1}\n Inner Exception: {2}", ex.Message, ex.StackTrace, ex.InnerException != null ? ex.InnerException.Message : "No Inner Exception");
throw ex;
}
}
/// <summary>
/// The example shows
/// - how to prepare input data as sequence using sparse input.
/// </summary>
/// <param name="device">Specify on which device to run the evaluation</param>
public static void EvaluationSingleSequenceUsingSparse(DeviceDescriptor device)
{
try
{
Console.WriteLine("\n===== Evaluate single sequence using sparse input =====");
// The model atis.dnn is trained by <CNTK>/Examples/LanguageUnderstanding/ATIS/Python/LanguageUnderstanding.py
// Please see README.md in <CNTK>/Examples/LanguageUnderstanding/ATIS about how to train the model.
string modelFilePath = "atis.dnn";
ThrowIfFileNotExist(modelFilePath, string.Format("Error: The model '{0}' does not exist. Please follow instructions in README.md in <CNTK>/Examples/LanguageUnderstanding/ATIS to create the model.", modelFilePath));
Function modelFunc = Function.Load(modelFilePath, device);
// Read word and slot index files.
string vocabFile = "query.wl";
string labelFile = "slots.wl";
ThrowIfFileNotExist(vocabFile, string.Format("Error: The file '{0}' does not exist. Please copy it from <CNTK>/Examples/LanguageUnderstanding/ATIS/BrainScript/ to the output directory.", vocabFile));
ThrowIfFileNotExist(labelFile, string.Format("Error: The file '{0}' does not exist. Please copy it from <CNTK>/Examples/LanguageUnderstanding/ATIS/BrainScript/ to the output directory.", labelFile));
var vocabToIndex = buildVocabIndex(vocabFile);
var indexToSlots = buildSlotIndex(labelFile);
// Get input variable
var inputVar = modelFunc.Arguments.Single();
int vocabSize = inputVar.Shape.TotalSize;
var inputSentence = "BOS i would like to find a flight from charlotte to las vegas that makes a stop in st. louis EOS";
// Get the index of each word in the sentence.
string[] inputWords = inputSentence.Split(' ');
var seqLen = inputWords.Length;
// For this example, only 1 non-zero value for each sample.
var numNonZeroValues = seqLen * 1;
var colStarts = new int[seqLen + 1];
var rowIndices = new int[numNonZeroValues];
var nonZeroValues = new float[numNonZeroValues];
int count = 0;
for (; count < seqLen; count++)
{
// Get the index of the word
var nonZeroValueIndex = vocabToIndex[inputWords[count]];
// Add the sample to the sequence
nonZeroValues[count] = (float)1.0;
rowIndices[count] = nonZeroValueIndex;
colStarts[count] = count;
}
colStarts[count] = numNonZeroValues;
// Create input value using OneHot vector data.
var inputValue = Value.CreateSequence<float>(vocabSize, seqLen, colStarts, rowIndices, nonZeroValues, device);
// Build input data map.
var inputDataMap = new Dictionary<Variable, Value>();
inputDataMap.Add(inputVar, inputValue);
// Prepare output
Variable outputVar = modelFunc.Output;
// Create output data map. Using null as Value to indicate using system allocated memory.
var outputDataMap = new Dictionary<Variable, Value>();
outputDataMap.Add(outputVar, null);
// Evaluate the model.
modelFunc.Evaluate(inputDataMap, outputDataMap, device);
// Get result
var outputVal = outputDataMap[outputVar];
var outputData = outputVal.GetDenseData<float>(outputVar);
// Output the result
var outputSampleSize = outputVar.Shape.TotalSize;
if (outputData.Count != 1)
{
throw new ApplicationException("Only one sequence of slots is expected as output.");
}
var slotSeq = outputData[0];
if (slotSeq.Count % outputSampleSize != 0)
{
throw new ApplicationException("The number of elements in the slot sequence is not a multiple of sample size");
}
var numOfSlotsInOutput = slotSeq.Count / outputSampleSize;
if (inputWords.Count() != numOfSlotsInOutput)
{
throw new ApplicationException("The number of input words and the number of output slots do not match");
}
for (int i = 0; i < numOfSlotsInOutput; i++)
{
var max = slotSeq[i * outputSampleSize];
var maxIndex = 0;
for (int j = 1; j < outputSampleSize; j++)
{
if (slotSeq[i * outputSampleSize + j] > max)
{
max = slotSeq[i * outputSampleSize + j];
maxIndex = j;
}
}
Console.WriteLine(String.Format(" {0, 10} ---- {1}", inputWords[i], indexToSlots[maxIndex]));
}
Console.WriteLine();
}
catch (Exception ex)
{
Console.WriteLine("Error: {0}\nCallStack: {1}\n Inner Exception: {2}", ex.Message, ex.StackTrace, ex.InnerException != null ? ex.InnerException.Message : "No Inner Exception");
throw ex;
}
}
/// <summary>
/// The example shows
/// - how to load a pretrained model and evaluate an intermediate layer of its network
/// </summary>
/// <param name="device">Specify on which device to run the evaluation</param>
public static void EvaluateIntermediateLayer(DeviceDescriptor device)
{
try
{
Console.WriteLine("\n===== Evaluate intermediate layer =====\n");
// Load the model.
// The model resnet20.dnn is trained by <CNTK>/Examples/Image/Classification/ResNet/Python/TrainResNet_CIFAR10.py
// Please see README.md in <CNTK>/Examples/Image/Classification/ResNet about how to train the model.
string modelFilePath = "resnet20.dnn";
ThrowIfFileNotExist(modelFilePath, string.Format("Error: The model '{0}' does not exist. Please follow instructions in README.md in <CNTK>/Examples/Image/Classification/ResNet to create the model.", modelFilePath));
Function rootFunc = Function.Load(modelFilePath, device);
Function interLayerPrimitiveFunc = rootFunc.FindByName("final_avg_pooling");
// The Function returned by FindByName is a primitive function.
// For evaluation, it is required to create a composite function from the primitive function.
Function modelFunc = Function.AsComposite(interLayerPrimitiveFunc);
Variable outputVar = modelFunc.Output;
Variable inputVar = modelFunc.Arguments.Single();
// Get shape data for the input variable
NDShape inputShape = inputVar.Shape;
int imageWidth = inputShape[0];
int imageHeight = inputShape[1];
int imageChannels = inputShape[2];
int imageSize = inputShape.TotalSize;
var inputDataMap = new Dictionary<Variable, Value>();
var outputDataMap = new Dictionary<Variable, Value>();
// Image preprocessing to match input requirements of the model.
// This program uses images from the CIFAR-10 dataset for evaluation.
// Please see README.md in <CNTK>/Examples/Image/DataSets/CIFAR-10 about how to download the CIFAR-10 dataset.
string sampleImage = "00000.png";
ThrowIfFileNotExist(sampleImage, string.Format("Error: The sample image '{0}' does not exist. Please see README.md in <CNTK>/Examples/Image/DataSets/CIFAR-10 about how to download the CIFAR-10 dataset.", sampleImage));
Bitmap bmp = new Bitmap(Bitmap.FromFile(sampleImage));
var resized = bmp.Resize((int)imageWidth, (int)imageHeight, true);
List<float> resizedCHW = resized.ParallelExtractCHW();
// Create input data map
var inputVal = Value.CreateBatch(inputVar.Shape, resizedCHW, device);
inputDataMap.Add(inputVar, inputVal);
// Create output data map. Using null as Value to indicate using system allocated memory.
// Alternatively, create a Value object and add it to the data map.
outputDataMap.Add(outputVar, null);
// Start evaluation on the device
modelFunc.Evaluate(inputDataMap, outputDataMap, device);
// Get evaluate result as dense output
var outputVal = outputDataMap[outputVar];
var outputData = outputVal.GetDenseData<float>(outputVar);
Console.WriteLine("Evaluation result of intermediate layer final_avg_pooling");
PrintOutput(outputVar.Shape.TotalSize, outputData);
}
catch (Exception ex)
{
Console.WriteLine("Error: {0}\nCallStack: {1}\n Inner Exception: {2}", ex.Message, ex.StackTrace, ex.InnerException != null ? ex.InnerException.Message : "No Inner Exception");
throw ex;
}
}
/// <summary>
/// The example shows
/// - how to load a pretrained model and evaluate several nodes by combining their outputs
/// </summary>
/// <param name="device">Specify on which device to run the evaluation</param>
public static void EvaluateCombinedOutputs(DeviceDescriptor device)
{
try
{
Console.WriteLine("\n===== Evaluate combined outputs =====\n");
// Load the model.
// The model resnet20.dnn is trained by <CNTK>/Examples/Image/Classification/ResNet/Python/TrainResNet_CIFAR10.py
// Please see README.md in <CNTK>/Examples/Image/Classification/ResNet about how to train the model.
string modelFilePath = "resnet20.dnn";
ThrowIfFileNotExist(modelFilePath, string.Format("Error: The model '{0}' does not exist. Please follow instructions in README.md in <CNTK>/Examples/Image/Classification/ResNet to create the model.", modelFilePath));
Function modelFunc = Function.Load(modelFilePath, device);
// Get node of interest
Function interLayerPrimitiveFunc = modelFunc.FindByName("final_avg_pooling");
Variable poolingOutput = interLayerPrimitiveFunc.Output;
// Create a function which combine outputs from the node "final_avg_polling" and the final layer of the model.
Function evalFunc = Function.Combine(new[] { modelFunc.Output, poolingOutput });
Variable inputVar = evalFunc.Arguments.Single();
// Get shape data for the input variable
NDShape inputShape = inputVar.Shape;
int imageWidth = inputShape[0];
int imageHeight = inputShape[1];
int imageChannels = inputShape[2];
int imageSize = inputShape.TotalSize;
var inputDataMap = new Dictionary<Variable, Value>();
var outputDataMap = new Dictionary<Variable, Value>();
// Image preprocessing to match input requirements of the model.
// This program uses images from the CIFAR-10 dataset for evaluation.
// Please see README.md in <CNTK>/Examples/Image/DataSets/CIFAR-10 about how to download the CIFAR-10 dataset.
string sampleImage = "00000.png";
ThrowIfFileNotExist(sampleImage, string.Format("Error: The sample image '{0}' does not exist. Please see README.md in <CNTK>/Examples/Image/DataSets/CIFAR-10 about how to download the CIFAR-10 dataset.", sampleImage));
Bitmap bmp = new Bitmap(Bitmap.FromFile(sampleImage));
var resized = bmp.Resize((int)imageWidth, (int)imageHeight, true);
List<float> resizedCHW = resized.ParallelExtractCHW();
// Create input data map
var inputVal = Value.CreateBatch(inputVar.Shape, resizedCHW, device);
inputDataMap.Add(inputVar, inputVal);
// Create output data map. Using null as Value to indicate using system allocated memory.
// Alternatively, create a Value object and add it to the data map.
var modelOutput = evalFunc.Outputs[0];
var interLayerOutput = evalFunc.Outputs[1];
outputDataMap.Add(modelOutput, null);
outputDataMap.Add(interLayerOutput, null);
// Start evaluation on the device
evalFunc.Evaluate(inputDataMap, outputDataMap, device);
// Get evaluate result as dense output
foreach (var outputVariableValuePair in outputDataMap)
{
var variable = outputVariableValuePair.Key;
var value = outputVariableValuePair.Value;
var outputData = value.GetDenseData<float>(variable);
string variableName = "last layer of the model";
if (variable.Name == interLayerPrimitiveFunc.Name) {
variableName = "intermediate layer " + variable.Name;
}
Console.WriteLine("Evaluation result of {0}", variableName);
PrintOutput(variable.Shape.TotalSize, outputData);
}
}
catch (Exception ex)
{
Console.WriteLine("Error: {0}\nCallStack: {1}\n Inner Exception: {2}", ex.Message, ex.StackTrace, ex.InnerException != null ? ex.InnerException.Message : "No Inner Exception");
throw ex;
}
}
/// <summary>
/// Checks whether the file exists. If not, write the error message on the console and throw FileNotFoundException.
/// </summary>
/// <param name="filePath">The file to check.</param>
/// <param name="errorMsg">The message to write on console if the file does not exist.</param>
internal static void ThrowIfFileNotExist(string filePath, string errorMsg)
{
if (!File.Exists(filePath))
{
if (!string.IsNullOrEmpty(errorMsg))
{
Console.WriteLine(errorMsg);
}
throw new FileNotFoundException(string.Format("File '{0}' not found.", filePath));
}
}
private static Dictionary<string, int> buildVocabIndex(string filePath)
{
var vocab = new Dictionary<string, int>();
string[] lines = File.ReadAllLines(filePath);
for (int idx = 0; idx < lines.Count(); idx++)
vocab.Add(lines[idx], idx);
return vocab;
}
private static string[] buildSlotIndex(string filePath)
{
return File.ReadAllLines(filePath);
}
}
}