[CPU] EmbeddingBagOffsetsSum, EmbeddingBagPackedSum, EmbeddingSegmentsSum operations. (#576)

* [CPU] EmbeddingBagOffsetsSum, EmbeddingBagPackedSum, EmbeddingSegmentsSum operations.

* Performance fix

* Perf v2

* Code style
This commit is contained in:
Nikolay Shchegolev authored and GitHub committed 2020-06-02 21:56:17 +03:00
1 parent 4c44ce9795
commit 4f6c976add
26 files changed
+1706 -1

No files matched your search

@@ -53,6 +53,10 @@ set(LAYERS
${CMAKE_CURRENT_SOURCE_DIR}/nodes/depth_to_space.cpp
${CMAKE_CURRENT_SOURCE_DIR}/nodes/detectionoutput.cpp
${CMAKE_CURRENT_SOURCE_DIR}/nodes/detectionoutput_onnx.cpp
${CMAKE_CURRENT_SOURCE_DIR}/nodes/embedding_bag_offset_sum.cpp
${CMAKE_CURRENT_SOURCE_DIR}/nodes/embedding_bag_packed_sum.cpp
${CMAKE_CURRENT_SOURCE_DIR}/nodes/embedding_bag_sum.cpp
${CMAKE_CURRENT_SOURCE_DIR}/nodes/embedding_segments_sum.cpp
${CMAKE_CURRENT_SOURCE_DIR}/nodes/extract_image_patches.cpp
${CMAKE_CURRENT_SOURCE_DIR}/nodes/fill.cpp
${CMAKE_CURRENT_SOURCE_DIR}/nodes/gather.cpp
@@ -0,0 +1,248 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "embedding_bag_sum.hpp"
#include "ie_parallel.hpp"
#include <vector>
namespace InferenceEngine {
namespace Extensions {
namespace Cpu {
class EmbeddingBagOffsetsSumImpl: public MKLDNNEmbeddingBagSum {
public:
explicit EmbeddingBagOffsetsSumImpl(const CNNLayer* layer) :
MKLDNNEmbeddingBagSum(layer, 3lu, 1lu, 4lu, 3lu) {
auto indicesData = layer->insData[INDICES_IDX].lock();
if (indicesData == nullptr)
THROW_IE_EXCEPTION << "'" << layer->name << "' layer has nullable indices data.";
if (indicesData->getTensorDesc().getDims().size() != 1)
THROW_IE_EXCEPTION << "'" << layer->name << "' layer has indices data with invalid shape.";
auto offsetsData = layer->insData[OFFSETS_IDX].lock();
if (offsetsData == nullptr)
THROW_IE_EXCEPTION << "'" << layer->name << "' layer has invalid offsets data.";
if (offsetsData->getTensorDesc().getDims().size() != 1)
THROW_IE_EXCEPTION << "'" << layer->name << "' layer's offsets data has invalid shape.";
_indicesLen = indicesData->getTensorDesc().getDims()[0];
_offsetsLen = offsetsData->getTensorDesc().getDims()[0];
}
StatusCode execute(
std::vector<Blob::Ptr>& inputs,
std::vector<Blob::Ptr>& outputs,
ResponseDesc* resp) noexcept override {
switch (inputs[0]->getTensorDesc().getPrecision()) {
case Precision::FP32: {
return processData<PrecisionTrait<Precision::FP32>::value_type>(inputs, outputs, resp);
}
case Precision::I8: {
return processData<PrecisionTrait<Precision::I8>::value_type>(inputs, outputs, resp);
}
case Precision::U8: {
return processData<PrecisionTrait<Precision::U8>::value_type>(inputs, outputs, resp);
}
case Precision::I32: {
return processData<PrecisionTrait<Precision::I32>::value_type>(inputs, outputs, resp);
}
default: {
if (resp) {
std::string errorMsg = "EmbeddingBagSum layer does not support embedding table precision '"
+ std::string(inputs[0]->getTensorDesc().getPrecision().name()) + "'";
errorMsg.copy(resp->msg, sizeof(resp->msg) - 1);
}
return GENERAL_ERROR;
}
}
}
protected:
template<typename T>
StatusCode processData(
std::vector<Blob::Ptr>& inputs,
std::vector<Blob::Ptr>& outputs,
ResponseDesc* resp) noexcept {
switch (inputs[1]->getTensorDesc().getPrecision()) {
case Precision::I32: {
return processData<T, PrecisionTrait<Precision::I32>::value_type>(inputs, outputs, resp);
}
case Precision::I64: {
return processData<T, PrecisionTrait<Precision::I64>::value_type>(inputs, outputs, resp);
}
case Precision::U64: {
return processData<T, PrecisionTrait<Precision::U64>::value_type>(inputs, outputs, resp);
}
default: {
if (resp) {
std::string errorMsg = "EmbeddingBagSum layer does not support indices precision '"
+ std::string(inputs[1]->getTensorDesc().getPrecision().name()) + "'";
errorMsg.copy(resp->msg, sizeof(resp->msg) - 1);
}
return GENERAL_ERROR;
}
}
}
template<typename T, typename I>
StatusCode processData(
std::vector<Blob::Ptr>& inputs,
std::vector<Blob::Ptr>& outputs,
ResponseDesc* resp) noexcept {
std::string errorMsg;
std::string msgPrefix = std::string("Layer EmbeddingBagOffsetsSum with name '") + _layerName + "' ";
const T* srcData = inputs[0]->cbuffer().as<const T*>() +
inputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding();
T* dstData = outputs[0]->buffer().as<T*>() +
outputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding();
const I* indicesData = inputs[INDICES_IDX]->cbuffer().as<const I*>();
const I* offsetsData = inputs[OFFSETS_IDX]->cbuffer().as<const I*>();
int64_t defaultIndex = -1;
if (inputs.size() > DEFAULT_INDEX_IDX) {
defaultIndex = (int64_t)inputs[DEFAULT_INDEX_IDX]->cbuffer().as<const I*>()[0];
if (defaultIndex < 0 || defaultIndex >= _indicesLen) {
std::string msg = "Invalid default index: " + std::to_string(defaultIndex);
msg.copy(resp->msg, sizeof(resp->msg) - 1);
return GENERAL_ERROR;
}
}
const T* weightsData = nullptr;
if (_withWeights)
weightsData = inputs[PER_SAMPLE_WEIGHTS_IDX]->cbuffer().as<const T*>();
const auto& inDataDims = inputs[0]->getTensorDesc().getDims();
const size_t IN_BAGS_DEPTH = inDataDims.size() - 1;
const size_t OUTPUT_BAGS_NUM = outputs[0]->getTensorDesc().getDims()[0];
std::function<void(size_t, const I*&, size_t&, size_t&, bool&)> get_idx =
[&](size_t embIndex, const I*& indicesRef, size_t& outSize, size_t& weightsIdx, bool& withWeights) {
if (embIndex >= _offsetsLen) {
errorMsg = msgPrefix + "has invalid embedding bag index.";
return;
}
if (offsetsData[embIndex] >= _indicesLen) {
errorMsg = msgPrefix + ". Offset value exceeds indices size in the model.\noffset: "
+ std::to_string(offsetsData[embIndex]) + "; indices size: " + std::to_string(_indicesLen);
return;
}
indicesRef = nullptr;
outSize = 0lu;
withWeights = _withWeights;
if (embIndex == _offsetsLen - 1lu)
outSize = _indicesLen - offsetsData[embIndex];
else
outSize = offsetsData[embIndex + 1lu] - offsetsData[embIndex];
if (outSize != 0lu) {
indicesRef = indicesData + offsetsData[embIndex];
} else {
// Empty or default bag
withWeights = false;
if (defaultIndex >= 0) {
indicesRef = reinterpret_cast<I*>(&defaultIndex);
outSize = 1lu;
}
return;
}
if (withWeights)
weightsIdx = offsetsData[embIndex];
};
auto threadBody = [&](const int ithr, const int nthr) {
size_t start(0lu), end(0lu);
splitter(OUTPUT_BAGS_NUM, nthr, ithr, start, end);
if (start >= end)
return;
size_t indicesSize = 0lu;
const I* indices = nullptr;
size_t weightsIdx = 0lu;
bool withWeights = _withWeights;
for (size_t obi = start; obi < end; obi++) {
size_t dstIndex = obi * _embDepth;
get_idx(obi, indices, indicesSize, weightsIdx, withWeights);
if (indices != nullptr) {
withWeights = withWeights & _withWeights;
size_t inIdx = 0lu;
if (indices[inIdx] >= inDataDims[0]) {
errorMsg = msgPrefix + "has invalid embedding bag index: " + std::to_string(indices[inIdx]);
return;
}
size_t srcIndex = indices[inIdx] * _embDepth;
if (withWeights) {
for (size_t i = 0lu; i < _embDepth; i++) {
dstData[dstIndex + i] = srcData[srcIndex + i] * weightsData[weightsIdx];
}
weightsIdx++;
} else {
for (size_t i = 0lu; i < _embDepth; i++) {
dstData[dstIndex + i] = srcData[srcIndex + i];
}
}
for (inIdx = 1lu; inIdx < indicesSize; inIdx++) {
if (indices[inIdx] >= inDataDims[0]) {
errorMsg = msgPrefix + "has invalid embedding bag index: " + std::to_string(indices[inIdx]);
return;
}
size_t srcIndex = indices[inIdx] * _embDepth;
if (withWeights) {
for (size_t i = 0lu; i < _embDepth; i++) {
dstData[dstIndex + i] += srcData[srcIndex + i] * weightsData[weightsIdx];
}
weightsIdx++;
} else {
for (size_t i = 0lu; i < _embDepth; i++) {
dstData[dstIndex + i] += srcData[srcIndex + i];
}
}
}
} else {
for (size_t i = 0lu; i < _embDepth; i++) {
dstData[dstIndex + i] = 0;
}
}
}
};
parallel_nt(0, threadBody);
if (!errorMsg.empty()) {
errorMsg.copy(resp->msg, sizeof(resp->msg) - 1);
return GENERAL_ERROR;
}
return OK;
}
void initFromInputs(std::vector<Blob::Ptr>& inputs) override {
}
void getIndices(size_t embIndex, const size_t*& indices, size_t& size, size_t& weightsIdx, bool& withWeights) override {
}
const size_t OFFSETS_IDX = 2lu;
size_t _indicesLen;
size_t _offsetsLen;
};
REG_FACTORY_FOR(EmbeddingBagOffsetsSumImpl, EmbeddingBagOffsetsSum);
} // namespace Cpu
} // namespace Extensions
} // namespace InferenceEngine
@@ -0,0 +1,66 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "embedding_bag_sum.hpp"
namespace InferenceEngine {
namespace Extensions {
namespace Cpu {
class EmbeddingBagPackedSumImpl: public MKLDNNEmbeddingBagSum {
public:
explicit EmbeddingBagPackedSumImpl(const CNNLayer* layer) :
MKLDNNEmbeddingBagSum(layer, 2lu, 1lu, 2lu, 3lu) {
auto indicesData = layer->insData[INDICES_IDX].lock();
if (indicesData == nullptr)
THROW_IE_EXCEPTION << "'" << layer->name << "' layer has nullable indices data.";
if (indicesData->getTensorDesc().getDims().size() != 2)
THROW_IE_EXCEPTION << "'" << layer->name << "' layer has indices data with invalid shape.";
_indices = std::vector<std::vector<size_t>>(
indicesData->getTensorDesc().getDims()[0],
std::vector<size_t>(indicesData->getTensorDesc().getDims()[1], 0lu));
}
void initFromInputs(std::vector<Blob::Ptr>& inputs) override {
// Initialize indices
const size_t bagsNum = inputs[INDICES_IDX]->getTensorDesc().getDims()[0];
const size_t batch = inputs[INDICES_IDX]->getTensorDesc().getDims()[1];
if (inputs[INDICES_IDX]->getTensorDesc().getPrecision().size() == sizeof(INT32)) {
const INT32* src = inputs[INDICES_IDX]->cbuffer().as<const INT32*>();
for (size_t i = 0lu; i < bagsNum; i++) {
size_t ibn = i * batch;
for (size_t j = 0lu; j < batch; j++) {
_indices[i][j] = static_cast<size_t>(src[ibn + j]);
}
}
} else if (inputs[INDICES_IDX]->getTensorDesc().getPrecision().size() == sizeof(UINT64)) {
const UINT64* src = inputs[INDICES_IDX]->cbuffer().as<const UINT64*>();
for (size_t i = 0lu; i < bagsNum; i++) {
memcpy(_indices[i].data(), src + i * batch, batch * sizeof(UINT64));
}
}
}
void getIndices(size_t embIndex, const size_t*& indices, size_t& size, size_t& weightsIdx, bool& withWeights) override {
if (embIndex >= _indices.size())
THROW_IE_EXCEPTION << "Invalid embedding bag index.";
withWeights = true;
indices = _indices[embIndex].data();
size = _indices[0].size();
weightsIdx = embIndex * _indices[0].size();
}
protected:
std::vector<std::vector<size_t>> _indices;
};
REG_FACTORY_FOR(EmbeddingBagPackedSumImpl, EmbeddingBagPackedSum);
} // namespace Cpu
} // namespace Extensions
} // namespace InferenceEngine
@@ -0,0 +1,210 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "embedding_bag_sum.hpp"
#include "ie_parallel.hpp"
#include "jit_generator.hpp"
#include "list.hpp"
#include <set>
#include <string>
#include <vector>
using namespace InferenceEngine;
using namespace InferenceEngine::Extensions::Cpu;
const std::set<size_t> MKLDNNEmbeddingBagSum::_supportedIndicesTypeSize = {sizeof(INT32), sizeof(INT64)};
MKLDNNEmbeddingBagSum::MKLDNNEmbeddingBagSum(
const CNNLayer* layer,
size_t requiredInputNum,
size_t indicesIdx,
size_t perSampleWeightsIdx,
size_t defaultIndexIdx,
const std::set<Precision>& supportedPrecisions) :
INDICES_IDX(indicesIdx),
PER_SAMPLE_WEIGHTS_IDX(perSampleWeightsIdx),
DEFAULT_INDEX_IDX(defaultIndexIdx) {
try {
std::string logPrefix = std::string("Layer EmbeddingBagSum with name '") + layer->name + "' ";
if (layer->insData.size() < requiredInputNum || layer->outData.size() != 1)
THROW_IE_EXCEPTION << logPrefix << "has incorrect number of input or output edges!";
_layerName = layer->name;
auto inData = layer->insData[0].lock();
auto indicesData = layer->insData[INDICES_IDX].lock();
if (inData == nullptr || indicesData == nullptr)
THROW_IE_EXCEPTION << logPrefix << "has nullable input data.";
auto dataPrecision = inData->getTensorDesc().getPrecision();
if (dataPrecision == Precision::BF16)
dataPrecision = Precision::FP32;
if (!supportedPrecisions.empty()) {
if (supportedPrecisions.find(dataPrecision) == supportedPrecisions.end())
THROW_IE_EXCEPTION << logPrefix << "has unsupported precision: " << dataPrecision.name();
} else {
static const std::set<Precision> defaultSupportedPrecisions =
{Precision::FP32, Precision::I8, Precision::U8, Precision::I32};
if (defaultSupportedPrecisions.find(dataPrecision) == defaultSupportedPrecisions.end())
THROW_IE_EXCEPTION << logPrefix << "has unsupported precision: " << dataPrecision.name();
}
if (layer->insData.size() > PER_SAMPLE_WEIGHTS_IDX)
_withWeights = true;
if (_withWeights) {
auto weightsData = layer->insData[PER_SAMPLE_WEIGHTS_IDX].lock();
if (weightsData == nullptr)
THROW_IE_EXCEPTION << logPrefix << "has nullable weights data";
if (weightsData->getTensorDesc().getDims() != indicesData->getTensorDesc().getDims())
THROW_IE_EXCEPTION << logPrefix << "must have equal shapes for indices and per_sample_weights inputs.";
}
LayerConfig config;
config.inConfs.resize(layer->insData.size());
for (int i = 0; i < layer->insData.size(); i++) {
auto data = layer->insData[i].lock();
if (data == nullptr)
THROW_IE_EXCEPTION << logPrefix << "has nullable input data";
auto prc = data->getTensorDesc().getPrecision();
if (prc == Precision::BF16)
prc = Precision::FP32;
config.inConfs[i].desc = TensorDesc(prc,
data->getTensorDesc().getDims(),
TensorDesc::getLayoutByDims(data->getTensorDesc().getDims()));
}
DataConfig outConfig;
auto& outDims = layer->outData[0]->getTensorDesc().getDims();
outConfig.desc = TensorDesc(dataPrecision,
outDims,
TensorDesc::getLayoutByDims(outDims));
config.outConfs.push_back(outConfig);
config.dynBatchSupport = false;
confs.push_back(config);
const auto& inDataDims = inData->getTensorDesc().getDims();
_embDepth = 1lu;
for (size_t i = 1lu; i < inDataDims.size(); i++) {
_embDepth *= inDataDims[i];
}
} catch (InferenceEngine::details::InferenceEngineException &ex) {
errorMsg = ex.what();
}
}
StatusCode MKLDNNEmbeddingBagSum::execute(
std::vector<Blob::Ptr>& inputs,
std::vector<Blob::Ptr>& outputs,
ResponseDesc *resp) noexcept {
switch (inputs[0]->getTensorDesc().getPrecision()) {
case Precision::FP32: {
processData<PrecisionTrait<Precision::FP32>::value_type>(inputs, outputs);
break;
}
case Precision::I8: {
processData<PrecisionTrait<Precision::I8>::value_type>(inputs, outputs);
break;
}
case Precision::U8: {
processData<PrecisionTrait<Precision::U8>::value_type>(inputs, outputs);
break;
}
case Precision::I32: {
processData<PrecisionTrait<Precision::I32>::value_type>(inputs, outputs);
break;
}
default: {
if (resp) {
std::string errorMsg = "EmbeddingBagSum layer does not support precision '"
+ std::string(inputs[0]->getTensorDesc().getPrecision().name()) + "'";
errorMsg.copy(resp->msg, sizeof(resp->msg) - 1);
}
return GENERAL_ERROR;
}
}
return OK;
}
template<typename T>
void MKLDNNEmbeddingBagSum::processData(
std::vector<Blob::Ptr>& inputs,
std::vector<Blob::Ptr>& outputs) noexcept {
const T* srcData = inputs[0]->cbuffer().as<const T*>() +
inputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding();
T* dstData = outputs[0]->buffer().as<T*>() +
outputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding();
const T* weightsData = nullptr;
if (_withWeights)
weightsData = inputs[PER_SAMPLE_WEIGHTS_IDX]->cbuffer().as<const T*>();
initFromInputs(inputs);
const auto& inDataDims = inputs[0]->getTensorDesc().getDims();
const size_t outputBagsNum = outputs[0]->getTensorDesc().getDims()[0];
auto threadBody = [&](const int ithr, const int nthr) {
size_t start(0lu), end(0lu);
splitter(outputBagsNum, nthr, ithr, start, end);
if (start >= end)
return;
size_t indicesSize = 0lu;
const size_t* indices = nullptr;
size_t weightsIdx = 0lu;
bool withWeights = _withWeights;
for (size_t obi = start; obi < end; obi++) {
size_t dstIndex = obi * _embDepth;
getIndices(obi, indices, indicesSize, weightsIdx, withWeights);
if (indices != nullptr) {
withWeights = withWeights & _withWeights;
size_t inIdx = 0lu;
if (indices[inIdx] >= inDataDims[0])
THROW_IE_EXCEPTION << "EmbeddingBagSum layer '" << _layerName
<< "' has invalid embedding bag index: " << indices[inIdx];
size_t srcIndex = indices[inIdx] * _embDepth;
if (withWeights) {
for (size_t i = 0lu; i < _embDepth; i++) {
dstData[dstIndex + i] = srcData[srcIndex + i] * weightsData[weightsIdx];
}
weightsIdx++;
} else {
for (size_t i = 0lu; i < _embDepth; i++) {
dstData[dstIndex + i] = srcData[srcIndex + i];
}
}
for (inIdx = 1lu; inIdx < indicesSize; inIdx++) {
if (indices[inIdx] >= inDataDims[0])
THROW_IE_EXCEPTION << "EmbeddingBagSum layer '" << _layerName
<< "' has invalid embedding bag index: " << indices[inIdx];
size_t srcIndex = indices[inIdx] * _embDepth;
if (withWeights) {
for (size_t i = 0lu; i < _embDepth; i++) {
dstData[dstIndex + i] += srcData[srcIndex + i] * weightsData[weightsIdx];
}
weightsIdx++;
} else {
for (size_t i = 0lu; i < _embDepth; i++) {
dstData[dstIndex + i] += srcData[srcIndex + i];
}
}
}
} else {
for (size_t i = 0lu; i < _embDepth; i++) {
dstData[dstIndex + i] = 0;
}
}
}
};
parallel_nt(0, threadBody);
}
@@ -0,0 +1,63 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include "base.hpp"
#include <memory>
#include <set>
#include <vector>
namespace InferenceEngine {
namespace Extensions {
namespace Cpu {
class MKLDNNEmbeddingBagSum : public ExtLayerBase {
public:
MKLDNNEmbeddingBagSum(
const CNNLayer* layer,
size_t requiredInputsNum,
size_t indicesIdx,
size_t perSampleWeightsIdx,
size_t defaultIndexIdx,
const std::set<Precision>& supportedPrecisions = {});
StatusCode execute(
std::vector<Blob::Ptr>& inputs,
std::vector<Blob::Ptr>& outputs,
ResponseDesc *resp) noexcept override;
protected:
virtual void initFromInputs(std::vector<Blob::Ptr>& inputs) = 0;
virtual void getIndices(
size_t embIndex,
const size_t*& indicesRef,
size_t& size,
size_t& weightsIdx,
bool& withWeights) = 0;
template<typename T>
void processData(std::vector<Blob::Ptr>& inputs, std::vector<Blob::Ptr>& outputs) noexcept;
std::set<Precision> _supportedPrecisions;
const size_t INDICES_IDX;
const size_t PER_SAMPLE_WEIGHTS_IDX;
const size_t DEFAULT_INDEX_IDX;
bool _withWeights = false;
size_t _embDepth = 0;
std::string _layerName;
using INT32 = PrecisionTrait<Precision::I32>::value_type;
using INT64 = PrecisionTrait<Precision::I64>::value_type;
using UINT64 = PrecisionTrait<Precision::U64>::value_type;
static const std::set<size_t> _supportedIndicesTypeSize;
};
} // namespace Cpu
} // namespace Extensions
} // namespace InferenceEngine
@@ -0,0 +1,133 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "embedding_bag_sum.hpp"
namespace InferenceEngine {
namespace Extensions {
namespace Cpu {
class EmbeddingSegmentsSumImpl: public MKLDNNEmbeddingBagSum {
public:
explicit EmbeddingSegmentsSumImpl(const CNNLayer* layer) :
MKLDNNEmbeddingBagSum(layer, 4lu, 1lu, 5lu, 4lu) {
std::string errPrefix = std::string("EmbeddingSegmentsSum layer with name '") + _layerName + "' ";
auto indicesData = layer->insData[INDICES_IDX].lock();
if (indicesData == nullptr)
THROW_IE_EXCEPTION << errPrefix << "has nullable indices data.";
if (indicesData->getTensorDesc().getDims().size() != 1)
THROW_IE_EXCEPTION << errPrefix << "has indices data with invalid shape: "
<< indicesData->getTensorDesc().getDims().size();
auto segmentIdData = layer->insData[SEGMENT_ID_IDX].lock();
if (segmentIdData == nullptr)
THROW_IE_EXCEPTION << errPrefix << "has invalid segmentID data.";
if (segmentIdData->getTensorDesc().getDims().size() != 1)
THROW_IE_EXCEPTION << errPrefix << "has invalid segmentID data shape: "
<< segmentIdData->getTensorDesc().getDims().size();
auto numSegmentData = layer->insData[NUM_SEGMENTS_IDX].lock();
if (numSegmentData == nullptr)
THROW_IE_EXCEPTION << errPrefix << "has nullable numSegmentID data.";
if (_supportedIndicesTypeSize.find(indicesData->getTensorDesc().getPrecision().size())
== _supportedIndicesTypeSize.end()
|| _supportedIndicesTypeSize.find(segmentIdData->getTensorDesc().getPrecision().size())
== _supportedIndicesTypeSize.end()
|| _supportedIndicesTypeSize.find(numSegmentData->getTensorDesc().getPrecision().size())
== _supportedIndicesTypeSize.end())
THROW_IE_EXCEPTION << errPrefix << "has unsupported input data type.";
_indices = std::vector<size_t>(indicesData->getTensorDesc().getDims()[0], 0lu);
_segmentIds = std::vector<size_t>(segmentIdData->getTensorDesc().getDims()[0], 0lu);
}
void initFromInputs(std::vector<Blob::Ptr>& inputs) override {
// Initialize indices
if (inputs[INDICES_IDX]->getTensorDesc().getPrecision().size() == sizeof(INT32)) {
const INT32* src = inputs[INDICES_IDX]->cbuffer().as<const INT32*>();
for (size_t i = 0lu; i < inputs[INDICES_IDX]->size(); i++)
_indices[i] = static_cast<size_t>(src[i]);
} else if (inputs[INDICES_IDX]->getTensorDesc().getPrecision().size() == sizeof(UINT64)) {
const UINT64* src = inputs[INDICES_IDX]->cbuffer().as<const UINT64*>();
memcpy(_indices.data(), src, inputs[INDICES_IDX]->byteSize());
}
// Initialize segments ids
if (inputs[SEGMENT_ID_IDX]->getTensorDesc().getPrecision().size() == sizeof(INT32)) {
const INT32* src = inputs[SEGMENT_ID_IDX]->cbuffer().as<const INT32*>();
for (size_t i = 0lu; i < inputs[SEGMENT_ID_IDX]->size(); i++)
_segmentIds[i] = static_cast<size_t>(src[i]);
} else if (inputs[SEGMENT_ID_IDX]->getTensorDesc().getPrecision().size() == sizeof(UINT64)) {
const UINT64* src = inputs[SEGMENT_ID_IDX]->cbuffer().as<const UINT64*>();
memcpy(_segmentIds.data(), src, inputs[SEGMENT_ID_IDX]->byteSize());
}
if (inputs.size() > NUM_SEGMENTS_IDX) {
if (inputs[NUM_SEGMENTS_IDX]->getTensorDesc().getPrecision().size() == sizeof(INT32)) {
const INT32* src = inputs[NUM_SEGMENTS_IDX]->cbuffer().as<const INT32*>();
_numSegments = static_cast<size_t>(*src);
} else if (inputs[NUM_SEGMENTS_IDX]->getTensorDesc().getPrecision().size() == sizeof(UINT64)) {
const INT64* src = inputs[NUM_SEGMENTS_IDX]->cbuffer().as<const INT64*>();
_numSegments = *src;
}
}
// Initialize default index
_defaultIndices.clear();
if (inputs.size() > DEFAULT_INDEX_IDX) {
if (inputs[DEFAULT_INDEX_IDX]->getTensorDesc().getPrecision().size() == sizeof(INT32)) {
const INT32* src = inputs[DEFAULT_INDEX_IDX]->cbuffer().as<const INT32*>();
_defaultIndices.push_back(static_cast<size_t>(*src));
} else if (inputs[DEFAULT_INDEX_IDX]->getTensorDesc().getPrecision().size() == sizeof(UINT64)) {
const INT64* src = inputs[DEFAULT_INDEX_IDX]->cbuffer().as<const INT64*>();
_defaultIndices.push_back(*src);
}
}
}
void getIndices(size_t embIndex, const size_t*& indices, size_t& size, size_t& weightsIdx, bool& withWeight) override {
if (embIndex >= _numSegments)
THROW_IE_EXCEPTION << "Invalid embedding bag index.";
indices = nullptr;
size = 0lu;
withWeight = true;
for (size_t si = 0; si < _indices.size(); si++) {
if (_segmentIds[si] == embIndex) {
size++;
if (indices == nullptr) {
indices = _indices.data() + si;
weightsIdx = si;
}
}
}
// Empty bag
if (size == 0) {
size = 1lu;
withWeight = false;
if (_defaultIndices.size() == 1lu)
indices = _defaultIndices.data();
return;
}
}
protected:
const size_t SEGMENT_ID_IDX = 2lu;
const size_t NUM_SEGMENTS_IDX = 3lu;
size_t _numSegments = 0lu;
std::vector<size_t> _indices;
std::vector<size_t> _segmentIds;
std::vector<size_t> _defaultIndices;
};
REG_FACTORY_FOR(EmbeddingSegmentsSumImpl, EmbeddingSegmentsSum);
} // namespace Cpu
} // namespace Extensions
} // namespace InferenceEngine
@@ -7,6 +7,9 @@
# define MKLDNN_EXTENSION_NODE(__prim, __type)
#endif
MKLDNN_EXTENSION_NODE(EmbeddingBagOffsetsSumImpl, EmbeddingBagOffsetsSum);
MKLDNN_EXTENSION_NODE(EmbeddingBagPackedSumImpl, EmbeddingBagPackedSum);
MKLDNN_EXTENSION_NODE(EmbeddingSegmentsSumImpl, EmbeddingSegmentsSum);
MKLDNN_EXTENSION_NODE(PriorBoxImpl, PriorBox);
MKLDNN_EXTENSION_NODE(MathImpl, Abs);
MKLDNN_EXTENSION_NODE(MathImpl, Acos);
@@ -0,0 +1,49 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <vector>
#include "single_layer_tests/embedding_bag_offsets_sum.hpp"
#include "common_test_utils/test_constants.hpp"
using namespace LayerTestsDefinitions;
namespace {
const std::vector<InferenceEngine::Precision> netPrecisions = {
InferenceEngine::Precision::FP32,
InferenceEngine::Precision::I32,
InferenceEngine::Precision::U8
};
const std::vector<InferenceEngine::Precision> indPrecisions = {
InferenceEngine::Precision::I64,
InferenceEngine::Precision::I32
};
const std::vector<std::vector<size_t>> emb_table_shape = {{5, 6}, {10, 35}, {5, 4, 16}};
const std::vector<std::vector<size_t>> indices =
{{0, 1, 2, 2, 3}, {4, 4, 3, 1, 0}, {1, 2, 1, 2, 1, 2, 1, 2, 1, 2}};
const std::vector<std::vector<size_t>> offsets = {{0, 2}, {0, 0, 2, 2}, {2, 4}};
const std::vector<size_t> default_index = {0, 4};
const std::vector<bool> with_weights = {false, true};
const std::vector<bool> with_default_index = {false, true};
const auto embBagOffsetSumArgSet = ::testing::Combine(
::testing::ValuesIn(emb_table_shape),
::testing::ValuesIn(indices),
::testing::ValuesIn(offsets),
::testing::ValuesIn(default_index),
::testing::ValuesIn(with_weights),
::testing::ValuesIn(with_default_index)
);
INSTANTIATE_TEST_CASE_P(smoke, EmbeddingBagOffsetsSumLayerTest,
::testing::Combine(
embBagOffsetSumArgSet,
::testing::ValuesIn(netPrecisions),
::testing::ValuesIn(indPrecisions),
::testing::Values(CommonTestUtils::DEVICE_CPU)),
EmbeddingBagOffsetsSumLayerTest::getTestCaseName);
} // namespace
@@ -0,0 +1,43 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <vector>
#include "single_layer_tests/embedding_bag_packed_sum.hpp"
#include "common_test_utils/test_constants.hpp"
using namespace LayerTestsDefinitions;
namespace {
const std::vector<InferenceEngine::Precision> netPrecisions = {
InferenceEngine::Precision::FP32,
InferenceEngine::Precision::I32,
InferenceEngine::Precision::U8
};
const std::vector<InferenceEngine::Precision> indPrecisions = {
InferenceEngine::Precision::I64,
InferenceEngine::Precision::I32
};
const std::vector<std::vector<size_t>> emb_table_shape = {{5, 6}, {10, 35}, {5, 4, 16}};
const std::vector<std::vector<std::vector<size_t>>> indices =
{{{0, 1}, {2, 2}, {3, 4}}, {{4, 4, 3}, {1, 0, 2}}, {{1, 2, 1, 2}, {1, 2, 1, 2}}};
const std::vector<bool> with_weights = {false, true};
const auto embBagPackedSumArgSet = ::testing::Combine(
::testing::ValuesIn(emb_table_shape),
::testing::ValuesIn(indices),
::testing::ValuesIn(with_weights)
);
INSTANTIATE_TEST_CASE_P(smoke, EmbeddingBagPackedSumLayerTest,
::testing::Combine(
embBagPackedSumArgSet,
::testing::ValuesIn(netPrecisions),
::testing::ValuesIn(indPrecisions),
::testing::Values(CommonTestUtils::DEVICE_CPU)),
EmbeddingBagPackedSumLayerTest::getTestCaseName);
} // namespace
@@ -0,0 +1,51 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <vector>
#include "single_layer_tests/embedding_segments_sum.hpp"
#include "common_test_utils/test_constants.hpp"
using namespace LayerTestsDefinitions;
namespace {
const std::vector<InferenceEngine::Precision> netPrecisions = {
InferenceEngine::Precision::FP32,
InferenceEngine::Precision::I32,
InferenceEngine::Precision::U8
};
const std::vector<InferenceEngine::Precision> indPrecisions = {
InferenceEngine::Precision::I64,
InferenceEngine::Precision::I32
};
const std::vector<std::vector<size_t>> emb_table_shape = {{5, 6}, {10, 35}, {5, 4, 16}};
const std::vector<std::vector<size_t>> indices =
{{0, 1, 2, 2, 3}, {4, 4, 3, 1, 2}};
const std::vector<std::vector<size_t>> segment_ids = {{0, 1, 2, 3, 4}, {0, 0, 2, 2, 4}};
const std::vector<size_t> num_segments = {5, 7};
const std::vector<size_t> default_index = {0, 4};
const std::vector<bool> with_weights = {false, true};
const std::vector<bool> with_default_index = {false, true};
const auto embSegmentsSumArgSet = ::testing::Combine(
::testing::ValuesIn(emb_table_shape),
::testing::ValuesIn(indices),
::testing::ValuesIn(segment_ids),
::testing::ValuesIn(num_segments),
::testing::ValuesIn(default_index),
::testing::ValuesIn(with_weights),
::testing::ValuesIn(with_default_index)
);
INSTANTIATE_TEST_CASE_P(smoke, EmbeddingSegmentsSumLayerTest,
::testing::Combine(
embSegmentsSumArgSet,
::testing::ValuesIn(netPrecisions),
::testing::ValuesIn(indPrecisions),
::testing::Values(CommonTestUtils::DEVICE_CPU)),
EmbeddingSegmentsSumLayerTest::getTestCaseName);
} // namespace
@@ -0,0 +1,39 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <tuple>
#include <vector>
#include <string>
#include "functional_test_utils/layer_test_utils.hpp"
typedef std::tuple<
std::vector<size_t>, // emb_table_shape
std::vector<size_t>, // indices
std::vector<size_t>, // offsets
size_t, // default_index
bool, // with_weights
bool // with_def_index
> embeddingBagOffsetsSumParams;
typedef std::tuple<
embeddingBagOffsetsSumParams,
InferenceEngine::Precision, // embedding table
InferenceEngine::Precision, // indices
LayerTestsUtils::TargetDevice> embeddingBagOffsetsSumLayerTestParamsSet;
namespace LayerTestsDefinitions {
class EmbeddingBagOffsetsSumLayerTest : public testing::WithParamInterface<embeddingBagOffsetsSumLayerTestParamsSet>,
public LayerTestsUtils::LayerTestsCommon {
public:
static std::string getTestCaseName(testing::TestParamInfo<embeddingBagOffsetsSumLayerTestParamsSet> obj);
protected:
void SetUp() override;
};
} // namespace LayerTestsDefinitions
@@ -0,0 +1,36 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <tuple>
#include <vector>
#include <string>
#include "functional_test_utils/layer_test_utils.hpp"
typedef std::tuple<
std::vector<size_t>, // emb_table_shape
std::vector<std::vector<size_t>>, // indices
bool // with_weights
> embeddingBagPackedSumParams;
typedef std::tuple<
embeddingBagPackedSumParams,
InferenceEngine::Precision, // embedding table
InferenceEngine::Precision, // indices
LayerTestsUtils::TargetDevice> embeddingBagPackedSumLayerTestParamsSet;
namespace LayerTestsDefinitions {
class EmbeddingBagPackedSumLayerTest : public testing::WithParamInterface<embeddingBagPackedSumLayerTestParamsSet>,
public LayerTestsUtils::LayerTestsCommon {
public:
static std::string getTestCaseName(testing::TestParamInfo<embeddingBagPackedSumLayerTestParamsSet> obj);
protected:
void SetUp() override;
};
} // namespace LayerTestsDefinitions
@@ -0,0 +1,40 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <tuple>
#include <vector>
#include <string>
#include "functional_test_utils/layer_test_utils.hpp"
typedef std::tuple<
std::vector<size_t>, // emb_table_shape
std::vector<size_t>, // indices
std::vector<size_t>, // segment_ids
size_t, // num_segments
size_t, // default_index
bool, // with_weights
bool // with_def_index
> embeddingSegmentsSumParams;
typedef std::tuple<
embeddingSegmentsSumParams,
InferenceEngine::Precision, // embedding table
InferenceEngine::Precision, // indices
LayerTestsUtils::TargetDevice> embeddingSegmentsSumLayerTestParamsSet;
namespace LayerTestsDefinitions {
class EmbeddingSegmentsSumLayerTest : public testing::WithParamInterface<embeddingSegmentsSumLayerTestParamsSet>,
public LayerTestsUtils::LayerTestsCommon {
public:
static std::string getTestCaseName(testing::TestParamInfo<embeddingSegmentsSumLayerTestParamsSet> obj);
protected:
void SetUp() override;
};
} // namespace LayerTestsDefinitions
@@ -0,0 +1,66 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <tuple>
#include <vector>
#include <string>
#include <memory>
#include "single_layer_tests/embedding_bag_offsets_sum.hpp"
#include "functional_test_utils/layer_test_utils.hpp"
#include "ngraph_functions/builders.hpp"
namespace LayerTestsDefinitions {
std::string EmbeddingBagOffsetsSumLayerTest::getTestCaseName(testing::TestParamInfo<embeddingBagOffsetsSumLayerTestParamsSet> obj) {
embeddingBagOffsetsSumParams params;
InferenceEngine::Precision netPrecision, indPrecision;
std::string targetDevice;
std::tie(params, netPrecision, indPrecision, targetDevice) = obj.param;
std::vector<size_t> embTableShape, indices, offsets;
size_t defaultIndex;
bool withWeights, withDefIndex;
std::tie(embTableShape, indices, offsets, defaultIndex, withWeights, withDefIndex) = params;
std::ostringstream result;
result << "ETS=" << CommonTestUtils::vec2str(embTableShape) << "_";
result << "I" << CommonTestUtils::vec2str(indices) << "_";
result << "O" << CommonTestUtils::vec2str(offsets) << "_";
result << "DI" << defaultIndex << "_";
result << "WW" << withWeights << "_";
result << "WDI" << withDefIndex << "_";
result << "netPRC=" << netPrecision.name() << "_";
result << "indPRC=" << indPrecision.name() << "_";
result << "targetDevice=" << targetDevice;
return result.str();
}
void EmbeddingBagOffsetsSumLayerTest::SetUp() {
embeddingBagOffsetsSumParams embParams;
auto netPrecision = InferenceEngine::Precision::UNSPECIFIED;
auto indPrecision = netPrecision;
std::tie(embParams, netPrecision, indPrecision, targetDevice) = this->GetParam();
std::vector<size_t> embTableShape, indices, offsets;
bool withWeights, withDefIndex;
size_t defaultIndex;
std::tie(embTableShape, indices, offsets, defaultIndex, withWeights, withDefIndex) = embParams;
auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision);
auto ngIdxPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(indPrecision);
auto emb_table_node = std::make_shared<ngraph::opset1::Parameter>(ngPrc, ngraph::Shape(embTableShape));
ngraph::ParameterVector params = {emb_table_node};
auto embBag = std::dynamic_pointer_cast<ngraph::opset3::EmbeddingBagOffsetsSum>(
ngraph::builder::makeEmbeddingBagOffsetsSum(
ngPrc, ngIdxPrc, emb_table_node, indices, offsets, defaultIndex, withWeights, withDefIndex));
ngraph::ResultVector results{std::make_shared<ngraph::opset1::Result>(embBag)};
function = std::make_shared<ngraph::Function>(results, params, "embeddingBagOffsetsSum");
}
TEST_P(EmbeddingBagOffsetsSumLayerTest, CompareWithRefs) {
Run();
}
} // namespace LayerTestsDefinitions
@@ -0,0 +1,63 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <tuple>
#include <vector>
#include <string>
#include <memory>
#include "single_layer_tests/embedding_bag_packed_sum.hpp"
#include "functional_test_utils/layer_test_utils.hpp"
#include "ngraph_functions/builders.hpp"
namespace LayerTestsDefinitions {
std::string EmbeddingBagPackedSumLayerTest::getTestCaseName(testing::TestParamInfo<embeddingBagPackedSumLayerTestParamsSet> obj) {
embeddingBagPackedSumParams params;
InferenceEngine::Precision netPrecision, indPrecision;
std::string targetDevice;
std::tie(params, netPrecision, indPrecision, targetDevice) = obj.param;
std::vector<size_t> embTableShape;
std::vector<std::vector<size_t>> indices;
bool withWeights;
std::tie(embTableShape, indices, withWeights) = params;
std::ostringstream result;
result << "ETS=" << CommonTestUtils::vec2str(embTableShape) << "_";
result << "I" << CommonTestUtils::vec2str(indices) << "_";
result << "WW" << withWeights << "_";
result << "netPRC=" << netPrecision.name() << "_";
result << "indPRC=" << indPrecision.name() << "_";
result << "targetDevice=" << targetDevice;
return result.str();
}
void EmbeddingBagPackedSumLayerTest::SetUp() {
embeddingBagPackedSumParams embParams;
auto netPrecision = InferenceEngine::Precision::UNSPECIFIED;
auto indPrecision = netPrecision;
std::tie(embParams, netPrecision, indPrecision, targetDevice) = this->GetParam();
std::vector<size_t> embTableShape;
std::vector<std::vector<size_t>> indices;
bool withWeights;
std::tie(embTableShape, indices, withWeights) = embParams;
auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision);
auto ngIdxPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(indPrecision);
auto emb_table_node = std::make_shared<ngraph::opset1::Parameter>(ngPrc, ngraph::Shape(embTableShape));
ngraph::ParameterVector params = {emb_table_node};
auto embBag = std::dynamic_pointer_cast<ngraph::opset3::EmbeddingBagPackedSum>(
ngraph::builder::makeEmbeddingBagPackedSum(
ngPrc, ngIdxPrc, emb_table_node, indices, withWeights));
ngraph::ResultVector results{std::make_shared<ngraph::opset1::Result>(embBag)};
function = std::make_shared<ngraph::Function>(results, params, "embeddingBagPackedSum");
}
TEST_P(EmbeddingBagPackedSumLayerTest, CompareWithRefs) {
Run();
}
} // namespace LayerTestsDefinitions
@@ -0,0 +1,68 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <tuple>
#include <vector>
#include <string>
#include <memory>
#include "single_layer_tests/embedding_segments_sum.hpp"
#include "functional_test_utils/layer_test_utils.hpp"
#include "ngraph_functions/builders.hpp"
namespace LayerTestsDefinitions {
std::string EmbeddingSegmentsSumLayerTest::getTestCaseName(testing::TestParamInfo<embeddingSegmentsSumLayerTestParamsSet> obj) {
embeddingSegmentsSumParams params;
InferenceEngine::Precision netPrecision, indPrecision;
std::string targetDevice;
std::tie(params, netPrecision, indPrecision, targetDevice) = obj.param;
std::vector<size_t> embTableShape, indices, segmentIds;
size_t numSegments, defaultIndex;
bool withWeights, withDefIndex;
std::tie(embTableShape, indices, segmentIds, numSegments, defaultIndex, withWeights, withDefIndex) = params;
std::ostringstream result;
result << "ETS=" << CommonTestUtils::vec2str(embTableShape) << "_";
result << "I" << CommonTestUtils::vec2str(indices) << "_";
result << "SI" << CommonTestUtils::vec2str(segmentIds) << "_";
result << "NS" << numSegments << "_";
result << "DI" << defaultIndex << "_";
result << "WW" << withWeights << "_";
result << "WDI" << withDefIndex << "_";
result << "netPRC=" << netPrecision.name() << "_";
result << "indPRC=" << indPrecision.name() << "_";
result << "targetDevice=" << targetDevice;
return result.str();
}
void EmbeddingSegmentsSumLayerTest::SetUp() {
embeddingSegmentsSumParams embParams;
auto netPrecision = InferenceEngine::Precision::UNSPECIFIED;
auto indPrecision = netPrecision;
std::tie(embParams, netPrecision, indPrecision, targetDevice) = this->GetParam();
std::vector<size_t> embTableShape, indices, segmentIds;
bool withWeights, withDefIndex;
size_t numSegments, defaultIndex;
std::tie(embTableShape, indices, segmentIds, numSegments, defaultIndex, withWeights, withDefIndex) = embParams;
auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision);
auto ngIdxPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(indPrecision);
auto emb_table_node = std::make_shared<ngraph::opset1::Parameter>(ngPrc, ngraph::Shape(embTableShape));
ngraph::ParameterVector params = {emb_table_node};
auto embBag = std::dynamic_pointer_cast<ngraph::opset3::EmbeddingSegmentsSum>(
ngraph::builder::makeEmbeddingSegmentsSum(
ngPrc, ngIdxPrc, emb_table_node, indices, segmentIds, numSegments, defaultIndex, withWeights, withDefIndex));
ngraph::ResultVector results{std::make_shared<ngraph::opset1::Result>(embBag)};
function = std::make_shared<ngraph::Function>(results, params, "embeddingSegmentsSum");
}
TEST_P(EmbeddingSegmentsSumLayerTest, CompareWithRefs) {
Run();
}
} // namespace LayerTestsDefinitions
@@ -184,5 +184,34 @@ std::shared_ptr<ngraph::Node> makeCumSum(const ngraph::Output<Node> &in,
bool exclusive,
bool reverse);
std::shared_ptr<ngraph::Node> makeEmbeddingBagOffsetsSum(
const element::Type& dataType,
const element::Type& indicesType,
const ngraph::Output<Node>& emb_table_node,
const std::vector<size_t>& indices,
const std::vector<size_t>& offsets,
size_t default_index,
bool with_weights,
bool with_default_index);
std::shared_ptr<ngraph::Node> makeEmbeddingBagPackedSum(
const element::Type& dataType,
const element::Type& indicesType,
const ngraph::Output<Node>& emb_table_node,
const std::vector<std::vector<size_t>>& indices,
bool with_weights);
std::shared_ptr<ngraph::Node> makeEmbeddingSegmentsSum(
const element::Type& dataType,
const element::Type& indicesType,
const ngraph::Output<Node>& emb_table_node,
const std::vector<size_t>& indices,
const std::vector<size_t>& segment_ids,
size_t num_segments,
size_t default_index,
bool with_weights,
bool with_default_index);
} // namespace builder
} // namespace ngraph
@@ -0,0 +1,48 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <vector>
#include <memory>
#include "ngraph_functions/builders.hpp"
namespace ngraph {
namespace builder {
std::shared_ptr<Node> makeEmbeddingBagOffsetsSum(
const element::Type& dataType,
const element::Type& indicesType,
const ngraph::Output<Node>& embTableNode,
const std::vector<size_t>& indices,
const std::vector<size_t>& offsets,
size_t default_index,
bool with_weights,
bool with_default_index) {
std::vector<size_t> i_shape = {indices.size()};
auto indicesNode = std::make_shared<ngraph::opset1::Constant>(indicesType, i_shape, indices);
std::vector<size_t> o_shape = {offsets.size()};
auto offsetsNode = std::make_shared<ngraph::opset1::Constant>(indicesType, o_shape, offsets);
std::shared_ptr<Node> embBag;
if (with_default_index) {
std::vector<size_t> d_shape = {};
auto defIdxNode = std::make_shared<ngraph::opset1::Constant>(indicesType, d_shape, default_index);
if (with_weights) {
auto weightsNode = makeConstant(dataType, {indices.size()}, {}, true);
embBag = std::make_shared<opset3::EmbeddingBagOffsetsSum>(
embTableNode, indicesNode, offsetsNode, defIdxNode, weightsNode);
} else {
embBag = std::make_shared<opset3::EmbeddingBagOffsetsSum>(
embTableNode, indicesNode, offsetsNode, defIdxNode);
}
} else {
embBag = std::make_shared<opset3::EmbeddingBagOffsetsSum>(
embTableNode, indicesNode, offsetsNode);
}
return embBag;
}
} // namespace builder
} // namespace ngraph
@@ -0,0 +1,40 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <vector>
#include <memory>
#include "ngraph_functions/builders.hpp"
namespace ngraph {
namespace builder {
std::shared_ptr<Node> makeEmbeddingBagPackedSum(
const element::Type& dataType,
const element::Type& indicesType,
const ngraph::Output<Node>& embTableNode,
const std::vector<std::vector<size_t>>& indices,
bool with_weights) {
std::vector<size_t> i_shape({indices.size(), indices[0].size()});
size_t i_size = ngraph::shape_size(i_shape);
std::vector<size_t> i_values(i_size);
for (int i = 0; i < indices.size(); i++)
memcpy(i_values.data() + indices[0].size() * i, indices[i].data(), indices[0].size() * sizeof(size_t));
auto indicesNode = std::make_shared<ngraph::opset1::Constant>(indicesType, i_shape, i_values);
std::shared_ptr<Node> embBag;
if (with_weights) {
auto weightsNode = makeConstant(dataType, i_shape, {}, true);
embBag = std::make_shared<opset3::EmbeddingBagPackedSum>(
embTableNode, indicesNode, weightsNode);
} else {
embBag = std::make_shared<opset3::EmbeddingBagPackedSum>(
embTableNode, indicesNode);
}
return embBag;
}
} // namespace builder
} // namespace ngraph
@@ -0,0 +1,50 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <vector>
#include <memory>
#include "ngraph_functions/builders.hpp"
namespace ngraph {
namespace builder {
std::shared_ptr<Node> makeEmbeddingSegmentsSum(
const element::Type& dataType,
const element::Type& indicesType,
const ngraph::Output<Node>& embTableNode,
const std::vector<size_t>& indices,
const std::vector<size_t>& segment_ids,
size_t num_segments,
size_t default_index,
bool with_weights,
bool with_default_index) {
std::vector<size_t> i_shape = {indices.size()};
auto indicesNode = std::make_shared<ngraph::opset1::Constant>(indicesType, i_shape, indices);
std::vector<size_t> o_shape = {segment_ids.size()};
auto segmentIdNode = std::make_shared<ngraph::opset1::Constant>(indicesType, o_shape, segment_ids);
std::vector<size_t> shape_0 = {};
auto segmentNumNode = std::make_shared<ngraph::opset1::Constant>(indicesType, shape_0, num_segments);
std::shared_ptr<Node> embBag;
if (with_default_index) {
auto defIdxNode = std::make_shared<ngraph::opset1::Constant>(indicesType, shape_0, default_index);
if (with_weights) {
auto weightsNode = makeConstant(dataType, {indices.size()}, {}, true);
embBag = std::make_shared<opset3::EmbeddingSegmentsSum>(
embTableNode, indicesNode, segmentIdNode, segmentNumNode, defIdxNode, weightsNode);
} else {
embBag = std::make_shared<opset3::EmbeddingSegmentsSum>(
embTableNode, indicesNode, segmentIdNode, segmentNumNode, defIdxNode);
}
} else {
embBag = std::make_shared<opset3::EmbeddingSegmentsSum>(
embTableNode, indicesNode, segmentIdNode, segmentNumNode);
}
return embBag;
}
} // namespace builder
} // namespace ngraph
@@ -0,0 +1,98 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include "ngraph/shape_util.hpp"
namespace ngraph {
namespace runtime {
namespace reference {
template <typename T, typename U>
void embeddingBagOffsetsSum(
const T* emb_table,
const U* indices,
const U* offsets,
const U* default_index,
const T* weights,
T* out,
const size_t indices_count,
const Shape& outShape) {
const size_t offsets_size = outShape[0];
std::vector<U> default_indices;
if (default_index)
default_indices.push_back(default_index[0]);
size_t embDepth = 1;
for (size_t i = 1; i < outShape.size(); i++) {
embDepth *= outShape[i];
}
memset(out, 0, shape_size(outShape) * sizeof(T));
auto get_indices = [&](size_t emb_index, const U*& indices_ref, size_t& indices_num, size_t& weights_idx, bool& with_weights) {
if (emb_index >= offsets_size)
throw ngraph_error("Invalid embedding bag index.");
if (offsets[emb_index] >= indices_count)
throw ngraph_error(std::string("Offset value exceeds indices size in the model.\noffset: ")
+ std::to_string(offsets[emb_index]) + "; indices size: "
+ std::to_string(indices_count));
indices_ref = nullptr;
indices_num = 0lu;
with_weights = (weights != nullptr);
if (emb_index == offsets_size - 1lu)
indices_num = indices_count - offsets[emb_index];
else
indices_num = offsets[emb_index + 1lu] - offsets[emb_index];
if (indices_num != 0lu) {
indices_ref = indices + offsets[emb_index];
} else {
// Empty or default bag
with_weights = false;
if (default_indices.size() == 1lu) {
indices_ref = default_indices.data();
indices_num = 1lu;
}
return;
}
if (with_weights)
weights_idx = offsets[emb_index];
};
size_t indices_size = 0lu;
const U* indices_emb = nullptr;
size_t weights_idx = 0lu;
bool with_weights_b = (weights != nullptr);
bool with_weights = with_weights_b;
for (size_t obi = 0lu; obi < outShape.at(0); obi++) {
size_t dst_index = obi * embDepth;
get_indices(obi, indices_emb, indices_size, weights_idx, with_weights);
if (indices_emb != nullptr) {
with_weights = with_weights_b & with_weights;
for (size_t in_idx = 0lu; in_idx < indices_size; in_idx++) {
size_t src_index = indices_emb[in_idx] * embDepth;
if (with_weights) {
for (size_t i = 0lu; i < embDepth; i++) {
out[dst_index + i] += emb_table[src_index + i] * weights[weights_idx];
}
weights_idx++;
} else {
for (size_t i = 0lu; i < embDepth; i++) {
out[dst_index + i] += emb_table[src_index + i];
}
}
}
}
}
} // embeddingBagOffsetsSum
} // reference
} // runtime
} // ngraph
@@ -0,0 +1,52 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include "ngraph/shape_util.hpp"
namespace ngraph {
namespace runtime {
namespace reference {
template <typename T, typename U>
void embeddingBagPackedSum(
const T* emb_table,
const U* indices,
const T* weights,
T* out,
const Shape& indicesShape,
const Shape& outShape) {
const size_t indices_per_bag = indicesShape[1];
size_t embDepth = 1lu;
for (size_t i = 1; i < outShape.size(); i++) {
embDepth *= outShape[i];
}
memset(out, 0, shape_size(outShape) * sizeof(T));
bool with_weights = (weights != nullptr);
size_t idx_idx = 0lu;
for (size_t obi = 0lu; obi < outShape.at(0); obi++) {
size_t dst_index = obi * embDepth;
for (size_t in_idx = 0lu; in_idx < indices_per_bag; in_idx++, idx_idx++) {
size_t src_index = indices[idx_idx] * embDepth;
if (with_weights) {
for (size_t i = 0lu; i < embDepth; i++) {
out[dst_index + i] += emb_table[src_index + i] * weights[idx_idx];
}
} else {
for (size_t i = 0lu; i < embDepth; i++) {
out[dst_index + i] += emb_table[src_index + i];
}
}
}
}
} // embeddingBagPackedSum
} // reference
} // runtime
} // ngraph
@@ -0,0 +1,80 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include "ngraph/shape_util.hpp"
namespace ngraph {
namespace runtime {
namespace reference {
template <typename T, typename U>
void embeddingSegmentsSum(
const T* embTable,
const U* indices,
const U* segmentIds,
const U* defaultIndex,
const T* weights,
T* out,
const Shape& embTableShape,
const Shape& indicesShape,
const Shape& outShape) {
const size_t indices_len = indicesShape[0];
const size_t segments_num = outShape[0];
const size_t inDimsSize = outShape.size();
const size_t embDimsNum = outShape.size() - 1;
size_t embDepth = 1lu;
for (size_t i = 1; i < outShape.size(); i++) {
embDepth *= outShape[i];
}
memset(out, 0, shape_size(outShape) * sizeof(T));
bool with_weights = (weights != nullptr);
for (size_t index = 0; index < indices_len; index++) {
size_t obi = segmentIds[index];
if (obi >= segments_num)
throw ngraph_error("Segment index could not be more than segments number");
size_t dst_index = obi * embDepth;
size_t src_index = indices[index] * embDepth;
if (with_weights) {
for (size_t i = 0lu; i < embDepth; i++) {
out[dst_index + i] += embTable[src_index + i] * weights[index];
}
} else {
for (size_t i = 0lu; i < embDepth; i++) {
out[dst_index + i] += embTable[src_index + i];
}
}
}
if (defaultIndex != nullptr) {
U defIndex = defaultIndex[0];
if (defIndex < U(0) && defIndex >= embTableShape[0])
throw ngraph_error(std::string("Invalid default index") + std::to_string(defIndex)) ;
for (size_t obi = 0; obi < segments_num; obi++) {
bool found = false;
for (size_t index = 0; index < indices_len; index++) {
if (segmentIds[index] == obi) {
found = true;
break;
}
}
if (found)
continue;
size_t src_index = defIndex * embDepth;
size_t dst_index = obi * embDepth;
for (size_t i = 0lu; i < embDepth; i++) {
out[dst_index + i] = embTable[src_index + i];
}
}
}
} // embeddingSegmentsSum
} // reference
} // runtime
} // ngraph
+27
View File
@@ -456,6 +456,24 @@ namespace
EXPECT_FALSE(node.is_binary_elementwise_logical());
}
void op_is_EmbeddingBagOffsetsSum()
{
op::EmbeddingBagOffsetsSum node;
EXPECT_FALSE(node.is_unary_elementwise_arithmetic());
EXPECT_FALSE(node.is_binary_elementwise_arithmetic());
EXPECT_FALSE(node.is_binary_elementwise_comparison());
EXPECT_FALSE(node.is_binary_elementwise_logical());
}
void op_is_EmbeddingBagPackedSum()
{
op::EmbeddingBagPackedSum node;
EXPECT_FALSE(node.is_unary_elementwise_arithmetic());
EXPECT_FALSE(node.is_binary_elementwise_arithmetic());
EXPECT_FALSE(node.is_binary_elementwise_comparison());
EXPECT_FALSE(node.is_binary_elementwise_logical());
}
void op_is_EmbeddingLookup()
{
op::EmbeddingLookup node;
@@ -465,6 +483,15 @@ namespace
EXPECT_FALSE(node.is_binary_elementwise_logical());
}
void op_is_EmbeddingSegmentsSum()
{
op::EmbeddingSegmentsSum node;
EXPECT_FALSE(node.is_unary_elementwise_arithmetic());
EXPECT_FALSE(node.is_binary_elementwise_arithmetic());
EXPECT_FALSE(node.is_binary_elementwise_comparison());
EXPECT_FALSE(node.is_binary_elementwise_logical());
}
void op_is_Equal()
{
op::Equal node;
@@ -54,7 +54,10 @@
#include "ngraph/runtime/reference/dequantize.hpp"
#include "ngraph/runtime/reference/dot.hpp"
#include "ngraph/runtime/reference/elu.hpp"
#include "ngraph/runtime/reference/embedding_bag_offsets_sum.hpp"
#include "ngraph/runtime/reference/embedding_bag_packed_sum.hpp"
#include "ngraph/runtime/reference/embedding_lookup.hpp"
#include "ngraph/runtime/reference/embedding_segments_sum.hpp"
#include "ngraph/runtime/reference/erf.hpp"
#include "ngraph/runtime/reference/exp.hpp"
#include "ngraph/runtime/reference/extract_image_patches.hpp"
@@ -729,7 +732,100 @@ protected:
else
{
throw ngraph_error(std::string("Unsupported index type ") + type.c_type_string() +
std::string("in EmbeddingLookup"));
std::string(" in EmbeddingLookup"));
}
break;
}
case OP_TYPEID::EmbeddingBagOffsetsSum_v3:
{
const op::EmbeddingBagOffsetsSum* embed = static_cast<const op::EmbeddingBagOffsetsSum*>(&node);
auto indicesType = embed->input(1).get_element_type();
size_t indices_num = shape_size(embed->get_input_shape(1));
if (indicesType == element::u64 || indicesType == element::i64) {
reference::embeddingBagOffsetsSum<T, size_t>(
args[0]->get_data_ptr<const T>(),
args[1]->get_data_ptr<const size_t>(),
args[2]->get_data_ptr<const size_t>(),
args.size() > 3 ? args[3]->get_data_ptr<const size_t>() : nullptr,
args.size() > 4 ? args[4]->get_data_ptr<const T>() : nullptr,
out[0]->get_data_ptr<T>(),
indices_num,
embed->get_shape());
} else if (indicesType == element::u32 || indicesType == element::i32) {
reference::embeddingBagOffsetsSum<T, unsigned>(
args[0]->get_data_ptr<const T>(),
args[1]->get_data_ptr<const unsigned>(),
args[2]->get_data_ptr<const unsigned>(),
args.size() > 3 ? args[3]->get_data_ptr<const unsigned>() : nullptr,
args.size() > 4 ? args[4]->get_data_ptr<const T>() : nullptr,
out[0]->get_data_ptr<T>(),
indices_num,
embed->get_shape());
} else {
throw ngraph_error(std::string("Unsupported index type ") + indicesType.c_type_string() +
std::string(" in EmbeddingBagOffsetsSum"));
}
break;
}
case OP_TYPEID::EmbeddingBagPackedSum_v3:
{
const op::EmbeddingBagPackedSum* embed = static_cast<const op::EmbeddingBagPackedSum*>(&node);
auto indicesType = embed->input(1).get_element_type();
if (indicesType == element::u64 || indicesType == element::i64) {
reference::embeddingBagPackedSum<T, size_t>(
args[0]->get_data_ptr<const T>(),
args[1]->get_data_ptr<const size_t>(),
args.size() > 2 ? args[2]->get_data_ptr<const T>() : nullptr,
out[0]->get_data_ptr<T>(),
embed->get_input_shape(1),
embed->get_shape());
} else if (indicesType == element::u32 || indicesType == element::i32) {
reference::embeddingBagPackedSum<T, unsigned>(
args[0]->get_data_ptr<const T>(),
args[1]->get_data_ptr<const unsigned>(),
args.size() > 2 ? args[2]->get_data_ptr<const T>() : nullptr,
out[0]->get_data_ptr<T>(),
embed->get_input_shape(1),
embed->get_shape());
} else {
throw ngraph_error(std::string("Unsupported index type ") + indicesType.c_type_string() +
std::string(" in EmbeddingBagPackedSum"));
}
break;
}
case OP_TYPEID::EmbeddingSegmentsSum_v3:
{
const op::EmbeddingSegmentsSum* embed = static_cast<const op::EmbeddingSegmentsSum*>(&node);
auto indicesType = embed->input(1).get_element_type();
size_t indices_num = shape_size(embed->get_input_shape(1));
if (indicesType == element::u64 || indicesType == element::i64) {
reference::embeddingSegmentsSum<T, size_t>(
args[0]->get_data_ptr<const T>(),
args[1]->get_data_ptr<const size_t>(),
args[2]->get_data_ptr<const size_t>(),
args.size() > 4 ? args[4]->get_data_ptr<const size_t>() : nullptr,
args.size() > 5 ? args[5]->get_data_ptr<const T>() : nullptr,
out[0]->get_data_ptr<T>(),
embed->get_input_shape(0),
embed->get_input_shape(1),
embed->get_shape());
} else if (indicesType == element::u32 || indicesType == element::i32) {
reference::embeddingSegmentsSum<T, unsigned>(
args[0]->get_data_ptr<const T>(),
args[1]->get_data_ptr<const unsigned>(),
args[2]->get_data_ptr<const unsigned>(),
args.size() > 4 ? args[4]->get_data_ptr<const unsigned>() : nullptr,
args.size() > 5 ? args[5]->get_data_ptr<const T>() : nullptr,
out[0]->get_data_ptr<T>(),
embed->get_input_shape(0),
embed->get_input_shape(1),
embed->get_shape());
} else {
throw ngraph_error(std::string("Unsupported index type ") + indicesType.c_type_string() +
std::string(" in EmbeddingSegmentsSum"));
}
break;
}
@@ -27,6 +27,9 @@ NGRAPH_OP(LogicalNot, op::v1)
#undef ID_SUFFIX
#define ID_SUFFIX(NAME) NAME##_v3
NGRAPH_OP(EmbeddingBagOffsetsSum, op::v3)
NGRAPH_OP(EmbeddingBagPackedSum, op::v3)
NGRAPH_OP(EmbeddingSegmentsSum, op::v3)
NGRAPH_OP(ExtractImagePatches, op::v3)
NGRAPH_OP(ShapeOf, op::v3)
NGRAPH_OP(NonZero, op::v3)