Completes pinning managed memory prior to native evaluation.
Applies CR feedback
This commit is contained in:
Родитель
1104a7e134
Коммит
036476bf63
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче