Merge remote-tracking branch 'origin/master' into nikosk/keras_support2
This commit is contained in:
Коммит
cb4ef4243d
3
CNTK.sln
3
CNTK.sln
|
@ -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
|
||||
|
|
1
Makefile
1
Makefile
|
@ -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'])
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче