本文整理汇总了C++中NDShape::AppendShape方法的典型用法代码示例。如果您正苦于以下问题:C++ NDShape::AppendShape方法的具体用法?C++ NDShape::AppendShape怎么用?C++ NDShape::AppendShape使用的例子?那么, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类NDShape
的用法示例。
在下文中一共展示了NDShape::AppendShape方法的9个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: TestTimesNodeShapeInference
void TestTimesNodeShapeInference()
{
auto timesNodeShapeInferenceTest = [](size_t inputRank, size_t outputRank, int inputRankToMap) {
auto device = DeviceDescriptor::CPUDevice();
size_t maxDimSize = 15;
NDShape outputShape(outputRank);
for (size_t i = 0; i < outputRank; ++i)
outputShape[i] = (rand() % maxDimSize) + 1;
NDShape paramShape = outputShape;
if (inputRankToMap > 0)
paramShape = paramShape.AppendShape({ NDShape::InferredDimension });
else
paramShape = paramShape.AppendShape(NDShape(inputRank));
auto timesParam = Parameter(paramShape, DataType::Float, ConstantInitializer(), device);
auto placeholderInput = PlaceholderVariable();
auto timesFunction = Times(timesParam, placeholderInput, outputRank, inputRankToMap);
NDShape inputShape(inputRank);
for (size_t i = 0; i < inputRank; ++i)
inputShape[i] = (rand() % maxDimSize) + 1;
auto actualInput = InputVariable(inputShape, DataType::Float);
timesFunction->ReplacePlaceholders({ { placeholderInput, actualInput } });
// Verify that the inferred shape of the param, input and output matches expectation
auto expectedInputShape = inputShape;
auto expectedParamShape = outputShape;
if (inputRankToMap > 0)
expectedParamShape = expectedParamShape.AppendShape(inputShape.SubShape(0, inputRank - inputRankToMap));
else
expectedParamShape = expectedParamShape.AppendShape(inputShape);
auto expectedOutputShape = outputShape;
if (inputRankToMap > 0)
expectedOutputShape = expectedOutputShape.AppendShape(inputShape.SubShape(inputRank - inputRankToMap));
auto actualInputShape = timesFunction->Arguments()[0].Shape();
auto actualParamShape = timesFunction->Parameters()[0].Shape();
auto actualOutputShape = timesFunction->Output().Shape();
if (actualInputShape != expectedInputShape)
ReportFailure("Times nodes actual input shape (%S) does not match expectation (%S)", actualInputShape.AsString().c_str(), expectedInputShape.AsString().c_str());
if (actualParamShape != expectedParamShape)
ReportFailure("Times nodes actual parameter shape (%S) does not match expectation (%S)", actualParamShape.AsString().c_str(), expectedParamShape.AsString().c_str());
if (actualOutputShape != expectedOutputShape)
ReportFailure("Times nodes actual output shape (%S) does not match expectation (%S)", actualOutputShape.AsString().c_str(), expectedOutputShape.AsString().c_str());
};
timesNodeShapeInferenceTest(2, 2, -1);
timesNodeShapeInferenceTest(2, 1, 1);
timesNodeShapeInferenceTest(1, 2, 0);
timesNodeShapeInferenceTest(3, 2, 2);
}
示例2: MaskSection
void NDMask::MaskSection(const std::vector<size_t>& sectionOffset, const NDShape& sectionShape)
{
// TODO: Implement batching of masking operation for masks residing on GPUs to avoid making
// GPU invocations for each MaskSection call.
if (sectionOffset.size() > m_maskShape.NumAxes())
LogicError("NDMask::MaskSection: The sectionOffset cannot have dimensionality higher than the number of axes of 'this' mask");
if (sectionShape.NumAxes() > m_maskShape.NumAxes())
LogicError("NDMask::MaskSection: The section shape cannot have an axes count higher than the number of axes of 'this' mask");
std::vector<size_t> offset(m_maskShape.NumAxes(), 0);
for (size_t i = 0; i < sectionOffset.size(); ++i)
offset[i] = sectionOffset[i];
NDShape shape = sectionShape.AppendShape(NDShape(m_maskShape.NumAxes() - sectionShape.NumAxes(), NDShape::InferredDimension));
auto maskMatrix = GetMatrix();
size_t rowOffset = offset[0];
size_t colOffset = offset[1];
size_t sliceRowLength = (shape[0] != NDShape::InferredDimension) ? shape[0] : (maskMatrix->GetNumRows() - rowOffset);
size_t sliceColLength = (shape[1] != NDShape::InferredDimension) ? shape[1] : (maskMatrix->GetNumCols() - colOffset);
if ((rowOffset == 0) && (sliceRowLength == maskMatrix->GetNumRows()))
maskMatrix->ColumnSlice(colOffset, sliceColLength).SetValue(0);
else
{
// Since Matrix does not support strides in the row dimension, we will need to create separate slices for each column
for (size_t i = colOffset; i < (colOffset + sliceColLength); ++i)
{
auto column = maskMatrix->ColumnSlice(i, 1);
column.Reshape(1, maskMatrix->GetNumRows());
column.ColumnSlice(rowOffset, sliceRowLength).SetValue(0);
}
}
}
示例3: valueData
/*static*/ ValuePtr Value::Create(const NDShape& sampleShape, const std::vector<std::vector<ElementType>>& sequences, const DeviceDescriptor& device, bool readOnly/* = false*/)
{
size_t sampleSize = sampleShape.TotalSize();
NDMaskPtr deviceValueMask = CreateMask(sampleSize, sequences, device);
size_t maxSequenceLength = (deviceValueMask == nullptr) ? sequences[0].size() : deviceValueMask->Shape()[0];
size_t numSequences = sequences.size();
NDShape valueDataShape = sampleShape.AppendShape({ maxSequenceLength, numSequences });
NDArrayViewPtr valueData(new NDArrayView(AsDataType<ElementType>(), valueDataShape, DeviceDescriptor::CPUDevice()), [](ReferenceCount* ptr) { delete ptr; });
ElementType* dataBuffer = valueData->WritableDataBuffer<ElementType>();
for (size_t i = 0; i < numSequences; ++i)
std::copy(sequences[i].data(), sequences[i].data() + sequences[i].size(), dataBuffer + (maxSequenceLength * i * sampleSize));
NDArrayViewPtr deviceValueData;
if (device == DeviceDescriptor::CPUDevice())
{
if (readOnly)
deviceValueData = valueData->Alias(true);
else
deviceValueData = valueData;
}
else
{
deviceValueData = NDArrayViewPtr(new NDArrayView(AsDataType<ElementType>(), valueDataShape, device), [](ReferenceCount* ptr) { delete ptr; });
deviceValueData->CopyFrom(*valueData);
if (readOnly)
deviceValueData = deviceValueData->Alias(true);
}
return ValuePtr(new Value(deviceValueData, deviceValueMask), [](ReferenceCount* ptr) { delete ptr; });
}
示例4: deviceValueData
/*static*/ ValuePtr Value::Create(size_t vocabularySize, const std::vector<std::vector<size_t>>& oneHotSequences, const DeviceDescriptor& device, bool readOnly/* = false*/)
{
NDMaskPtr deviceValueMask = CreateMask(1, oneHotSequences, device);
size_t maxSequenceLength = (deviceValueMask == nullptr) ? oneHotSequences[0].size() : deviceValueMask->Shape()[0];
size_t numSequences = oneHotSequences.size();
NDShape sampleShape = { vocabularySize };
NDShape valueDataShape = sampleShape.AppendShape({ maxSequenceLength, numSequences });
size_t numCSCCols = valueDataShape.SubShape(1).TotalSize() + 1;
std::vector<SparseIndexType> colStarts(numCSCCols);
std::vector<ElementType> nonZeroValues;
std::vector<SparseIndexType> rowIndices;
for (size_t i = 0; i < numSequences; ++i)
{
size_t currentSequenceLength = oneHotSequences[i].size();
size_t j = 0;
for (; j < currentSequenceLength; ++j)
{
colStarts[(i * maxSequenceLength) + j] = (SparseIndexType)nonZeroValues.size();
nonZeroValues.push_back(1);
rowIndices.push_back((SparseIndexType)(oneHotSequences[i][j]));
}
for (; j < maxSequenceLength; ++j)
colStarts[(i * maxSequenceLength) + j] = (SparseIndexType)(nonZeroValues.size());
}
colStarts[numSequences * maxSequenceLength] = (SparseIndexType)(nonZeroValues.size());
NDArrayViewPtr deviceValueData(new NDArrayView(valueDataShape, colStarts.data(), rowIndices.data(), nonZeroValues.data(), nonZeroValues.size(), device, readOnly), [](ReferenceCount* ptr) { delete ptr; });
return ValuePtr(new Value(deviceValueData, deviceValueMask), [](ReferenceCount* ptr) { delete ptr; });
}
示例5: TestTranspose
void TestTranspose(size_t numAxes, int axis1, int axis2, const DeviceDescriptor& device)
{
srand(1);
size_t maxDimSize = 15;
NDShape inputShape(numAxes);
for (size_t i = 0; i < numAxes; ++i)
inputShape[i] = (rand() % maxDimSize) + 1;
auto inputVar = InputVariable(inputShape, DataType::Float, false, L"leftInput");
auto transposeFunc = TransposeAxes(inputVar, Axis(axis1), Axis(axis2));
std::vector<float> inputData(inputShape.TotalSize());
for (size_t i = 0; i < inputData.size(); ++i)
inputData[i] = ((float)rand()) / RAND_MAX;
auto inputValueShape = inputShape.AppendShape({ 1, 1 });
ValuePtr inputValue = MakeSharedObject<Value>(MakeSharedObject<NDArrayView>(inputValueShape, inputData, true));
NDShape outputShape = transposeFunc->Output().Shape();
NDShape outputValueShape = outputShape.AppendShape({ 1, 1 });
std::vector<float> outputData(outputValueShape.TotalSize());
ValuePtr outputValue = MakeSharedObject<Value>(MakeSharedObject<NDArrayView>(outputValueShape, outputData, false));
std::unordered_map<Variable, ValuePtr> outputs = { { transposeFunc->Output(), outputValue } };
transposeFunc->Forward({ { inputVar, inputValue } }, outputs, device);
std::vector<size_t> inputShapeStrides = GetStrides(inputShape);
std::vector<size_t> outputShapeStrides = GetStrides(outputShape);
// Verify forward prop results
std::vector<float> expectedOutputValues(outputShape.TotalSize());
for (size_t i = 0; i < expectedOutputValues.size(); ++i)
{
auto unflattenedShape = UnflattenedShape(i, outputShapeStrides);
std::swap(unflattenedShape[axis1], unflattenedShape[axis2]);
size_t flattenedIndex = FlattenedIndex(unflattenedShape, inputShapeStrides);
expectedOutputValues[i] = inputData[flattenedIndex];
}
FloatingPointVectorCompare(outputData, expectedOutputValues, "TestTimesAndPlus: Forward prop results do not match expected results");
}
示例6: CreateBatchWithVariableSequence
ValuePtr CreateBatchWithVariableSequence(const NDShape& sampleShape, size_t batchSize, const std::vector<size_t>& sequenceSize, const std::vector<ElementType>& batchData, const DeviceDescriptor& device, bool readOnly = false)
{
auto shapeSize = sampleShape.TotalSize();
if (batchData.size() % shapeSize != 0)
InvalidArgument("The number of elements (%zu) in the vector containing batch data must be a multiple of the size (%zu) of the sample shape '%S'.",
batchData.size(), shapeSize, sampleShape.AsString().c_str());
if (sequenceSize.size() != batchSize)
InvalidArgument("The number of sequences (%zu) in the vector containing sequence size must match batch size (%zu)", sequenceSize.size(), batchSize);
std::vector<NDArrayViewPtr> sequencesView(batchSize);
size_t curBatchDataIdx = 0;
for (size_t i = 0; i < batchSize; i++)
{
auto sequenceDataShape = sampleShape.AppendShape({sequenceSize[i]});
sequencesView[i] = MakeSharedObject<NDArrayView>(sequenceDataShape, batchData.data() + curBatchDataIdx, shapeSize * sequenceSize[i], DeviceDescriptor::CPUDevice());
curBatchDataIdx += shapeSize * sequenceSize[i];
}
return Value::Create(sampleShape, sequencesView, {}, device, readOnly, true);
}
示例7: TestReduceSum
void TestReduceSum(size_t sampleRank, const DeviceDescriptor& device)
{
size_t numSequences = 7;
size_t maxAllowedSequenceLength = 11;
size_t maxDimSize = 23;
NDShape inputShape(sampleRank);
for (size_t i = 0; i < sampleRank; ++i)
inputShape[i] = (rand() % maxDimSize) + 1;
auto sequenceLengths = GenerateSequenceLengths(numSequences, maxAllowedSequenceLength);
auto sequences = GenerateSequences<float>(sequenceLengths, inputShape);
ValuePtr sequencesValue = Value::Create(inputShape, sequences, device, true);
// Test ReduceSum along a static axis
{
auto testReduceSum = [&sequences, &sequenceLengths, inputShape, sequencesValue, device, sampleRank](int reductionAxis, bool useNegativeAxisIndex)
{
size_t maxActualSequenceLength = sequencesValue->Shape()[inputShape.Rank()];
size_t numSequences = sequencesValue->Shape()[inputShape.Rank() + 1];
auto inputVar = InputVariable(inputShape, DataType::Float, L"input");
FunctionPtr reduceSumFunc;
bool reduceAll = (reductionAxis < 0);
if (reduceAll)
reduceSumFunc = ReduceSum(inputVar);
else
reduceSumFunc = ReduceSum(inputVar, Axis(useNegativeAxisIndex ? (reductionAxis - (int)sampleRank) : reductionAxis));
NDShape outputShape = reduceSumFunc->Output().Shape();
NDShape outputDataShape = outputShape;
if (!reduceAll)
outputDataShape = outputDataShape.AppendShape({ maxActualSequenceLength, numSequences });
std::vector<float> outputData(outputDataShape.TotalSize());
ValuePtr outputValue = MakeSharedObject<Value>(MakeSharedObject<NDArrayView>(outputDataShape, outputData, false), reduceAll ? nullptr : sequencesValue->Mask()->DeepClone());
std::unordered_map<Variable, ValuePtr> outputs = { { reduceSumFunc->Output(), outputValue } };
reduceSumFunc->Forward({ { inputVar, sequencesValue } }, outputs, device);
std::vector<size_t> inputShapeStrides = GetStrides(inputShape);
std::vector<size_t> outputShapeStrides = GetStrides(outputShape);
std::vector<float> expectedPerFrameTotals(outputShape.TotalSize() * maxActualSequenceLength * numSequences, 0.0f);
float expectedTotal = 0.0f;
for (size_t i = 0; i < numSequences; ++i)
{
size_t currentSequenceLength = sequenceLengths[i];
for (size_t j = 0; j < currentSequenceLength; ++j)
{
for (size_t k = 0; k < inputShape.TotalSize(); ++k)
{
auto inputIdx = UnflattenedShape(k, inputShapeStrides);
auto outputIdx = inputIdx;
if (!reduceAll)
outputIdx[reductionAxis] = 0;
else
outputIdx = {};
auto flatOutputIdx = FlattenedIndex(outputIdx, outputShapeStrides);
float value = sequences[i][(j * inputShape.TotalSize()) + k];
expectedPerFrameTotals[(((i * maxActualSequenceLength) + j) * outputShape.TotalSize()) + flatOutputIdx] += value;
expectedTotal += value;
}
}
}
if (reduceAll)
FloatingPointVectorCompare(outputData, std::vector<float>({ expectedTotal }), "testReduceSum: Forward prop results do not match expected results");
else
FloatingPointVectorCompare(outputData, expectedPerFrameTotals, "testReduceSum: Forward prop results do not match expected results");
};
// Reduce over all axes
testReduceSum(-1, false);
int reductionAxis = 0;
testReduceSum(reductionAxis, true);
if (reductionAxis < (inputShape.Rank() - 1))
reductionAxis++;
testReduceSum(reductionAxis, false);
if (reductionAxis < (inputShape.Rank() - 1))
reductionAxis++;
testReduceSum(reductionAxis, true);
}
// Test ReduceSum along a dynamic axis
{
auto testReduceSum = [&sequences, &sequenceLengths, inputShape, sequencesValue, device](const Axis& axis)
{
if (!axis.IsDynamicAxis())
RuntimeError("Called the dynamic axis ReduceSum test with a static axis");
size_t maxActualSequenceLength = sequencesValue->Shape()[inputShape.Rank()];
size_t numSequences = sequencesValue->Shape()[inputShape.Rank() + 1];
//.........这里部分代码省略.........
示例8: TestSlice
void TestSlice(size_t sampleRank, const DeviceDescriptor& device)
{
size_t numSequences = 7;
size_t maxAllowedSequenceLength = 11;
size_t maxDimSize = 23;
size_t minDimSize = 5;
NDShape inputShape(sampleRank);
for (size_t i = 0; i < sampleRank; ++i)
inputShape[i] = (rand() % maxDimSize) + minDimSize;
auto sequenceLengths = GenerateSequenceLengths(numSequences, maxAllowedSequenceLength);
auto sequences = GenerateSequences<float>(sequenceLengths, inputShape);
ValuePtr sequencesValue = Value::Create(inputShape, sequences, device, true);
// Test slice along a static axis
{
auto testStaticAxisSlice = [&sequences, &sequenceLengths, inputShape, sequencesValue, device, sampleRank](int sliceAxis, int beginOffset, int endOffset, bool useNegativeAxisIndex)
{
size_t maxActualSequenceLength = sequencesValue->Shape()[inputShape.Rank()];
size_t numSequences = sequencesValue->Shape()[inputShape.Rank() + 1];
auto inputVar = InputVariable(inputShape, DataType::Float, L"input");
auto sliceFunc = Slice(inputVar, Axis(useNegativeAxisIndex ? (sliceAxis - (int)sampleRank) : sliceAxis), beginOffset, endOffset);
NDShape outputShape = sliceFunc->Output().Shape();
auto outputDataShape = outputShape.AppendShape({ maxActualSequenceLength, numSequences });
std::vector<float> outputData(outputDataShape.TotalSize());
ValuePtr outputValue = MakeSharedObject<Value>(MakeSharedObject<NDArrayView>(outputDataShape, outputData, false), sequencesValue->Mask()->DeepClone());
std::unordered_map<Variable, ValuePtr> outputs = { { sliceFunc->Output(), outputValue } };
sliceFunc->Forward({ { inputVar, sequencesValue } }, outputs, device);
std::vector<size_t> inputShapeStrides = GetStrides(inputShape);
std::vector<size_t> outputShapeStrides = GetStrides(outputShape);
size_t sliceStartOffset = (beginOffset >= 0) ? beginOffset : (inputShape[sliceAxis] + beginOffset);
std::vector<float> expectedOutputValues(outputShape.TotalSize() * maxActualSequenceLength * numSequences);
for (size_t i = 0; i < numSequences; ++i)
{
size_t currentSequenceLength = sequenceLengths[i];
for (size_t j = 0; j < currentSequenceLength; ++j)
{
for (size_t k = 0; k < outputShape.TotalSize(); ++k)
{
auto outputIdx = UnflattenedShape(k, outputShapeStrides);
auto inputIdx = outputIdx;
inputIdx[sliceAxis] += sliceStartOffset;
auto flatInputIdx = FlattenedIndex(inputIdx, inputShapeStrides);
expectedOutputValues[(((i * maxActualSequenceLength) + j) * outputShape.TotalSize()) + k] = sequences[i][(j * inputShape.TotalSize()) + flatInputIdx];
}
}
}
FloatingPointVectorCompare(outputData, expectedOutputValues, "testStaticAxisSlice: Forward prop results do not match expected results");
};
int sliceAxis = 0;
testStaticAxisSlice(sliceAxis, 3, 5, true);
if (sliceAxis < (inputShape.Rank() - 1))
sliceAxis++;
testStaticAxisSlice(sliceAxis, -1, 0, false);
if (sliceAxis < (inputShape.Rank() - 1))
sliceAxis++;
testStaticAxisSlice(sliceAxis, -3, -1, true);
}
// Test slice along a dynamic axis
{
auto testDynamicAxisSlice = [&sequences, &sequenceLengths, inputShape, sequencesValue, device](const Axis& axis, int beginOffset, int endOffset)
{
if (!axis.IsDynamicAxis())
RuntimeError("Called the dynamic axis slice test with a static axis");
size_t maxActualSequenceLength = sequencesValue->Shape()[inputShape.Rank()];
size_t numSequences = sequencesValue->Shape()[inputShape.Rank() + 1];
int endAndBeginOffsetDiff = endOffset - beginOffset;
size_t maxSliceLength = (endAndBeginOffsetDiff > 0) ? endAndBeginOffsetDiff : maxActualSequenceLength + endAndBeginOffsetDiff;
auto inputVar = InputVariable(inputShape, DataType::Float, L"input");
auto sliceFunc = Slice(inputVar, axis, beginOffset, endOffset);
sliceFunc = sliceFunc + sliceFunc;
size_t outputSequenceAxisLength = (axis == Axis::DefaultDynamicAxis()) ? maxSliceLength : maxActualSequenceLength;
size_t outputBatchAxisLength = (axis == Axis::DefaultBatchAxis()) ? maxSliceLength : numSequences;
NDShape outputShape = sliceFunc->Output().Shape().AppendShape({ outputSequenceAxisLength, outputBatchAxisLength });
std::vector<float> outputData(outputShape.TotalSize(), 0);
NDMaskPtr mask;
if (endAndBeginOffsetDiff < 0)
{
ValuePtr outputValue = MakeSharedObject<Value>(MakeSharedObject<NDArrayView>(outputShape, outputData, false));
mask = MakeSharedObject<NDMask>(std::initializer_list<size_t>({ outputSequenceAxisLength, outputBatchAxisLength }), device);
}
ValuePtr outputValue = MakeSharedObject<Value>(MakeSharedObject<NDArrayView>(outputShape, outputData, false), mask);
std::unordered_map<Variable, ValuePtr> outputs = { { sliceFunc->Output(), outputValue } };
//.........这里部分代码省略.........
示例9: TestTensorPlus
void TestTensorPlus(size_t numAxesLeftOperand, size_t numAxesRightOperand, const DeviceDescriptor& device, bool useConstantInputsOnly)
{
srand(1);
size_t maxDimSize = 15;
NDShape leftInputShape(numAxesLeftOperand);
for (size_t i = 0; i < numAxesLeftOperand; ++i)
leftInputShape[i] = (rand() % maxDimSize) + 1;
NDShape rightInputShape(numAxesRightOperand);
for (size_t i = 0; i < std::min(numAxesLeftOperand, numAxesRightOperand); ++i)
rightInputShape[i] = leftInputShape[i];
for (size_t i = std::min(numAxesLeftOperand, numAxesRightOperand); i < numAxesRightOperand; ++i)
rightInputShape[i] = (rand() % maxDimSize) + 1;
std::vector<ElementType> leftInputData(leftInputShape.TotalSize());
for (size_t i = 0; i < leftInputData.size(); ++i)
leftInputData[i] = ((ElementType)rand()) / RAND_MAX;
auto leftInputValueShape = leftInputShape.AppendShape({ 1, 1 });
auto leftInputValue = MakeSharedObject<NDArrayView>(leftInputValueShape, leftInputData, true);
std::vector<ElementType> rightInputData(rightInputShape.TotalSize());
for (size_t i = 0; i < rightInputData.size(); ++i)
rightInputData[i] = ((ElementType)rand()) / RAND_MAX;
auto rightInputValueShape = rightInputShape.AppendShape({ 1, 1 });
auto rightInputValue = MakeSharedObject<NDArrayView>(rightInputValueShape, rightInputData, true);
Variable leftInputVar, rightInputVar;
if (useConstantInputsOnly)
{
leftInputValue = leftInputValue->DeepClone(device, false);
rightInputValue = rightInputValue->DeepClone(device, false);
leftInputVar = Parameter(leftInputValue, L"leftInput");
rightInputVar = Parameter(rightInputValue, L"rightInput");
}
else
{
leftInputVar = InputVariable(leftInputShape, AsDataType<ElementType>(), true, L"leftInput");
rightInputVar = InputVariable(rightInputShape, AsDataType<ElementType>(), true, L"rightInput");
}
auto plusFunc = Plus(leftInputVar, rightInputVar);
NDShape outputShape = plusFunc->Output().Shape();
if (!useConstantInputsOnly)
outputShape = outputShape.AppendShape({ 1, 1 });
std::vector<ElementType> outputData(outputShape.TotalSize());
ValuePtr outputValue = MakeSharedObject<Value>(MakeSharedObject<NDArrayView>(outputShape, outputData, false));
std::unordered_map<Variable, ValuePtr> outputs = { { plusFunc->Output(), outputValue } };
BackPropStatePtr backPropState;
if (useConstantInputsOnly)
backPropState = plusFunc->Forward(std::unordered_map<Variable, ValuePtr>({}), outputs, device, { plusFunc->Output() });
else
backPropState = plusFunc->Forward({ { leftInputVar, MakeSharedObject<Value>(leftInputValue) }, { rightInputVar, MakeSharedObject<Value>(rightInputValue) } }, outputs, device, { plusFunc->Output() });
// Perform backprop
std::vector<ElementType> rootGradientsData(outputShape.TotalSize(), 1);
ValuePtr rootGradientValue = MakeSharedObject<Value>(MakeSharedObject<NDArrayView>(outputShape, rootGradientsData, true));
std::vector<ElementType> leftInputGradientsData(leftInputValueShape.TotalSize());
ValuePtr leftInputGradientValue = MakeSharedObject<Value>(MakeSharedObject<NDArrayView>(leftInputValueShape, leftInputGradientsData, false));
std::vector<ElementType> rightInputGradientsData(rightInputValueShape.TotalSize());
ValuePtr rightInputGradientValue = MakeSharedObject<Value>(MakeSharedObject<NDArrayView>(rightInputValueShape, rightInputGradientsData, false));
std::unordered_map<Variable, ValuePtr> gradients = { { leftInputVar, leftInputGradientValue }, { rightInputVar, rightInputGradientValue } };
plusFunc->Backward(backPropState, { { plusFunc->Output(), rootGradientValue } }, gradients);
// Verify forward prop results
auto& smallerInput = (numAxesLeftOperand < numAxesRightOperand) ? leftInputData : rightInputData;
auto& largerInput = (numAxesLeftOperand < numAxesRightOperand) ? rightInputData : leftInputData;
std::vector<ElementType> expectedOutputValues = largerInput;
for (size_t i = 0; i < (expectedOutputValues.size() / smallerInput.size()); ++i)
{
for (size_t j = 0; j < smallerInput.size(); ++j)
expectedOutputValues[(i * smallerInput.size()) + j] += smallerInput[j];
}
FloatingPointVectorCompare(outputData, expectedOutputValues, "Forward prop results do not match expected results");
auto& smallerInputGradients = (numAxesLeftOperand < numAxesRightOperand) ? leftInputGradientsData : rightInputGradientsData;
auto& largerInputGradients = (numAxesLeftOperand < numAxesRightOperand) ? rightInputGradientsData : leftInputGradientsData;
std::vector<ElementType> expectedLargerInputGradientValues(largerInputGradients.size(), (ElementType)1);
std::vector<ElementType> expectedSmallerInputGradientValues(smallerInputGradients.size(), (ElementType)(largerInputGradients.size() / smallerInputGradients.size()));
FloatingPointVectorCompare(smallerInputGradients, expectedSmallerInputGradientValues, "TestTimesAndPlus: Backward prop results do not match expected results");
FloatingPointVectorCompare(largerInputGradients, expectedLargerInputGradientValues, "TestTimesAndPlus: Backward prop results do not match expected results");
}