Merge remote-tracking branch 'origin/master' into nikosk/keras_support2

This commit is contained in:
Nikos Karampatziakis 2017-02-02 11:21:55 -08:00
Родитель 6a1ed294b2 62654a1594
Коммит cb4ef4243d
24 изменённых файлов: 351 добавлений и 132 удалений

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

@ -1452,6 +1452,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PerformanceProfilerDll", "S
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CNTKLibraryCSEvalExamplesTest", "Tests\EndToEndTests\EvalClientTests\CNTKLibraryCSEvalExamplesTest\CNTKLibraryCSEvalExamplesTest.csproj", "{3500A847-E024-4E7D-92DD-CC587C17460B}"
ProjectSection(ProjectDependencies) = postProject
{50EF9EE6-5018-453E-A063-F77044EF1A97} = {50EF9EE6-5018-453E-A063-F77044EF1A97}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GoogLeNet", "GoogLeNet", "{789B4AB8-40F1-4A37-823A-BC20D80C8BF1}"
ProjectSection(SolutionItems) = preProject

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

@ -506,6 +506,7 @@ CNTKLIBRARY_TESTS_SRC =\
$(CNTKLIBRARY_TESTS_SRC_PATH)/BlockTests.cpp \
$(CNTKLIBRARY_TESTS_SRC_PATH)/TensorTests.cpp \
$(CNTKLIBRARY_TESTS_SRC_PATH)/ValueTests.cpp \
$(CNTKLIBRARY_TESTS_SRC_PATH)/LoadLegacyModelTests.cpp \
$(CNTKLIBRARY_TESTS_SRC_PATH)/TrainerTests.cpp \
$(CNTKLIBRARY_TESTS_SRC_PATH)/CifarResNet.cpp \
$(CNTKLIBRARY_TESTS_SRC_PATH)/SerializationTests.cpp \

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

@ -1861,8 +1861,11 @@ private:
private:
explicit Parameter(const NDArrayViewPtr& value, const std::wstring& name, const std::wstring& uid)
: Variable(value->Shape(), VariableKind::Parameter, value->GetDataType(), value->DeepClone(false), true, {}, name, uid)
{}
: Variable(value->Shape(), VariableKind::Parameter, value->GetDataType(), value, true, {}, name, uid)
{
if (value->IsReadOnly())
InvalidArgument("Parameter cannot be constructed from a read-only NDArrayView value; you can create a non read-only clone of the value and use that instead!");
}
};
// Implementation note: The Variable type is a value type and not polymorphic in nature.
@ -1943,7 +1946,7 @@ private:
private:
Constant(const NDArrayViewPtr& value, const std::wstring& name, const std::wstring& uid)
: Variable(value->Shape(), VariableKind::Constant, value->GetDataType(), value->DeepClone(), false, {}, name, uid)
: Variable(value->Shape(), VariableKind::Constant, value->GetDataType(), value, false, {}, name, uid)
{}
///
@ -2603,6 +2606,7 @@ namespace CNTK
CNTK_API virtual void Backward(const BackPropStatePtr& state,
const std::unordered_map<Variable, ValuePtr>& rootGradientValues,
std::unordered_map<Variable, ValuePtr>& backPropagatedGradientValuesForInputs);
///
/// Returns the name of the operation that this Function denotes
///
@ -2631,8 +2635,11 @@ namespace CNTK
///
/// Infers the shape, data type and dynamic axes of the outputs of 'this' function based on the
/// Function's inputs, and returns Output Variable objects containing the inferred information
/// Result cannot exceed the max number of outputs (128).
/// The passed "outputs" vector should also reserve 128 elements in order to not cause memory allocation during
/// crossing of dll boundary.
///
CNTK_API virtual std::vector<Variable> InferOutputs() = 0;
CNTK_API virtual void InferOutputs(std::vector<Variable>& outputs) = 0;
public:
@ -2737,9 +2744,9 @@ namespace CNTK
///
/// Returns all Input variables of 'this' Function.
///
std::vector<Variable> Inputs() const
std::vector<Variable> Inputs(bool pythonOperandOrder = false) const
{
return *(InputsImpl().get());
return *(InputsImpl(pythonOperandOrder).get());
}
///
@ -2837,6 +2844,11 @@ namespace CNTK
///
CNTK_API void PrintGraph() const;
///
/// Maimum number of outputs that is currently supported.
///
static const int MaxNumOutputs = 64;
protected:
///
/// Protected constructor for derived 'Function' types to specify the actual input and output variables for the (primitive) Function instance.
@ -2858,6 +2870,7 @@ namespace CNTK
// Returns a outputs without ref-counting the owner.
CNTK_API std::vector<Variable>& RawOutputs() const;
private:
CNTK_API std::shared_ptr<std::vector<std::pair<Variable, Variable>>> BlockArgumentsMappingImpl() const;
@ -2882,10 +2895,10 @@ namespace CNTK
return filteredInputs;
}
CNTK_API std::shared_ptr<std::vector<Variable>> InputsImpl() const;
CNTK_API std::shared_ptr<std::vector<Variable>> InputsImpl(bool pythonOperandOrder = false) const;
CNTK_API std::shared_ptr<std::vector<Variable>> OutputsImpl() const;
void ValidateOrUpdateOutputs(std::unordered_map<const Function*, size_t>& visitedFunctions, bool& recurrentNodeOutputModified);
void ValidateOrUpdateOutputs(std::unordered_map<const Function*, size_t>& visitedFunctions, bool& recurrentNodeOutputModified, std::vector<Variable>& buffer);
static void ReplacePlaceholderInPlace(Variable& var,
const std::unordered_map<Variable, Variable>& placeholderReplacements,

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

@ -20,6 +20,8 @@
#include "ReshapingNodes.h"
#include "DeprecatedNodes.h"
#include "RNNNodes.h"
#include "PreComputeNodes.h"
#include "DeprecatedNodes.h"
using namespace Microsoft::MSR::CNTK;
@ -49,9 +51,7 @@ namespace CNTK
Variable var;
if (node->IsLeaf())
{
var = ResolveLeaf<ElementType>(node);
}
else
{
// This is a non-leaf node and maps to a primitive Function
@ -78,6 +78,22 @@ namespace CNTK
}
private:
template<class ElementType>
Variable CreateParameterOrConstantFromNodeValue(const ComputationNodeBasePtr& node, bool isConstant)
{
auto& matrix = node->As<ComputationNode<ElementType>>()->Value();
auto tensorView = new TensorView<ElementType>(std::make_shared<Matrix<ElementType>>(matrix.AsReference()), AsTensorViewShape(node->GetSampleLayout()));
NDArrayViewPtr value = MakeSharedObject<NDArrayView>(AsDataType<ElementType>(), AsDeviceDescriptor(matrix.GetDeviceId()), AsStorageFormat(matrix.GetFormat()), AsNDShape(node->GetSampleLayout()), false, tensorView);
auto kind = isConstant ? VariableKind::Constant : VariableKind::Parameter;
std::wstring varUid, varName;
std::tie(varUid, varName) = UidAndNameFromCNTKInternalNodeName(node->NodeName(), kind);
return isConstant ? (Variable)Constant(value, varName, varUid) : Parameter(value, varName, varUid);
}
template<class ElementType>
Variable ResolveLeaf(const ComputationNodeBasePtr& node)
{
@ -104,13 +120,7 @@ namespace CNTK
if (node->Is<LearnableParameter<ElementType>>())
{
bool isConstant = (node->GetLearningRateMultiplier() == 0);
auto& matrix = node->As<ComputationNode<ElementType>>()->Value();
auto tensorView = new TensorView<ElementType>(std::make_shared<Matrix<ElementType>>(matrix.AsReference()), AsTensorViewShape(node->GetSampleLayout()));
NDArrayViewPtr value = MakeSharedObject<NDArrayView>(AsDataType<ElementType>(), AsDeviceDescriptor(matrix.GetDeviceId()), AsStorageFormat(matrix.GetFormat()), variableShape, false, tensorView);
auto kind = isConstant ? VariableKind::Constant : VariableKind::Parameter;
std::tie(varUid, varName) = UidAndNameFromCNTKInternalNodeName(node->NodeName(), kind);
return isConstant ? (Variable)Constant(value, varName, varUid) : Parameter(value, varName, varUid);
return CreateParameterOrConstantFromNodeValue<ElementType>(node, isConstant);
}
LogicError("CNTK::LoadLegacyModel: Unsupported legacy CNTK node named '%S'", node->NodeName().c_str());
@ -311,7 +321,7 @@ namespace CNTK
// tensor dimensions flattended into the column dimension of the 2D paramater matrix
// We need to recover the actual tensor shape of the parameter in this case
auto& convolutionMapVar = inputVars[0];
if (convolutionNode->IsConvolution2D())
if (convolutionNode->IsConvolution2D() || (convolutionMapVar.Shape().Rank() == 2))
{
assert(convolutionMapVar.Shape().Rank() == 2);
assert(convolutionMapVar.IsConstant() || convolutionMapVar.IsParameter());
@ -444,6 +454,24 @@ namespace CNTK
opType = PrimitiveOpType::EditDistanceError;
}
else if ((node->OperationName() == OperationNameOf(MeanNode)) || (node->OperationName() == OperationNameOf(InvStdDevNode)))
{
auto precomputeNode = node->As<MeanInvStdDevNodeBase<ElementType>>();
if (!precomputeNode->HasComputed())
InvalidArgument("Loading a CNTK legacy V1 model containing a Mean/InvStdDev precompute node, whose computation is unfinished, is not supported!");
return CreateParameterOrConstantFromNodeValue<ElementType>(node, /* isConstant =*/ true);
}
else if (node->OperationName() == OperationNameOf(PerDimMeanVarNormalizationNode))
{
auto meanValue = Constant(inputVars[1]).Value();
auto invStdDevValue = Constant(inputVars[2]).Value();
std::wstring uid, name;
std::tie(uid, name) = UidAndNameFromCNTKInternalNodeName(node->NodeName());
return PerDimMeanVarianceNormalize(inputVars[0], meanValue, invStdDevValue, name);
}
else
LogicError("Unsupported ComputationNode with OperationName='%S' found when loading legacy CNTK model", node->OperationName().c_str());
@ -500,16 +528,16 @@ namespace CNTK
if (ComputationNetwork::IsNodePtr<ComputationNode<float>>(rootNode))
{
rootVariables.push_back(resolver.GetVariable<float>(rootNode).Owner());
auto var = resolver.GetVariable<float>(rootNode);
rootVariables.push_back(var.IsOutput() ? (Variable)var.Owner() : var);
}
else if (ComputationNetwork::IsNodePtr<ComputationNode<double>>(rootNode))
{
rootVariables.push_back(resolver.GetVariable<double>(rootNode).Owner());
auto var = resolver.GetVariable<double>(rootNode);
rootVariables.push_back(var.IsOutput() ? (Variable)var.Owner() : var);
}
else
{
LogicError("LoadLegacyModel(): invalid computation node element type.");
}
}
auto rootComposite = Combine(rootVariables);

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

@ -131,7 +131,7 @@ namespace CNTK
return blockFunctionInputs;
}
virtual std::vector<Variable> InferOutputs() override
void InferOutputs(std::vector<Variable>& outputs) override
{
// We determine the outputs by replacing the arguments of the composite with new placeholders with updated
// shape etc. information matching the corresponding mapped input
@ -148,17 +148,14 @@ namespace CNTK
m_composite->ReplacePlaceholders(replacementMap);
std::vector<Variable> blockFunctionOutputs;
auto compositeOutputs = m_composite->RawOutputs();
for (auto compositeOutput : compositeOutputs)
{
auto output = OutputVariable(compositeOutput.Shape(), compositeOutput.GetDataType(), compositeOutput.DynamicAxes(), Name());
output.m_dataFields->m_blockFunctionVariableMapping = compositeOutput;
blockFunctionOutputs.push_back(output);
outputs.push_back(output);
}
return blockFunctionOutputs;
}
private:

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

@ -93,9 +93,10 @@ namespace CNTK
NOT_IMPLEMENTED;
}
virtual std::vector<Variable> InferOutputs() override
void InferOutputs(std::vector<Variable>& outputs) override
{
return m_rootFunction->InitOutputs();
auto& inferred = m_rootFunction->InitOutputs();
outputs.assign(inferred.begin(), inferred.end());
}
virtual void Backward(const BackPropStatePtr& state,
@ -146,29 +147,29 @@ namespace CNTK
}
template <typename FunctionType>
static void PreorderTraverseVariables(const FunctionPtr& rootFunction, const FunctionType& functor)
static void PreorderTraverseVariables(const FunctionPtr& rootFunction, const FunctionType& functor, bool pythonOperandOrder = false)
{
std::unordered_set<FunctionPtr> visitedFunctions;
PreorderTraverseVariables(rootFunction, visitedFunctions, functor);
PreorderTraverseVariables(rootFunction, visitedFunctions, functor, pythonOperandOrder);
}
// Recursively traverses the Function graph underlying the 'rootFunction' invoking the provided functor for all visited nodes in the graph.
template <typename FunctionType>
static void PreorderTraverseVariables(const FunctionPtr& rootFunction, std::unordered_set<FunctionPtr>& visitedFunctions, const FunctionType& functor)
static void PreorderTraverseVariables(const FunctionPtr& rootFunction, std::unordered_set<FunctionPtr>& visitedFunctions, const FunctionType& functor, bool pythonOperandOrder = false)
{
visitedFunctions.insert(rootFunction);
auto rootFunctionOutputs = rootFunction->InitOutputs();
for (const auto& rootOutput : rootFunctionOutputs)
functor(rootOutput);
auto rootFunctionInputs = rootFunction->Inputs();
auto rootFunctionInputs = rootFunction->Inputs(pythonOperandOrder);
for (const auto& rootInput : rootFunctionInputs)
{
functor(rootInput);
if (rootInput.IsOutput() && visitedFunctions.find(rootInput.Owner()) == visitedFunctions.end())
{
const auto& function = rootInput.Owner();
PreorderTraverseVariables(function, visitedFunctions, functor);
PreorderTraverseVariables(function, visitedFunctions, functor, pythonOperandOrder);
}
}
}
@ -201,11 +202,11 @@ namespace CNTK
m_allPrimitiveFunctions(std::move(allPrimitiveFunctions)), m_networkMatricesAllocated(false)
{}
std::vector<Variable> DetermineInputs() const
std::vector<Variable> DetermineInputs(bool pythonOperandOrder = false) const
{
const auto& root = RootFunction();
std::unordered_set<FunctionPtr> visitedFunctions;
return DetermineInputs(root, visitedFunctions);
return DetermineInputs(root, visitedFunctions, pythonOperandOrder);
}
// Recursively traverses the Function graph and populates the provided set of functions.
@ -216,7 +217,7 @@ namespace CNTK
}
// Recursively traverses the Function graph underlying the 'rootFunction' to determine all the leaves (aka inputs) of the graph
static std::vector<Variable> DetermineInputs(const FunctionPtr& rootFunction, std::unordered_set<FunctionPtr>& visitedFunctions)
static std::vector<Variable> DetermineInputs(const FunctionPtr& rootFunction, std::unordered_set<FunctionPtr>& visitedFunctions, bool pythonOperandOrder = false)
{
vector<FunctionPtr> functions;
std::vector<Variable> inputs;
@ -227,7 +228,7 @@ namespace CNTK
inputs.push_back(var);
uniqueInputs.insert(var);
}
});
}, pythonOperandOrder);
return inputs;
}

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

@ -16,7 +16,9 @@ namespace CNTK
std::vector<Variable>& Function::InitOutputs()
{
std::call_once(m_outputsInitFlag, [this]() {
auto outputs = InferOutputs();
std::vector<Variable> outputs;
outputs.reserve(Function::MaxNumOutputs);
InferOutputs(outputs);
std::unordered_set<Variable> uniqueOutputs;
for (auto outputVar : outputs)
{
@ -51,14 +53,26 @@ namespace CNTK
return const_cast<Function*>(this)->InitOutputs();
}
std::shared_ptr<std::vector<Variable>> Function::InputsImpl() const
std::shared_ptr<std::vector<Variable>> Function::InputsImpl(bool pythonOperandOrder) const
{
const CompositeFunction* compositeFunction = dynamic_cast<const CompositeFunction*>(this);
std::vector<Variable> inputs;
const CompositeFunction* compositeFunction = dynamic_cast<const CompositeFunction*>(this);
if (compositeFunction == nullptr)
inputs = m_inputs;
{
// For the Times and TransposeTimes primitive functions, if we want the python operand order
// then we need to reorder the operands as stored in m_inputs
const PrimitiveFunction* primitiveFunction = dynamic_cast<const PrimitiveFunction*>(this);
if (pythonOperandOrder && primitiveFunction && ((primitiveFunction->OpType() == PrimitiveOpType::Times) || (primitiveFunction->OpType() == PrimitiveOpType::TransposeTimes)))
{
assert(m_inputs.size() == 2);
inputs = { m_inputs[1], m_inputs[0] };
}
else
inputs = m_inputs;
}
else
inputs = compositeFunction->DetermineInputs();
inputs = compositeFunction->DetermineInputs(pythonOperandOrder);
return std::shared_ptr<std::vector<Variable>>(new std::vector<Variable>(std::move(inputs)), [](std::vector<Variable>* ptr) { delete ptr; });
}
@ -289,7 +303,7 @@ namespace CNTK
return updated;
}
void Function::ValidateOrUpdateOutputs(std::unordered_map<const Function*, size_t>& visitedFunctions, bool& recurrentNodeOutputModified)
void Function::ValidateOrUpdateOutputs(std::unordered_map<const Function*, size_t>& visitedFunctions, bool& recurrentNodeOutputModified, std::vector<Variable>& outputsUsingNewInputs)
{
assert(visitedFunctions.find(this) == visitedFunctions.end());
visitedFunctions[this] = 1;
@ -301,13 +315,17 @@ namespace CNTK
{
auto owner = input.Owner().get();
if (visitedFunctions.find(owner) == visitedFunctions.end())
owner->ValidateOrUpdateOutputs(visitedFunctions, recurrentNodeOutputModified);
{
outputsUsingNewInputs.clear();
owner->ValidateOrUpdateOutputs(visitedFunctions, recurrentNodeOutputModified, outputsUsingNewInputs);
}
else
visitedFunctions[owner]++;
}
}
auto outputsUsingNewInputs = this->InferOutputs();
outputsUsingNewInputs.clear();
this->InferOutputs(outputsUsingNewInputs);
auto currentOutputs = RawOutputs();
for (size_t i = 0; i < currentOutputs.size(); ++i)
{
@ -468,11 +486,13 @@ namespace CNTK
const size_t maxNumValidationPassesAllowed = 128;
bool recurrentNodeOutputModified = false;
size_t numValidationPasses = 0;
std::vector<Variable> outputVarBuffer;
outputVarBuffer.reserve(Function::MaxNumOutputs);
do
{
recurrentNodeOutputModified = false;
functionVisitCounts.clear();
RootFunction()->ValidateOrUpdateOutputs(functionVisitCounts, recurrentNodeOutputModified);
RootFunction()->ValidateOrUpdateOutputs(functionVisitCounts, recurrentNodeOutputModified, outputVarBuffer);
numValidationPasses++;
} while (recurrentNodeOutputModified && (numValidationPasses < maxNumValidationPassesAllowed));
@ -1120,12 +1140,11 @@ namespace CNTK
FunctionPtr PerDimMeanVarianceNormalize(const Variable& operand, const NDArrayViewPtr& mean, const NDArrayViewPtr& invStdDev, const std::wstring& name)
{
// TODO: Should this too be encapsulated as a block?
auto operandPlaceholder = PlaceholderVariable(L"operand");
Constant meanVar(mean);
Constant invStdDevVar(invStdDev);
return ElementTimes(Minus(operand, meanVar), invStdDevVar, name);
return AsBlock(std::move(ElementTimes(Minus(operandPlaceholder, meanVar), invStdDevVar)), { { operandPlaceholder, operand } }, L"PerDimMeanVarianceNormalize", name);
}
FunctionPtr Convolution(const Variable& convolutionMap,

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

@ -216,10 +216,13 @@ namespace CNTK
return outputDynamicAxes;
}
/*virtual*/ std::vector<Variable> PrimitiveFunction::InferOutputs() /*override*/
void PrimitiveFunction::InferOutputs(std::vector<Variable>& outputs)
{
if (m_op == PrimitiveOpType::Combine)
return m_inputs;
{
outputs.assign(m_inputs.begin(), m_inputs.end());
return;
}
DataType outputDataType = GetOutputDataType(m_op, m_inputs, true);
std::vector<Axis> outputDynamicAxes = GetOutputDynamicAxes(m_op, m_inputs, m_attributes);
@ -682,7 +685,7 @@ namespace CNTK
}
}
return{ OutputVariable(outputShape, outputDataType, outputDynamicAxes, Name().empty() ? L"" : Name()) };
outputs.push_back({ OutputVariable(outputShape, outputDataType, outputDynamicAxes, Name().empty() ? L"" : Name()) });
}
static const std::wstring s_primitiveFunctionTypeValue = L"PrimitiveFunction";

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

@ -700,7 +700,7 @@ namespace CNTK
static DataType GetOutputDataType(PrimitiveOpType op, std::vector<Variable>& inputs, bool inferDimensions);
static std::vector<Axis> GetOutputDynamicAxes(PrimitiveOpType op, std::vector<Variable>& inputs, Dictionary& functionConfig);
virtual std::vector<Variable> InferOutputs() override;
void InferOutputs(std::vector<Variable>& outputs) override;
private:
PrimitiveOpType m_op;

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

@ -44,6 +44,20 @@ DeleteModelsAfterTest=0
cntkrun 01_OneHidden.cntk "stderr=- command=trainNetwork trainNetwork=[SGD=[maxEpochs=1]]" || exit $?
cp $OutputDir/Models/01_OneHidden $TestDataDir || exit $?
# Train model that is used by LoadLegacyModel tests.
# Setup predefined variables $DataDir, $ConfigDir, and $OutputDir that are required by cntkrun
ConfigDir=$TEST_ROOT_DIR/../../Examples/Speech/AN4/Config
OutputDir=$ConfigDir/../Output
DataDir=$ConfigDir/../Data
[ -d $OutputDir ] || mkdir $OutputDir || exit $?
[ -d $OutputDir/Models ] && rm -rf $OutputDir/Models
DeleteModelsAfterTest=0
[ -f $ConfigDir/FeedForward.cntk ] || exit 1
cntkrun FeedForward.cntk "stderr=- command=speechTrain parallelTrain=false speechTrain=[SGD=[maxEpochs=1]]" || exit $?
cp $OutputDir/Models/cntkSpeechFF.dnn $TestDataDir || exit $?
# Set CUDA_VISIBLE_DEVICES to exclude all gpu if running on cpu device
if [ "$TEST_DEVICE" == "cpu" ]; then
export CUDA_VISIBLE_DEVICES=-1

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

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project ToolsVersion="14.0" DefaultTargets="Build" InitialTargets="CheckDependencies" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@ -60,21 +60,16 @@
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="CNTKLibraryManaged-2.0, Version=1.0.0.0, Culture=neutral, processorArchitecture=AMD64" />
<Reference Include="System" />
<Reference Include="System.Drawing" />
</ItemGroup>
<ItemGroup Condition="Exists('$(SWIG_PATH)\swig.exe')">
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\bindings\csharp\CNTKLibraryManagedDll\CNTKLibraryManagedDll.csproj">
<Project>{50ef9ee6-5018-453e-a063-f77044ef1a97}</Project>
<Name>CNTKLibraryManagedDll</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\..\Examples\Evaluation\CNTKLibraryCSEvalCPUOnlyExamples\CntkBitmapExtensions.cs">
<Link>CntkBitmapExtensions.cs</Link>
@ -84,7 +79,11 @@
</Compile>
<Compile Include="Program.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" Condition="Exists('$(SWIG_PATH)\swig.exe')" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="Build" Condition="Exists('$(SWIG_PATH)\swig.exe')" DependsOnTargets="$(BuildDependsOn)" />
<Target Name="CheckDependencies">
<Warning Condition="!Exists('$(SWIG_PATH)\swig.exe')" Text="The project requires SWIG to be installed. Please see https://github.com/Microsoft/CNTK/wiki/Setup-CNTK-on-Windows#optional-cntk-cnet-library-for-evaluation for installation instructions." />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">

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

@ -640,3 +640,46 @@ inline void CompareFunctions(const FunctionPtr& first, const FunctionPtr& second
}
}
}
inline MinibatchSourcePtr CreateHTKMinibatchSource(size_t featureDim, size_t numOutputClasses, const Dictionary& readModeConfig, size_t epochSize, bool randomize = true)
{
auto featuresFilePath = L"glob_0000.scp";
auto labelsFilePath = L"glob_0000.mlf";
auto labelMappingFile = L"state.list";
Dictionary featuresStreamConfig;
featuresStreamConfig[L"dim"] = featureDim;
featuresStreamConfig[L"scpFile"] = featuresFilePath;
CNTK::Dictionary featInputStreamsConfig;
featInputStreamsConfig[L"features"] = featuresStreamConfig;
CNTK::Dictionary featDeserializerConfiguration;
featDeserializerConfiguration[L"type"] = L"HTKFeatureDeserializer";
featDeserializerConfiguration[L"input"] = featInputStreamsConfig;
Dictionary labelsStreamConfig;
labelsStreamConfig[L"dim"] = numOutputClasses;
labelsStreamConfig[L"mlfFile"] = labelsFilePath;
labelsStreamConfig[L"labelMappingFile"] = labelMappingFile;
labelsStreamConfig[L"scpFile"] = featuresFilePath;
CNTK::Dictionary labelsInputStreamsConfig;
labelsInputStreamsConfig[L"labels"] = labelsStreamConfig;
CNTK::Dictionary labelsDeserializerConfiguration;
labelsDeserializerConfiguration[L"type"] = L"HTKMLFDeserializer";
labelsDeserializerConfiguration[L"input"] = labelsInputStreamsConfig;
Dictionary minibatchSourceConfiguration;
if (randomize)
minibatchSourceConfiguration[L"randomize"] = true;
minibatchSourceConfiguration[L"epochSize"] = epochSize;
minibatchSourceConfiguration[L"deserializers"] = std::vector<DictionaryValue>({ featDeserializerConfiguration, labelsDeserializerConfiguration });
minibatchSourceConfiguration.Add(readModeConfig);
return CreateCompositeMinibatchSource(minibatchSourceConfiguration);
}

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

@ -0,0 +1,73 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
//
// EvalMultithreads.cpp : Sample application shows how to evaluate a model in multiple threading environment.
//
#include <functional>
#include <thread>
#include <iostream>
#include "CNTKLibrary.h"
#include "Common.h"
using namespace CNTK;
void TestLoadLegacyModelWithPrecompute(const DeviceDescriptor& device)
{
const size_t baseFeaturesDim = 363;
const size_t numOutputClasses = 132;
auto modelFuncPtr = CNTK::Function::LoadModel(L"cntkSpeechFF.dnn", device);
auto FindVariableByName = [](const std::vector<Variable>& variables, const std::wstring& name) {
for (size_t i = 0; i < variables.size(); ++i)
if (variables[i].Name() == name)
return variables[i];
throw std::runtime_error("No output foudn with teh given name");
};
auto arguments = modelFuncPtr->Arguments();
auto features = FindVariableByName(arguments, L"features");
auto labels = FindVariableByName(arguments, L"labels");
auto outputs = modelFuncPtr->Outputs();
FunctionPtr prediction = FindVariableByName(outputs, L"PosteriorProb");
FunctionPtr loss = FindVariableByName(outputs, L"CrossEntropyWithSoftmax");
FunctionPtr eval = FindVariableByName(outputs, L"EvalClassificationError");
Dictionary frameModeConfig;
frameModeConfig[L"frameMode"] = true;
auto minibatchSource = CreateHTKMinibatchSource(baseFeaturesDim, numOutputClasses, frameModeConfig, MinibatchSource::InfinitelyRepeat, true);
const size_t minbatchSize = 256;
size_t numMinibatches = 10;
auto featureStreamInfo = minibatchSource->StreamInfo(L"features");
auto labelStreamInfo = minibatchSource->StreamInfo(L"labels");
LearningRatePerSampleSchedule learningRatePerSample = 0.000781;
MomentumAsTimeConstantSchedule momentumTimeConstant = 6074;
auto learner = MomentumSGDLearner(prediction->Parameters(), learningRatePerSample, momentumTimeConstant, /*unitGainMomentum = */true);
auto trainer = CreateTrainer(prediction, loss, eval, { learner });
for (size_t i = 0; i < numMinibatches; i++)
{
auto minibatchData = minibatchSource->GetNextMinibatch(minbatchSize, device);
if (minibatchData.empty())
break;
trainer->TrainMinibatch({ { features, minibatchData[featureStreamInfo] },{ labels, minibatchData[labelStreamInfo] } }, device);
PrintTrainingProgress(trainer, i, 1);
}
}
void LoadLegacyModelTests()
{
fprintf(stderr, "\nLoadLegacyModelTests..\n");
TestLoadLegacyModelWithPrecompute(DeviceDescriptor::CPUDevice());
if (IsGPUAvailable())
TestLoadLegacyModelWithPrecompute(DeviceDescriptor::GPUDevice(0));
}

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

@ -27,6 +27,7 @@ void DeviceSelectionTests();
void MultiThreadsEvaluation(bool);
void MinibatchSourceTests();
void UserDefinedFunctionTests();
void LoadLegacyModelTests();
int main()
{
@ -60,10 +61,11 @@ int main()
FeedForwardTests();
RecurrentFunctionTests();
UserDefinedFunctionTests();
SerializationTests();
LoadLegacyModelTests();
LearnerTests();
TrainerTests();

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

@ -41,8 +41,8 @@ void TestTensorPlus(size_t numAxesLeftOperand, size_t numAxesRightOperand, const
Variable leftInputVar, rightInputVar;
if (useConstantInputsOnly)
{
leftInputValue = leftInputValue->DeepClone(device, true);
rightInputValue = rightInputValue->DeepClone(device, true);
leftInputValue = leftInputValue->DeepClone(device, false);
rightInputValue = rightInputValue->DeepClone(device, false);
leftInputVar = Parameter(leftInputValue, L"leftInput");
rightInputVar = Parameter(rightInputValue, L"rightInput");

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

@ -6,47 +6,6 @@ using namespace CNTK;
using namespace std::placeholders;
MinibatchSourcePtr CreateMinibatchSource(size_t featureDim, size_t numOutputClasses, const Dictionary& readModeConfig, size_t epochSize, bool randomize = true)
{
auto featuresFilePath = L"glob_0000.scp";
auto labelsFilePath = L"glob_0000.mlf";
auto labelMappingFile = L"state.list";
Dictionary featuresStreamConfig;
featuresStreamConfig[L"dim"] = featureDim;
featuresStreamConfig[L"scpFile"] = featuresFilePath;
CNTK::Dictionary featInputStreamsConfig;
featInputStreamsConfig[L"features"] = featuresStreamConfig;
CNTK::Dictionary featDeserializerConfiguration;
featDeserializerConfiguration[L"type"] = L"HTKFeatureDeserializer";
featDeserializerConfiguration[L"input"] = featInputStreamsConfig;
Dictionary labelsStreamConfig;
labelsStreamConfig[L"dim"] = numOutputClasses;
labelsStreamConfig[L"mlfFile"] = labelsFilePath;
labelsStreamConfig[L"labelMappingFile"] = labelMappingFile;
labelsStreamConfig[L"scpFile"] = featuresFilePath;
CNTK::Dictionary labelsInputStreamsConfig;
labelsInputStreamsConfig[L"labels"] = labelsStreamConfig;
CNTK::Dictionary labelsDeserializerConfiguration;
labelsDeserializerConfiguration[L"type"] = L"HTKMLFDeserializer";
labelsDeserializerConfiguration[L"input"] = labelsInputStreamsConfig;
Dictionary minibatchSourceConfiguration;
if (randomize)
minibatchSourceConfiguration[L"randomize"] = true;
minibatchSourceConfiguration[L"epochSize"] = epochSize;
minibatchSourceConfiguration[L"deserializers"] = std::vector<DictionaryValue>({ featDeserializerConfiguration, labelsDeserializerConfiguration });
minibatchSourceConfiguration.Add(readModeConfig);
return CreateCompositeMinibatchSource(minibatchSourceConfiguration);
}
static FunctionPtr LSTMAcousticSequenceClassiferNet(const Variable& input, size_t numOutputClasses, size_t LSTMDim, size_t cellDim, size_t numLSTMs, const DeviceDescriptor& device, const std::wstring& outputName)
{
auto pastValueRecurrenceHook = [](const Variable& x) { return PastValue(x); };
@ -71,7 +30,7 @@ void TrainTruncatedLSTMAcousticModelClassifer(const DeviceDescriptor& device, bo
const size_t numSamplesForFeatureStatistics = MinibatchSource::FullDataSweep;
Dictionary frameModeConfig;
frameModeConfig[L"frameMode"] = true;
auto minibatchSource = CreateMinibatchSource(baseFeaturesDim, numOutputClasses, frameModeConfig, numSamplesForFeatureStatistics, false);
auto minibatchSource = CreateHTKMinibatchSource(baseFeaturesDim, numOutputClasses, frameModeConfig, numSamplesForFeatureStatistics, false);
auto featureStreamInfo = minibatchSource->StreamInfo(features);
std::unordered_map<StreamInformation, std::pair<NDArrayViewPtr, NDArrayViewPtr>> featureMeansAndInvStdDevs = { { featureStreamInfo, { nullptr, nullptr } } };
ComputeInputPerDimMeansAndInvStdDevs(minibatchSource, featureMeansAndInvStdDevs);
@ -100,7 +59,7 @@ void TrainTruncatedLSTMAcousticModelClassifer(const DeviceDescriptor& device, bo
Dictionary truncatedModeConfig;
truncatedModeConfig[L"truncated"] = true;
truncatedModeConfig[L"truncationLength"] = truncationLength;
minibatchSource = CreateMinibatchSource(baseFeaturesDim, numOutputClasses, truncatedModeConfig, numTrainingSamples);
minibatchSource = CreateHTKMinibatchSource(baseFeaturesDim, numOutputClasses, truncatedModeConfig, numTrainingSamples);
const size_t numberParallelSequencesPerMB1 = 16;
const size_t numberParallelSequencesPerMB2 = 32;

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

@ -110,18 +110,15 @@ public:
size_t CurrentVersion() const override { NOT_IMPLEMENTED; }
private:
std::vector<Variable> InferOutputs() override
void InferOutputs(std::vector<Variable>& outputs) override
{
auto leftOperand = Inputs()[0];
auto rightOperand = Inputs()[1];
auto tempFunc = m_isTimes ? Times(leftOperand, rightOperand) : Plus(leftOperand, rightOperand);
auto tempFuncOutputs = tempFunc->Outputs();
std::vector<Variable> outputs;
for (auto tempFuncOutput : tempFuncOutputs)
outputs.push_back(OutputVariable(tempFuncOutput.Shape(), tempFuncOutput.GetDataType(), tempFuncOutput.DynamicAxes()));
return outputs;
}
UserDefinedTimesOrPlusFunction(const Variable& leftOperand, const Variable& rightOperand, bool isTimes, const std::wstring& name)

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

@ -120,6 +120,7 @@
<ClCompile Include="Common.cpp" />
<ClCompile Include="DeviceSelectionTests.cpp" />
<ClCompile Include="LearnerTests.cpp" />
<ClCompile Include="LoadLegacyModelTests.cpp" />
<ClCompile Include="MinibatchSourceTest.cpp" />
<ClCompile Include="Seq2Seq.cpp" />
<ClCompile Include="SerializationTests.cpp" />

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

@ -78,6 +78,9 @@
<ClCompile Include="..\..\..\Examples\Evaluation\CNTKLibraryCPPEvalExamples\EvalMultithreads.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="LoadLegacyModelTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Common.h">

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

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project ToolsVersion="14.0" DefaultTargets="Build" InitialTargets="CheckDependencies" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@ -63,7 +63,7 @@
<Reference Include="System" />
<Reference Include="System.Drawing" />
</ItemGroup>
<ItemGroup Condition="Exists('$(SWIG_PATH)\swig.exe')">
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
@ -98,10 +98,11 @@
<Compile Include="SwigProxyClasses\VariableKind.cs" />
<Compile Include="SwigProxyClasses\VariableVector.cs" />
</ItemGroup>
<Target Name="Build" Condition="!Exists('$(SWIG_PATH)\swig.exe')">
<Warning Condition="!Exists('$(SWIG_PATH)\swig.exe')" Text="The project requires SWIG to be installed." />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="Build" Condition="Exists('$(SWIG_PATH)\swig.exe')" DependsOnTargets="$(BuildDependsOn)" />
<Target Name="CheckDependencies">
<Warning Condition="!Exists('$(SWIG_PATH)\swig.exe')" Text="The project requires SWIG to be installed. Please see https://github.com/Microsoft/CNTK/wiki/Setup-CNTK-on-Windows#optional-cntk-cnet-library-for-evaluation for installation instructions." />
</Target>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" Condition="Exists('$(SWIG_PATH)\swig.exe')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">

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

@ -101,7 +101,7 @@
</ItemDefinitionGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemGroup Condition="$(HasSwig)">
<ItemGroup>
<CustomBuild Include="cntk_cs.i">
<FileType>Document</FileType>
<Command>$(SWIG_PATH)\swig.exe -c++ -csharp -DMSC_VER -I$(SolutionDir)Source\CNTKv2LibraryDll\API -I$(SolutionDir)bindings\common -namespace CNTK -outdir $(SolutionDir)bindings\csharp\CNTKLibraryManagedDll\SwigProxyClasses -dllimport CNTKLibraryCSBinding cntk_cs.i</Command>
@ -109,10 +109,10 @@
<AdditionalInputs>$(SolutionDir)Source\CNTKv2LibraryDll\API\CNTKLibrary.h;$(SolutionDir)bindings\common\CNTKValueExtend.i;std_unordered_map.i</AdditionalInputs>
</CustomBuild>
</ItemGroup>
<ItemGroup Condition="$(HasSwig)">
<ItemGroup>
<ClCompile Include="cntk_cs_wrap.cxx" />
</ItemGroup>
<ItemGroup Condition="$(HasSwig)">
<ItemGroup>
<ClInclude Include="..\..\..\Source\CNTKv2LibraryDll\API\CNTKLibrary.h" />
<ClInclude Include="..\..\..\Source\CNTKv2LibraryDll\API\CNTKLibraryInternals.h" />
<ClInclude Include="cntk_cs_wrap.h" />
@ -120,9 +120,10 @@
<ItemGroup>
<None Include="..\..\common\CNTKValueExtend.i" />
</ItemGroup>
<Target Name="CheckDependencies" Condition="!$(HasSwig)">
<Warning Condition="!$(HasSwig)" Text="The project requires SWIG to be installed." />
<Target Name="CheckDependencies">
<Warning Condition="!$(HasSwig)" Text="The project requires SWIG to be installed. Please see https://github.com/Microsoft/CNTK/wiki/Setup-CNTK-on-Windows#optional-cntk-cnet-library-for-evaluation for installation instructions." />
</Target>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Target Name="Build" Condition="$(HasSwig)" Outputs="$(TargetPath)" DependsOnTargets="$(BuildDependsOn)" />
<ImportGroup Label="ExtensionTargets" />
</Project>

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

@ -17,6 +17,7 @@
%rename(_forward) CNTK::Function::Forward;
%rename(_backward) CNTK::Function::Backward;
%rename(_infer_outputs) CNTK::Function::InferOutputs;
%rename(sgd_learner) CNTK::SGDLearner;
%rename(momentum_sgd_learner) CNTK::MomentumSGDLearner;
%rename(gpu_device) CNTK::DeviceDescriptor::GPUDevice;
@ -581,10 +582,11 @@ public:
//
%exception {
try { $action }
catch (Swig::DirectorException &e) { SWIG_exception(SWIG_RuntimeError,e.what()); }
catch (std::runtime_error &e) { SWIG_exception(SWIG_RuntimeError,e.what()); }
catch (std::invalid_argument &e) { SWIG_exception(SWIG_ValueError,e.what()); }
catch (std::logic_error &e) { SWIG_exception(SWIG_RuntimeError,e.what()); }
catch (const Swig::DirectorException &e) { SWIG_exception(SWIG_RuntimeError, e.what()); }
catch (const std::runtime_error &e) { SWIG_exception(SWIG_RuntimeError, e.what()); }
catch (const std::invalid_argument &e) { SWIG_exception(SWIG_ValueError, e.what()); }
catch (const std::logic_error &e) { SWIG_exception(SWIG_RuntimeError, e.what()); }
catch (const std::exception &e) { SWIG_exception(SWIG_UnknownError, e.what()); }
catch (...) { SWIG_exception(SWIG_UnknownError,"Runtime exception"); }
}
@ -739,6 +741,43 @@ public:
%enddef
// Implementing typemapping for InferOutputs virtual function that takes vector of variables by reference
// And can be implemented in Python.
%typemap(directorin) std::vector<CNTK::Variable>& outputs
{
$input = PyList_New(0);
}
%typemap(directorargout) std::vector<CNTK::Variable>& outputs
{
if (!PyList_Check($input))
RuntimeError("List expected");
auto iterator = std::shared_ptr<PyObject>(PyObject_GetIter($input), [](PyObject* p) { Py_DECREF(p); });
if (!iterator)
RuntimeError("Cannot get iterator to the list");
PyObject *item = nullptr;
while ((item = PyIter_Next(iterator.get())))
{
void *raw_var = nullptr;
int res = SWIG_ConvertPtr(item, &raw_var, swig::type_info<CNTK::Variable>(), 0);
if (!SWIG_IsOK(res))
RuntimeError("Cannot convert list element to CNTK::Variable");
if (!raw_var)
RuntimeError("Invalid null reference when converting a list element to CNTK::Variable");
auto var = reinterpret_cast<CNTK::Variable*>(raw_var);
$1.push_back(*var);
Py_DECREF(item);
}
if (PyErr_Occurred())
RuntimeError("Cannot convert list element to CNTK::Variable");
}
// For the output dict (the non-const unordered_map) we need to get the
// modified values and put them back into the dictionary. This is used, when
// e.g. the user puts a variable into the dictionary, hoping that it will

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

@ -391,11 +391,7 @@ class Function(cntk_py.Function):
'''
List of all input variables of this function.
'''
input_nodes = super(Function, self).inputs()
if self.is_primitive and self.root_function.op_name in ['Times', 'TransposeTimes']:
input_nodes = tuple(reversed(input_nodes))
return input_nodes
return super(Function, self).inputs(True)
@property
def name(self):
@ -753,6 +749,9 @@ class UserFunction(Function):
variables[k] = sanitize_batch(k, v, None, state.device())
def _infer_outputs(self, outputs):
outputs.extend(self.infer_outputs())
def infer_outputs(self):
raise NotImplementedError('infer_outputs has to be overridden')

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

@ -229,3 +229,26 @@ def test_as_composite():
assert(composite.root_function.name == func_name)
composite = as_composite(t_plus_b)
assert(composite.root_function.name == func_name)
def test_input_order():
input_dim = 1
proj_dim = 2
x = input_variable((input_dim,), name='x')
b = parameter((proj_dim), name='b')
w = parameter((input_dim, proj_dim), name='w')
func_name = 't_plus_b'
t = times(x, w)
t_plus_b = plus(t, b, name=func_name)
def compare_var_names(vars, names):
num_vars = len(vars)
for i in range(num_vars):
if (vars[i].name != names[i]):
return False
return True
assert compare_var_names(t.root_function.inputs, ['x', 'w'])
assert compare_var_names(t.inputs, ['x', 'w'])
assert compare_var_names(t_plus_b.inputs, ['x', 'w', 'b'])