Completes pinning managed memory prior to native evaluation.

Applies CR feedback
This commit is contained in:
Gaizka Navarro 2016-06-13 14:51:58 +02:00
Родитель 1104a7e134
Коммит 036476bf63
3 изменённых файлов: 121 добавлений и 62 удалений

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

@ -269,7 +269,7 @@ namespace Microsoft.MSR.CNTK.Extensibility.Managed.CSEvalClient
string workingDirectory = Path.Combine(initialDirectory, @"..\..\Examples\Other\Simple2d\Config");
Environment.CurrentDirectory = initialDirectory;
using (var model = new IEvaluateModelExtendedManagedF())
using (var model = new ModelEvaluationExtendedF())
{
// Create the network
// This network (AddOperatorConstantNoInput.cntk) is a simple network consisting of a single binary operator (Plus)
@ -279,7 +279,7 @@ namespace Microsoft.MSR.CNTK.Extensibility.Managed.CSEvalClient
VariableSchema outputSchema = model.GetOutputSchema();
model.StartForwardEvaluation(outputSchema.Select(s => s.m_name).ToList<string>());
model.StartForwardEvaluation(outputSchema.Select(s => s.Name).ToList<string>());
List<ValueBuffer<float>> outputBuffer = outputSchema.CreateBuffers<float>();
List<ValueBuffer<float>> inputBuffer = new List<ValueBuffer<float>>();
@ -291,7 +291,7 @@ namespace Microsoft.MSR.CNTK.Extensibility.Managed.CSEvalClient
float[][] expected = {new float[]{2}, new float[]{3}};
Console.WriteLine("Expected values: {0}", string.Join(" - ", expected.Select(b => string.Join(", ", b)).ToList<string>()));
Console.WriteLine("Actual Values : {0}", string.Join(" - ", outputBuffer.Select(b => string.Join(", ", b.m_buffer)).ToList<string>()));
Console.WriteLine("Actual Values : {0}", string.Join(" - ", outputBuffer.Select(b => string.Join(", ", b.Buffer)).ToList<string>()));
}
}
catch (CNTKException ex)

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

@ -56,6 +56,29 @@ generic<class ElemType>
m_colIndices = gcnew array<int>(size);
m_size = size;
}
property int Size
{
int get() { return m_size; }
}
property array<ElemType>^ Buffer
{
array<ElemType>^ get() { return m_buffer; }
}
property array<int>^ Indices
{
array<int>^ get() { return m_indices; }
}
property array<int>^ ColIndices
{
array<int>^ get() { return m_colIndices;
}
}
private:
int m_size;
@ -111,15 +134,15 @@ public ref struct VariableLayout
};
// Name of the input
String^ m_name;
property String^ Name;
DataType m_dataType;
property DataType DataKind;
StorageType m_storageType;
property StorageType StorageKind;
// Dimension of the tensor, flattened to 1 dimension, for one entry on the dynamic axis.
// E.g. for a tensor [2,3,*] this would be 6.
int m_numElements;
property int NumElements;
};
public ref class VariableSchema : List<VariableLayout^>
@ -136,7 +159,7 @@ public:
List<ValueBuffer<ElemType>^>^ buffers = gcnew List<ValueBuffer<ElemType>^>(this->Count);
for (int i = 0; i < this->Count; i++)
{
buffers->Add(gcnew ValueBuffer<ElemType>(this[i]->m_numElements * maxLengths[i]));
buffers->Add(gcnew ValueBuffer<ElemType>(this[i]->NumElements * maxLengths[i]));
}
return buffers;
@ -149,7 +172,7 @@ public:
List<ValueBuffer<ElemType>^>^ buffers = gcnew List<ValueBuffer<ElemType>^>(this->Count);
for (int i = 0; i < this->Count; i++)
{
buffers->Add(gcnew ValueBuffer<ElemType>(this[i]->m_numElements));
buffers->Add(gcnew ValueBuffer<ElemType>(this[i]->NumElements));
}
return buffers;
@ -158,14 +181,14 @@ public:
/// Managed wrapper for the native evaluation model
template<typename ElemType>
public ref class IEvaluateModelExtendedManaged : IDisposable
public ref class ModelEvaluationExtended : IDisposable
{
typedef std::pair<std::wstring, std::vector<ElemType>*> MapEntry;
public:
/// <summary>Initializes a new instance of the <see cref="IEvaluateModelExtendedManaged"> class.</summary>
/// <summary>Initializes a new instance of the <see cref="ModelEvaluationExtended"> class.</summary>
/// <param name="funcName">Factory function name for retrieving the native model from the dll.</param>
IEvaluateModelExtendedManaged(String^ funcName)
ModelEvaluationExtended(String^ funcName)
{
pin_ptr<const WCHAR> dllname = PtrToStringChars("evaldll.dll");
auto hModule = LoadLibrary(dllname);
@ -228,9 +251,10 @@ public:
for (auto& lay : outputLayout)
{
VariableLayout^ layout = gcnew VariableLayout();
layout->m_name = gcnew String(lay.m_name.c_str());
layout->m_dataType = GetDataType(lay.m_dataType);
layout->m_numElements = lay.m_numElements;
layout->Name = gcnew String(lay.m_name.c_str());
layout->DataKind = GetDataKind(lay.m_dataType);
layout->NumElements = lay.m_numElements;
layout->StorageKind = GetStorageKind(lay.m_storageType);
outputSchema->Add(layout);
}
@ -275,9 +299,10 @@ public:
for (auto& lay : inputLayout)
{
VariableLayout^ layout = gcnew VariableLayout();
layout->m_name = gcnew String(lay.m_name.c_str());
layout->m_dataType = GetDataType(lay.m_dataType);
layout->m_numElements = lay.m_numElements;
layout->Name = gcnew String(lay.m_name.c_str());
layout->DataKind = GetDataKind(lay.m_dataType);
layout->NumElements = lay.m_numElements;
layout->StorageKind = GetStorageKind(lay.m_storageType);
inputSchema->Add(layout);
}
@ -307,26 +332,54 @@ public:
Native::ValueRefs<ElemType> stdOutputs;
Native::ValueBuffer<ElemType, Native::VectorRef>* vb = new Native::ValueBuffer<ElemType, Native::VectorRef>();
// Hold gc objects in the stack, while performing native actions
vector<gcroot<array<ElemType>^>*> pinBuffers;
vector<gcroot<array<int>^>*> pinIndices;
// Map the managed space into the native space, results will be written directly into the managed memory space
// https://msdn.microsoft.com/en-us/library/1dz8byfh.aspx
for each (auto item in inputs)
{
pin_ptr<ElemType> pb = &(item->m_buffer[0]);
pin_ptr<int> pi = &(item->m_indices[0]);
pin_ptr<int> pci = &(item->m_colIndices[0]);
vb->m_buffer.InitFrom(pb, item->m_size, item->m_size);
vb->m_indices.InitFrom(pi, item->m_size, item->m_size);
vb->m_colIndices.InitFrom(pci, item->m_size, item->m_size);
int size = item->Size;
// gcroot object manages the pointer so that it always corresponds to the correct managed location (even after gc relocation)
gcroot<array<ElemType>^>* pBuf = new gcroot<array<ElemType>^>(item->Buffer);
gcroot<array<int>^>* pInd = new gcroot<array<int>^>(item->Indices);
gcroot<array<int>^>* pColInd = new gcroot<array<int>^>(item->ColIndices);
pinBuffers.push_back(pBuf);
pinIndices.push_back(pInd);
pinIndices.push_back(pColInd);
pin_ptr<ElemType> pp = &(*pBuf)[0];
pin_ptr<int> pi = &(*pInd)[0];
pin_ptr<int> pci = &(*pColInd)[0];
vb->m_buffer.InitFrom(pp, size, size);
vb->m_indices.InitFrom(pi, size, size);
vb->m_colIndices.InitFrom(pci, size, size);
stdInputs.push_back(*vb);
}
for each (auto item in outputs)
{
pin_ptr<ElemType> pb = &(item->m_buffer[0]);
pin_ptr<int> pi = &(item->m_indices[0]);
pin_ptr<int> pci = &(item->m_colIndices[0]);
vb->m_buffer.InitFrom(pb, item->m_size, item->m_size);
vb->m_indices.InitFrom(pi, item->m_size, item->m_size);
vb->m_colIndices.InitFrom(pci, item->m_size, item->m_size);
int size = item->Size;
gcroot<array<ElemType>^>* pBuf = new gcroot<array<ElemType>^>(item->Buffer);
gcroot<array<int>^>* pInd = new gcroot<array<int>^>(item->Indices);
gcroot<array<int>^>* pColInd = new gcroot<array<int>^>(item->ColIndices);
pin_ptr<ElemType> pp = &(*pBuf)[0];
pin_ptr<int> pi = &(*pInd)[0];
pin_ptr<int> pci = &(*pColInd)[0];
pinBuffers.push_back(pBuf);
pinIndices.push_back(pInd);
pinIndices.push_back(pColInd);
vb->m_buffer.InitFrom(pp, size, size);
vb->m_indices.InitFrom(pi, size, size);
vb->m_colIndices.InitFrom(pci, size, size);
stdOutputs.push_back(*vb);
}
@ -345,18 +398,18 @@ public:
}
}
~IEvaluateModelExtendedManaged()
~ModelEvaluationExtended()
{
if (m_eval == nullptr)
{
return;
}
this->!IEvaluateModelExtendedManaged();
this->!ModelEvaluationExtended();
}
protected:
!IEvaluateModelExtendedManaged()
!ModelEvaluationExtended()
{
if (m_eval != nullptr)
{
@ -417,7 +470,7 @@ private:
}
}
VariableLayout::DataType GetDataType(Microsoft::MSR::CNTK::VariableLayout::DataType dataType)
VariableLayout::DataType GetDataKind(Microsoft::MSR::CNTK::VariableLayout::DataType dataType)
{
switch ((int)dataType)
{
@ -430,7 +483,7 @@ private:
}
}
VariableLayout::StorageType GetStorageType(Microsoft::MSR::CNTK::VariableLayout::StorageType storageType)
VariableLayout::StorageType GetStorageKind(Microsoft::MSR::CNTK::VariableLayout::StorageType storageType)
{
switch ((int)storageType)
{
@ -448,22 +501,22 @@ private:
/// <summary>Managed float-specific model evaluation class</summary>
/// <remarks>This class is necessary due to how generics and templates work in CLR</remarks>
public ref class IEvaluateModelExtendedManagedF : IEvaluateModelExtendedManaged<float>
public ref class ModelEvaluationExtendedF : ModelEvaluationExtended<float>
{
public:
IEvaluateModelExtendedManagedF::IEvaluateModelExtendedManagedF()
: IEvaluateModelExtendedManaged("GetEvalExtendedF")
ModelEvaluationExtendedF::ModelEvaluationExtendedF()
: ModelEvaluationExtended("GetEvalExtendedF")
{
}
};
/// <summary>Managed double-specific model evaluation class</summary>
/// <remarks>This class is necessary due to how generics and templates work in CLR</remarks>
public ref class IEvaluateModelExtendedManagedD : IEvaluateModelExtendedManaged<double>
public ref class ModelEvaluationExtendedD : ModelEvaluationExtended<double>
{
public:
IEvaluateModelExtendedManagedD::IEvaluateModelExtendedManagedD()
: IEvaluateModelExtendedManaged("GetEvalExtendedD")
ModelEvaluationExtendedD::ModelEvaluationExtendedD()
: ModelEvaluationExtended("GetEvalExtendedD")
{
}
};
@ -472,16 +525,16 @@ public:
// This method tricks the compiler into emitting the methods of the classes
// Refer to https://msdn.microsoft.com/en-us/library/ms177213.aspx for an
// explanation to this behavior
void emitExtended()
void EmitExtended()
{
IEvaluateModelExtendedManagedF f;
ModelEvaluationExtendedF f;
f.CreateNetwork("");
f.GetOutputSchema();
f.GetInputSchema();
f.StartForwardEvaluation(nullptr);
f.ForwardPass(nullptr, nullptr);
IEvaluateModelExtendedManagedD d;
ModelEvaluationExtendedD d;
d.CreateNetwork("");
d.GetOutputSchema();
d.GetInputSchema();

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

@ -17,9 +17,9 @@ namespace Microsoft.MSR.CNTK.Extensibility.Managed.Tests
{
int size = 2;
var vb = new ValueBuffer<float>(size);
Assert.AreEqual(size, vb.m_buffer.Length);
Assert.AreEqual(size, vb.m_indices.Length);
Assert.AreEqual(size, vb.m_colIndices.Length);
Assert.AreEqual(size, vb.Buffer.Length);
Assert.AreEqual(size, vb.Indices.Length);
Assert.AreEqual(size, vb.ColIndices.Length);
}
[TestMethod]
@ -35,13 +35,13 @@ namespace Microsoft.MSR.CNTK.Extensibility.Managed.Tests
"FeatureNodes = (v1) \n" +
"] \n";
using (var model = new IEvaluateModelExtendedManagedF())
using (var model = new ModelEvaluationExtendedF())
{
model.CreateNetwork(modelDefinition);
VariableSchema outputSchema = model.GetOutputSchema();
model.StartForwardEvaluation(outputSchema.Select(s => s.m_name).ToList<string>());
model.StartForwardEvaluation(outputSchema.Select(s => s.Name).ToList<string>());
List<ValueBuffer<float>> outputBuffer = outputSchema.CreateBuffers<float>();
List<ValueBuffer<float>> inputBuffer = new List<ValueBuffer<float>>();
@ -49,10 +49,13 @@ namespace Microsoft.MSR.CNTK.Extensibility.Managed.Tests
// We can call the evaluate method and get back the results...
model.ForwardPass(inputBuffer, outputBuffer);
List<float> expected = new List<float>() { 2, 3 /* 1 + 2 */ };
var buf = outputBuffer[0].m_buffer;
float[][] expected = { new float[] { 2 }, new float[] {3} };
Assert.AreEqual(string.Join(" - ", expected), string.Join(" - ", outputBuffer.Select(b => string.Join(", ", b.m_buffer)).ToList<string>()));
Assert.AreEqual(expected.Length, outputBuffer.Count);
for (int idx = 0; idx < expected.Length; idx++)
{
CollectionAssert.AreEqual(expected[idx], outputBuffer[idx].Buffer);
}
}
}
@ -68,26 +71,29 @@ namespace Microsoft.MSR.CNTK.Extensibility.Managed.Tests
"FeatureNodes = (i1) \n" +
"] \n";
using (var model = new IEvaluateModelExtendedManagedF())
using (var model = new ModelEvaluationExtendedF())
{
model.CreateNetwork(modelDefinition);
VariableSchema outputSchema = model.GetOutputSchema();
VariableSchema inputSchema = model.GetInputSchema();
model.StartForwardEvaluation(outputSchema.Select(s => s.m_name).ToList<string>());
model.StartForwardEvaluation(outputSchema.Select(s => s.Name).ToList<string>());
List<ValueBuffer<float>> outputBuffer = outputSchema.CreateBuffers<float>();
List<ValueBuffer<float>> inputBuffer = inputSchema.CreateBuffers<float>();
inputBuffer[0].m_buffer = new float[]{ 2 };
inputBuffer[0].Buffer[0] = 2;
// We can call the evaluate method and get back the results...
model.ForwardPass(inputBuffer, outputBuffer);
List<float> expected = new List<float>() { 6 };
var buf = outputBuffer[0].m_buffer;
float[][] expected = {new float[]{6}};
Assert.AreEqual(string.Join(" - ", expected), string.Join(" - ", outputBuffer.Select(b => string.Join(", ", b.m_buffer)).ToList<string>()));
Assert.AreEqual(expected.Length, outputBuffer.Count);
for (int idx = 0; idx < expected.Length; idx++)
{
CollectionAssert.AreEqual(expected[idx], outputBuffer[idx].Buffer);
}
}
}
@ -106,18 +112,18 @@ namespace Microsoft.MSR.CNTK.Extensibility.Managed.Tests
"FeatureNodes = (i1) \n" +
"] \n";
using (var model = new IEvaluateModelExtendedManagedF())
using (var model = new ModelEvaluationExtendedF())
{
model.CreateNetwork(modelDefinition);
VariableSchema outputSchema = model.GetOutputSchema();
VariableSchema inputSchema = model.GetInputSchema();
model.StartForwardEvaluation(outputSchema.Select(s => s.m_name).ToList<string>());
model.StartForwardEvaluation(outputSchema.Select(s => s.Name).ToList<string>());
List<ValueBuffer<float>> outputBuffer = outputSchema.CreateBuffers<float>();
List<ValueBuffer<float>> inputBuffer = inputSchema.CreateBuffers<float>();
inputBuffer[0].m_buffer = new float[] {2};
inputBuffer[0].Buffer[0] = 2;
// We can call the evaluate method and get back the results...
model.ForwardPass(inputBuffer, outputBuffer);
@ -127,7 +133,7 @@ namespace Microsoft.MSR.CNTK.Extensibility.Managed.Tests
Assert.AreEqual(expected.Length, outputBuffer.Count);
for(int idx=0; idx<expected.Length; idx++ )
{
CollectionAssert.AreEqual(expected[idx], outputBuffer[idx].m_buffer);
CollectionAssert.AreEqual(expected[idx], outputBuffer[idx].Buffer);
}
}
}