Skip to content

Commit

Permalink
Enables EvalWrapper to evaluate ndl networks without a model
Browse files Browse the repository at this point in the history
Adds a sample NDL operator for the C# application
Refactors C# Eval Client application to have 3 separate examples
  • Loading branch information
gaizkan committed Mar 17, 2016
1 parent a3ec754 commit 09c1355
Show file tree
Hide file tree
Showing 9 changed files with 226 additions and 27 deletions.
1 change: 1 addition & 0 deletions CNTK.sln
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Simple2d", "Simple2d", "{D2
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NdlExamples", "NdlExamples", "{FC573A62-6DAE-40A4-8153-520C8571A007}"
ProjectSection(SolutionItems) = preProject
Examples\Other\NdlExamples\AddOperator.ndl = Examples\Other\NdlExamples\AddOperator.ndl
Examples\Other\NdlExamples\NDLExamples.ndl = Examples\Other\NdlExamples\NDLExamples.ndl
EndProjectSection
EndProject
Expand Down
12 changes: 12 additions & 0 deletions Examples/Other/NdlExamples/AddOperator.ndl
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# This file is a sample ndl script for a single operator (Plus) adding a constant to an input
# It is used by the Extensibility\CSEvalClient program
deviceId=0
run=AddOne
AddOne=[
features = Input(1)
v2 = Constant(1)
ol = Plus(features, v2)

FeatureNodes=(features)
OutputNodes=(ol)
]
8 changes: 8 additions & 0 deletions Source/Common/Eval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@ void Eval<ElemType>::LoadModel(const std::wstring& modelFileName)
m_eval->LoadModel(modelFileName);
}

// CreateNetwork - create the network from the specified description
// networkDescription - network description
template <class ElemType>
void Eval<ElemType>::CreateNetwork(const std::string& networkDescription)
{
m_eval->CreateNetwork(networkDescription);
}

// GetNodeDimensions - Get the node dimensions of the specified nodes
// dimensions - map from name of node to dimension of the node
// nodeGroup - type of node we are requesting (input/output/specified)
Expand Down
5 changes: 5 additions & 0 deletions Source/Common/Include/Eval.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class IEvaluateModel // Evaluate Model Interface
virtual void Destroy() = 0;

virtual void LoadModel(const std::wstring& modelFileName) = 0;
virtual void CreateNetwork(const std::string& networkDescription) = 0;
virtual void GetNodeDimensions(std::map<std::wstring, size_t>& dimensions, NodeGroup nodeGroup) = 0;
virtual void StartEvaluateMinibatchLoop(const std::wstring& outputNodeName) = 0;
virtual void Evaluate(std::map<std::wstring, std::vector<ElemType>*>& inputs, std::map<std::wstring, std::vector<ElemType>*>& outputs) = 0;
Expand Down Expand Up @@ -86,6 +87,10 @@ class Eval : public IEvaluateModel<ElemType>, protected Plugin
// modelFileName - file holding the model to load
virtual void LoadModel(const std::wstring& modelFileName);

// CreateNetwork - create a network based on the network description
// networkDescription - network description
virtual void CreateNetwork(const std::string& networkDescription);

// GetNodeDimensions - Get the node dimensions of the specified nodes
// dimensions - map from name of node to dimension of the node
// nodeGroup - type of node we are requesting (input/output/specified)
Expand Down
16 changes: 16 additions & 0 deletions Source/EvalDll/CNTKEval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "CNTKEval.h"
#include "CPUMatrix.h" // for SetNumThreads()
#include "SimpleOutputWriter.h"
#include "NDLNetworkBuilder.h"
#ifdef LEAKDETECT
#include <vld.h> // leak detection
#endif
Expand Down Expand Up @@ -77,6 +78,21 @@ void CNTKEval<ElemType>::LoadModel(const std::wstring& modelFileName)
m_net = ComputationNetwork::CreateFromFile<ElemType>(deviceId, modelFileName);
}

// CreateNetwork - create a network based on the network description
// networkDescription - network description
template <class ElemType>
void CNTKEval<ElemType>::CreateNetwork(const std::string& networkDescription)
{
ConfigParameters config;
config.Parse(networkDescription);
auto netBuilder = make_shared<NDLBuilder<ElemType>>(config);
m_net = netBuilder->BuildNetworkFromDescription();
if (m_net == nullptr)
{
// TODO: Throw appropriate exception
}
}

// GetNodeDimensions - Get the node dimensions of the specified nodes
// dimensions - map from name of node to dimension of the node, will be appended to for Input/Output scenarios
// nodeGroup - type of node we are requesting (input/output/specified)
Expand Down
4 changes: 4 additions & 0 deletions Source/EvalDll/CNTKEval.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ class CNTKEval : public IEvaluateModel<ElemType>
// modelFileName - file holding the model to load
virtual void LoadModel(const std::wstring& modelFileName);

// CreateNetwork - create a network based on the network description
// networkDescription - network description
virtual void CreateNetwork(const std::string& networkDescription);

// GetNodeDimensions - Get the node dimensions of the specified nodes
// dimensions - map from name of node to dimension of the node
// nodeGroup - type of node we are requesting (input/output/specified)
Expand Down
8 changes: 4 additions & 4 deletions Source/EvalDll/EvalDll.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,13 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="$(DebugBuild)">
<LinkIncremental>true</LinkIncremental>
<IncludePath>..\SGDLib;..\ComputationNetworkLib;..\SequenceTrainingLib;..\Math;..\Common\Include;..\CNTK\BrainScript;$(MSMPI_INC);$(VCInstallDir)include;$(WindowsSDK_IncludePath)</IncludePath>
<IncludePath>..\SGDLib;..\ComputationNetworkLib;..\SequenceTrainingLib;..\Math;..\Common\Include;..\CNTK\BrainScript;..\ActionsLib;$(MSMPI_INC);$(VCInstallDir)include;$(WindowsSDK_IncludePath)</IncludePath>
<LibraryPath>..\ComputationNetworkLib;..\Math;$(MSMPI_LIB64);$(VCInstallDir)lib\amd64;$(WindowsSDK_LibraryPath_x64);$(Platform);$(SolutionDir)$(Platform)\$(Configuration)\</LibraryPath>
<TargetName>EvalDll</TargetName>
</PropertyGroup>
<PropertyGroup Condition="$(ReleaseBuild)">
<LinkIncremental>false</LinkIncremental>
<IncludePath>..\SGDLib;..\ComputationNetworkLib;..\SequenceTrainingLib;..\Math;..\Common\Include;..\CNTK\BrainScript;$(MSMPI_INC);$(CUDA_PATH)\include;$(VCInstallDir)include;$(WindowsSDK_IncludePath)</IncludePath>
<IncludePath>..\SGDLib;..\ComputationNetworkLib;..\SequenceTrainingLib;..\Math;..\Common\Include;..\CNTK\BrainScript;..\ActionsLib;$(MSMPI_INC);$(CUDA_PATH)\include;$(VCInstallDir)include;$(WindowsSDK_IncludePath)</IncludePath>
<LibraryPath>..\ComputationNetworkLib;..\Math;$(MSMPI_LIB64);$(CUDA_PATH)\lib\$(Platform);$(VCInstallDir)lib\amd64;$(WindowsSDK_LibraryPath_x64);$(Platform);$(SolutionDir)$(Platform)\$(Configuration)\</LibraryPath>
<TargetName>EvalDll</TargetName>
</PropertyGroup>
Expand All @@ -76,7 +76,7 @@
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ComputationNetworkLib.lib; Math.lib; kernel32.lib; user32.lib; shell32.lib; SequenceTrainingLib.lib; %(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ComputationNetworkLib.lib; Math.lib; ActionsLib.lib; kernel32.lib; user32.lib; shell32.lib; SequenceTrainingLib.lib; %(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>"c:\Program Files\NVIDIA Corporation\GDK\gdk_win7_amd64_release\nvml\lib"</AdditionalLibraryDirectories>
<DelayLoadDLLs>Math.dll; nvml.dll; cudart64_70.dll</DelayLoadDLLs>
</Link>
Expand All @@ -102,7 +102,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>ComputationNetworkLib.lib; Math.lib; kernel32.lib; user32.lib; shell32.lib; SequenceTrainingLib.lib; %(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ComputationNetworkLib.lib; Math.lib; ActionsLib.lib; kernel32.lib; user32.lib; shell32.lib; SequenceTrainingLib.lib; %(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>"c:\Program Files\NVIDIA Corporation\GDK\gdk_win7_amd64_release\nvml\lib"</AdditionalLibraryDirectories>
<Profile>true</Profile>
<DelayLoadDLLs>Math.dll; nvml.dll; cudart64_70.dll</DelayLoadDLLs>
Expand Down
175 changes: 152 additions & 23 deletions Source/Extensibility/CSEvalClient/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Configuration;

namespace Microsoft.MSR.CNTK.Extensibility.Managed.CSEvalClient
{
Expand All @@ -21,30 +22,53 @@ namespace Microsoft.MSR.CNTK.Extensibility.Managed.CSEvalClient
/// In order to run this program the model must already exist in the example. To create the model,
/// first run the example in <CNTK>/Examples/Image/MNIST. Once the model file 01_OneHidden is created,
/// you can run this client.
/// This client shows two methods for obtaining the output results from the evaluation, the first as
/// This example also shows evaluating a network without first training the model. This is accomplished
/// by creating the network and evaluating a single forward pass.
/// This client also shows two methods for obtaining the output results from the evaluation, the first as
/// return values from the Evaluate method call (which only returns a single layer output), and the second
/// by passing the allocated output layers to the evaluate method.
/// </description>
class Program
{
private static string initialDirectory;

/// <summary>
/// Program entry point
/// </summary>
/// <param name="args">Program arguments (ignored)</param>
private static void Main(string[] args)
{
initialDirectory = Environment.CurrentDirectory;

Console.WriteLine("====== EvaluateModelSingleLayer ========");
EvaluateModelSingleLayer();

Console.WriteLine("\n====== EvaluateModelMultipleLayers ========");
EvaluateModelMultipleLayers();

Console.WriteLine("\n====== EvaluateNetworkSingleLayer ========");
EvaluateNetworkSingleLayer();

Console.WriteLine("Press <Enter> to terminate.");
Console.ReadLine();
}

/// <summary>
/// Evaluates a trained model and obtains a single layer output
/// </summary>
private static void EvaluateModelSingleLayer()
{
try
{
// The examples assume the executable is running from the data folder
// We switch the current directory to the data folder (assuming the executable is in the <CNTK>/x64/Debug|Release folder
Environment.CurrentDirectory = Path.Combine(Environment.CurrentDirectory, @"..\..\Examples\Image\MNIST\Data\");

Dictionary<string, List<float>> outputs;
Environment.CurrentDirectory = Path.Combine(initialDirectory, @"..\..\Examples\Image\MNIST\Data\");
List<float> outputs;

using (var model = new IEvaluateModelManagedF())
{
// Initialize model evaluator
string config = GetConfig();
string config = GetFileContents(Path.Combine(Environment.CurrentDirectory, @"..\Config\01_OneHidden.cntk"));
model.Init(config);

// Load model
Expand All @@ -55,30 +79,138 @@ private static void Main(string[] args)
var inputs = GetDictionary("features", 28*28, 255);

// We can call the evaluate method and get back the results (single layer)...
// List<float> outputList = model.Evaluate(inputs, "ol.z", 10);
outputs = model.Evaluate(inputs, "ol.z", 10);
}

OutputResults("ol.z", outputs);
}
catch (CNTKException ex)
{
Console.WriteLine("Error: {0}\nNative CallStack: {1}\n Inner Exception: {2}", ex.Message, ex.NativeCallStack, ex.InnerException != null ? ex.InnerException.Message : "No Inner Exception");
}
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");
}
}

// ... or we can preallocate the structure and pass it in (multiple output layers)
/// <summary>
/// Evaluates a trained model and obtains multiple layers output
/// </summary>
private static void EvaluateModelMultipleLayers()
{
try
{
// The examples assume the executable is running from the data folder
// We switch the current directory to the data folder (assuming the executable is in the <CNTK>/x64/Debug|Release folder
Environment.CurrentDirectory = Path.Combine(initialDirectory, @"..\..\Examples\Image\MNIST\Data\");

Dictionary<string, List<float>> outputs;

using (var model = new IEvaluateModelManagedF())
{
// Initialize model evaluator
string config = GetFileContents(Path.Combine(Environment.CurrentDirectory, @"..\Config\01_OneHidden.cntk"));
model.Init(config);

// Load model
string modelFilePath = Path.Combine(Environment.CurrentDirectory, @"..\Output\Models\01_OneHidden");
model.LoadModel(modelFilePath);

// Generate random input values in the appropriate structure and size
var inputs = GetDictionary("features", 28*28, 255);

// We can preallocate the output structure and pass it in (multiple output layers)
outputs = GetDictionary("ol.z", 10, 1);
model.Evaluate(inputs, outputs);

model.Evaluate(inputs, outputs);
}

Console.WriteLine("--- Output results ---");
foreach (var item in outputs)

OutputResults(outputs);
}
catch (CNTKException ex)
{
Console.WriteLine("Error: {0}\nNative CallStack: {1}\n Inner Exception: {2}", ex.Message, ex.NativeCallStack, ex.InnerException != null ? ex.InnerException.Message : "No Inner Exception");
}
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");
}
}

/// <summary>
/// Evaluates a network (without a model) and obtains a single layer output
/// </summary>
private static void EvaluateNetworkSingleLayer()
{
try
{
// The examples assume the executable is running from the data folder
// We switch the current directory to the data folder (assuming the executable is in the <CNTK>/x64/Debug|Release folder
string workingDirectory = Path.Combine(initialDirectory, @"..\..\Examples\Other\NDlExamples");
Environment.CurrentDirectory = initialDirectory;

List<float> outputs;

using (var model = new IEvaluateModelManagedF())
{
Console.WriteLine("Output layer: {0}", item.Key);
foreach (var entry in item.Value)
{
Console.WriteLine(entry);
}
// Initialize model evaluator
model.Init("deviceId=0");

// Create the network
string networkDescription = GetFileContents(Path.Combine(workingDirectory, @"AddOperator.ndl"));
model.CreateNetwork(networkDescription);

// Generate random input values in the appropriate structure and size
var inputs = new Dictionary<string, List<float>>() { { "features", new List<float>() { { 1.0f } } } };

// We can call the evaluate method and get back the results (single layer)...
outputs = model.Evaluate(inputs, "ol", 1);
}

OutputResults("ol", outputs);
}
catch (CNTKException ex)
{
Console.WriteLine("Error: {0}\nNative CallStack: {1}\n Inner Exception: {2}", ex.Message, ex.NativeCallStack, ex.InnerException != null ? ex.InnerException.Message : "No Inner Exception");
}
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");
}
}

Console.WriteLine("Press <Enter> to terminate.");
Console.ReadLine();
/// <summary>
/// Dumps the output to the console
/// </summary>
/// <param name="outputs">The structure containing the output layers</param>
private static void OutputResults(Dictionary<string, List<float>> outputs)
{
Console.WriteLine("--- Output results ---");
foreach (var item in outputs)
{
OutputResults(item.Key, item.Value);
}
}

/// <summary>
/// Dumps the output of a layer to the console
/// </summary>
/// <param name="layer">The display name for the layer</param>
/// <param name="values">The layer values</param>
private static void OutputResults(string layer, List<float> values)
{
if (values == null)
{
Console.WriteLine("No Output for layer: {0}", layer);
return;
}

Console.WriteLine("Output layer: {0}", layer);
foreach (var entry in values)
{
Console.WriteLine(entry);
}
}

/// <summary>
Expand All @@ -103,12 +235,9 @@ static Dictionary<string, List<float>> GetDictionary(string key, int size, int m
/// Reads the configuration file and returns the contents as a string
/// </summary>
/// <returns>The content of the configuration file</returns>
static string GetConfig()
static string GetFileContents(string filePath)
{
string configFilePath = Path.Combine(Environment.CurrentDirectory,
@"..\Config\01_OneHidden.cntk");

var lines = System.IO.File.ReadAllLines(configFilePath);
var lines = System.IO.File.ReadAllLines(filePath);
return string.Join("\n", lines);
}

Expand Down
Loading

0 comments on commit 09c1355

Please sign in to comment.