chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==============================================================================*/
|
||||
|
||||
//
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com)
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_batch_to_space)
|
||||
|
||||
#include <ops/declarable/headers/parity_ops.h>
|
||||
#include <ops/declarable/helpers/s_t_b.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
CUSTOM_OP_IMPL(batch_to_space, 2, 1, false, 0, 1) {
|
||||
// [bS*blockSize*blockSize, H/blockSize, W/blockSize, iC] is rearranged/permuted to [bS, oH, oW, iC]
|
||||
// oH = H - cropTop - cropBottom
|
||||
// oW = W - cropLeft - cropRight
|
||||
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto crop = INPUT_VARIABLE(1);
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
const LongType blockSize = INT_ARG(0);
|
||||
REQUIRE_TRUE(blockSize >= 2, 0, "BatchToSpace: integer parameter block_size must be >= 2, but got %i instead",
|
||||
blockSize);
|
||||
|
||||
const int rank = input->rankOf();
|
||||
const int dim0 = input->sizeAt(0);
|
||||
REQUIRE_TRUE(rank == 4, 0, "BatchToSpace: rank of input array must be equal 4, but got %i instead", rank);
|
||||
REQUIRE_TRUE(dim0 % (blockSize * blockSize) == 0, 0,
|
||||
"BatchToSpace: first dimension of input array must be divisible by blockSize * blockSize (that is by "
|
||||
"%i), but got first dimension equal to %i",
|
||||
blockSize * blockSize, dim0);
|
||||
|
||||
if (crop->sizeAt(0) != 2 || crop->sizeAt(1) != 2)
|
||||
REQUIRE_TRUE(false, 0, "BatchToSpace: operation expects crop shape to be {2, 2}, but got %s instead",
|
||||
ShapeUtils::shapeAsString(crop).c_str());
|
||||
|
||||
const LongType cropBottom = crop->e<LongType>(0, 0);
|
||||
const LongType cropTop = crop->e<LongType>(0, 1);
|
||||
const LongType cropLeft = crop->e<LongType>(1, 0);
|
||||
const LongType cropRight = crop->e<LongType>(1, 1);
|
||||
|
||||
const int oH = input->sizeAt(1) * blockSize - cropBottom - cropTop; // top and bottom
|
||||
const int oW = input->sizeAt(2) * blockSize - cropLeft - cropRight; // left and right
|
||||
REQUIRE_TRUE(oH >= 0, 0,
|
||||
"BatchToSpace: crop top/bottom values are too big and cause negative output height dimension !");
|
||||
REQUIRE_TRUE(oW >= 0, 0,
|
||||
"BatchToSpace: crop left/right values are too big and cause negative output width dimension !");
|
||||
|
||||
if (shape::strideDescendingCAscendingF(input->shapeInfo()))
|
||||
helpers::batchToSpace(block.launchContext(), *input, *output, cropBottom, cropTop, cropLeft, cropRight, blockSize);
|
||||
else {
|
||||
auto dupped = input->dup(input->ordering());
|
||||
helpers::batchToSpace(block.launchContext(), *dupped, *output, cropBottom, cropTop, cropLeft, cropRight, blockSize);
|
||||
delete dupped;
|
||||
}
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
DECLARE_TYPES(batch_to_space) {
|
||||
getOpDescriptor()->setAllowedInputTypes(0, ANY)->setAllowedInputTypes(1, {ALL_INTS})->setSameMode(true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
DECLARE_SHAPE_FN(batch_to_space) {
|
||||
auto inputShapeInfo = inputShape->at(0);
|
||||
auto cropShapeInfo = inputShape->at(1);
|
||||
|
||||
const LongType blockSize = INT_ARG(0);
|
||||
REQUIRE_TRUE(blockSize >= 2, 0, "BatchToSpace: integer parameter block_size must be >= 2, but got %i instead",
|
||||
blockSize);
|
||||
|
||||
const int rank = inputShapeInfo[0];
|
||||
const int dim0 = inputShapeInfo[1];
|
||||
REQUIRE_TRUE(rank == 4, 0, "BatchToSpace: rank of input array must be equal 4, but got %i instead", rank);
|
||||
REQUIRE_TRUE(dim0 % (blockSize * blockSize) == 0, 0,
|
||||
"BatchToSpace: first dimension of input array must be divisible by blockSize * blockSize (that is by "
|
||||
"%i), but got first dimension equal to %i",
|
||||
blockSize * blockSize, dim0);
|
||||
|
||||
if (cropShapeInfo[1] != 2 || cropShapeInfo[2] != 2)
|
||||
REQUIRE_TRUE(false, 0, "BatchToSpace: operation expects crop shape to be {2, 2}, but got %s instead",
|
||||
ShapeUtils::shapeAsString(cropShapeInfo).c_str());
|
||||
|
||||
const LongType cropBottom = INPUT_VARIABLE(1)->e<LongType>(0, 0);
|
||||
const LongType cropTop = INPUT_VARIABLE(1)->e<LongType>(0, 1);
|
||||
const LongType cropLeft = INPUT_VARIABLE(1)->e<LongType>(1, 0);
|
||||
const LongType cropRight = INPUT_VARIABLE(1)->e<LongType>(1, 1);
|
||||
|
||||
const int oH = inputShapeInfo[2] * blockSize - cropTop - cropBottom; // top and bottom
|
||||
const int oW = inputShapeInfo[3] * blockSize - cropLeft - cropRight; // left and right
|
||||
REQUIRE_TRUE(oH >= 0, 0,
|
||||
"BatchToSpace: crop top/bottom values are too big and cause negative output height dimension !");
|
||||
REQUIRE_TRUE(oW >= 0, 0,
|
||||
"BatchToSpace: crop left/right values are too big and cause negative output width dimension !");
|
||||
|
||||
// we always give out C order here
|
||||
return SHAPELIST(ConstantShapeHelper::getInstance().createShapeInfo(
|
||||
ArrayOptions::dataType(inputShapeInfo), 'c', {dim0 / (blockSize * blockSize), oH, oW, inputShapeInfo[4]}));
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,148 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==============================================================================*/
|
||||
|
||||
//
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com)
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_batch_to_space_nd)
|
||||
|
||||
#include <ops/declarable/headers/parity_ops.h>
|
||||
#include <ops/declarable/helpers/s_t_b.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
CUSTOM_OP_IMPL(batch_to_space_nd, 3, 1, false, 0, 0) {
|
||||
// 4D example, numOfSpatialDims = 2 - two spatial dimensions
|
||||
// [bS*blockShape[0]*blockShape[1], iH, iW, iC] is rearranged/permuted to [bS, iH*blockShape[0] - cropTop -
|
||||
// cropBottom, iW*blockShape[1] - cropLeft - cropRight, iC]
|
||||
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto blockShape = INPUT_VARIABLE(1);
|
||||
auto crop = INPUT_VARIABLE(2);
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
REQUIRE_TRUE(blockShape->rankOf() == 1, 0,
|
||||
"BatchToSpaceND: rank of blockShape array must be equal to one, but got %i instead !",
|
||||
blockShape->rankOf());
|
||||
|
||||
const sd::LongType numOfSpatialDims = blockShape->sizeAt(0);
|
||||
|
||||
auto prod = blockShape->reduceNumber(sd::reduce::Prod);
|
||||
const auto product = prod->e<sd::LongType>(0);
|
||||
delete prod;
|
||||
REQUIRE_TRUE(input->sizeAt(0) % product == 0, 0,
|
||||
"BatchToSpaceND: first dimension of input array must be divisible by product of blockShape array "
|
||||
"elements (= %lld), but got first dimension equal to %i",
|
||||
product, input->sizeAt(0));
|
||||
|
||||
if (crop->sizeAt(0) != numOfSpatialDims || crop->sizeAt(1) != 2) {
|
||||
const std::string expectedCropShape = "[" + std::to_string(numOfSpatialDims) + ", 2]"; // [numOfSpatialDims, 2]
|
||||
REQUIRE_TRUE(false, 0, "BatchToSpaceND: operation expects padding shape to be %s, but got %s instead",
|
||||
expectedCropShape.c_str(), ShapeUtils::shapeAsString(crop).c_str());
|
||||
}
|
||||
|
||||
// FIXME - should we use this time-consuming validation ?
|
||||
for (sd::LongType i = 0; i < numOfSpatialDims; ++i) {
|
||||
const auto cropLeft = crop->e<sd::LongType>(i, 0);
|
||||
const auto cropRight = crop->e<sd::LongType>(i, 1);
|
||||
const auto outSpatialDim = input->sizeAt(i + 1) * blockShape->e<sd::LongType>(i) - cropLeft - cropRight;
|
||||
REQUIRE_TRUE(
|
||||
outSpatialDim >= 0, 0,
|
||||
"BatchToSpaceND: crop left/right values are too big and cause negative output spatial dimension/dimensions !");
|
||||
}
|
||||
|
||||
if (shape::strideDescendingCAscendingF(input->shapeInfo()))
|
||||
helpers::batchToSpaceND(block.launchContext(), *input, *blockShape, *crop, *output);
|
||||
else {
|
||||
auto dupped = input->dup();
|
||||
helpers::batchToSpaceND(block.launchContext(), *dupped, *blockShape, *crop, *output);
|
||||
delete dupped;
|
||||
}
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
DECLARE_TYPES(batch_to_space_nd) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, sd::DataType::ANY)
|
||||
->setAllowedInputTypes(1, {ALL_INTS})
|
||||
->setAllowedInputTypes(2, {ALL_INTS})
|
||||
->setSameMode(true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
DECLARE_SHAPE_FN(batch_to_space_nd) {
|
||||
auto inputShapeInfo = inputShape->at(0);
|
||||
auto blockShapeInfo = inputShape->at(1);
|
||||
auto cropShapeInfo = inputShape->at(2);
|
||||
|
||||
REQUIRE_TRUE(blockShapeInfo[0] == 1, 0,
|
||||
"BatchToSpaceND: rank of blockShape array must be equal to one, but got %i instead !",
|
||||
blockShapeInfo[0]);
|
||||
|
||||
auto prod = INPUT_VARIABLE(1)->reduceNumber(sd::reduce::Prod);
|
||||
const auto product = prod->e<sd::LongType>(0);
|
||||
delete prod;
|
||||
REQUIRE_TRUE(inputShapeInfo[1] % product == 0, 0,
|
||||
"BatchToSpaceND: first dimension of input array must be divisible by product of blockShape array "
|
||||
"elements (= %lld), but got first dimension equal to %i",
|
||||
product, inputShapeInfo[1]);
|
||||
|
||||
const auto numOfSpatialDims = blockShapeInfo[1];
|
||||
|
||||
if (cropShapeInfo[1] != numOfSpatialDims || cropShapeInfo[2] != 2) {
|
||||
const std::string expectedCropShape = "[" + std::to_string(numOfSpatialDims) + ", 2]"; // [numOfSpatialDims, 2]
|
||||
REQUIRE_TRUE(false, 0, "BatchToSpaceND: operation expects padding shape to be %s, but got %s instead",
|
||||
expectedCropShape.c_str(), ShapeUtils::shapeAsString(cropShapeInfo).c_str());
|
||||
}
|
||||
|
||||
std::vector<sd::LongType> outShape(inputShapeInfo + 1, inputShapeInfo + 1 + inputShapeInfo[0]);
|
||||
|
||||
outShape[0] /= product;
|
||||
|
||||
for (sd::LongType i = 0; i < numOfSpatialDims; ++i)
|
||||
outShape[i + 1] = outShape[i + 1] * INPUT_VARIABLE(1)->e<sd::LongType>(i) -
|
||||
INPUT_VARIABLE(2)->e<sd::LongType>(i, 0) - INPUT_VARIABLE(2)->e<sd::LongType>(i, 1);
|
||||
|
||||
return SHAPELIST(
|
||||
ConstantShapeHelper::getInstance().createShapeInfo(ArrayOptions::dataType(inputShapeInfo), 'c', outShape));
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,92 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com)
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_clipbyavgnorm)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/transforms.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CONFIGURABLE_OP_IMPL(clipbyavgnorm, -1, 1, true, -2, 0) {
|
||||
if (block.inputs()->size() > 1) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto clipNorm = INPUT_VARIABLE(1);
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
const bool isInplace = block.isInplace();
|
||||
helpers::clipByNorm(block.launchContext(), input, output, *block.getIArguments(), clipNorm, isInplace, true);
|
||||
} else {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
const bool isInplace = block.isInplace();
|
||||
auto clipNorm = NDArrayFactory::create(T_ARG(0), block.launchContext());
|
||||
|
||||
helpers::clipByNorm(block.launchContext(), input, output, *block.getIArguments(), clipNorm, isInplace, true);
|
||||
delete clipNorm;
|
||||
}
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(clipbyavgnorm) {
|
||||
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CUSTOM_OP_IMPL(clipbyavgnorm_bp, -2, 1, false, -1, 0) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto gradO = INPUT_VARIABLE(1);
|
||||
|
||||
auto gradI = OUTPUT_VARIABLE(0);
|
||||
if (block.inputs()->size() > 2) {
|
||||
const auto clipNorm = INPUT_VARIABLE(2);
|
||||
helpers::clipByNormBp(block.launchContext(), input, gradO, gradI, *block.getIArguments(), clipNorm, true);
|
||||
} else {
|
||||
auto clipNorm = NDArrayFactory::create(gradI->dataType(), T_ARG(0), block.launchContext());
|
||||
helpers::clipByNormBp(block.launchContext(), input, gradO, gradI, *block.getIArguments(), clipNorm, true);
|
||||
delete clipNorm;
|
||||
}
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
DECLARE_SHAPE_FN(clipbyavgnorm_bp) {
|
||||
return SHAPELIST(CONSTANT(inputShape->at(1)));
|
||||
}
|
||||
|
||||
DECLARE_TYPES(clipbyavgnorm_bp) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, DataType::ANY)
|
||||
->setAllowedInputTypes(1, {ALL_FLOATS})
|
||||
->setAllowedOutputTypes(0, {ALL_FLOATS});
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,69 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author sgazeos@gmail.com
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_clip_by_global_norm)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/transforms.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
CUSTOM_OP_IMPL(clip_by_global_norm, 1, 2, true, 1, 0) {
|
||||
std::vector<NDArray*> inputs(block.width());
|
||||
std::vector<NDArray*> outputs(block.width() + 1);
|
||||
for (size_t i = 0; i < inputs.size(); ++i) {
|
||||
inputs[i] = INPUT_VARIABLE(i);
|
||||
outputs[i] = OUTPUT_VARIABLE(i);
|
||||
}
|
||||
outputs[inputs.size()] = OUTPUT_VARIABLE(inputs.size());
|
||||
double clipNorm = T_ARG(0);
|
||||
bool isInplace = block.isInplace();
|
||||
helpers::clipByGlobalNorm(block.launchContext(), inputs, clipNorm, block.workspace(), outputs, isInplace);
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(clip_by_global_norm) {
|
||||
auto shapeList = SHAPELIST();
|
||||
|
||||
for (size_t e = 0; e < block.width(); e++) {
|
||||
auto in = inputShape->at(e);
|
||||
|
||||
sd::LongType* newShape;
|
||||
COPY_SHAPE(in, newShape);
|
||||
shapeList->push_back(CONSTANT(newShape));
|
||||
}
|
||||
|
||||
shapeList->push_back(ConstantShapeHelper::getInstance().scalarShapeInfo(ArrayOptions::dataType(inputShape->at(0))));
|
||||
return shapeList;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(clip_by_global_norm) {
|
||||
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,88 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_clipbynorm)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/transforms.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
CONFIGURABLE_OP_IMPL(clipbynorm, 1, 1, true, 1, 0) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
if (block.numT() > 0) {
|
||||
auto clipNorm = NDArrayFactory::create(output->dataType(), T_ARG(0), block.launchContext());
|
||||
const bool isInplace = block.isInplace();
|
||||
helpers::clipByNorm(block.launchContext(), input, output, *block.getIArguments(), clipNorm, isInplace, false);
|
||||
delete clipNorm;
|
||||
} else {
|
||||
auto clipNorm = INPUT_VARIABLE(1);
|
||||
const bool isInplace = block.isInplace();
|
||||
helpers::clipByNorm(block.launchContext(), input, output, *block.getIArguments(), clipNorm, isInplace, false);
|
||||
}
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
CUSTOM_OP_IMPL(clipbynorm_bp, 2, 1, false, 1, 0) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto gradO = INPUT_VARIABLE(1);
|
||||
|
||||
auto gradI = OUTPUT_VARIABLE(0);
|
||||
if (block.numT() > 0) {
|
||||
auto clipNorm = NDArrayFactory::create(gradI->dataType(), T_ARG(0), block.launchContext());
|
||||
helpers::clipByNormBp(block.launchContext(), input, gradO, gradI, *block.getIArguments(), clipNorm, false);
|
||||
delete clipNorm;
|
||||
} else {
|
||||
const auto clipNorm = INPUT_VARIABLE(1);
|
||||
helpers::clipByNormBp(block.launchContext(), input, gradO, gradI, *block.getIArguments(), clipNorm, false);
|
||||
}
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(clipbynorm_bp) {
|
||||
auto inShapeInfo = inputShape->at(1);
|
||||
|
||||
LongType *newShape = nullptr;
|
||||
COPY_SHAPE(inShapeInfo, newShape);
|
||||
|
||||
return SHAPELIST(CONSTANT(newShape));
|
||||
}
|
||||
|
||||
DECLARE_TYPES(clipbynorm) {
|
||||
getOpDescriptor()->setAllowedInputTypes(ANY)->setAllowedOutputTypes({ALL_FLOATS});
|
||||
}
|
||||
|
||||
DECLARE_TYPES(clipbynorm_bp) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, ANY)
|
||||
->setAllowedInputTypes(1, {ALL_FLOATS})
|
||||
->setAllowedOutputTypes(0, {ALL_FLOATS});
|
||||
}
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,163 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
// @author Adam Gibson
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_clipbyvalue)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/transforms.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
CONFIGURABLE_OP_IMPL(clipbyvalue, -2, 1, true, -2, 0) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
if (block.getTArguments()->size() > 0) {
|
||||
auto left = T_ARG(0);
|
||||
auto right = T_ARG(1);
|
||||
|
||||
REQUIRE_TRUE(left < right, 0, "clip_by_value: left bound should be lesser than right. But %f >= %f given.", left,
|
||||
right);
|
||||
helpers::clipByValue(block.launchContext(), input, left, right, output);
|
||||
|
||||
} else {
|
||||
auto left = INPUT_VARIABLE(1);
|
||||
auto right = INPUT_VARIABLE(2);
|
||||
|
||||
switch (input->dataType()) {
|
||||
#if defined(HAS_DOUBLE)
|
||||
case DOUBLE: {
|
||||
auto leftValueDouble = left->e<double>(0);
|
||||
auto rightValueDouble = right->e<double>(0);
|
||||
helpers::clipByValue(block.launchContext(), input, leftValueDouble, rightValueDouble, output);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if defined(HAS_FLOAT32)
|
||||
case FLOAT32: {
|
||||
auto leftValueFloat = left->e<float>(0);
|
||||
auto rightValueFloat = right->e<float>(0);
|
||||
helpers::clipByValue(block.launchContext(), input, leftValueFloat, rightValueFloat, output);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if defined(HAS_FLOAT16)
|
||||
case HALF: {
|
||||
auto leftValueFloat16 = left->e<float16>(0);
|
||||
auto rightValueFloat16 = right->e<float16>(0);
|
||||
helpers::clipByValue(block.launchContext(), input, leftValueFloat16, rightValueFloat16, output);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if defined(HAS_BFLOAT16)
|
||||
case BFLOAT16: {
|
||||
auto leftValueBFloat16 = left->e<bfloat16>(0);
|
||||
auto rightValueBFloat16 = right->e<bfloat16>(0);
|
||||
helpers::clipByValue(block.launchContext(), input, leftValueBFloat16, rightValueBFloat16, output);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
// Non-floating point types that might be present but not used in clip_by_value
|
||||
case INHERIT:
|
||||
break;
|
||||
#if defined(HAS_BOOL)
|
||||
case BOOL:
|
||||
break;
|
||||
#endif
|
||||
case FLOAT8:
|
||||
break;
|
||||
case HALF2:
|
||||
break;
|
||||
#if defined(HAS_INT8)
|
||||
case INT8:
|
||||
break;
|
||||
#endif
|
||||
#if defined(HAS_INT16)
|
||||
case INT16:
|
||||
break;
|
||||
#endif
|
||||
#if defined(HAS_INT32)
|
||||
case INT32:
|
||||
break;
|
||||
#endif
|
||||
#if defined(HAS_LONG)
|
||||
case INT64:
|
||||
break;
|
||||
#endif
|
||||
#if defined(HAS_UINT8)
|
||||
case UINT8:
|
||||
break;
|
||||
#endif
|
||||
#if defined(HAS_UINT16)
|
||||
case UINT16:
|
||||
break;
|
||||
#endif
|
||||
#if defined(HAS_UINT32)
|
||||
case UINT32:
|
||||
break;
|
||||
#endif
|
||||
#if defined(HAS_UNSIGNEDLONG)
|
||||
case UINT64:
|
||||
break;
|
||||
#endif
|
||||
case QINT8:
|
||||
break;
|
||||
case QINT16:
|
||||
break;
|
||||
#if defined(HAS_UTF8)
|
||||
case UTF8:
|
||||
break;
|
||||
#endif
|
||||
#if defined(HAS_UTF16)
|
||||
case UTF16:
|
||||
break;
|
||||
#endif
|
||||
#if defined(HAS_UTF32)
|
||||
case UTF32:
|
||||
break;
|
||||
#endif
|
||||
case ANY:
|
||||
break;
|
||||
case AUTO:
|
||||
break;
|
||||
case UNKNOWN:
|
||||
break;
|
||||
default:
|
||||
// Handle any other types that might not be covered
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_SYN(ClipByValue, clipbyvalue);
|
||||
|
||||
DECLARE_TYPES(clipbyvalue) {
|
||||
getOpDescriptor()->setAllowedInputTypes(ANY)->setAllowedOutputTypes({ALL_FLOATS});
|
||||
}
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,366 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com)
|
||||
//
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/transforms.h>
|
||||
|
||||
#include <array>
|
||||
#if NOT_EXCLUDED(OP_concat)
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CUSTOM_OP_IMPL(concat, -1, 1, false, 0, 0) {
|
||||
REQUIRE_TRUE(block.width() > 0, 0, "CONCAT op: No input arrays were provided");
|
||||
|
||||
const bool isAxisInLastArr = block.getBArguments()->size() == 0 ? false : B_ARG(0);
|
||||
|
||||
const int numOfInArrs = isAxisInLastArr ? block.width() - 1 : block.width();
|
||||
|
||||
// first of all take into account possible presence of empty arrays
|
||||
// also if scalar is present -> copy its value to vector with length=1
|
||||
std::vector<NDArray*> nonEmptyArrs;
|
||||
std::vector<NDArray*> arrsToDelete; // Track allocated arrays for cleanup
|
||||
LongType index = 0;
|
||||
bool allOfSameType = true;
|
||||
auto rankOfFirstArr = block.width() > 0 ? INPUT_VARIABLE(0)->rankOf() : 0;
|
||||
auto typeOfFirstArr = block.width() > 0 ? INPUT_VARIABLE(0)->dataType() : block.dataType();
|
||||
|
||||
for (LongType i = 0; i < numOfInArrs; ++i) {
|
||||
auto input = INPUT_VARIABLE(i);
|
||||
if (!input->isEmpty()) {
|
||||
allOfSameType &= (typeOfFirstArr == input->dataType());
|
||||
|
||||
if (input->rankOf() == 0) {
|
||||
std::vector<sd::LongType> shape = {1};
|
||||
NDArray* vec = nullptr;
|
||||
#ifdef __cpp_exceptions
|
||||
try {
|
||||
vec = new NDArray('c', shape, input->dataType(), block.launchContext());
|
||||
vec->assign(input);
|
||||
nonEmptyArrs.push_back(vec);
|
||||
arrsToDelete.push_back(vec); // Mark for cleanup
|
||||
} catch (...) {
|
||||
// If allocation fails, clean up what we've created so far
|
||||
if (vec) delete vec;
|
||||
for (auto arr : arrsToDelete) {
|
||||
delete arr;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
#else
|
||||
vec = new NDArray('c', shape, input->dataType(), block.launchContext());
|
||||
vec->assign(input);
|
||||
nonEmptyArrs.push_back(vec);
|
||||
arrsToDelete.push_back(vec); // Mark for cleanup
|
||||
#endif
|
||||
} else {
|
||||
nonEmptyArrs.push_back(input);
|
||||
}
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
const LongType numOfNonEmptyArrs = nonEmptyArrs.size();
|
||||
|
||||
if (numOfNonEmptyArrs == 0) {
|
||||
// Clean up allocated temporary arrays before returning
|
||||
for (auto arr : arrsToDelete) {
|
||||
if(arr != nullptr) {
|
||||
delete arr;
|
||||
|
||||
}
|
||||
}
|
||||
// All inputs are empty arrays -> return empty, mainly for TF import compatibility (no op)
|
||||
REQUIRE_TRUE(OUTPUT_VARIABLE(0)->isEmpty(), 0, "CONCAT op: If all input variables are empty, output must be empty");
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
const LongType rank = nonEmptyArrs[0]->rankOf(); // look up to first non-empty array
|
||||
LongType axis = isAxisInLastArr ? INPUT_VARIABLE(block.width() - 1)->e<LongType>(0) : INT_ARG(0);
|
||||
if (axis < 0) {
|
||||
axis += rank;
|
||||
}
|
||||
|
||||
// ******** input validation ******** //
|
||||
if (!allOfSameType) {
|
||||
for (auto arr : arrsToDelete) delete arr;
|
||||
REQUIRE_TRUE(false, 0, "CONCAT op: all of input arrays must have same type !");
|
||||
}
|
||||
|
||||
if (nonEmptyArrs[0]->dataType() != OUTPUT_VARIABLE(0)->dataType()) {
|
||||
for (auto arr : arrsToDelete) delete arr;
|
||||
REQUIRE_TRUE(false, 0, "CONCAT op: output array should have the same type as inputs arrays !");
|
||||
}
|
||||
|
||||
if (!(0 <= axis && (axis < rank || (axis == 0 && rank == 0)))) {
|
||||
for (auto arr : arrsToDelete) delete arr;
|
||||
REQUIRE_TRUE(false, 0, "CONCAT op: input axis must be in range [0, %i], but got %i instead!", rank - 1, axis);
|
||||
}
|
||||
|
||||
for (LongType i = 1; i < numOfNonEmptyArrs; ++i) {
|
||||
if (nonEmptyArrs[i]->rankOf() != rank) {
|
||||
std::string error;
|
||||
error += "CONCAT op: array at index ";
|
||||
error += std::to_string(i);
|
||||
error += " did not have same rank. Expected rank: ";
|
||||
error += std::to_string(rank);
|
||||
error += " but was: ";
|
||||
error += std::to_string(nonEmptyArrs[i]->rankOf());
|
||||
|
||||
// Cleanup before throwing
|
||||
for (auto arr : arrsToDelete) delete arr;
|
||||
REQUIRE_TRUE(false, 0, error.c_str());
|
||||
}
|
||||
|
||||
for (LongType dim = 0; dim < rank; ++dim) {
|
||||
if (dim != axis) {
|
||||
if (nonEmptyArrs[i]->sizeAt(dim) != nonEmptyArrs[0]->sizeAt(dim)) {
|
||||
std::string error;
|
||||
error += "CONCAT op: array at index ";
|
||||
error += std::to_string(i);
|
||||
error += " did not have same dimension at position ";
|
||||
error += std::to_string(dim);
|
||||
error += ". Expected dimension: ";
|
||||
error += std::to_string(nonEmptyArrs[0]->sizeAt(dim));
|
||||
error += " but was: ";
|
||||
error += std::to_string(nonEmptyArrs[i]->sizeAt(dim));
|
||||
|
||||
// Cleanup before throwing
|
||||
for (auto arr : arrsToDelete) delete arr;
|
||||
REQUIRE_TRUE(false, 0, error.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ******** end of input validation ******** //
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
helpers::concat(block.launchContext(), nonEmptyArrs, *output, axis);
|
||||
|
||||
// Clean up allocated temporary arrays
|
||||
for (auto arr : arrsToDelete) {
|
||||
delete arr;
|
||||
}
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_SYN(ParallelConcat, concat);
|
||||
DECLARE_SYN(concat_v2, concat);
|
||||
DECLARE_SYN(concatv2, concat);
|
||||
|
||||
DECLARE_TYPES(concat) {
|
||||
getOpDescriptor()->setAllowedInputTypes(ANY);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
DECLARE_SHAPE_FN(concat) {
|
||||
REQUIRE_TRUE(block.width() > 0, 0, "CONCAT op: No input arrays were provided");
|
||||
|
||||
const bool isAxisInLastArr = block.getBArguments()->size() == 0 ? false : B_ARG(0);
|
||||
|
||||
//used for copying shape later if we have a mix of empty and non empty
|
||||
//all arrays but empty should fit same pattern
|
||||
int firstNonEmptyShapeIdx = -1;
|
||||
const LongType numOfInArrs = isAxisInLastArr ? block.width() - 1 : block.width();
|
||||
// first of all take into account possible presence of empty arrays
|
||||
// also if scalar is present -> use the shape of vector with length=1 instead
|
||||
ShapeList arrShapes;
|
||||
std::vector<LongType> shapesToDelete;
|
||||
LongType numOfNonEmptyArrs = 0;
|
||||
const LongType rank = shape::rank(INPUT_VARIABLE(0)->shapeInfo());
|
||||
LongType newDim = 0;
|
||||
LongType axis = isAxisInLastArr ? INPUT_VARIABLE(block.width() - 1)->e<LongType>(0) : INT_ARG(0);
|
||||
if (axis < 0) {
|
||||
axis += rank;
|
||||
}
|
||||
|
||||
for (LongType i = 0; i < numOfInArrs; i++) {
|
||||
if (shape::rank(inputShape->at(i)) <= 1) {
|
||||
if (shape::isEmptyConst(inputShape->at(i))) {
|
||||
int isScalar = shape::isScalar(inputShape->at(i));
|
||||
int len = isScalar ? 1 : shape::length(inputShape->at(i));
|
||||
newDim += len;
|
||||
arrShapes.push_back(inputShape->at(i));
|
||||
} else {
|
||||
int isScalar = shape::isScalar(inputShape->at(i));
|
||||
int len = isScalar ? 1 : shape::length(inputShape->at(i));
|
||||
newDim += len;
|
||||
arrShapes.push_back(ConstantShapeHelper::getInstance().vectorShapeInfo(len, INPUT_VARIABLE(0)->dataType()));
|
||||
|
||||
if (firstNonEmptyShapeIdx < 0)
|
||||
firstNonEmptyShapeIdx = i;
|
||||
numOfNonEmptyArrs++;
|
||||
}
|
||||
} else {
|
||||
if (!shape::isEmptyConst(inputShape->at(i))) {
|
||||
numOfNonEmptyArrs++;
|
||||
if (firstNonEmptyShapeIdx < 0)
|
||||
firstNonEmptyShapeIdx = i;
|
||||
auto currShape = shape::shapeOf(inputShape->at(i));
|
||||
newDim += currShape[axis];
|
||||
} else {
|
||||
//empty arrays can still have a shape and should be accounted for
|
||||
auto currShape = shape::shapeOf(inputShape->at(i));
|
||||
newDim += currShape[axis];
|
||||
}
|
||||
|
||||
arrShapes.push_back(inputShape->at(i));
|
||||
}
|
||||
}
|
||||
|
||||
if (numOfNonEmptyArrs < 1) {
|
||||
//this case is all empty arrays
|
||||
//in this case we need to set the shape to be
|
||||
//whatever the number of empty arrays is
|
||||
//plus the shape of whatever the rest of the array is
|
||||
//for example if empty shape is 1,2,1,0 and we have 3
|
||||
// arrays a concat at axis 0 would be 3,2,1,0
|
||||
LongType* outShapeInfo(nullptr);
|
||||
COPY_SHAPE(arrShapes.at(0), outShapeInfo);
|
||||
auto currShape = shape::shapeOf(outShapeInfo);
|
||||
currShape[axis] = newDim;
|
||||
std::vector<LongType> shapeVec;
|
||||
for (int i = 0; i < rank; i++) {
|
||||
shapeVec.push_back(currShape[i]);
|
||||
}
|
||||
|
||||
// All inputs are empty arrays -> return empty, mainly for TF import compatibility (no op)
|
||||
auto newShape = ConstantShapeHelper::getInstance().emptyShapeInfoWithShape(INPUT_VARIABLE(0)->dataType(), shapeVec);
|
||||
delete[] outShapeInfo;
|
||||
|
||||
// Clean up allocated vectors
|
||||
for (auto idx : shapesToDelete) {
|
||||
delete[] const_cast<LongType*>(arrShapes.at(idx));
|
||||
}
|
||||
|
||||
return SHAPELIST(newShape);
|
||||
}
|
||||
|
||||
// ******** input validation ******** //
|
||||
//axis needs to be flexible between 0 and 1
|
||||
if (axis > 1)
|
||||
REQUIRE_TRUE(0 <= axis && axis < rank, 0, "CONCAT op: input axis must be in range [0, %i], but got %i instead!",
|
||||
rank - 1, axis);
|
||||
|
||||
// ******** end of input validation ******** //
|
||||
|
||||
if (shape::isScalar(arrShapes.at(firstNonEmptyShapeIdx))) {
|
||||
//concat of scalar should be a 1d vector
|
||||
auto newShape = ConstantShapeHelper::getInstance().vectorShapeInfo(newDim, INPUT_VARIABLE(0)->dataType());
|
||||
return SHAPELIST(CONSTANT(newShape));
|
||||
} else {
|
||||
LongType* outShapeInfo(nullptr);
|
||||
COPY_SHAPE(arrShapes.at(firstNonEmptyShapeIdx), outShapeInfo);
|
||||
//reset flags: if an array is empty we can have unintended side effects from the flags
|
||||
//in our case by this point we handled empty and should only need the data type.
|
||||
ArrayOptions::resetFlags(outShapeInfo);
|
||||
// case when we have only one input array
|
||||
if (numOfNonEmptyArrs == 1) {
|
||||
ShapeUtils::updateStridesAndType(outShapeInfo, arrShapes.at(firstNonEmptyShapeIdx), shape::order(arrShapes.at(firstNonEmptyShapeIdx)));
|
||||
auto result = CONSTANT(outShapeInfo);
|
||||
delete[] outShapeInfo;
|
||||
return SHAPELIST(result);
|
||||
}
|
||||
|
||||
auto currShape = shape::shapeOf(outShapeInfo);
|
||||
currShape[axis] = newDim;
|
||||
ShapeUtils::updateStridesAndType(outShapeInfo, arrShapes.at(firstNonEmptyShapeIdx), shape::order(arrShapes.at(firstNonEmptyShapeIdx)));
|
||||
|
||||
//note: always ensure that the constant shape helper is used, otherwise we could end up with
|
||||
//some modification of pre existing cache values.
|
||||
auto result = ConstantShapeHelper::getInstance().createFromExisting(outShapeInfo);
|
||||
delete[] outShapeInfo;
|
||||
return SHAPELIST(result);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CUSTOM_OP_IMPL(concat_bp, -1, -1, false, 0, 0) {
|
||||
const bool isAxisInLastArr = block.getBArguments()->size() == 0 ? false : B_ARG(0);
|
||||
|
||||
const LongType numOfInArrs = isAxisInLastArr ? block.width() - 1 : block.width();
|
||||
|
||||
auto epsilonNext = INPUT_VARIABLE(numOfInArrs - 1);
|
||||
|
||||
auto first = INPUT_VARIABLE(0);
|
||||
|
||||
const LongType axis = isAxisInLastArr ? INPUT_VARIABLE(block.width() - 1)->e<int>(0)
|
||||
: (INT_ARG(0) >= 0 ? INT_ARG(0) : INT_ARG(0) + INPUT_VARIABLE(0)->rankOf());
|
||||
|
||||
LongType startPos = 0;
|
||||
|
||||
for (LongType e = 0; e < numOfInArrs - 1; e++) {
|
||||
auto originalChunk = INPUT_VARIABLE(e);
|
||||
auto epsilonChunk = OUTPUT_VARIABLE(e);
|
||||
std::vector<LongType> indices(2 * epsilonNext->rankOf());
|
||||
|
||||
int width = originalChunk->sizeAt(axis);
|
||||
|
||||
for (LongType e2 = 0; e2 < epsilonNext->rankOf(); e2++) {
|
||||
if (e2 == axis)
|
||||
indices[2 * e2 + 1] = (indices[2 * e2] = startPos) + width;
|
||||
else
|
||||
indices[2 * e2 + 1] = indices[2 * e2] = 0;
|
||||
}
|
||||
|
||||
auto subarray = (*epsilonNext)(indices, true);
|
||||
epsilonChunk->assign(subarray);
|
||||
|
||||
delete subarray;
|
||||
startPos += width;
|
||||
}
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(concat_bp) {
|
||||
getOpDescriptor()->setAllowedInputTypes(ANY)->setAllowedOutputTypes({ALL_FLOATS});
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(concat_bp) {
|
||||
const bool isAxisInLastArr = block.getBArguments()->size() == 0 ? false : B_ARG(0);
|
||||
|
||||
const LongType numOfInArrs = isAxisInLastArr ? block.width() - 1 : block.width();
|
||||
|
||||
auto shapeList = SHAPELIST();
|
||||
|
||||
for (int e = 0; e < numOfInArrs - 1; e++) {
|
||||
auto inShape = inputShape->at(e);
|
||||
shapeList->push_back(ConstantShapeHelper::getInstance().bufferForShapeInfo(ArrayOptions::dataType(inShape),
|
||||
shape::order(inShape),
|
||||
shape::rank(inShape),
|
||||
shape::shapeOf(inShape))->primary());
|
||||
}
|
||||
|
||||
return shapeList;
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,149 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_cumprod)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/prefix.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
CONFIGURABLE_OP_IMPL(cumprod, 1, 1, true, 0, 2) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
REQUIRE_TRUE(input->dataType() == output->dataType(), 0, "CumSum: input and output data types must be equal");
|
||||
|
||||
if (input->isEmpty()) {
|
||||
// No-op
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
const bool exclusive = INT_ARG(0) == 1;
|
||||
const bool reverse = INT_ARG(1) == 1;
|
||||
|
||||
if (block.getIArguments()->size() == 2 && block.width() == 1) {
|
||||
// all at once case
|
||||
sd::ops::helpers::prefix(block.launchContext(), scalar::Multiply, input, output, exclusive, reverse);
|
||||
} else {
|
||||
std::vector<sd::LongType> dims(block.numI() - 2);
|
||||
|
||||
if (block.width() == 1) {
|
||||
for (size_t e = 0; e < block.numI() - 2; e++) dims[e] = INT_ARG(e + 2);
|
||||
} else {
|
||||
auto ax = INPUT_VARIABLE(1);
|
||||
dims = ax->template asVectorT<sd::LongType>();
|
||||
}
|
||||
|
||||
for (size_t e = 0; e < dims.size(); e++)
|
||||
if (dims[e] < 0) dims[e] += input->rankOf();
|
||||
|
||||
sd::ops::helpers::prefix(block.launchContext(), scalar::Multiply, input, output, dims, exclusive, reverse);
|
||||
}
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(cumprod) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, sd::DataType::ANY)
|
||||
->setAllowedInputTypes(1, {ALL_INTS})
|
||||
->setAllowedOutputTypes({ALL_FLOATS})
|
||||
->setSameMode(true);
|
||||
}
|
||||
|
||||
DECLARE_TYPES(cumprod_bp) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, sd::DataType::ANY)
|
||||
->setAllowedInputTypes(1, {ALL_INTS, ALL_FLOATS}) // there is a case when axes given as IArgs
|
||||
->setAllowedInputTypes(2, {ALL_FLOATS})
|
||||
->setAllowedOutputTypes({ALL_FLOATS})
|
||||
->setSameMode(true);
|
||||
}
|
||||
|
||||
CUSTOM_OP_IMPL(cumprod_bp, 2, 1, false, 0, 2) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto axis = block.width() == 3 ? INPUT_VARIABLE(1) : nullptr;
|
||||
auto gradOut = block.width() == 3 ? INPUT_VARIABLE(2) : INPUT_VARIABLE(1);
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
const bool exclusive = INT_ARG(0) == 1;
|
||||
const bool reverse = INT_ARG(1) == 1;
|
||||
|
||||
std::vector<sd::LongType> dims;
|
||||
|
||||
if (block.width() > 2) {
|
||||
dims = axis->template asVectorT<sd::LongType>();
|
||||
float one = 1.f;
|
||||
OUTPUT_VARIABLE(1)->assign(one);
|
||||
} else if (int newSize = (block.numI() - 2)) {
|
||||
dims.resize(newSize);
|
||||
|
||||
for (int e = 0; e < newSize; e++) dims[e] = INT_ARG(e + 2);
|
||||
}
|
||||
|
||||
sd::ops::helpers::prefix(block.launchContext(), scalar::Multiply, input, output, dims, exclusive, reverse);
|
||||
NDArray *val = output->dup();
|
||||
|
||||
gradOut->applyPairwiseTransform(pairwise::Multiply, output, val);
|
||||
val->applyPairwiseTransform(pairwise::Divide, input, val);
|
||||
if (!exclusive && !reverse) {
|
||||
if (dims.size())
|
||||
sd::ops::helpers::prefix(block.launchContext(), scalar::Add, val, output, dims, true, false);
|
||||
else
|
||||
sd::ops::helpers::prefix(block.launchContext(), scalar::Add, val, output, false, true);
|
||||
|
||||
} else if (!exclusive && reverse) {
|
||||
if (dims.size())
|
||||
sd::ops::helpers::prefix(block.launchContext(), scalar::Add, val, output, dims, false, false);
|
||||
else
|
||||
sd::ops::helpers::prefix(block.launchContext(), scalar::Add, val, output, false, false);
|
||||
} else if (exclusive && !reverse) {
|
||||
if (dims.size())
|
||||
sd::ops::helpers::prefix(block.launchContext(), scalar::Add, val, output, dims, true, true);
|
||||
else
|
||||
sd::ops::helpers::prefix(block.launchContext(), scalar::Add, val, output, true, true);
|
||||
} else {
|
||||
if (dims.size())
|
||||
sd::ops::helpers::prefix(block.launchContext(), scalar::Add, val, output, dims, true, false);
|
||||
else
|
||||
sd::ops::helpers::prefix(block.launchContext(), scalar::Add, val, output, true, false);
|
||||
}
|
||||
|
||||
delete val;
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(cumprod_bp) {
|
||||
auto inp = inputShape->at(0);
|
||||
if (block.width() == 2) {
|
||||
return SHAPELIST(CONSTANT(inp));
|
||||
} else {
|
||||
return SHAPELIST(CONSTANT(inp), CONSTANT(inputShape->at(1)));
|
||||
}
|
||||
}
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,149 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_cumsum)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/prefix.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
CONFIGURABLE_OP_IMPL(cumsum, 1, 1, true, 0, 2) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
const bool exclusive = INT_ARG(0) == 1;
|
||||
const bool reverse = INT_ARG(1) == 1;
|
||||
|
||||
REQUIRE_TRUE(input->dataType() == output->dataType(), 0, "CumSum: input and output data types must be equal");
|
||||
|
||||
if (input->isEmpty()) {
|
||||
// No-op
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
if (block.getIArguments()->size() == 2 && block.width() == 1) {
|
||||
// all at once case
|
||||
sd::ops::helpers::prefix(block.launchContext(), scalar::Add, input, output, exclusive, reverse);
|
||||
} else {
|
||||
std::vector<sd::LongType> dims(block.numI() - 2);
|
||||
|
||||
if (block.width() == 1) {
|
||||
for (size_t e = 0; e < block.numI() - 2; e++) dims[e] = INT_ARG(e + 2);
|
||||
} else {
|
||||
auto ax = INPUT_VARIABLE(1);
|
||||
dims = ax->template asVectorT<sd::LongType>();
|
||||
}
|
||||
|
||||
for (size_t e = 0; e < dims.size(); e++)
|
||||
if (dims[e] < 0) dims[e] += input->rankOf();
|
||||
|
||||
sd::ops::helpers::prefix(block.launchContext(), scalar::Add, input, output, dims, exclusive, reverse);
|
||||
}
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
DECLARE_TYPES(cumsum) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, {ALL_FLOATS, ALL_INTS})
|
||||
->setAllowedInputTypes(1, {ALL_FLOATS,ALL_INTS})
|
||||
->setAllowedOutputTypes({ALL_FLOATS})
|
||||
->setSameMode(false);
|
||||
}
|
||||
|
||||
CUSTOM_OP_IMPL(cumsum_bp, 2, -1, true, 0, 2) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto axis = block.width() == 3 ? INPUT_VARIABLE(1) : nullptr;
|
||||
auto gradOut = block.width() == 3 ? INPUT_VARIABLE(2) : INPUT_VARIABLE(1);
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
const bool exclusive = INT_ARG(0) == 1;
|
||||
const bool reverse = INT_ARG(1) == 1;
|
||||
|
||||
std::vector<sd::LongType> dims;
|
||||
|
||||
if (block.width() > 2) {
|
||||
dims = axis->template asVectorT<sd::LongType>();
|
||||
float one = 1.f;
|
||||
OUTPUT_VARIABLE(1)->assign(one);
|
||||
} else if (int newSize = (block.numI() - 2)) {
|
||||
dims.resize(newSize);
|
||||
|
||||
for (int e = 0; e < newSize; e++) dims[e] = INT_ARG(e + 2);
|
||||
}
|
||||
if (!exclusive && !reverse) {
|
||||
if (dims.size())
|
||||
sd::ops::helpers::prefix(block.launchContext(), scalar::Add, gradOut, output, dims, false, true);
|
||||
else
|
||||
sd::ops::helpers::prefix(block.launchContext(), scalar::Add, gradOut, output, false, true);
|
||||
|
||||
} else if (!exclusive && reverse) {
|
||||
if (dims.size())
|
||||
sd::ops::helpers::prefix(block.launchContext(), scalar::Add, gradOut, output, dims, false, false);
|
||||
else
|
||||
sd::ops::helpers::prefix(block.launchContext(), scalar::Add, gradOut, output, false, false);
|
||||
} else if (exclusive && !reverse) {
|
||||
if (dims.size())
|
||||
sd::ops::helpers::prefix(block.launchContext(), scalar::Add, gradOut, output, dims, true, true);
|
||||
else
|
||||
sd::ops::helpers::prefix(block.launchContext(), scalar::Add, gradOut, output, true, true);
|
||||
} else {
|
||||
if (dims.size())
|
||||
sd::ops::helpers::prefix(block.launchContext(), scalar::Add, gradOut, output, dims, true, false);
|
||||
else
|
||||
sd::ops::helpers::prefix(block.launchContext(), scalar::Add, gradOut, output, true, false);
|
||||
}
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
DECLARE_TYPES(cumsum_bp) {
|
||||
getOpDescriptor()->setAllowedInputTypes(0, {ALL_FLOATS, ALL_INTS});
|
||||
getOpDescriptor()->setAllowedInputTypes(1, {ALL_FLOATS, ALL_INTS}); // axes can be set as the second param
|
||||
getOpDescriptor()->setAllowedInputTypes(2, {ALL_FLOATS});
|
||||
getOpDescriptor()->setAllowedOutputTypes(0, {ALL_FLOATS});
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(cumsum_bp) {
|
||||
auto inp = inputShape->at(0);
|
||||
sd::LongType *newShapeX = nullptr;
|
||||
COPY_SHAPE(inp, newShapeX);
|
||||
|
||||
if (block.width() == 2) {
|
||||
auto result = CONSTANT(newShapeX);
|
||||
delete[] newShapeX;
|
||||
return SHAPELIST(result);
|
||||
} else {
|
||||
sd::LongType *newShapeA = nullptr;
|
||||
COPY_SHAPE(inputShape->at(1), newShapeA);
|
||||
|
||||
auto resultX = CONSTANT(newShapeX);
|
||||
auto resultA = CONSTANT(newShapeA);
|
||||
delete[] newShapeX;
|
||||
delete[] newShapeA;
|
||||
return SHAPELIST(resultX, resultA);
|
||||
}
|
||||
}
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,101 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_depth_to_space)
|
||||
|
||||
#include <ops/declarable/headers/parity_ops.h>
|
||||
#include <ops/declarable/helpers/d_t_s.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
CUSTOM_OP_IMPL(depth_to_space, 1, 1, false, 0, 2) {
|
||||
int block_size = INT_ARG(0);
|
||||
REQUIRE_TRUE(block_size > 0,0, "DepthToSpace: block_size should be > 0");
|
||||
bool isNHWC = INT_ARG(1) == 1;
|
||||
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
|
||||
REQUIRE_TRUE(input->rankOf() == 4, 0, "DepthToSpace: input should be 4D array, but got %f instead", input->rankOf());
|
||||
|
||||
int bS = input->sizeAt(0);
|
||||
int iD = isNHWC ? input->sizeAt(3) : input->sizeAt(1);
|
||||
int iH = isNHWC ? input->sizeAt(1) : input->sizeAt(2);
|
||||
int iW = isNHWC ? input->sizeAt(2) : input->sizeAt(3);
|
||||
|
||||
REQUIRE_TRUE(iD % (block_size * block_size) == 0, 0, "DepthToSpace: input number of channels should be divisible by square(block_size)");
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
if (shape::strideDescendingCAscendingF(input->shapeInfo()))
|
||||
helpers::_depthToSpace(block.launchContext(), *input, output, block_size, isNHWC);
|
||||
else {
|
||||
NDArray *dup = input->dup();
|
||||
helpers::_depthToSpace(block.launchContext(), *dup, output, block_size, isNHWC);
|
||||
delete dup;
|
||||
}
|
||||
STORE_RESULT(output);
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(depth_to_space) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(sd::DataType::ANY)
|
||||
->setSameMode(true);
|
||||
}
|
||||
|
||||
|
||||
DECLARE_SHAPE_FN(depth_to_space) {
|
||||
auto in = inputShape->at(0);
|
||||
auto block_size = INT_ARG(0);
|
||||
REQUIRE_TRUE(block_size > 0,0, "DepthToSpace: input should be > 0");
|
||||
|
||||
bool isNHWC = INT_ARG(1) == 1;
|
||||
|
||||
int bS = shape::sizeAt(in, static_cast<sd::LongType>(0));
|
||||
int iD = isNHWC ? shape::sizeAt(in, static_cast<sd::LongType>(3)) : shape::sizeAt(in, static_cast<sd::LongType>(1));
|
||||
int iH = isNHWC ? shape::sizeAt(in, static_cast<sd::LongType>(1)) : shape::sizeAt(in, static_cast<sd::LongType>(2));
|
||||
int iW = isNHWC ? shape::sizeAt(in, static_cast<sd::LongType>(2)) : shape::sizeAt(in, static_cast<sd::LongType>(3));
|
||||
|
||||
int oD = iD / (block_size * block_size);
|
||||
int oH = iH * block_size;
|
||||
int oW = iW * block_size;
|
||||
|
||||
|
||||
std::array<sd::LongType, 4> shape;
|
||||
if (isNHWC)
|
||||
shape = {{bS, oH, oW, oD }};
|
||||
else
|
||||
shape = {{bS, oD, oH, oW }};
|
||||
|
||||
auto newShape = ConstantShapeHelper::getInstance().createShapeInfo(ArrayOptions::dataType(in), 'c', 4, shape.data(),0);
|
||||
return SHAPELIST(newShape);
|
||||
}
|
||||
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,139 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author GS <sgazeos@gmail.com>
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_dynamic_partition)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/dynamic.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
CUSTOM_OP_IMPL(dynamic_partition, 2, 1, false, 0, 1) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto indices = INPUT_VARIABLE(1);
|
||||
|
||||
REQUIRE_TRUE(input->rankOf() >= indices->rankOf(), 0,
|
||||
"dynamic_partition: data tensor rank should be non-lesser than indices\' tensor, but %i < %i given,",
|
||||
input->rankOf(), indices->rankOf());
|
||||
for (int dim = 0; dim < indices->rankOf(); dim++) {
|
||||
REQUIRE_TRUE(
|
||||
input->sizeAt(dim) == indices->sizeAt(dim), 0,
|
||||
"dynamic_partition: dimensions should be equals for data and indices tensors, but at axis[%i] %i != %i given",
|
||||
dim, input->sizeAt(dim), indices->sizeAt(dim));
|
||||
}
|
||||
|
||||
auto numPartition = INT_ARG(0);
|
||||
std::vector<NDArray *> outputList(numPartition);
|
||||
for (int o = 0; o < numPartition; ++o) {
|
||||
outputList[o] = OUTPUT_VARIABLE(o);
|
||||
}
|
||||
helpers::dynamicPartitionFunctor(block.launchContext(), input, indices, outputList);
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(dynamic_partition) {
|
||||
auto numPartition = INT_ARG(0);
|
||||
auto indices = INPUT_VARIABLE(1);
|
||||
std::vector<sd::LongType> partitionSizes(numPartition, 0);
|
||||
auto in = inputShape->at(0);
|
||||
auto idx = inputShape->at(1);
|
||||
for (int i = 0; i < numPartition; i++) {
|
||||
for (int e = 0; e < indices->lengthOf(); ++e)
|
||||
if (indices->e<sd::LongType>(e) == i) partitionSizes[i]++;
|
||||
}
|
||||
|
||||
auto shapes = SHAPELIST();
|
||||
sd::LongType outRank = shape::rank(in) - shape::rank(idx) + 1;
|
||||
for (sd::LongType e = 0; e < numPartition; e++) {
|
||||
sd::LongType *newShape;
|
||||
ALLOCATE(newShape, block.getWorkspace(), shape::shapeInfoLength(outRank), sd::LongType);
|
||||
newShape[0] = outRank;
|
||||
newShape[1] = partitionSizes[e];
|
||||
for (sd::LongType i = 1; i < outRank; ++i) newShape[i + 1] = shape::sizeAt(in, outRank + i - 1);
|
||||
|
||||
shape::updateStrides(newShape, shape::order(in), false);
|
||||
ArrayOptions::setDataType(newShape, ArrayOptions::dataType(in));
|
||||
shapes->push_back(CONSTANT(newShape));
|
||||
}
|
||||
|
||||
return shapes;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(dynamic_partition) {
|
||||
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS, ALL_INTS});
|
||||
}
|
||||
|
||||
DECLARE_TYPES(dynamic_partition_bp) { getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setSameMode(true); }
|
||||
|
||||
CUSTOM_OP_IMPL(dynamic_partition_bp, 3, 2, false, 0, 1) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto indices = INPUT_VARIABLE(1);
|
||||
auto numPartition = INT_ARG(0);
|
||||
|
||||
std::vector<NDArray *> outputList(2); // only for output
|
||||
std::vector<NDArray *> gradOutList(numPartition);
|
||||
for (sd::LongType e = 0; e < numPartition; e++) {
|
||||
gradOutList[e] = INPUT_VARIABLE(e + 2);
|
||||
}
|
||||
outputList[0] = OUTPUT_VARIABLE(0);
|
||||
outputList[1] = OUTPUT_VARIABLE(1);
|
||||
NDArray originalIndices(*indices);
|
||||
originalIndices.linspace(0);
|
||||
ops::dynamic_partition op;
|
||||
auto res = op.evaluate({&originalIndices, indices}, {numPartition});
|
||||
REQUIRE_TRUE(res.status() == sd::Status::OK, 0, "dynamic_partition_bp: Error with dynamic partitioning.");
|
||||
ops::dynamic_stitch stitchOp;
|
||||
std::vector<NDArray *> partitions(numPartition * 2);
|
||||
for (int i = 0; i < res.size(); i++) {
|
||||
partitions[i] = res.at(i);
|
||||
partitions[i + numPartition] = gradOutList[i];
|
||||
}
|
||||
|
||||
auto result = stitchOp.evaluate(partitions, {numPartition});
|
||||
REQUIRE_TRUE(result.status() == sd::Status::OK, 0, "dynamic_partition_bp: Error with dynamic partitioning.");
|
||||
outputList[1]->assign(indices);
|
||||
outputList[0]->assign(result.at(0));
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(dynamic_partition_bp) {
|
||||
auto numPartition = INT_ARG(0);
|
||||
auto indices = INPUT_VARIABLE(1);
|
||||
std::vector<sd::LongType> partitionSizes(numPartition, 0);
|
||||
|
||||
auto shapes = SHAPELIST();
|
||||
// just copy shape info from input and indices to output
|
||||
for (sd::LongType i = 0; i < 2; i++) {
|
||||
shapes->push_back(CONSTANT(inputShape->at(i)));
|
||||
}
|
||||
|
||||
return shapes;
|
||||
}
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,91 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author GS <sgazeos@gmail.com>
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_dynamic_stitch)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/dynamic.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
CUSTOM_OP_IMPL(dynamic_stitch, 2, 1, false, 0, 0) {
|
||||
int numOfData = block.width();
|
||||
// int k = 0;
|
||||
// checking input data size
|
||||
REQUIRE_TRUE(numOfData % 2 == 0, 0,
|
||||
"dynamic_stitch: The input params should contains"
|
||||
" both indeces and data lists with same length.");
|
||||
// split input data list on two equal parts
|
||||
numOfData /= 2;
|
||||
|
||||
// form input lists to use with helpers - both indices and float data inputs
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
std::vector<NDArray*> inputs(numOfData);
|
||||
std::vector<NDArray*> indices(numOfData);
|
||||
|
||||
for (int e = 0; e < numOfData; e++) {
|
||||
auto data = INPUT_VARIABLE(numOfData + e);
|
||||
auto index = INPUT_VARIABLE(e);
|
||||
|
||||
inputs[e] = data;
|
||||
indices[e] = index;
|
||||
}
|
||||
// run helper
|
||||
return helpers::dynamicStitchFunctor(block.launchContext(), inputs, indices, output);
|
||||
}
|
||||
|
||||
DECLARE_TYPES(dynamic_stitch) {
|
||||
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_INTS, ALL_FLOATS});
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(dynamic_stitch) {
|
||||
sd::LongType maxValue = 0;
|
||||
auto numOfData = block.width();
|
||||
numOfData /= 2; // only index part it's needed to review
|
||||
auto restShape = inputShape->at(numOfData);
|
||||
auto firstShape = inputShape->at(0);
|
||||
// check up inputs to avoid non-int indices and calculate max value from indices to output shape length
|
||||
for (size_t i = 0; i < numOfData; i++) {
|
||||
auto input = INPUT_VARIABLE(i);
|
||||
REQUIRE_TRUE(input->isZ(), 0, "dynamic_stitch: Indices should be integer, but %d type given.",
|
||||
(int)input->dataType());
|
||||
auto maxV = input->reduceNumber(reduce::Max);
|
||||
if (maxV->e<sd::LongType>(0) > maxValue) maxValue = maxV->e<sd::LongType>(0);
|
||||
delete maxV;
|
||||
}
|
||||
// calculate output rank - difference between indices shape and data shape
|
||||
int outRank = shape::rank(restShape) - shape::rank(firstShape) + 1; // at least 1D tensor
|
||||
std::vector<sd::LongType> outShape(outRank);
|
||||
// fill up output shape template: the first to max index, and rests - to vals from the first data input
|
||||
outShape[0] = maxValue + 1;
|
||||
for (sd::LongType i = 1; i < outRank; ++i) outShape[i] = shape::sizeAt(restShape, i);
|
||||
|
||||
auto ret = SHAPELIST(ConstantShapeHelper::getInstance().bufferForShapeInfo(ArrayOptions::dataType(restShape),
|
||||
shape::order(firstShape),
|
||||
outShape)->primary());
|
||||
return ret;
|
||||
}
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_Floor)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
OP_IMPL(Floor, 1, 1, true) {
|
||||
auto first = INPUT_VARIABLE(0);
|
||||
auto z = OUTPUT_VARIABLE(0);
|
||||
|
||||
first->applyTransform(transform::Floor, z);
|
||||
|
||||
STORE_RESULT(*z);
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
DECLARE_SYN(floor, Floor);
|
||||
|
||||
DECLARE_TYPES(Floor) { getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setSameMode(true); }
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,175 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author Shyrma Yurii (iuriish@yahoo.com), created on 16.11.2017
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_gather)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/gather.h>
|
||||
#include <ops/declarable/helpers/scatter.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CUSTOM_OP_IMPL(gather, 1, 1, false, 0, -2) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto indices = block.width() > 1 ? INPUT_VARIABLE(1) : nullptr;
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
const bool checkIndices = block.getBArguments()->empty() ? true : B_ARG(0);
|
||||
|
||||
// Edge case: empty indices -> empty output
|
||||
if (indices != nullptr && indices->isEmpty()) {
|
||||
REQUIRE_TRUE(output->isEmpty(), 0, "Gather op: If indices are empty, output must also be empty");
|
||||
return sd::Status::OK; // No op
|
||||
}
|
||||
|
||||
const sd::LongType numOfIntArgs = block.numI();
|
||||
|
||||
std::vector<sd::LongType> intArgs;
|
||||
if (block.width() > 2) {
|
||||
intArgs = INPUT_VARIABLE(2)->template asVectorT<sd::LongType>();
|
||||
} else {
|
||||
if (numOfIntArgs == 0)
|
||||
intArgs.emplace_back(0);
|
||||
else
|
||||
for (sd::LongType i = 0; i < numOfIntArgs; i++) intArgs.emplace_back(block.getIArguments()->at(i));
|
||||
}
|
||||
|
||||
const sd::LongType inputRank = input->rankOf();
|
||||
if (intArgs[0] < 0) intArgs[0] += inputRank;
|
||||
|
||||
// input validation
|
||||
REQUIRE_TRUE(intArgs[0] < inputRank, 0,
|
||||
"GATHER op: input axis must be smaller than input array rank, but got %i and %i correspondingly!",
|
||||
intArgs[0], inputRank);
|
||||
REQUIRE_TRUE(indices != nullptr || numOfIntArgs > 1, 0,
|
||||
"GATHER op: indices should be provided either as additional input array or as IntArguments !");
|
||||
|
||||
if (checkIndices) {
|
||||
NDArray* pIndices = indices;
|
||||
bool ownsIndices = false;
|
||||
|
||||
if (indices == nullptr) {
|
||||
std::vector<sd::LongType> shape = {static_cast<sd::LongType>(intArgs.size()) - 1};
|
||||
std::vector<double> inputVec = std::vector<double>(intArgs.begin() + 1, intArgs.end());
|
||||
pIndices = new NDArray(input->ordering(), shape, inputVec, DataType::INT64, block.launchContext());
|
||||
ownsIndices = true;
|
||||
}
|
||||
|
||||
const sd::LongType numOfBadIndx = helpers::checkIndices(block.launchContext(), *pIndices, *input, intArgs[0]);
|
||||
|
||||
// FIXED: Cleanup BEFORE checking condition (REQUIRE_TRUE can throw)
|
||||
if (ownsIndices) {
|
||||
delete pIndices;
|
||||
pIndices = nullptr;
|
||||
}
|
||||
|
||||
// Check condition after cleanup
|
||||
REQUIRE_TRUE(numOfBadIndx == 0, 0,
|
||||
"GATHER OP: please check elements of indices-array, total number of wrong elements is %lld!",
|
||||
numOfBadIndx);
|
||||
}
|
||||
|
||||
helpers::gather(block.launchContext(), input, indices, output, intArgs);
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(gather) {
|
||||
getOpDescriptor()->setAllowedInputTypes(0, {ALL_INTS, ALL_FLOATS});
|
||||
getOpDescriptor()->setAllowedInputTypes(1, {ALL_INTS,ALL_FLOATS});
|
||||
getOpDescriptor()->setAllowedOutputTypes(0, {ALL_INTS, ALL_FLOATS});
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(gather) {
|
||||
// check shape of paddings
|
||||
auto inputShapeInfo = inputShape->at(0);
|
||||
sd::LongType* outputShapeInfo = nullptr;
|
||||
|
||||
sd::LongType axis = 0;
|
||||
|
||||
if (block.width() > 2) {
|
||||
axis = INPUT_VARIABLE(2)->e<sd::LongType>(0);
|
||||
} else
|
||||
axis = block.numI() > 0 ? block.getIArguments()->at(0) : 0;
|
||||
|
||||
sd::LongType inputRank = shape::rank(inputShapeInfo);
|
||||
if (axis < 0) axis += inputRank;
|
||||
|
||||
REQUIRE_TRUE(axis < inputRank, 0,
|
||||
"GATHER op: input axis must be smaller than input array rank, but got %i and %i correspondingly!", axis,
|
||||
inputRank);
|
||||
|
||||
bool isEmpty = false;
|
||||
|
||||
if (block.width() > 1) {
|
||||
auto indicesShapeInfo = inputShape->at(1);
|
||||
|
||||
sd::LongType indicesRank = shape::rank(indicesShapeInfo);
|
||||
|
||||
sd::LongType outputRank = inputRank + indicesRank - 1;
|
||||
|
||||
ALLOCATE(outputShapeInfo, block.getWorkspace(), shape::shapeInfoLength(outputRank), sd::LongType);
|
||||
|
||||
// fill output shapeInfo
|
||||
outputShapeInfo[0] = outputRank;
|
||||
sd::LongType shapeIdx = 1;
|
||||
|
||||
for (sd::LongType i = 0; i < axis; ++i) outputShapeInfo[shapeIdx++] = inputShapeInfo[i + 1];
|
||||
|
||||
for (sd::LongType i = 0; i < indicesRank; ++i) outputShapeInfo[shapeIdx++] = indicesShapeInfo[i + 1];
|
||||
|
||||
for (sd::LongType i = axis + 1; i < inputRank; ++i) outputShapeInfo[shapeIdx++] = inputShapeInfo[i + 1];
|
||||
} else if (block.numI() > 1) {
|
||||
int indicesRank = block.numI() == 2 ? 0 : 1;
|
||||
|
||||
sd::LongType outputRank = inputRank + indicesRank - 1;
|
||||
ALLOCATE(outputShapeInfo, block.getWorkspace(), shape::shapeInfoLength(outputRank), sd::LongType);
|
||||
|
||||
// building shape manually
|
||||
outputShapeInfo[0] = outputRank;
|
||||
int shapeIdx = 1;
|
||||
for (sd::LongType i = 0; i < axis; ++i) outputShapeInfo[shapeIdx++] = inputShapeInfo[i + 1];
|
||||
|
||||
if (block.numI() > 2) outputShapeInfo[shapeIdx++] = block.numI() - 1;
|
||||
|
||||
for (sd::LongType i = axis + 1; i < inputRank; ++i) outputShapeInfo[shapeIdx++] = inputShapeInfo[i + 1];
|
||||
} else
|
||||
REQUIRE_TRUE(false, 0,
|
||||
"GATHER op: indices should be provided either as additional input array or as IntArguments !");
|
||||
|
||||
ShapeUtils::updateStridesAndType(outputShapeInfo, inputShapeInfo, shape::order(inputShapeInfo));
|
||||
|
||||
if (isEmpty) {
|
||||
ArrayOptions::setPropertyBit(outputShapeInfo, ARRAY_EMPTY);
|
||||
}
|
||||
|
||||
auto result = ConstantShapeHelper::getInstance().bufferForShapeInfo(outputShapeInfo)->primary();
|
||||
RELEASE(outputShapeInfo, block.getWorkspace());
|
||||
return SHAPELIST(result);
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
#endif
|
||||
@@ -0,0 +1,108 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author Shyrma Yurii (iuriish@yahoo.com), created on 23.01.2018
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_gather_nd)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/scatter.h>
|
||||
#include <ops/declarable/helpers/transforms.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CUSTOM_OP_IMPL(gather_nd, 2, 1, false, 0, 0) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto indices = INPUT_VARIABLE(1);
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
const bool checkIndices = block.getBArguments()->empty() ? false : B_ARG(0);
|
||||
|
||||
const int rankIn = input->rankOf();
|
||||
const int rankInd = indices->rankOf();
|
||||
|
||||
REQUIRE_TRUE(
|
||||
rankInd > 0, 0,
|
||||
"GATHER_ND op: array of indexes can't be single scalar, the requirement is: rank > 0, but got rank = %i instead!",
|
||||
rankInd);
|
||||
int lastIndDim = indices->sizeAt(-1);
|
||||
REQUIRE_TRUE(lastIndDim <= rankIn, 0,
|
||||
"GATHER_ND op: the last dimension of indices array must be <= rank of input array but got %i and %i "
|
||||
"correspondingly!",
|
||||
lastIndDim, rankIn);
|
||||
|
||||
if (checkIndices) {
|
||||
const sd::LongType numOfBadIndx = helpers::checkIndices(block.launchContext(), *indices, *input);
|
||||
REQUIRE_TRUE(numOfBadIndx == 0, 0,
|
||||
"GATHER_ND OP: please check elements of indices-array, total number of wrong elements is %lld!",
|
||||
numOfBadIndx);
|
||||
}
|
||||
|
||||
helpers::gatherND(block.launchContext(), *input, *indices, *output);
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(gather_nd) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedInputTypes(1, {ALL_INTS})
|
||||
->setAllowedOutputTypes({ALL_INTS, ALL_FLOATS});
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(gather_nd) {
|
||||
auto inShapeInfoIn = inputShape->at(0);
|
||||
auto inShapeInfoInd = inputShape->at(1);
|
||||
|
||||
const int rankIn = inShapeInfoIn[0];
|
||||
const int rankInd = inShapeInfoInd[0];
|
||||
REQUIRE_TRUE(
|
||||
rankInd > 0, 0,
|
||||
"GATHER_ND op: array of indexes can't be single scalar, the requirement is: rank > 0, but got rank = %i instead!",
|
||||
rankInd);
|
||||
const int lastIndDim = inShapeInfoInd[rankInd];
|
||||
REQUIRE_TRUE(lastIndDim <= rankIn, 0,
|
||||
"GATHER_ND op: the last dimension of indices array must be <= rank of input array but got %i and %i "
|
||||
"correspondingly!",
|
||||
lastIndDim, rankIn);
|
||||
|
||||
int outRank = (rankInd - 1) + (rankIn - lastIndDim);
|
||||
|
||||
sd::LongType* outShapeInfo = nullptr;
|
||||
ALLOCATE(outShapeInfo, block.getWorkspace(), shape::shapeInfoLength(outRank), sd::LongType);
|
||||
|
||||
outShapeInfo[0] = outRank;
|
||||
|
||||
for (int i = 1; i <= rankInd - 1; ++i) outShapeInfo[i] = inShapeInfoInd[i];
|
||||
|
||||
for (int i = 0; i < rankIn - lastIndDim; ++i) outShapeInfo[rankInd + i] = inShapeInfoIn[lastIndDim + i + 1];
|
||||
|
||||
ShapeUtils::updateStridesAndType(outShapeInfo, inShapeInfoIn, 'c');
|
||||
// ArrayOptions::setDataType(outShapeInfo, ArrayOptions::dataType(inShapeInfoIn));
|
||||
return SHAPELIST(CONSTANT(outShapeInfo));
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,58 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_hashcode)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/hashcode.h>
|
||||
#include <ops/declarable/helpers/transforms.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
CUSTOM_OP_IMPL(hashcode, 1, 1, false, 0, 0) {
|
||||
REQUIRE_TRUE(block.width() == 1, 0, "hashcode: this op can't be applied along dimension");
|
||||
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
REQUIRE_TRUE(output->isScalar(), 0, "hashcode: this op requires scalar output");
|
||||
|
||||
helpers::hashCode(block.launchContext(), *input, *output);
|
||||
|
||||
return sd::Status::OK;
|
||||
};
|
||||
|
||||
DECLARE_SHAPE_FN(hashcode) {
|
||||
return SHAPELIST(ConstantShapeHelper::getInstance().scalarShapeInfo(sd::DataType::INT64));
|
||||
}
|
||||
|
||||
DECLARE_TYPES(hashcode) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, {ANY})
|
||||
->setAllowedInputTypes(1, {ANY})
|
||||
->setAllowedOutputTypes({sd::DataType::INT64});
|
||||
};
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,57 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_histogram)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/histogram.h>
|
||||
#include <ops/declarable/helpers/transforms.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
CUSTOM_OP_IMPL(histogram, 1, 1, false, 0, 1) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto numBins = INT_ARG(0);
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
REQUIRE_TRUE(numBins == output->lengthOf(), 0, "Histogram: numBins must match output length")
|
||||
|
||||
output->nullify();
|
||||
helpers::histogramHelper(block.launchContext(), *input, *output);
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(histogram) {
|
||||
auto numBins = INT_ARG(0);
|
||||
|
||||
return SHAPELIST(ConstantShapeHelper::getInstance().vectorShapeInfo(numBins, sd::DataType::INT64));
|
||||
}
|
||||
|
||||
DECLARE_TYPES(histogram) {
|
||||
getOpDescriptor()->setAllowedInputTypes(0, {ALL_INTS, ALL_FLOATS})->setAllowedOutputTypes({ALL_INTS});
|
||||
};
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,71 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com), created on 31.08.2018
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_histogram_fixed_width)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/histogramFixedWidth.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
CUSTOM_OP_IMPL(histogram_fixed_width, 2, 1, false, 0, 0) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto range = INPUT_VARIABLE(1);
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
const int nbins =
|
||||
block.width() == 3 ? INPUT_VARIABLE(2)->e<int>(0) : block.getIArguments()->empty() ? 100 : INT_ARG(0);
|
||||
|
||||
const double leftEdge = range->e<double>(0);
|
||||
const double rightEdge = range->e<double>(1);
|
||||
|
||||
REQUIRE_TRUE(leftEdge < rightEdge, 0,
|
||||
"HISTOGRAM_FIXED_WIDTH OP: wrong content of range input array, bottom_edge must be smaller than "
|
||||
"top_edge, but got %f and %f correspondingly !",
|
||||
leftEdge, rightEdge);
|
||||
REQUIRE_TRUE(nbins >= 1, 0,
|
||||
"HISTOGRAM_FIXED_WIDTH OP: wrong nbins value, expected value should be >= 1, however got %i instead !",
|
||||
nbins);
|
||||
|
||||
helpers::histogramFixedWidth(block.launchContext(), *input, *range, *output);
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(histogram_fixed_width) {
|
||||
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_INDICES});
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
DECLARE_SHAPE_FN(histogram_fixed_width) {
|
||||
const int nbins =
|
||||
block.width() == 3 ? INPUT_VARIABLE(2)->e<int>(0) : block.getIArguments()->empty() ? 100 : INT_ARG(0);
|
||||
auto outShapeInfo = ConstantShapeHelper::getInstance().vectorShapeInfo(nbins, DataType::INT64);
|
||||
return SHAPELIST(outShapeInfo);
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author, Yurii Shyrma (iuriish@yahoo.com), created on 06.12.2017
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_invert_permutation)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/transforms.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
CONFIGURABLE_OP_IMPL(invert_permutation, 1, 1, false, 0, 0) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
REQUIRE_TRUE(input->isVector(), 0, "INVERT_PERMUTATION op: input array must be vector, but got shape %s instead !",
|
||||
ShapeUtils::shapeAsString(input).c_str());
|
||||
|
||||
helpers::invertPermutation(block.launchContext(), *input, *output);
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_SYN(InvertPermutation, invert_permutation);
|
||||
|
||||
DECLARE_TYPES(invert_permutation) { getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setSameMode(true); }
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,102 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// Created by raver119 on 24.11.17.
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_mergeadd)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/transforms.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
OP_IMPL(mergeadd, -1, 1, false) {
|
||||
REQUIRE_OK(this->validateInputDimensionsMatch(block));
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
if (output->isEmpty()) {
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
int nonEmpty = 0;
|
||||
for (size_t i = 0; i < block.width(); i++)
|
||||
if (!INPUT_VARIABLE(i)->isEmpty()) nonEmpty++;
|
||||
|
||||
|
||||
std::vector<NDArray*> inArrs(nonEmpty);
|
||||
int numNonEmptyAdded = 0;
|
||||
if(nonEmpty > 0)
|
||||
for (size_t i = 0; i < block.width(); ++i) {
|
||||
if(!INPUT_VARIABLE(i)->isEmpty())inArrs[numNonEmptyAdded++] = INPUT_VARIABLE(i);
|
||||
}
|
||||
|
||||
helpers::mergeAdd(block.launchContext(), inArrs, *output);
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_SYN(mergesum, mergeadd);
|
||||
DECLARE_SYN(add_n, mergeadd);
|
||||
DECLARE_SYN(addn, mergeadd);
|
||||
DECLARE_SYN(accumulaten, mergeadd);
|
||||
DECLARE_SYN(accumulate_n, mergeadd);
|
||||
|
||||
DECLARE_TYPES(mergeadd) { getOpDescriptor()->setAllowedInputTypes(ANY)->setAllowedOutputTypes(ANY); }
|
||||
|
||||
CUSTOM_OP_IMPL(mergeadd_bp, 2, 1, false, 0, 0) {
|
||||
auto inSize = block.width() - 1;
|
||||
|
||||
REQUIRE_OK(this->validateInputDimensionsMatch(block));
|
||||
|
||||
std::vector<NDArray*> outArrs(inSize);
|
||||
|
||||
const auto gradient = INPUT_VARIABLE(inSize);
|
||||
|
||||
for (size_t i = 0; i < inSize; ++i) {
|
||||
outArrs[i] = OUTPUT_VARIABLE(i);
|
||||
}
|
||||
helpers::mergeAddBp(block.launchContext(), *gradient, outArrs);
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(mergeadd_bp) { getOpDescriptor()->setAllowedInputTypes(ANY)->setAllowedOutputTypes(ANY); }
|
||||
DECLARE_SHAPE_FN(mergeadd_bp) {
|
||||
const int numOfInArrs = block.width() - 1;
|
||||
|
||||
auto shapeList = SHAPELIST();
|
||||
|
||||
for (int e = 0; e < numOfInArrs; e++) {
|
||||
auto inShape = inputShape->at(e);
|
||||
shapeList->push_back(ConstantShapeHelper::getInstance().bufferForShapeInfo(ArrayOptions::dataType(inShape),
|
||||
shape::order(inShape),
|
||||
shape::rank(inShape),
|
||||
shape::shapeOf(inShape))->primary());
|
||||
}
|
||||
|
||||
return shapeList;
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// Created by raver119 on 24.11.17.
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_mergeavg)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/transforms.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
OP_IMPL(mergeavg, -1, 1, false) {
|
||||
REQUIRE_OK(this->validateInputDimensionsMatch(block));
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
if (output->isEmpty()) {
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
int nonEmpty = 0;
|
||||
for (size_t i = 0; i < block.width(); i++)
|
||||
if (!INPUT_VARIABLE(i)->isEmpty()) nonEmpty++;
|
||||
|
||||
std::vector<NDArray*> inArrs(nonEmpty);
|
||||
int numNonEmptyAdded = 0;
|
||||
if(nonEmpty > 0)
|
||||
for (size_t i = 0; i < block.width(); ++i) if(!INPUT_VARIABLE(i)->isEmpty())inArrs[numNonEmptyAdded++] = INPUT_VARIABLE(i);
|
||||
|
||||
helpers::mergeAvg(block.launchContext(), inArrs, *output);
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(mergeavg) { getOpDescriptor()->setAllowedInputTypes({ALL_FLOATS})->setAllowedOutputTypes({ALL_FLOATS}); }
|
||||
|
||||
CUSTOM_OP_IMPL(mergeavg_bp, 2, 1, false, 0, 0) {
|
||||
auto inSize = block.width() - 1;
|
||||
|
||||
REQUIRE_OK(this->validateInputDimensionsMatch(block));
|
||||
|
||||
std::vector<NDArray*> outArrs(inSize);
|
||||
|
||||
const auto gradient = INPUT_VARIABLE(inSize);
|
||||
|
||||
for (size_t i = 0; i < inSize; ++i) {
|
||||
outArrs[i] = OUTPUT_VARIABLE(i);
|
||||
}
|
||||
helpers::mergeAvgBp(block.launchContext(), *gradient, outArrs);
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(mergeavg_bp) {
|
||||
getOpDescriptor()->setAllowedInputTypes(ANY)->setAllowedOutputTypes(ANY);
|
||||
}
|
||||
DECLARE_SHAPE_FN(mergeavg_bp) {
|
||||
const int numOfInArrs = block.width() - 1;
|
||||
|
||||
auto shapeList = SHAPELIST();
|
||||
|
||||
for (int e = 0; e < numOfInArrs; e++) {
|
||||
auto inShape = inputShape->at(e);
|
||||
shapeList->push_back(ConstantShapeHelper::getInstance().bufferForShapeInfo(ArrayOptions::dataType(inShape),
|
||||
shape::order(inShape),
|
||||
shape::rank(inShape),
|
||||
shape::shapeOf(inShape))->primary());
|
||||
}
|
||||
|
||||
return shapeList;
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,100 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// Created by raver119 on 24.11.17.
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_mergemax)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/transforms.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
OP_IMPL(mergemax, -1, 1, false) {
|
||||
REQUIRE_OK(this->validateInputDimensionsMatch(block));
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
if (output->isEmpty()) {
|
||||
return Status::OK;
|
||||
}
|
||||
int nonEmpty = 0;
|
||||
for (size_t i = 0; i < block.width(); i++)
|
||||
if (!INPUT_VARIABLE(i)->isEmpty()) nonEmpty++;
|
||||
|
||||
std::vector<NDArray*> inArrs(nonEmpty);
|
||||
|
||||
int numNonEmptyAdded = 0;
|
||||
if(nonEmpty > 0)
|
||||
for (size_t i = 0; i < block.width(); ++i) if(!INPUT_VARIABLE(i)->isEmpty())inArrs[numNonEmptyAdded++] = INPUT_VARIABLE(i);
|
||||
|
||||
helpers::mergeMax(block.launchContext(), inArrs, *output);
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
DECLARE_SYN(MergeMax, mergemax);
|
||||
|
||||
DECLARE_TYPES(mergemax) {
|
||||
getOpDescriptor()->setAllowedInputTypes(ANY)->setAllowedOutputTypes(ANY);
|
||||
}
|
||||
|
||||
CUSTOM_OP_IMPL(mergemax_bp, 2, 1, false, 0, 0) {
|
||||
auto inSize = block.width();
|
||||
|
||||
REQUIRE_OK(this->validateInputDimensionsMatch(block));
|
||||
|
||||
std::vector<NDArray*> inArrs(inSize);
|
||||
std::vector<NDArray*> outArrs(inSize - 1);
|
||||
|
||||
for (size_t i = 0; i < inSize; ++i) inArrs[i] = INPUT_VARIABLE(i);
|
||||
|
||||
for (size_t i = 0; i < (inSize - 1); ++i) {
|
||||
outArrs[i] = OUTPUT_NULLIFIED(i);
|
||||
}
|
||||
|
||||
helpers::mergeMaxBp(block.launchContext(), inArrs, outArrs);
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(mergemax_bp) {
|
||||
getOpDescriptor()->setAllowedInputTypes(ANY)->setAllowedOutputTypes(ANY);
|
||||
}
|
||||
DECLARE_SHAPE_FN(mergemax_bp) {
|
||||
const int numOfInArrs = block.width() - 1;
|
||||
|
||||
auto shapeList = SHAPELIST();
|
||||
|
||||
for (int e = 0; e < numOfInArrs; e++) {
|
||||
auto inShape = inputShape->at(e);
|
||||
shapeList->push_back(ConstantShapeHelper::getInstance().bufferForShapeInfo(ArrayOptions::dataType(inShape),
|
||||
shape::order(inShape),
|
||||
shape::rank(inShape),
|
||||
shape::shapeOf(inShape))->primary());
|
||||
}
|
||||
|
||||
return shapeList;
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,61 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// Created by raver119 on 24.11.17.
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_mergemaxindex)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/transforms.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
CUSTOM_OP_IMPL(mergemaxindex, -1, 1, false, 0, 0) {
|
||||
REQUIRE_OK(this->validateInputDimensionsMatch(block));
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
std::vector<NDArray*> inArrs(block.width());
|
||||
|
||||
for (size_t i = 0; i < block.width(); ++i) inArrs[i] = INPUT_VARIABLE(i);
|
||||
|
||||
helpers::mergeMaxIndex(block.launchContext(), inArrs, *output);
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_SYN(MergeMaxIndex, mergemaxindex);
|
||||
|
||||
DECLARE_TYPES(mergemaxindex) {
|
||||
getOpDescriptor()->setAllowedInputTypes({ALL_INTS, ALL_FLOATS})->setAllowedOutputTypes({ALL_INDICES});
|
||||
}
|
||||
} // namespace ops
|
||||
DECLARE_SHAPE_FN(mergemaxindex) {
|
||||
auto in = inputShape->at(0);
|
||||
auto dtype = INT32;
|
||||
if (block.getIArguments()->size() > 0) dtype = (DataType)INT_ARG(0);
|
||||
|
||||
auto resShape = ShapeBuilders::copyShapeInfoAndType(in, dtype, block.workspace());
|
||||
return SHAPELIST(CONSTANT(resShape));
|
||||
}
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,86 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com), created on 07.06.2018
|
||||
//
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_mirror_pad)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/transforms.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
CUSTOM_OP_IMPL(mirror_pad, 2, 1, false, 0, 1) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto paddings = INPUT_VARIABLE(1);
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
const int mode = INT_ARG(0); // 0 - REFLECT, else - SYMMETRIC
|
||||
const int includeBorder = mode ? 0 : 1;
|
||||
helpers::mirrorPad(block.launchContext(), *input, *paddings, *output, mode);
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(mirror_pad) {
|
||||
getOpDescriptor()->setAllowedInputTypes(0, {ALL_FLOATS});
|
||||
getOpDescriptor()->setAllowedInputTypes(1, {DataType::INT32, DataType::INT64}); // to conform with TF
|
||||
getOpDescriptor()->setAllowedOutputTypes(0, {ALL_FLOATS});
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(mirror_pad) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto paddings = INPUT_VARIABLE(1);
|
||||
|
||||
const int includeBorder = static_cast<bool>(INT_ARG(0)) ? 0 : 1;
|
||||
|
||||
if (input->isScalar()) {
|
||||
sd::LongType len = input->isScalar() ? 1 + paddings->e<sd::LongType>(0) + paddings->e<sd::LongType>(1) : input->lengthOf() + paddings->e<sd::LongType>(0) + paddings->e<sd::LongType>(1);
|
||||
return SHAPELIST(ConstantShapeHelper::getInstance().vectorShapeInfo(len, input->dataType()));
|
||||
}
|
||||
|
||||
sd::LongType* outShapeInfo(nullptr);
|
||||
int rank = input->rankOf();
|
||||
|
||||
ALLOCATE(outShapeInfo, block.getWorkspace(), shape::shapeInfoLength(rank), sd::LongType);
|
||||
outShapeInfo[0] = rank;
|
||||
if(paddings->isVector()) {
|
||||
for (int i = 0; i < rank; ++i) {
|
||||
outShapeInfo[i + 1] = input->sizeAt(i) + paddings->e<sd::LongType>(0) + paddings->e<sd::LongType>(1);
|
||||
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < rank; ++i) {
|
||||
outShapeInfo[i + 1] = input->sizeAt(i) + paddings->e<sd::LongType>(i, 0) + paddings->e<sd::LongType>(i, 1);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ShapeUtils::updateStridesAndType(outShapeInfo, input->shapeInfo(), input->ordering());
|
||||
|
||||
return SHAPELIST(CONSTANT(outShapeInfo));
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,128 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author Shyrma Yurii (iuriish@yahoo.com), created on 06.11.2017.
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_pad)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/transforms.h>
|
||||
|
||||
#include <numeric>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CUSTOM_OP_IMPL(pad, 2, 1, false, 0, 1) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto paddings = INPUT_VARIABLE(1);
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
const int rank = input->rankOf();
|
||||
|
||||
// input validation
|
||||
std::vector<sd::LongType> expectedPaddingsShape = {rank, 2};
|
||||
std::vector<sd::LongType> *currentPaddingsShape = paddings->getShapeAsVector();
|
||||
REQUIRE_TRUE(expectedPaddingsShape == *currentPaddingsShape, 0,
|
||||
"PAD op: wrong shape of paddings array, expected is %s, but got %s instead !",
|
||||
ShapeUtils::shapeAsString(expectedPaddingsShape).c_str(),
|
||||
ShapeUtils::shapeAsString(*currentPaddingsShape).c_str());
|
||||
|
||||
|
||||
NDArray padValue(input->dataType(), block.launchContext());
|
||||
|
||||
// in case of REFLECT and SYMMETRIC modes paddings must obey additional shape requirements
|
||||
if (INT_ARG(0) == 0) { // CONSTANT mode
|
||||
if (block.width() > 2) {
|
||||
REQUIRE_TRUE(
|
||||
input->dataType() == INPUT_VARIABLE(2)->dataType(), 0,
|
||||
"PAD op: data types of input and padValue arrays should be the same but got %i and %i correspondingly !",
|
||||
input->dataType(), INPUT_VARIABLE(2)->dataType());
|
||||
auto get = INPUT_VARIABLE(2)->e(0);
|
||||
padValue.assign(&get);
|
||||
} else if (!block.getTArguments()->empty())
|
||||
padValue = T_ARG(0);
|
||||
} else if (INT_ARG(0) == 1) { // REFLECT mode
|
||||
for (int dim = 0; dim < rank; ++dim)
|
||||
REQUIRE_TRUE(paddings->e<sd::LongType>(dim, 0) <= (input->shapeOf()[dim] - 1) &&
|
||||
paddings->e<sd::LongType>(dim, 1) <= (input->shapeOf()[dim] - 1),
|
||||
0, "PAD op: wrong content of paddings array for REFLECT mode !");
|
||||
}
|
||||
if (INT_ARG(0) == 2) { // SYMMETRIC mode
|
||||
for (int dim = 0; dim < rank; ++dim)
|
||||
REQUIRE_TRUE(paddings->e<sd::LongType>(dim, 0) <= input->shapeOf()[dim] &&
|
||||
paddings->e<sd::LongType>(dim, 1) <= input->shapeOf()[dim],
|
||||
0, "PAD op: wrong content of paddings array for SYMMETRIC mode !");
|
||||
}
|
||||
|
||||
// CONSTANT->0, REFLECT->1, SYMMETRIC->2
|
||||
REQUIRE_TRUE(
|
||||
INT_ARG(0) >= 0 && INT_ARG(0) <= 2, 0,
|
||||
"PAD op: unknown padding mode, there are only three possible legal values -> 0,1,2, but got %i instead !",
|
||||
INT_ARG(0));
|
||||
|
||||
helpers::pad(block.launchContext(), INT_ARG(0), *input, *paddings, *output, padValue);
|
||||
|
||||
delete currentPaddingsShape;
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(pad) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, sd::DataType::ANY)
|
||||
->setAllowedInputTypes(1, {DataType::INT32, DataType::INT64}) // INT32 with TF
|
||||
->setSameMode(true);
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(pad) {
|
||||
// check shape of paddings
|
||||
auto inputShapeInfo = inputShape->at(0);
|
||||
auto paddings = INPUT_VARIABLE(1);
|
||||
const int rank = inputShapeInfo[0];
|
||||
if(rank < 0 || rank > SD_MAX_RANK) {
|
||||
THROW_EXCEPTION("PAD op: Bad shape buffer. Likely corrupt. Please ensure buffer was not deallocated.");
|
||||
}
|
||||
// paddings validation
|
||||
const std::vector<sd::LongType> expectedPaddingsShape = {rank, 2};
|
||||
const std::vector<sd::LongType> *currentPaddingsShape = paddings->getShapeAsVector();
|
||||
REQUIRE_TRUE(expectedPaddingsShape == *currentPaddingsShape, 0,
|
||||
"PAD op: wrong shape of paddings array, expected is %s, but got %s instead !",
|
||||
ShapeUtils::shapeAsString(expectedPaddingsShape).c_str(),
|
||||
ShapeUtils::shapeAsString(*currentPaddingsShape).c_str());
|
||||
|
||||
delete currentPaddingsShape;
|
||||
sd::LongType* outShapeInfo = nullptr;
|
||||
ALLOCATE(outShapeInfo, block.getWorkspace(), shape::shapeInfoLength(rank), sd::LongType);
|
||||
outShapeInfo[0] = rank;
|
||||
for (int i = 1; i <= rank; ++i)
|
||||
outShapeInfo[i] = inputShapeInfo[i] + paddings->e<sd::LongType>(i - 1, 0) + paddings->e<sd::LongType>(i - 1, 1);
|
||||
|
||||
ShapeUtils::updateStridesAndType(outShapeInfo, inputShapeInfo, shape::order(inputShapeInfo));
|
||||
auto ret = SHAPELIST(ConstantShapeHelper::getInstance().bufferForShapeInfo(outShapeInfo)->primary());
|
||||
RELEASE(outShapeInfo, block.getWorkspace());
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,73 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com), created on 01.11.2017
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_parallel_stack)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/stack.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
CUSTOM_OP_IMPL(parallel_stack, -1, 1, false, 0, 0) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
// check whether shapes of all input array are the same
|
||||
for (int i = 0; i < (int)block.width() - 1; ++i)
|
||||
REQUIRE_TRUE(shape::equalsSoft((INPUT_VARIABLE(i))->shapeInfo(), (INPUT_VARIABLE(i + 1))->shapeInfo()), 0,
|
||||
"PARALLEL_STACK op: the shapes of all input arrays must be the same !");
|
||||
|
||||
std::vector<NDArray*> inArrs(block.width());
|
||||
for (size_t i = 0; i < block.width(); ++i) inArrs[i] = INPUT_VARIABLE(i);
|
||||
|
||||
const int dim = 0;
|
||||
helpers::stack(block.launchContext(), inArrs, *output, dim);
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(parallel_stack) {
|
||||
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(parallel_stack) {
|
||||
auto inShapeInfo = inputShape->at(0);
|
||||
int rank = inShapeInfo[0];
|
||||
|
||||
sd::LongType* outShapeInfo = nullptr;
|
||||
ALLOCATE(outShapeInfo, block.getWorkspace(), shape::shapeInfoLength(rank + 1), sd::LongType);
|
||||
|
||||
outShapeInfo[0] = rank + 1;
|
||||
outShapeInfo[1] = block.width();
|
||||
for (int i = 1; i <= rank; ++i) outShapeInfo[i + 1] = inShapeInfo[i];
|
||||
|
||||
ShapeUtils::updateStridesAndType(outShapeInfo, inShapeInfo, shape::order(inShapeInfo));
|
||||
|
||||
return SHAPELIST(CONSTANT(outShapeInfo));
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,78 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com)
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_repeat)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// here iArgs is int vector of repeats at the beginning and last element in iArgs is dimension
|
||||
CUSTOM_OP_IMPL(repeat, 1, 1, true, 0, -1) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
std::vector<LongType> repeats = *block.getIArguments();
|
||||
|
||||
const int axis = repeats.back() < 0 ? repeats.back() + input->rankOf() : repeats.back();
|
||||
|
||||
repeats.pop_back();
|
||||
|
||||
REQUIRE_TRUE(0 <= axis && axis < input->rankOf(), 0,
|
||||
"CUSTOM REPEAT OP: wrong axis argument it should be less then input array rank %i, but got %i instead !",
|
||||
input->rankOf(), axis);
|
||||
|
||||
REQUIRE_TRUE(repeats.size() == 1 || repeats.size() == static_cast<size_t>(input->sizeAt(axis)), 0,
|
||||
"CUSTOM REPEAT OP: wrong axis argument, size of repeats vector must be 1 or equal to dimension at given "
|
||||
"axis, but got repeats.size = %i and axis = %i !",
|
||||
repeats.size(), axis);
|
||||
|
||||
input->repeat(axis, repeats, *output);
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(repeat) { getOpDescriptor()->setAllowedInputTypes(ANY)->setSameMode(true); }
|
||||
|
||||
DECLARE_SHAPE_FN(repeat) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
|
||||
std::vector<LongType> repeats = *block.getIArguments();
|
||||
|
||||
const int axis = repeats.back() < 0 ? repeats.back() + input->rankOf() : repeats.back();
|
||||
|
||||
repeats.pop_back();
|
||||
|
||||
auto outShape = ShapeUtils::evalRepeatShape(axis, repeats, *input);
|
||||
|
||||
auto ret = SHAPELIST(ConstantShapeHelper::getInstance().bufferForShapeInfo(input->dataType(),
|
||||
input->ordering(),
|
||||
outShape)->primary());
|
||||
return ret;
|
||||
}
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,106 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com), created on 02.11.2017
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_reverse)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/reverse.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
CONFIGURABLE_OP_IMPL(reverse, 1, 1, true, 0, -2) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
if (output->isEmpty()) {
|
||||
// No-op
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
std::vector<LongType> axis;
|
||||
|
||||
if (block.width() > 1)
|
||||
axis = INPUT_VARIABLE(1)->template asVectorT<LongType>();
|
||||
else if (block.numI() > 0)
|
||||
axis = *block.getIArguments();
|
||||
|
||||
if (axis.empty()) { // do not perform reversion
|
||||
if (!block.isInplace()) output->assign(input);
|
||||
} else {
|
||||
// check the consistency of input dimensions to reverse along
|
||||
shape::checkDimensions(input->rankOf(), &axis);
|
||||
helpers::reverse(block.launchContext(), input, output, &axis);
|
||||
}
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_SYN(reverse_v2, reverse);
|
||||
|
||||
DECLARE_TYPES(reverse) {
|
||||
getOpDescriptor()->setAllowedInputTypes(0, ANY);
|
||||
getOpDescriptor()->setAllowedInputTypes(1, {INT32, INT64});
|
||||
getOpDescriptor()->setAllowedOutputTypes(0, INHERIT);
|
||||
}
|
||||
|
||||
CUSTOM_OP_IMPL(reverse_bp, 2, 1, false, 0, -2) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto eps = block.width() == 3 ? INPUT_VARIABLE(2) : INPUT_VARIABLE(1);
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
std::vector<LongType> axis;
|
||||
|
||||
if (block.width() == 3)
|
||||
axis = INPUT_VARIABLE(1)->template asVectorT<LongType>();
|
||||
else if (block.numI() > 0)
|
||||
axis = *block.getIArguments();
|
||||
|
||||
if (axis.empty()) { // reversion is not performed in this case
|
||||
output->assign(eps);
|
||||
} else {
|
||||
// check the consistency of input dimensions to reverse along
|
||||
shape::checkDimensions(input->rankOf(), &axis);
|
||||
// we just reverse back original array
|
||||
helpers::reverse(block.launchContext(), eps, output, &axis);
|
||||
}
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(reverse_bp) {
|
||||
getOpDescriptor()->setAllowedInputTypes(ANY)->setAllowedOutputTypes({ALL_FLOATS});
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(reverse_bp) {
|
||||
auto in = inputShape->at(0);
|
||||
LongType *out;
|
||||
COPY_SHAPE(in, out);
|
||||
|
||||
return SHAPELIST(CONSTANT(out));
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,111 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// Created by Yurii Shyrma on 25.01.2018
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_reverse_sequence)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/reverse.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
CUSTOM_OP_IMPL(reverse_sequence, 2, 1, false, 0, 2) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto seqLengths = INPUT_VARIABLE(1);
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
int seqDim = INT_ARG(0);
|
||||
int batchDim = block.numI() > 1 ? INT_ARG(1) : 0;
|
||||
|
||||
REQUIRE_TRUE(input->rankOf() > 1, 0,
|
||||
"REVERSE_SEQUENSE operation: input array must have rank > 1, but got %i instead !", input->rankOf());
|
||||
REQUIRE_TRUE(seqLengths->rankOf() == 1, 0,
|
||||
"REVERSE_SEQUENSE operation: input array seqLengths must be 1D vector, that is it must have rank == 1, "
|
||||
"but got %i instead !",
|
||||
seqLengths->rankOf());
|
||||
REQUIRE_TRUE(seqLengths->lengthOf() == input->sizeAt(batchDim), 0,
|
||||
"REVERSE_SEQUENSE custom operation: the length of array seqLengths must be equal to the value of "
|
||||
"batchDim dimension of input array, but got %i and %i correspondingly !",
|
||||
seqLengths->lengthOf(), input->sizeAt(batchDim));
|
||||
REQUIRE_TRUE(seqDim != batchDim, 0,
|
||||
"REVERSE_SEQUENSE operation: input integer parameters seqDim and batchDim must be different, but they "
|
||||
"both are equal to %i !",
|
||||
batchDim);
|
||||
REQUIRE_TRUE(batchDim < input->rankOf(), 0,
|
||||
"REVERSE_SEQUENSE operation: input integer parameter batchDim must be smaller than input array rank, "
|
||||
"but got %i and %i correspondingly !",
|
||||
batchDim, input->rankOf());
|
||||
REQUIRE_TRUE(seqDim < input->rankOf(), 0,
|
||||
"REVERSE_SEQUENSE operation: input integer parameter seqDim must be smaller than input array rank, but "
|
||||
"got %i and %i correspondingly !",
|
||||
seqDim, input->rankOf());
|
||||
|
||||
auto maxElem = seqLengths->reduceNumber(reduce::Max);
|
||||
REQUIRE_TRUE(maxElem->e<sd::LongType>(0) <= input->sizeAt(seqDim), 0,
|
||||
"REVERSE_SEQUENSE operation: max element in seqLengths array must be not greater than value of seqDim "
|
||||
"dimension of input array !");
|
||||
|
||||
helpers::reverseSequence(block.launchContext(), input, seqLengths, output, seqDim, batchDim);
|
||||
delete maxElem;
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(reverse_sequence) {
|
||||
getOpDescriptor()->setAllowedInputTypes(0, {ALL_FLOATS, ALL_INTS});
|
||||
getOpDescriptor()->setAllowedInputTypes(1, {DataType::INT32, DataType::INT64});
|
||||
getOpDescriptor()->setAllowedOutputTypes(0, DataType::INHERIT);
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(reverse_sequence) {
|
||||
auto inShapeInfo = inputShape->at(0);
|
||||
auto seqLenShapeInfo = inputShape->at(1);
|
||||
|
||||
int seqDim = INT_ARG(0);
|
||||
int batchDim = block.numI() > 1 ? INT_ARG(1) : 0;
|
||||
|
||||
REQUIRE_TRUE(batchDim < inShapeInfo[0], 0,
|
||||
"REVERSE_SEQUENSE operation: input integer parameter batchDim must be smaller than input array rank, "
|
||||
"but got %i and %i correspondingly !",
|
||||
batchDim, inShapeInfo[0]);
|
||||
REQUIRE_TRUE(seqDim < inShapeInfo[0], 0,
|
||||
"REVERSE_SEQUENSE operation: input integer parameter seqDim must be smaller than input array rank, but "
|
||||
"got %i and %i correspondingly !",
|
||||
seqDim, inShapeInfo[0]);
|
||||
REQUIRE_TRUE(inShapeInfo[0] > 1, 0,
|
||||
"REVERSE_SEQUENSE operation: input array must have rank > 1, but got %i instead !", inShapeInfo[0]);
|
||||
REQUIRE_TRUE(seqLenShapeInfo[0] == 1, 0,
|
||||
"REVERSE_SEQUENSE operation: input array seqLengths must be 1D vector, that is it must have rank == 1, "
|
||||
"but got %i instead !",
|
||||
seqLenShapeInfo[0]);
|
||||
REQUIRE_TRUE(seqLenShapeInfo[1] == inShapeInfo[batchDim + 1], 0,
|
||||
"REVERSE_SEQUENSE custom operation: the length of array seqLengths must be equal to the value of "
|
||||
"batchDim dimension of input array, but got %i and %i correspondingly !",
|
||||
seqLenShapeInfo[1], inShapeInfo[batchDim + 1]);
|
||||
|
||||
return SHAPELIST(CONSTANT(inShapeInfo));
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,108 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com, created on 24.11.17.
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com)
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_scatter_add)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/generic/helpers/ScatterHelper.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
OP_IMPL(scatter_add, 3, 1, true) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto indices = INPUT_VARIABLE(1);
|
||||
auto updates = INPUT_VARIABLE(2);
|
||||
if(indices->isEmpty())
|
||||
return Status::OK;
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
if (!block.isInplace())
|
||||
output->assign(input);
|
||||
|
||||
const bool lock = block.getBArguments()->empty() ? false : B_ARG(0);
|
||||
const bool checkIndices = block.getBArguments()->size() <= 1 ? false : B_ARG(1);
|
||||
|
||||
const int inRank = input->rankOf();
|
||||
const int indRank = indices->rankOf();
|
||||
const int updRank = updates->rankOf();
|
||||
const LongType indLen = indices->lengthOf();
|
||||
|
||||
REQUIRE_TRUE(inRank > 0, 0, "SCATTER_ADD OP: input should not be scalar !");
|
||||
|
||||
if(inRank == 1) {
|
||||
REQUIRE_TRUE(indices->isSameShape(updates), 0, "SCATTER_ADD OP: when input array has rank = 1 then indices and updates must have the same shapes, but got %s and %s correspondingly !", ShapeUtils::shapeAsString(indices).c_str(), ShapeUtils::shapeAsString(updates).c_str());
|
||||
}
|
||||
else if (inRank == updRank && indices->isVector()) {
|
||||
auto* updShapeVec = updates->getShapeAsVector();
|
||||
auto* inShapeVec = input->getShapeAsVector();
|
||||
std::vector<LongType> expectedUpdShape = {indices->lengthOf()};
|
||||
expectedUpdShape.insert(expectedUpdShape.end(), inShapeVec->begin()+1, inShapeVec->end());
|
||||
delete updShapeVec;
|
||||
delete inShapeVec;
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
REQUIRE_TRUE(updRank == indRank + inRank - 1, 0, "SCATTER_ADD OP: wrong rank of updates array, expected is %i, but got %i instead !", indRank + inRank - 1 , updRank);
|
||||
|
||||
auto* updShapeVec = updates->getShapeAsVector();
|
||||
auto* inShapeVec = input->getShapeAsVector();
|
||||
auto* indShapeVec = indices->getShapeAsVector();
|
||||
std::vector<LongType> expectedUpdShape = *indShapeVec;
|
||||
expectedUpdShape.insert(expectedUpdShape.end(), inShapeVec->begin() + LongType(1L), inShapeVec->end());
|
||||
delete updShapeVec;
|
||||
delete inShapeVec;
|
||||
delete indShapeVec;
|
||||
|
||||
}
|
||||
|
||||
if (!indices->isEmpty()) {
|
||||
|
||||
if(checkIndices) {
|
||||
const LongType numOfBadIndx = helpers::checkIndices(block.launchContext(), *indices, *output, 0);
|
||||
REQUIRE_TRUE(numOfBadIndx == 0, 0, "SCATTER_ADD OP: please check elements of indices-array, total number of wrong elements is %lld!", numOfBadIndx);
|
||||
}
|
||||
|
||||
helpers::scatter(block.launchContext(), pairwise::Add, *indices, *updates, *output, lock);
|
||||
}
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_SYN(ScatterAdd, scatter_add);
|
||||
|
||||
DECLARE_TYPES(scatter_add) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedInputTypes(1, {ALL_INTS})
|
||||
->setAllowedInputTypes(2, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedOutputTypes({ALL_INTS, ALL_FLOATS});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,108 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author Created by raver119 on 24.11.17.
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com)
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_scatter_div)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/generic/helpers/ScatterHelper.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
OP_IMPL(scatter_div, 3, 1, true) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto indices = INPUT_VARIABLE(1);
|
||||
auto updates = INPUT_VARIABLE(2);
|
||||
if(indices->isEmpty())
|
||||
return Status::OK;
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
if (!block.isInplace()) output->assign(input);
|
||||
|
||||
const bool lock = block.getBArguments()->empty() ? false : B_ARG(0);
|
||||
const bool checkIndices = block.getBArguments()->size() <= 1 ? false : B_ARG(1);
|
||||
|
||||
const int inRank = input->rankOf();
|
||||
const int indRank = indices->rankOf();
|
||||
const int updRank = updates->rankOf();
|
||||
|
||||
REQUIRE_TRUE(inRank > 0, 0, "SCATTER_DIV OP: input should not be scalar !");
|
||||
|
||||
if (inRank == 1) {
|
||||
REQUIRE_TRUE(indices->isSameShape(updates), 0,
|
||||
"SCATTER_DIV OP: when input array has rank = 1 then indices and updates must have the same shapes, "
|
||||
"but got %s and %s correspondingly !",
|
||||
ShapeUtils::shapeAsString(indices).c_str(), ShapeUtils::shapeAsString(updates).c_str());
|
||||
} else if (inRank == updRank && indices->isVector()) {
|
||||
auto* updShapeVec = updates->getShapeAsVector();
|
||||
auto* inShapeVec = input->getShapeAsVector();
|
||||
std::vector<LongType> expectedUpdShape = {indices->lengthOf()};
|
||||
expectedUpdShape.insert(expectedUpdShape.end(), inShapeVec->begin() + 1, inShapeVec->end());
|
||||
|
||||
REQUIRE_TRUE(expectedUpdShape == *updShapeVec, 0,
|
||||
"SCATTER_DIV OP: wrong shape of updates array, expected is %s, but got %s instead !",
|
||||
ShapeUtils::shapeAsString(expectedUpdShape).c_str(), ShapeUtils::shapeAsString(*updShapeVec).c_str());
|
||||
delete updShapeVec;
|
||||
delete inShapeVec;
|
||||
} else {
|
||||
auto* updShapeVec = updates->getShapeAsVector();
|
||||
auto* inShapeVec = input->getShapeAsVector();
|
||||
auto* indShapeVec = indices->getShapeAsVector();
|
||||
std::vector<LongType> expectedUpdShape = *indShapeVec;
|
||||
expectedUpdShape.insert(expectedUpdShape.end(), inShapeVec->begin() + 1, inShapeVec->end());
|
||||
|
||||
REQUIRE_TRUE(expectedUpdShape == *updShapeVec, 0,
|
||||
"SCATTER_DIV OP: wrong shape of updates array, expected is %s, but got %s instead !",
|
||||
ShapeUtils::shapeAsString(expectedUpdShape).c_str(), ShapeUtils::shapeAsString(*updShapeVec).c_str());
|
||||
delete updShapeVec;
|
||||
delete inShapeVec;
|
||||
delete indShapeVec;
|
||||
}
|
||||
|
||||
if (!indices->isEmpty()) {
|
||||
if (checkIndices) {
|
||||
const LongType numOfBadIndx = helpers::checkIndices(block.launchContext(), *indices, *output, 0);
|
||||
REQUIRE_TRUE(numOfBadIndx == 0, 0,
|
||||
"SCATTER_DIV OP: please check elements of indices-array, total number of wrong elements is %lld!",
|
||||
numOfBadIndx);
|
||||
}
|
||||
|
||||
helpers::scatter(block.launchContext(), pairwise::Divide, *indices, *updates, *output, lock);
|
||||
}
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
DECLARE_SYN(ScatterDiv, scatter_div);
|
||||
|
||||
DECLARE_TYPES(scatter_div) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedInputTypes(1, {ALL_INTS})
|
||||
->setAllowedInputTypes(2, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedOutputTypes({ALL_INTS, ALL_FLOATS});
|
||||
}
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,113 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com), created on 1.08.2018
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_scatter_max)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/generic/helpers/ScatterHelper.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
OP_IMPL(scatter_max, 3, 1, true) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto indices = INPUT_VARIABLE(1);
|
||||
auto updates = INPUT_VARIABLE(2);
|
||||
if(indices->isEmpty())
|
||||
return Status::OK;
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
if (!block.isInplace()) output->assign(input);
|
||||
|
||||
const bool lock = block.getBArguments()->empty() ? false : B_ARG(0);
|
||||
const bool checkIndices = block.getBArguments()->size() <= 1 ? false : B_ARG(1);
|
||||
|
||||
const int inRank = input->rankOf();
|
||||
const int indRank = indices->rankOf();
|
||||
const int updRank = updates->rankOf();
|
||||
|
||||
REQUIRE_TRUE(inRank > 0, 0, "SCATTER_MAX OP: input should not be scalar !");
|
||||
|
||||
if (inRank == 1) {
|
||||
REQUIRE_TRUE(indices->isSameShape(updates), 0,
|
||||
"SCATTER_MAX OP: when input array has rank = 1 then indices and updates must have the same shapes, "
|
||||
"but got %s and %s correspondingly !",
|
||||
ShapeUtils::shapeAsString(indices).c_str(), ShapeUtils::shapeAsString(updates).c_str());
|
||||
} else if (inRank == updRank && indices->isVector()) {
|
||||
auto* updShapeVec = updates->getShapeAsVector();
|
||||
auto* inShapeVec = input->getShapeAsVector();
|
||||
std::vector<LongType> expectedUpdShape = {indices->lengthOf()};
|
||||
expectedUpdShape.insert(expectedUpdShape.end(), inShapeVec->begin() + 1, inShapeVec->end());
|
||||
|
||||
REQUIRE_TRUE(expectedUpdShape == *updShapeVec, 0,
|
||||
"SCATTER_MAX OP: wrong shape of updates array, expected is %s, but got %s instead !",
|
||||
ShapeUtils::shapeAsString(expectedUpdShape).c_str(), ShapeUtils::shapeAsString(*updShapeVec).c_str());
|
||||
delete updShapeVec;
|
||||
delete inShapeVec;
|
||||
} else {
|
||||
REQUIRE_TRUE(updRank == indRank + inRank - 1, 0,
|
||||
"SCATTER_MAX OP: wrong rank of updates array, expected is %i, but got %i instead !",
|
||||
indRank + inRank - 1, updRank);
|
||||
|
||||
auto* updShapeVec = updates->getShapeAsVector();
|
||||
auto* inShapeVec = input->getShapeAsVector();
|
||||
auto* indShapeVec = indices->getShapeAsVector();
|
||||
std::vector<LongType> expectedUpdShape = *indShapeVec;
|
||||
expectedUpdShape.insert(expectedUpdShape.end(), inShapeVec->begin() + 1, inShapeVec->end());
|
||||
|
||||
REQUIRE_TRUE(expectedUpdShape == *updShapeVec, 0,
|
||||
"SCATTER_MAX OP: wrong shape of updates array, expected is %s, but got %s instead !",
|
||||
ShapeUtils::shapeAsString(expectedUpdShape).c_str(), ShapeUtils::shapeAsString(*updShapeVec).c_str());
|
||||
delete updShapeVec;
|
||||
delete inShapeVec;
|
||||
delete indShapeVec;
|
||||
}
|
||||
|
||||
if (!indices->isEmpty()) {
|
||||
if (checkIndices) {
|
||||
const LongType numOfBadIndx = helpers::checkIndices(block.launchContext(), *indices, *output, 0);
|
||||
REQUIRE_TRUE(numOfBadIndx == 0, 0,
|
||||
"SCATTER_MAX OP: please check elements of indices-array, total number of wrong elements is %lld!",
|
||||
numOfBadIndx);
|
||||
}
|
||||
|
||||
helpers::scatter(block.launchContext(), pairwise::MaxPairwise, *indices, *updates, *output, lock);
|
||||
}
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
DECLARE_SYN(ScatterMax, scatter_max);
|
||||
|
||||
DECLARE_TYPES(scatter_max) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedInputTypes(1, {ALL_INTS})
|
||||
->setAllowedInputTypes(2, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedOutputTypes({ALL_INTS, ALL_FLOATS});
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,106 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com), created on 1.08.2018
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_scatter_min)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/generic/helpers/ScatterHelper.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
OP_IMPL(scatter_min, 3, 1, true) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto indices = INPUT_VARIABLE(1);
|
||||
auto updates = INPUT_VARIABLE(2);
|
||||
if(indices->isEmpty())
|
||||
return Status::OK;
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
if (!block.isInplace()) output->assign(input);
|
||||
|
||||
const bool lock = block.getBArguments()->empty() ? false : B_ARG(0);
|
||||
const bool checkIndices = block.getBArguments()->size() <= 1 ? false : B_ARG(1);
|
||||
|
||||
const int inRank = input->rankOf();
|
||||
const int indRank = indices->rankOf();
|
||||
const int updRank = updates->rankOf();
|
||||
|
||||
REQUIRE_TRUE(inRank > 0, 0, "SCATTER_MIN OP: input should not be scalar !");
|
||||
|
||||
if (inRank <= 1) {
|
||||
REQUIRE_TRUE(indices->isSameShape(updates), 0,
|
||||
"SCATTER_MIN OP: when input array has rank = 1 then indices and updates must have the same shapes, "
|
||||
"but got %s and %s correspondingly !",
|
||||
ShapeUtils::shapeAsString(indices).c_str(), ShapeUtils::shapeAsString(updates).c_str());
|
||||
} else if (inRank == updRank && indices->isVector()) {
|
||||
auto* updShapeVec = updates->getShapeAsVector();
|
||||
auto* inShapeVec = input->getShapeAsVector();
|
||||
std::vector<LongType> expectedUpdShape = {indices->lengthOf()};
|
||||
expectedUpdShape.insert(expectedUpdShape.end(), inShapeVec->begin() + 1, inShapeVec->end());
|
||||
|
||||
REQUIRE_TRUE(expectedUpdShape == *updShapeVec, 0,
|
||||
"SCATTER_MIN OP: wrong shape of updates array, expected is %s, but got %s instead !",
|
||||
ShapeUtils::shapeAsString(expectedUpdShape).c_str(), ShapeUtils::shapeAsString(*updShapeVec).c_str());
|
||||
delete updShapeVec;
|
||||
delete inShapeVec;
|
||||
} else {
|
||||
auto* updShapeVec = updates->getShapeAsVector();
|
||||
auto* inShapeVec = input->getShapeAsVector();
|
||||
auto* indShapeVec = indices->getShapeAsVector();
|
||||
std::vector<LongType> expectedUpdShape = *indShapeVec;
|
||||
expectedUpdShape.insert(expectedUpdShape.end(), inShapeVec->begin() + 1, inShapeVec->end());
|
||||
delete updShapeVec;
|
||||
delete inShapeVec;
|
||||
delete indShapeVec;
|
||||
|
||||
}
|
||||
|
||||
if (!indices->isEmpty()) {
|
||||
if (checkIndices) {
|
||||
const LongType numOfBadIndx = helpers::checkIndices(block.launchContext(), *indices, *output, 0);
|
||||
REQUIRE_TRUE(numOfBadIndx == 0, 0,
|
||||
"SCATTER_MIN OP: please check elements of indices-array, total number of wrong elements is %lld!",
|
||||
numOfBadIndx);
|
||||
}
|
||||
|
||||
helpers::scatter(block.launchContext(), pairwise::MinPairwise, *indices, *updates, *output, lock);
|
||||
}
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
DECLARE_SYN(ScatterMin, scatter_min);
|
||||
|
||||
DECLARE_TYPES(scatter_min) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedInputTypes(1, {ALL_INTS})
|
||||
->setAllowedInputTypes(2, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedOutputTypes({ALL_INTS, ALL_FLOATS});
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,112 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author Created by raver119 on 24.11.17.
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com)
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_scatter_mul)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/generic/helpers/ScatterHelper.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
OP_IMPL(scatter_mul, 3, 1, true) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto indices = INPUT_VARIABLE(1);
|
||||
auto updates = INPUT_VARIABLE(2);
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
if(indices->isEmpty())
|
||||
return Status::OK;
|
||||
|
||||
const bool lock = block.getBArguments()->empty() ? false : B_ARG(0);
|
||||
const bool checkIndices = block.getBArguments()->size() <= 1 ? false : B_ARG(1);
|
||||
|
||||
const int inRank = input->rankOf();
|
||||
const int indRank = indices->rankOf();
|
||||
const int updRank = updates->rankOf();
|
||||
|
||||
if (!block.isInplace()) output->assign(input);
|
||||
|
||||
REQUIRE_TRUE(inRank > 0, 0, "SCATTER_MUL OP: input should not be scalar !");
|
||||
|
||||
if (inRank == 1) {
|
||||
REQUIRE_TRUE(indices->isSameShape(updates), 0,
|
||||
"SCATTER_MUL OP: when input array has rank = 1 then indices and updates must have the same shapes, "
|
||||
"but got %s and %s correspondingly !",
|
||||
ShapeUtils::shapeAsString(indices).c_str(), ShapeUtils::shapeAsString(updates).c_str());
|
||||
} else if (inRank == updRank && indices->isVector()) {
|
||||
auto* updShapeVec = updates->getShapeAsVector();
|
||||
auto* inShapeVec = input->getShapeAsVector();
|
||||
std::vector<LongType> expectedUpdShape = {indices->lengthOf()};
|
||||
expectedUpdShape.insert(expectedUpdShape.end(), inShapeVec->begin() + 1, inShapeVec->end());
|
||||
|
||||
REQUIRE_TRUE(expectedUpdShape == *updShapeVec, 0,
|
||||
"SCATTER_MUL OP: wrong shape of updates array, expected is %s, but got %s instead !",
|
||||
ShapeUtils::shapeAsString(expectedUpdShape).c_str(), ShapeUtils::shapeAsString(*updShapeVec).c_str());
|
||||
delete updShapeVec;
|
||||
delete inShapeVec;
|
||||
} else {
|
||||
REQUIRE_TRUE(updRank == indRank + inRank - 1, 0,
|
||||
"SCATTER_MUL OP: wrong rank of updates array, expected is %i, but got %i instead !",
|
||||
indRank + inRank - 1, updRank);
|
||||
|
||||
auto* updShapeVec = updates->getShapeAsVector();
|
||||
auto* inShapeVec = input->getShapeAsVector();
|
||||
auto* indShapeVec = indices->getShapeAsVector();
|
||||
std::vector<LongType> expectedUpdShape = *indShapeVec;
|
||||
expectedUpdShape.insert(expectedUpdShape.end(), inShapeVec->begin() + 1, inShapeVec->end());
|
||||
|
||||
REQUIRE_TRUE(expectedUpdShape == *updShapeVec, 0,
|
||||
"SCATTER_MUL OP: wrong shape of updates array, expected is %s, but got %s instead !",
|
||||
ShapeUtils::shapeAsString(expectedUpdShape).c_str(), ShapeUtils::shapeAsString(*updShapeVec).c_str());
|
||||
delete updShapeVec;
|
||||
delete inShapeVec;
|
||||
delete indShapeVec;
|
||||
}
|
||||
|
||||
if (!indices->isEmpty()) {
|
||||
if (checkIndices) {
|
||||
const LongType numOfBadIndx = helpers::checkIndices(block.launchContext(), *indices, *output, 0);
|
||||
REQUIRE_TRUE(numOfBadIndx == 0, 0,
|
||||
"SCATTER_MUL OP: please check elements of indices-array, total number of wrong elements is %lld!",
|
||||
numOfBadIndx);
|
||||
}
|
||||
|
||||
helpers::scatter(block.launchContext(), pairwise::Multiply, *indices, *updates, *output, lock);
|
||||
}
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
DECLARE_SYN(ScatterMul, scatter_mul);
|
||||
|
||||
DECLARE_TYPES(scatter_mul) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedInputTypes(1, {ALL_INTS})
|
||||
->setAllowedInputTypes(2, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedOutputTypes({ALL_INTS, ALL_FLOATS});
|
||||
}
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,118 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com), created on 21.08.2018
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_scatter_nd)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/generic/helpers/ScatterHelper.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
CUSTOM_OP_IMPL(scatter_nd, 3, 1, false, 0, 0) {
|
||||
auto indices = INPUT_VARIABLE(0);
|
||||
auto updates = INPUT_VARIABLE(1);
|
||||
auto shape = INPUT_VARIABLE(2);
|
||||
if(indices->isEmpty())
|
||||
return Status::OK;
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
const bool lock = block.getBArguments()->empty() ? false : B_ARG(0);
|
||||
const bool checkIndices = block.getBArguments()->size() <= 1 ? false : B_ARG(1);
|
||||
|
||||
const int indRank = indices->rankOf();
|
||||
const int updRank = updates->rankOf();
|
||||
const int shapeRank = shape->rankOf();
|
||||
const LongType shapeLen = shape->lengthOf();
|
||||
|
||||
REQUIRE_TRUE(shapeRank == 1, 0, "SCATTER_ND OP: the rank of shape array must be 1, but got %i instead !", shapeRank);
|
||||
REQUIRE_TRUE(indices->sizeAt(-1) <= shapeLen, 0,
|
||||
"SCATTER_ND OP: last dimension of indices array must be <= length of shape array, but got %i and %i "
|
||||
"correspondingly !",
|
||||
indices->sizeAt(-1), shapeLen);
|
||||
|
||||
REQUIRE_TRUE(
|
||||
updRank == (indRank - 1 + shapeLen - indices->sizeAt(-1)), 0,
|
||||
"SCATTER_ND OP: the equality updates_rank = (indices_rank - 1 + shape_length - last_indices_dimension) must be "
|
||||
"true for input arrays, but got instead: updates_rank = %i, shape_length = %i, last_indices_dimension = %i !",
|
||||
updRank, shapeLen, indices->sizeAt(-1));
|
||||
|
||||
std::vector<LongType> outShape = shape->getBufferAsVector<LongType>();
|
||||
auto* updShapePtr = updates->getShapeAsVector();
|
||||
std::vector<LongType> updShape = *updShapePtr;
|
||||
delete updShapePtr;
|
||||
auto* indShapePtr = indices->getShapeAsVector();
|
||||
std::vector<LongType> indShape = *indShapePtr;
|
||||
delete indShapePtr;
|
||||
std::vector<LongType> expectedUpdShape(std::begin(indShape), std::end(indShape) - 1);
|
||||
std::move(std::begin(outShape) + indices->sizeAt(-1), std::end(outShape), std::back_inserter(expectedUpdShape));
|
||||
REQUIRE_TRUE(expectedUpdShape == updShape, 0,
|
||||
"SCATTER_ND OP: wrong shape of updates array, expected is %s, but got %s instead !",
|
||||
ShapeUtils::shapeAsString(expectedUpdShape).c_str(), ShapeUtils::shapeAsString(updShape).c_str());
|
||||
|
||||
if (checkIndices) {
|
||||
const LongType numOfBadIndx = helpers::checkIndices(block.launchContext(), *indices, *output);
|
||||
REQUIRE_TRUE(numOfBadIndx == 0, 0,
|
||||
"SCATTER_ND OP: please check elements of indices-array, total number of wrong elements is %lld!",
|
||||
numOfBadIndx);
|
||||
}
|
||||
|
||||
// initial zeroing of output
|
||||
*output = 0;
|
||||
|
||||
helpers::scatterND(block.launchContext(), pairwise::Add, *indices, *updates, *output, lock);
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(scatter_nd) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, {ALL_INTS})
|
||||
->setAllowedInputTypes(1, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedInputTypes(2, {ALL_INTS})
|
||||
->setAllowedOutputTypes({ALL_INTS, ALL_FLOATS});
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
DECLARE_SHAPE_FN(scatter_nd) {
|
||||
auto shape = INPUT_VARIABLE(2);
|
||||
auto updShapeInfo = inputShape->at(1);
|
||||
|
||||
LongType *outShapeInfo;
|
||||
ALLOCATE(outShapeInfo, block.getWorkspace(), shape::shapeInfoLength(shape->lengthOf()), sd::LongType);
|
||||
|
||||
outShapeInfo[0] = shape->lengthOf();
|
||||
for (int i = 0; i < outShapeInfo[0]; ++i) outShapeInfo[i + 1] = shape->e<LongType>(i);
|
||||
|
||||
ShapeUtils::updateStridesAndType(outShapeInfo, updShapeInfo, shape::order(updShapeInfo));
|
||||
|
||||
auto result = SHAPELIST(CONSTANT(outShapeInfo));
|
||||
RELEASE(outShapeInfo, block.getWorkspace());
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,101 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com), created on 22.08.2018
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_scatter_nd_add)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/generic/helpers/ScatterHelper.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
OP_IMPL(scatter_nd_add, 3, 1, true) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto indices = INPUT_VARIABLE(1);
|
||||
auto updates = INPUT_VARIABLE(2);
|
||||
if(indices->isEmpty())
|
||||
return Status::OK;
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
const bool lock = block.getBArguments()->empty() ? false : B_ARG(0);
|
||||
const bool checkIndices = block.getBArguments()->size() <= 1 ? false : B_ARG(1);
|
||||
|
||||
const int inRank = input->rankOf();
|
||||
const int indRank = indices->rankOf();
|
||||
const int updRank = updates->rankOf();
|
||||
|
||||
const LongType indLastDim = indices->sizeAt(-1);
|
||||
|
||||
REQUIRE_TRUE(
|
||||
indLastDim <= inRank, 0,
|
||||
"SCATTER_ND_ADD OP: the last dimension of indices array must be <= input_array_rank, but got %i instead !",
|
||||
indLastDim);
|
||||
REQUIRE_TRUE(
|
||||
updRank == (indRank - 1 + inRank - indLastDim), 0,
|
||||
"SCATTER_ND_ADD OP: the equality updates_rank = (indices_rank - 1 + input_rank - last_indices_dimension) must be "
|
||||
"true for input arrays, but got instead: updates_rank = %i, indices_rank = %i, last_indices_dimension = %i !",
|
||||
updRank, indRank, indLastDim);
|
||||
|
||||
auto* inShapePtr = input->getShapeAsVector();
|
||||
std::vector<LongType> inShape = *inShapePtr;
|
||||
delete inShapePtr;
|
||||
auto* updShapePtr = updates->getShapeAsVector();
|
||||
std::vector<LongType> updShape = *updShapePtr;
|
||||
delete updShapePtr;
|
||||
auto* indShapePtr = indices->getShapeAsVector();
|
||||
std::vector<LongType> indShape = *indShapePtr;
|
||||
delete indShapePtr;
|
||||
std::vector<LongType> expectedUpdShape(std::begin(indShape), std::end(indShape) - 1);
|
||||
if (inRank > indLastDim)
|
||||
std::move(std::begin(inShape) + indLastDim, std::end(inShape), std::back_inserter(expectedUpdShape));
|
||||
REQUIRE_TRUE(expectedUpdShape == updShape, 0,
|
||||
"SCATTER_ND_ADD OP: wrong shape of updates array, expected is %s, but got %s instead !",
|
||||
ShapeUtils::shapeAsString(expectedUpdShape).c_str(), ShapeUtils::shapeAsString(updShape).c_str());
|
||||
|
||||
if (checkIndices) {
|
||||
const LongType numOfBadIndx = helpers::checkIndices(block.launchContext(), *indices, *output);
|
||||
REQUIRE_TRUE(numOfBadIndx == 0, 0,
|
||||
"SCATTER_ND_ADD OP: please check elements of indices-array, total number of wrong elements is %lld!",
|
||||
numOfBadIndx);
|
||||
}
|
||||
|
||||
if (!block.isInplace()) output->assign(input);
|
||||
|
||||
helpers::scatterND(block.launchContext(), pairwise::Add, *indices, *updates, *output, lock);
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(scatter_nd_add) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedInputTypes(1, {ALL_INTS})
|
||||
->setAllowedInputTypes(2, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedOutputTypes({ALL_INTS, ALL_FLOATS});
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,101 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com), created on 24.08.2018
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_scatter_nd_sub)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/generic/helpers/ScatterHelper.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
OP_IMPL(scatter_nd_sub, 3, 1, true) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto indices = INPUT_VARIABLE(1);
|
||||
auto updates = INPUT_VARIABLE(2);
|
||||
if(indices->isEmpty())
|
||||
return Status::OK;
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
const bool lock = block.getBArguments()->empty() ? false : B_ARG(0);
|
||||
const bool checkIndices = block.getBArguments()->size() <= 1 ? false : B_ARG(1);
|
||||
|
||||
const int inRank = input->rankOf();
|
||||
const int indRank = indices->rankOf();
|
||||
const int updRank = updates->rankOf();
|
||||
|
||||
const LongType indLastDim = indices->sizeAt(-1);
|
||||
|
||||
REQUIRE_TRUE(
|
||||
indLastDim <= inRank, 0,
|
||||
"SCATTER_ND_SUB OP: the last dimension of indices array must be <= input_array_rank, but got %i instead !",
|
||||
indLastDim);
|
||||
REQUIRE_TRUE(
|
||||
updRank == (indRank - 1 + inRank - indLastDim), 0,
|
||||
"SCATTER_ND_SUB OP: the equality updates_rank = (indices_rank - 1 + input_rank - last_indices_dimension) must be "
|
||||
"true for input arrays, but got instead: updates_rank = %i, indices_rank = %i, last_indices_dimension = %i !",
|
||||
updRank, indRank, indLastDim);
|
||||
|
||||
auto* inShapePtr = input->getShapeAsVector();
|
||||
std::vector<LongType> inShape = *inShapePtr;
|
||||
delete inShapePtr;
|
||||
auto* updShapePtr = updates->getShapeAsVector();
|
||||
std::vector<LongType> updShape = *updShapePtr;
|
||||
delete updShapePtr;
|
||||
auto* indShapePtr = indices->getShapeAsVector();
|
||||
std::vector<LongType> indShape = *indShapePtr;
|
||||
delete indShapePtr;
|
||||
std::vector<LongType> expectedUpdShape(std::begin(indShape), std::end(indShape) - 1);
|
||||
if (inRank > indLastDim)
|
||||
std::move(std::begin(inShape) + indLastDim, std::end(inShape), std::back_inserter(expectedUpdShape));
|
||||
REQUIRE_TRUE(expectedUpdShape == updShape, 0,
|
||||
"SCATTER_ND_SUB OP: wrong shape of updates array, expected is %s, but got %s instead !",
|
||||
ShapeUtils::shapeAsString(expectedUpdShape).c_str(), ShapeUtils::shapeAsString(updShape).c_str());
|
||||
|
||||
if (checkIndices) {
|
||||
const LongType numOfBadIndx = helpers::checkIndices(block.launchContext(), *indices, *output);
|
||||
REQUIRE_TRUE(numOfBadIndx == 0, 0,
|
||||
"SCATTER_ND_SUB OP: please check elements of indices-array, total number of wrong elements is %lld!",
|
||||
numOfBadIndx);
|
||||
}
|
||||
|
||||
if (!block.isInplace()) output->assign(input);
|
||||
|
||||
helpers::scatterND(block.launchContext(), pairwise::Subtract, *indices, *updates, *output, lock);
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(scatter_nd_sub) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedInputTypes(1, {ALL_INTS})
|
||||
->setAllowedInputTypes(2, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedOutputTypes({ALL_INTS, ALL_FLOATS});
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,102 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com), created on 24.08.2018
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_scatter_nd_update)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/generic/helpers/ScatterHelper.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
OP_IMPL(scatter_nd_update, 3, 1, true) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto indices = INPUT_VARIABLE(1);
|
||||
auto updates = INPUT_VARIABLE(2);
|
||||
if(indices->isEmpty())
|
||||
return Status::OK;
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
const bool lock = block.getBArguments()->empty() ? true : B_ARG(0);
|
||||
const bool checkIndices = block.getBArguments()->size() <= 1 ? false : B_ARG(1);
|
||||
|
||||
const int inRank = input->rankOf();
|
||||
const int indRank = indices->rankOf();
|
||||
const int updRank = updates->rankOf();
|
||||
|
||||
const LongType indLastDim = indices->sizeAt(-1);
|
||||
|
||||
REQUIRE_TRUE(
|
||||
indLastDim <= inRank, 0,
|
||||
"SCATTER_ND_UPDATE OP: the last dimension of indices array must be <= input_array_rank, but got %i instead !",
|
||||
indLastDim);
|
||||
REQUIRE_TRUE(
|
||||
updRank == (indRank - 1 + inRank - indLastDim), 0,
|
||||
"SCATTER_ND_UPDATE OP: the equality updates_rank = (indices_rank - 1 + input_rank - last_indices_dimension) must "
|
||||
"be true for input arrays, but got instead: updates_rank = %i, indices_rank = %i, last_indices_dimension = %i !",
|
||||
updRank, indRank, indLastDim);
|
||||
|
||||
auto* inShapePtr = input->getShapeAsVector();
|
||||
std::vector<LongType> inShape = *inShapePtr;
|
||||
delete inShapePtr;
|
||||
auto* updShapePtr = updates->getShapeAsVector();
|
||||
std::vector<LongType> updShape = *updShapePtr;
|
||||
delete updShapePtr;
|
||||
auto* indShapePtr = indices->getShapeAsVector();
|
||||
std::vector<LongType> indShape = *indShapePtr;
|
||||
delete indShapePtr;
|
||||
std::vector<LongType> expectedUpdShape(std::begin(indShape), std::end(indShape) - 1);
|
||||
if (inRank > indLastDim)
|
||||
std::move(std::begin(inShape) + indLastDim, std::end(inShape), std::back_inserter(expectedUpdShape));
|
||||
REQUIRE_TRUE(expectedUpdShape == updShape, 0,
|
||||
"SCATTER_ND_UPDATE OP: wrong shape of updates array, expected is %s, but got %s instead !",
|
||||
ShapeUtils::shapeAsString(expectedUpdShape).c_str(), ShapeUtils::shapeAsString(updShape).c_str());
|
||||
|
||||
if (checkIndices) {
|
||||
const LongType numOfBadIndx = helpers::checkIndices(block.launchContext(), *indices, *output);
|
||||
REQUIRE_TRUE(
|
||||
numOfBadIndx == 0, 0,
|
||||
"SCATTER_ND_UPDATE OP: please check elements of indices-array, total number of wrong elements is %lld!",
|
||||
numOfBadIndx);
|
||||
}
|
||||
|
||||
if (!block.isInplace()) output->assign(input);
|
||||
|
||||
helpers::scatterND(block.launchContext(), pairwise::CopyPws, *indices, *updates, *output, lock);
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(scatter_nd_update) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedInputTypes(1, {ALL_INTS})
|
||||
->setAllowedInputTypes(2, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedOutputTypes({ALL_INTS, ALL_FLOATS});
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,115 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author Created by raver119 on 24.11.17.
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com)
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_scatter_sub)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/generic/helpers/ScatterHelper.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
OP_IMPL(scatter_sub, 3, 1, true) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto indices = INPUT_VARIABLE(1);
|
||||
auto updates = INPUT_VARIABLE(2);
|
||||
if(indices->isEmpty())
|
||||
return Status::OK;
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
if (!block.isInplace()) output->assign(input);
|
||||
|
||||
const bool lock = block.getBArguments()->empty() ? false : B_ARG(0);
|
||||
const bool checkIndices = block.getBArguments()->size() <= 1 ? false : B_ARG(1);
|
||||
|
||||
const int inRank = input->rankOf();
|
||||
const int indRank = indices->rankOf();
|
||||
const int updRank = updates->rankOf();
|
||||
|
||||
REQUIRE_TRUE(inRank > 0, 0, "SCATTER_SUB OP: input should not be scalar !");
|
||||
|
||||
if (inRank == 1) {
|
||||
REQUIRE_TRUE(indices->isSameShape(updates), 0,
|
||||
"SCATTER_SUB OP: when input array has rank = 1 then indices and updates must have the same shapes, "
|
||||
"but got %s and %s correspondingly !",
|
||||
ShapeUtils::shapeAsString(indices).c_str(), ShapeUtils::shapeAsString(updates).c_str());
|
||||
} else if (inRank == updRank && indices->isVector()) {
|
||||
auto* updShapeVec = updates->getShapeAsVector();
|
||||
auto* inShapeVec = input->getShapeAsVector();
|
||||
std::vector<LongType> expectedUpdShape = {indices->lengthOf()};
|
||||
expectedUpdShape.insert(expectedUpdShape.end(), inShapeVec->begin() + 1, inShapeVec->end());
|
||||
|
||||
REQUIRE_TRUE(expectedUpdShape == *updShapeVec, 0,
|
||||
"SCATTER_SUB OP: wrong shape of updates array, expected is %s, but got %s instead !",
|
||||
ShapeUtils::shapeAsString(expectedUpdShape).c_str(), ShapeUtils::shapeAsString(*updShapeVec).c_str());
|
||||
delete updShapeVec;
|
||||
delete inShapeVec;
|
||||
}
|
||||
|
||||
else {
|
||||
REQUIRE_TRUE(updRank == indRank + inRank - 1, 0,
|
||||
"SCATTER_SUB OP: wrong rank of updates array, expected is %i, but got %i instead !",
|
||||
indRank + inRank - 1, updRank);
|
||||
|
||||
auto* updShapeVec = updates->getShapeAsVector();
|
||||
auto* inShapeVec = input->getShapeAsVector();
|
||||
auto* indShapeVec = indices->getShapeAsVector();
|
||||
std::vector<LongType> expectedUpdShape = *indShapeVec;
|
||||
expectedUpdShape.insert(expectedUpdShape.end(), inShapeVec->begin() + 1, inShapeVec->end());
|
||||
|
||||
REQUIRE_TRUE(expectedUpdShape == *updShapeVec, 0,
|
||||
"SCATTER_SUB OP: wrong shape of updates array, expected is %s, but got %s instead !",
|
||||
ShapeUtils::shapeAsString(expectedUpdShape).c_str(), ShapeUtils::shapeAsString(*updShapeVec).c_str());
|
||||
delete updShapeVec;
|
||||
delete inShapeVec;
|
||||
delete indShapeVec;
|
||||
}
|
||||
|
||||
if (!indices->isEmpty()) {
|
||||
if (checkIndices) {
|
||||
const LongType numOfBadIndx = helpers::checkIndices(block.launchContext(), *indices, *output, 0);
|
||||
REQUIRE_TRUE(numOfBadIndx == 0, 0,
|
||||
"SCATTER_SUB OP: please check elements of indices-array, total number of wrong elements is %lld!",
|
||||
numOfBadIndx);
|
||||
}
|
||||
|
||||
// ScatterHelper<T>::template scatterApply<simdOps::Subtract<T>>(output, indices, updates);
|
||||
helpers::scatter(block.launchContext(), pairwise::Subtract, *indices, *updates, *output, lock);
|
||||
}
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
DECLARE_SYN(ScatterSub, scatter_sub);
|
||||
|
||||
DECLARE_TYPES(scatter_sub) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedInputTypes(1, {ALL_INTS})
|
||||
->setAllowedInputTypes(2, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedOutputTypes({ALL_INTS, ALL_FLOATS});
|
||||
}
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,111 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// Created by raver119 on 24.11.17.
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_scatter_upd)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/generic/helpers/ScatterHelper.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
OP_IMPL(scatter_upd, 3, 1, true) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto indices = INPUT_VARIABLE(1);
|
||||
auto updates = INPUT_VARIABLE(2);
|
||||
if(indices->isEmpty())
|
||||
return Status::OK;
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
if (!block.isInplace()) output->assign(input);
|
||||
|
||||
const bool lock = block.getBArguments()->empty() ? true : B_ARG(0);
|
||||
const bool checkIndices = block.getBArguments()->size() <= 1 ? false : B_ARG(1);
|
||||
|
||||
const int inRank = input->rankOf();
|
||||
const int indRank = indices->rankOf();
|
||||
const int updRank = updates->rankOf();
|
||||
|
||||
REQUIRE_TRUE(inRank > 0, 0, "SCATTER_UPD OP: input should not be scalar !");
|
||||
|
||||
if (inRank == 1) {
|
||||
REQUIRE_TRUE(indices->isSameShape(updates), 0,
|
||||
"SCATTER_UPD OP: when input array has rank = 1 then indices and updates must have the same shapes, "
|
||||
"but got %s and %s correspondingly !",
|
||||
ShapeUtils::shapeAsString(indices).c_str(), ShapeUtils::shapeAsString(updates).c_str());
|
||||
} else if (inRank == updRank && indices->isVector()) {
|
||||
auto* updShapeVec = updates->getShapeAsVector();
|
||||
auto* inShapeVec = input->getShapeAsVector();
|
||||
std::vector<LongType> expectedUpdShape = {indices->lengthOf()};
|
||||
expectedUpdShape.insert(expectedUpdShape.end(), inShapeVec->begin() + 1, inShapeVec->end());
|
||||
|
||||
REQUIRE_TRUE(expectedUpdShape == *updShapeVec, 0,
|
||||
"SCATTER_UPD OP: wrong shape of updates array, expected is %s, but got %s instead !",
|
||||
ShapeUtils::shapeAsString(expectedUpdShape).c_str(), ShapeUtils::shapeAsString(*updShapeVec).c_str());
|
||||
delete updShapeVec;
|
||||
delete inShapeVec;
|
||||
} else {
|
||||
REQUIRE_TRUE(updRank == indRank + inRank - 1, 0,
|
||||
"SCATTER_UPD OP: wrong rank of updates array, expected is %i, but got %i instead !",
|
||||
indRank + inRank - 1, updRank);
|
||||
|
||||
auto* updShapeVec = updates->getShapeAsVector();
|
||||
auto* inShapeVec = input->getShapeAsVector();
|
||||
auto* indShapeVec = indices->getShapeAsVector();
|
||||
std::vector<LongType> expectedUpdShape = *indShapeVec;
|
||||
expectedUpdShape.insert(expectedUpdShape.end(), inShapeVec->begin() + 1, inShapeVec->end());
|
||||
|
||||
REQUIRE_TRUE(expectedUpdShape == *updShapeVec, 0,
|
||||
"SCATTER_UPD OP: wrong shape of updates array, expected is %s, but got %s instead !",
|
||||
ShapeUtils::shapeAsString(expectedUpdShape).c_str(), ShapeUtils::shapeAsString(*updShapeVec).c_str());
|
||||
delete updShapeVec;
|
||||
delete inShapeVec;
|
||||
delete indShapeVec;
|
||||
}
|
||||
|
||||
if (!indices->isEmpty()) {
|
||||
if (checkIndices) {
|
||||
const LongType numOfBadIndx = helpers::checkIndices(block.launchContext(), *indices, *output, 0);
|
||||
REQUIRE_TRUE(numOfBadIndx == 0, 0,
|
||||
"SCATTER_UPD OP: please check elements of indices-array, total number of wrong elements is %lld!",
|
||||
numOfBadIndx);
|
||||
}
|
||||
|
||||
helpers::scatter(block.launchContext(), pairwise::CopyPws, *indices, *updates, *output, lock);
|
||||
}
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
DECLARE_SYN(ScatterUpdate, scatter_upd);
|
||||
|
||||
DECLARE_TYPES(scatter_upd) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedInputTypes(1, {ALL_INTS})
|
||||
->setAllowedInputTypes(2, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedOutputTypes({ALL_INTS, ALL_FLOATS});
|
||||
}
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,60 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// Created by raver119 on 24.11.17.
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_scatter_update)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/transforms.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
/**
|
||||
* scatter update operation
|
||||
*
|
||||
* IArgs map:
|
||||
* IArgs[0] - update operation: 0 - add; 1 - sub; 2 - mul; 3 - div; 4 - rsub; 5 - rdiv; 6 - assign
|
||||
* IArgs[1] - number of dimensions
|
||||
* IArgs[...] - dimensions
|
||||
* IArgs[...] - number of indices
|
||||
* IArgs[...] - indices
|
||||
*
|
||||
* @tparam T
|
||||
*/
|
||||
CONFIGURABLE_OP_IMPL(scatter_update, -2, 1, true, 0, -2) {
|
||||
//NOTE: DO NOT USE. USE scatter_upd instead.
|
||||
auto operand = INPUT_VARIABLE(0);
|
||||
auto updates = INPUT_VARIABLE(1);
|
||||
if(updates->isEmpty())
|
||||
return Status::OK;
|
||||
|
||||
helpers::scatterUpdate(block.launchContext(), *operand, *updates, block.getIArguments());
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
DECLARE_SYN(scatterupdate, scatter_update);
|
||||
|
||||
DECLARE_TYPES(scatter_update) { getOpDescriptor()->setAllowedInputTypes(ANY)->setSameMode(true); }
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,273 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// Created by raver119 on 02.11.2017.
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#include <legacy/NativeOpExecutioner.h>
|
||||
#include <helpers/ShapeUtils.h>
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#if NOT_EXCLUDED(OP_slice)
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
CUSTOM_OP_IMPL(slice, 1, 1, false, 0, -2) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
int x_rank = input->rankOf();
|
||||
|
||||
std::vector<LongType> begin;
|
||||
std::vector<LongType> sz;
|
||||
|
||||
if (block.width() == 3) {
|
||||
auto b = INPUT_VARIABLE(1);
|
||||
auto e = INPUT_VARIABLE(2);
|
||||
|
||||
begin = b->template asVectorT<LongType>();
|
||||
sz = e->template asVectorT<LongType>();
|
||||
} else {
|
||||
REQUIRE_TRUE(block.numI() >= static_cast<size_t>(x_rank * 2), 0, "Number of IArgs should be equal to [%i] but got [%i] instead",
|
||||
x_rank * 2, block.numI());
|
||||
|
||||
ShapeUtils::copyVectorPart(begin, *(block.getIArguments()), x_rank, 0);
|
||||
ShapeUtils::copyVectorPart(sz, *(block.getIArguments()), x_rank, x_rank);
|
||||
}
|
||||
|
||||
REQUIRE_TRUE(begin.size() == static_cast<size_t>(x_rank), 0, "begin array should have length of [%i] but got [%i] instead", x_rank,
|
||||
begin.size());
|
||||
REQUIRE_TRUE(sz.size() == static_cast<size_t>(x_rank), 0, "size array should have length of [%i] but got [%i] instead", x_rank, sz.size());
|
||||
|
||||
std::vector<LongType> indices(2 * x_rank);
|
||||
auto empty = false;
|
||||
for (int e = 0; e < x_rank; e++) {
|
||||
int size = sz[e];
|
||||
int start = begin[e];
|
||||
|
||||
REQUIRE_TRUE(start >= 0, 0, "Slice: start index should not be negative");
|
||||
|
||||
REQUIRE_TRUE(start <= input->sizeAt(e), 0, "Index %i is invalid for dimension %i with size %i.", start, e,
|
||||
input->shapeInfo()[e + 1]);
|
||||
if (size == -1) {
|
||||
size = input->sizeAt(e) - start;
|
||||
}
|
||||
REQUIRE_TRUE(size >= 0, 0, "Slice: interval for dimension %i is less then 1");
|
||||
REQUIRE_TRUE(start + size <= input->sizeAt(e), 0,
|
||||
"Slice: interval [%i, %i] is out of bounds for dimension %i with size %i", start, start + size, e,
|
||||
input->sizeAt(e));
|
||||
|
||||
if (start == input->sizeAt(e) || size == 0) {
|
||||
empty = true;
|
||||
// Don't break to perform input validation on other dims
|
||||
}
|
||||
|
||||
indices[2 * e] = start;
|
||||
indices[2 * e + 1] = start + size;
|
||||
}
|
||||
|
||||
if (empty) {
|
||||
REQUIRE_TRUE(output->isEmpty(), 0, "Slice: empty array indices requested, but output array is not empty");
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
LongType* subArrShapeInfo = nullptr;
|
||||
ALLOCATE(subArrShapeInfo, block.getWorkspace(), shape::shapeInfoLength(input->rankOf()), sd::LongType);
|
||||
|
||||
LongType offset;
|
||||
|
||||
shape::calcSubArrShapeInfoAndOffset(indices.data(), input->shapeInfo(), subArrShapeInfo, offset, true);
|
||||
|
||||
auto subArrShapeInfoPack = ConstantShapeHelper::getInstance().bufferForShapeInfo(subArrShapeInfo);
|
||||
|
||||
NDArray::prepareSpecialUse({output}, {input});
|
||||
|
||||
NativeOpExecutioner::execTransformAny(block.launchContext(), transform::Assign, input->bufferWithOffset(offset),
|
||||
subArrShapeInfoPack->primary(), input->specialBufferWithOffset(offset),
|
||||
subArrShapeInfoPack->special(), output->buffer(), output->shapeInfo(),
|
||||
output->specialBuffer(), output->specialShapeInfo(), nullptr, true);
|
||||
|
||||
NDArray::registerSpecialUse({output}, {input});
|
||||
|
||||
RELEASE(subArrShapeInfo, block.getWorkspace());
|
||||
|
||||
STORE_RESULT(output);
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(slice) { getOpDescriptor()->setAllowedInputTypes(ANY)->setSameMode(true); }
|
||||
|
||||
DECLARE_SHAPE_FN(slice) {
|
||||
auto inShape = inputShape->at(0);
|
||||
if(shape::isEmptyConst(inShape)) {
|
||||
std::vector<LongType> emptyShape = {0};
|
||||
return SHAPELIST(ConstantShapeHelper::getInstance().emptyShapeInfoWithShape(ArrayOptions::dataType(inShape), emptyShape));
|
||||
}
|
||||
auto x_rank = shape::rank(inShape);
|
||||
|
||||
std::vector<LongType> begin;
|
||||
std::vector<LongType> sz;
|
||||
|
||||
if (block.width() == 3) {
|
||||
auto b = INPUT_VARIABLE(1);
|
||||
auto e = INPUT_VARIABLE(2);
|
||||
|
||||
// Check if begin/end are empty - this can happen during graph construction
|
||||
if (b->isEmpty() || e->isEmpty()) {
|
||||
// For slicing a 1D shape tensor to extract a single element, return scalar
|
||||
if (x_rank == 1) {
|
||||
auto scalarShape = ConstantShapeHelper::getInstance().scalarShapeInfo(ArrayOptions::dataType(inShape));
|
||||
return SHAPELIST(scalarShape);
|
||||
}
|
||||
// Otherwise cannot determine shape at compile time
|
||||
std::vector<LongType> unknownShape(x_rank, -1);
|
||||
auto newShape = ConstantShapeHelper::getInstance().createShapeInfo(ArrayOptions::dataType(inShape), 'c', unknownShape);
|
||||
return SHAPELIST(newShape);
|
||||
}
|
||||
|
||||
begin = b->template asVectorT<LongType>();
|
||||
sz = e->template asVectorT<LongType>();
|
||||
} else {
|
||||
REQUIRE_TRUE(block.numI() >= static_cast<size_t>(x_rank) * 2, 0, "Number of IArgs should be equal to [%i] but got [%i] instead",
|
||||
x_rank * 2, block.numI());
|
||||
|
||||
ShapeUtils::copyVectorPart(begin, *(block.getIArguments()), x_rank, 0);
|
||||
ShapeUtils::copyVectorPart(sz, *(block.getIArguments()), x_rank, x_rank);
|
||||
}
|
||||
|
||||
REQUIRE_TRUE(begin.size() == static_cast<size_t>(x_rank), 0, "Begin array should have length of [%i] but got [%i] instead", x_rank,
|
||||
begin.size());
|
||||
REQUIRE_TRUE(sz.size() == static_cast<size_t>(x_rank), 0, "Size array should have length of [%i] but got [%i] instead", x_rank, sz.size());
|
||||
|
||||
std::vector<LongType> shape;
|
||||
auto empty = false;
|
||||
for (int e = 0; e < x_rank; e++) {
|
||||
auto size = sz[e];
|
||||
auto start = begin[e];
|
||||
|
||||
// Handle unknown/dynamic dimensions
|
||||
if (inShape[e + 1] < 0) {
|
||||
shape.emplace_back(-1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (size == -1) {
|
||||
size = inShape[e + 1] - start;
|
||||
}
|
||||
|
||||
// Bounds checking. Note that begin[i] == size[i] means empty array
|
||||
REQUIRE_TRUE(
|
||||
start >= 0 && start <= inShape[e + 1], 0,
|
||||
"Invalid begin[%i] value: Begin must satisfy 0 <= begin <= size[i], got begin=%i for dimension size %i", e,
|
||||
start, inShape[e + 1]);
|
||||
REQUIRE_TRUE(size == -1 || size >= 0, 0,
|
||||
"Invalid size[%i] value: must be positive (or -1 for 'all remaining'), got %i", e, size,
|
||||
inShape[e + 1]);
|
||||
REQUIRE_TRUE(
|
||||
start >= 0 && start <= inShape[e + 1], 0,
|
||||
"Invalid begin[%i] value: Begin must satisfy 0 <= begin <= size[i], got begin=%i for dimension size %i", e,
|
||||
start, inShape[e + 1]);
|
||||
REQUIRE_TRUE(start + size <= inShape[e + 1], 0,
|
||||
"Slice: interval [%i, %i] is out of bounds for dimension %i with size %i", start, start + size, e,
|
||||
inShape[e + 1]);
|
||||
if (start == inShape[e + 1]) {
|
||||
size = 0;
|
||||
}
|
||||
|
||||
shape.emplace_back(size);
|
||||
}
|
||||
|
||||
// Special case: slicing a 1D tensor with size 1 should produce a scalar
|
||||
if (x_rank == 1 && shape.size() == 1 && shape[0] == 1) {
|
||||
auto scalarShape = ConstantShapeHelper::getInstance().scalarShapeInfo(ArrayOptions::dataType(inShape));
|
||||
return SHAPELIST(scalarShape);
|
||||
}
|
||||
|
||||
if(shape.size() == 1 && shape[0] == 0) {
|
||||
std::vector<LongType> emptyShape = {0};
|
||||
return SHAPELIST(ConstantShapeHelper::getInstance().emptyShapeInfoWithShape(ArrayOptions::dataType(inShape), emptyShape));
|
||||
}
|
||||
|
||||
auto newShape = ConstantShapeHelper::getInstance().createShapeInfo(ArrayOptions::dataType(inShape), 'c', shape);
|
||||
return SHAPELIST(newShape);
|
||||
}
|
||||
|
||||
DECLARE_TYPES(slice_bp) {
|
||||
getOpDescriptor()->setAllowedInputTypes(ANY)->setAllowedOutputTypes({ALL_FLOATS});
|
||||
}
|
||||
|
||||
CUSTOM_OP_IMPL(slice_bp, 2, 1, false, 0, -2) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto epsNext = block.width() == 4 ? INPUT_VARIABLE(3) : INPUT_VARIABLE(1);
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
double zero = 0.;
|
||||
output->assign(zero);
|
||||
int x_rank = input->rankOf();
|
||||
|
||||
std::vector<LongType> begin;
|
||||
std::vector<LongType> end;
|
||||
|
||||
if (block.width() == 4) {
|
||||
auto b = INPUT_VARIABLE(1);
|
||||
auto e = INPUT_VARIABLE(2);
|
||||
|
||||
begin = b->template asVectorT<LongType>();
|
||||
end = e->template asVectorT<LongType>();
|
||||
} else {
|
||||
REQUIRE_TRUE(block.numI() >= static_cast<size_t>(x_rank) * 2, 0, "Number of IArgs should be equal to [%i] but got [%i] instead",
|
||||
x_rank * 2, block.numI());
|
||||
|
||||
ShapeUtils::copyVectorPart(begin, *(block.getIArguments()), x_rank, 0);
|
||||
ShapeUtils::copyVectorPart(end, *(block.getIArguments()), x_rank, x_rank);
|
||||
}
|
||||
|
||||
REQUIRE_TRUE(begin.size() == static_cast<size_t>(x_rank), 0, "begin array should have length of [%i] but got [%i] instead", x_rank,
|
||||
begin.size());
|
||||
REQUIRE_TRUE(end.size() == static_cast<size_t>(x_rank), 0, "end array should have length of [%i] but got [%i] instead", x_rank,
|
||||
end.size());
|
||||
|
||||
std::vector<LongType> indices(2 * x_rank);
|
||||
for (int e = 0; e < x_rank; e++) {
|
||||
int size = end[e];
|
||||
int start = begin[e];
|
||||
|
||||
if (size == -1) { //-1 means all remaining values
|
||||
size = input->sizeAt(e) - start;
|
||||
}
|
||||
REQUIRE_TRUE(size > 0, 0, "Slice: interval for dimension %i is less then 1", e);
|
||||
|
||||
indices[2 * e] = start;
|
||||
indices[2 * e + 1] = start + size;
|
||||
}
|
||||
auto sub = (*output)(indices, true);
|
||||
sub->assign(epsNext);
|
||||
|
||||
delete sub;
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(slice_bp) {
|
||||
auto inShape = inputShape->at(0);
|
||||
return SHAPELIST(CONSTANT(inShape));
|
||||
}
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,117 @@
|
||||
// Copyright 2016 The TensorFlow Authors. All Rights Reserved.
|
||||
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com)
|
||||
// @author raver119@gmail.com
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_space_to_batch)
|
||||
|
||||
#include <ops/declarable/headers/parity_ops.h>
|
||||
#include <ops/declarable/helpers/s_t_b.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
CUSTOM_OP_IMPL(space_to_batch, 2, 1, false, 0, 1) {
|
||||
// [bS, iH, iW, iC] is rearranged/permuted to [bS*blockSize*blockSize, (iH + padBottom + padTop)/blockSize, (iW +
|
||||
// padLeft + padRight)/blockSize, iC]
|
||||
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto padding = INPUT_VARIABLE(1);
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
const LongType blockSize = INT_ARG(0);
|
||||
REQUIRE_TRUE(blockSize >= 2, 0, "SpaceToBatch: integer parameter block_size must be >= 2, but got %i instead",
|
||||
blockSize);
|
||||
|
||||
REQUIRE_TRUE(input->rankOf() == 4, 0, "SpaceToBatch: rank of input array must be equal 4, but got %i instead",
|
||||
input->rankOf());
|
||||
REQUIRE_TRUE(output->rankOf() == 4, 0, "SpaceToBatch: rank of output array must be equal 4, but got %i instead",
|
||||
output->rankOf());
|
||||
|
||||
if (padding->sizeAt(0) != 2 || padding->sizeAt(1) != 2)
|
||||
REQUIRE_TRUE(false, 0, "SpaceToBatch: operation expects padding shape to be {2, 2}, but got %s instead",
|
||||
ShapeUtils::shapeAsString(padding).c_str());
|
||||
|
||||
const LongType padBottom = padding->e<LongType>(0, 0);
|
||||
const LongType padTop = padding->e<LongType>(0, 1);
|
||||
const LongType padLeft = padding->e<LongType>(1, 0);
|
||||
const LongType padRight = padding->e<LongType>(1, 1);
|
||||
|
||||
REQUIRE_TRUE(
|
||||
(input->sizeAt(1) + padBottom + padTop) % blockSize == 0 &&
|
||||
(input->sizeAt(2) + padLeft + padRight) % blockSize == 0,
|
||||
0, "SpaceToBatch: after padding, second and third dimensions of input array must be divisible by blockSize !");
|
||||
|
||||
if (shape::strideDescendingCAscendingF(input->shapeInfo()))
|
||||
helpers::spaceToBatch(block.launchContext(), *input, *output, padBottom, padTop, padLeft, padRight, blockSize);
|
||||
else {
|
||||
NDArray *inputDup = input->dup(input->ordering());
|
||||
helpers::spaceToBatch(block.launchContext(), *inputDup, *output, padBottom, padTop, padLeft, padRight,
|
||||
blockSize);
|
||||
}
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
DECLARE_TYPES(space_to_batch) {
|
||||
getOpDescriptor()->setAllowedInputTypes(0, ANY)->setAllowedInputTypes(1, {ALL_INTS})->setSameMode(true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
DECLARE_SHAPE_FN(space_to_batch) {
|
||||
auto inputShapeInfo = inputShape->at(0);
|
||||
auto paddingShapeInfo = inputShape->at(1);
|
||||
|
||||
const LongType blockSize = INT_ARG(0);
|
||||
REQUIRE_TRUE(blockSize >= 2, 0, "SpaceToBatch: integer parameter block_size must be >= 2, but got %i instead",
|
||||
blockSize);
|
||||
|
||||
const int rank = inputShapeInfo[0];
|
||||
REQUIRE_TRUE(rank == 4, 0, "SpaceToBatch: rank of input array must be equal 4, but got %i instead", rank);
|
||||
|
||||
if (paddingShapeInfo[1] != 2 || paddingShapeInfo[1] != 2)
|
||||
REQUIRE_TRUE(false, 0, "SpaceToBatch: operation expects padding shape to be {2, 2}, but got %s instead",
|
||||
ShapeUtils::shapeAsString(paddingShapeInfo).c_str());
|
||||
|
||||
const LongType padBottom = INPUT_VARIABLE(1)->e<LongType>(0, 0);
|
||||
const LongType padTop = INPUT_VARIABLE(1)->e<LongType>(0, 1);
|
||||
const LongType padLeft = INPUT_VARIABLE(1)->e<LongType>(1, 0);
|
||||
const LongType padRight = INPUT_VARIABLE(1)->e<LongType>(1, 1);
|
||||
|
||||
REQUIRE_TRUE(
|
||||
(inputShapeInfo[2] + padBottom + padTop) % blockSize == 0 &&
|
||||
(inputShapeInfo[3] + padLeft + padRight) % blockSize == 0,
|
||||
0, "SpaceToBatch: after padding, second and third dimensions of input array must be divisible by blockSize !");
|
||||
|
||||
return SHAPELIST(ConstantShapeHelper::getInstance().createShapeInfo(
|
||||
ArrayOptions::dataType(inputShapeInfo), 'c',
|
||||
{inputShapeInfo[1] * blockSize * blockSize, (inputShapeInfo[2] + padBottom + padTop) / blockSize,
|
||||
(inputShapeInfo[3] + padLeft + padRight) / blockSize, inputShapeInfo[4]}));
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,123 @@
|
||||
|
||||
// Copyright 2016 The TensorFlow Authors. All Rights Reserved.
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com)
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_space_to_batch_nd)
|
||||
|
||||
#include <ops/declarable/headers/parity_ops.h>
|
||||
#include <ops/declarable/helpers/s_t_b.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
CUSTOM_OP_IMPL(space_to_batch_nd, 3, 1, false, 0, 0) {
|
||||
// 4D example, numOfSpatialDims = 2 - two spatial dimensions
|
||||
// [bS, iH, iW, iC] is rearranged/permuted to [bS*blockShape[0]*blockShape[1], (iH + padBottom + padTop)/blockSize[0],
|
||||
// (iW + padLeft + padRight)/blockSize[1], iC]
|
||||
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto blockShape = INPUT_VARIABLE(1);
|
||||
auto padding = INPUT_VARIABLE(2);
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
REQUIRE_TRUE(blockShape->rankOf() == 1, 0,
|
||||
"SpaceToBatchND: rank of blockShape array must be equal to one, but got %i instead !",
|
||||
blockShape->rankOf());
|
||||
|
||||
const LongType numOfSpatialDims = blockShape->sizeAt(0);
|
||||
|
||||
REQUIRE_TRUE(input->rankOf() == output->rankOf(), 0,
|
||||
"SpaceToBatchND: rank of input and output array must be the same, but got %i and %i correspondingly !",
|
||||
input->rankOf(), output->rankOf());
|
||||
|
||||
if (padding->sizeAt(0) != numOfSpatialDims || padding->sizeAt(1) != 2) {
|
||||
const std::string expectedpaddingShape = "[" + std::to_string(numOfSpatialDims) + ", 2]"; // [numOfSpatialDims, 2]
|
||||
REQUIRE_TRUE(false, 0, "SpaceToBatchND: operation expects padding shape to be %s, but got %s instead",
|
||||
expectedpaddingShape.c_str(), ShapeUtils::shapeAsString(padding).c_str());
|
||||
}
|
||||
|
||||
// FIXME - should we use this time-consuming validation ?
|
||||
for (LongType i = 0; i < numOfSpatialDims; ++i) {
|
||||
const LongType padLeft = padding->e<LongType>(i, 0);
|
||||
const LongType padRight = padding->e<LongType>(i, 1);
|
||||
const LongType blockSize = blockShape->e<LongType>(i);
|
||||
REQUIRE_TRUE((input->sizeAt(i + 1) + padLeft + padRight) % blockSize == 0, 0,
|
||||
"SpaceToBatchND: after padding, spatial dimensions of input array must be divisible by blockSize !");
|
||||
}
|
||||
|
||||
if (shape::strideDescendingCAscendingF(input->shapeInfo()))
|
||||
helpers::spaceToBatchND(block.launchContext(), *input, *blockShape, *padding, *output);
|
||||
else {
|
||||
NDArray *inputDup = input->dup(input->ordering());
|
||||
helpers::spaceToBatchND(block.launchContext(), *inputDup, *blockShape, *padding, *output);
|
||||
delete inputDup;
|
||||
}
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
DECLARE_TYPES(space_to_batch_nd) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, ANY)
|
||||
->setAllowedInputTypes(1, {ALL_INTS})
|
||||
->setAllowedInputTypes(2, {ALL_INTS})
|
||||
->setSameMode(true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
DECLARE_SHAPE_FN(space_to_batch_nd) {
|
||||
auto inputShapeInfo = inputShape->at(0);
|
||||
auto blockShapeInfo = inputShape->at(1);
|
||||
auto paddingShapeInfo = inputShape->at(2);
|
||||
|
||||
REQUIRE_TRUE(blockShapeInfo[0] == 1, 0,
|
||||
"SpaceToBatchND: rank of blockShape array must be equal to one, but got %i instead !",
|
||||
blockShapeInfo[0]);
|
||||
|
||||
const LongType numOfSpatialDims = blockShapeInfo[1];
|
||||
|
||||
if (paddingShapeInfo[1] != numOfSpatialDims || paddingShapeInfo[2] != 2) {
|
||||
const std::string expectedpaddingShape = "[" + std::to_string(numOfSpatialDims) + ", 2]"; // [numOfSpatialDims, 2]
|
||||
REQUIRE_TRUE(false, 0, "SpaceToBatchND: operation expects padding shape to be %s, but got %s instead",
|
||||
expectedpaddingShape.c_str(), ShapeUtils::shapeAsString(paddingShapeInfo).c_str());
|
||||
}
|
||||
|
||||
std::vector<LongType> outShape(inputShapeInfo + 1, inputShapeInfo + 1 + inputShapeInfo[0]);
|
||||
auto prod = INPUT_VARIABLE(1)->reduceNumber(reduce::Prod);
|
||||
outShape[0] *= prod->e<LongType>(0);
|
||||
delete prod;
|
||||
for (LongType i = 0; i < numOfSpatialDims; ++i)
|
||||
outShape[i + 1] =
|
||||
(outShape[i + 1] + INPUT_VARIABLE(2)->e<LongType>(i, 0) + INPUT_VARIABLE(2)->e<LongType>(i, 1)) /
|
||||
INPUT_VARIABLE(1)->e<LongType>(i);
|
||||
|
||||
return SHAPELIST(
|
||||
ConstantShapeHelper::getInstance().createShapeInfo(ArrayOptions::dataType(inputShapeInfo), 'c', outShape));
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,98 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_space_to_depth)
|
||||
|
||||
#include <ops/declarable/headers/parity_ops.h>
|
||||
#include <ops/declarable/helpers/s_t_d.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
|
||||
DECLARE_TYPES(space_to_depth) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(sd::DataType::ANY)
|
||||
->setSameMode(true);
|
||||
}
|
||||
|
||||
CUSTOM_OP_IMPL(space_to_depth, 1, 1, false, 0, 2) {
|
||||
int block_size = INT_ARG(0);
|
||||
REQUIRE_TRUE(block_size > 0,0, "SpaceToDepth: input should be > 0");
|
||||
|
||||
bool isNHWC = INT_ARG(1) == 1;
|
||||
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
|
||||
REQUIRE_TRUE(input->rankOf() == 4, 0, "SpaceToDepth: input should be 4D array, but got %f instead", input->rankOf());
|
||||
|
||||
int bS = input->sizeAt(0);
|
||||
int iD = isNHWC ? input->sizeAt(3) : input->sizeAt(1);
|
||||
int iH = isNHWC ? input->sizeAt(1) : input->sizeAt(2);
|
||||
int iW = isNHWC ? input->sizeAt(2) : input->sizeAt(3);
|
||||
|
||||
REQUIRE_TRUE(iH % block_size == 0 && iW % block_size == 0, 0, "SpaceToDepth: input Height & Width should be divisible by block_size");
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
if (shape::strideDescendingCAscendingF(input->shapeInfo()))
|
||||
helpers::_spaceTodepth(block.launchContext(), *input, output, block_size, isNHWC);
|
||||
else {
|
||||
NDArray *inputDup = input->dup(input->ordering());
|
||||
helpers::_spaceTodepth(block.launchContext(), *inputDup, output, block_size, isNHWC);
|
||||
}
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
|
||||
DECLARE_SHAPE_FN(space_to_depth) {
|
||||
auto in = inputShape->at(0);
|
||||
int block_size = INT_ARG(0);
|
||||
REQUIRE_TRUE(block_size > 0,0, "SpaceToDepth: input should be > 0");
|
||||
bool isNHWC = INT_ARG(1) == 1;
|
||||
|
||||
int bS = shape::sizeAt(in, static_cast<sd::LongType>(0));
|
||||
int iD = isNHWC ? shape::sizeAt(in, static_cast<sd::LongType>(3)) : shape::sizeAt(in, static_cast<sd::LongType>(1));
|
||||
int iH = isNHWC ? shape::sizeAt(in, static_cast<sd::LongType>(1)) : shape::sizeAt(in, static_cast<sd::LongType>(2));
|
||||
int iW = isNHWC ? shape::sizeAt(in, static_cast<sd::LongType>(2)) : shape::sizeAt(in, static_cast<sd::LongType>(3));
|
||||
|
||||
int oD = iD * block_size * block_size;
|
||||
int oH = iH / block_size;
|
||||
int oW = iW / block_size;
|
||||
|
||||
std::array<sd::LongType, 4> shape;
|
||||
if (isNHWC)
|
||||
shape = {{bS, oH, oW, oD }};
|
||||
else
|
||||
shape = {{bS, oD, oH, oW }};
|
||||
|
||||
auto newShape = ConstantShapeHelper::getInstance().createShapeInfo(ArrayOptions::dataType(in), 'c', 4, shape.data(),0);
|
||||
return SHAPELIST(newShape);
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,149 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_split)
|
||||
|
||||
#include <ops/declarable/headers/parity_ops.h>
|
||||
#include <ops/declarable/helpers/transforms.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
CUSTOM_OP_IMPL(split, 1, -1, false, 0, 1) {
|
||||
NDArray *input = nullptr;
|
||||
int num_splits = INT_ARG(0);
|
||||
|
||||
// axis is 0 by default
|
||||
sd::LongType axis = 0;
|
||||
|
||||
if (block.width() == 1) {
|
||||
input = INPUT_VARIABLE(0);
|
||||
} else {
|
||||
auto a = INPUT_VARIABLE(0);
|
||||
auto b = INPUT_VARIABLE(1);
|
||||
|
||||
if (a->isScalar()) {
|
||||
// axis goes first
|
||||
axis = a->e<sd::LongType>(0);
|
||||
input = b;
|
||||
} else if (b->isScalar()) {
|
||||
axis = b->e<sd::LongType>(0);
|
||||
input = a;
|
||||
}
|
||||
}
|
||||
|
||||
// Edge case: splitting empty array (mainly for TF import compatibility) -> return N empty arrays
|
||||
if (input->isEmpty()) {
|
||||
for (int i = 0; i < num_splits; i++) {
|
||||
REQUIRE_TRUE(OUTPUT_VARIABLE(i)->isEmpty(), 0,
|
||||
"Split: When input array is empty, all output arrays must be empty");
|
||||
}
|
||||
// No op
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
if (block.numI() == 2) axis = INT_ARG(1);
|
||||
|
||||
if (axis < 0) axis += input->rankOf();
|
||||
|
||||
REQUIRE_TRUE(input->sizeAt(axis) % num_splits == 0, 0,
|
||||
"Split: num_splits has wrong value, remainder of division should be 0, but it's %i",
|
||||
input->sizeAt(axis) % num_splits);
|
||||
|
||||
std::vector<NDArray *> outArrs(num_splits);
|
||||
for (int e = 0; e < num_splits; e++) {
|
||||
outArrs[e] = OUTPUT_VARIABLE(e);
|
||||
}
|
||||
|
||||
helpers::split(block.launchContext(), *input, outArrs, axis);
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(split) {
|
||||
getOpDescriptor()->setAllowedInputTypes({ALL_INTS, ALL_FLOATS})->setAllowedOutputTypes({ALL_INTS, ALL_FLOATS});
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(split) {
|
||||
int num_splits = INT_ARG(0);
|
||||
auto input = inputShape->at(0);
|
||||
sd::DataType dataType = ArrayOptions::dataType(input);
|
||||
|
||||
// axis is 0 by default
|
||||
int axis = 0;
|
||||
|
||||
int inputVar = 0;
|
||||
if (inputShape->size() != 1) {
|
||||
auto shape0 = inputShape->at(0);
|
||||
auto shape1 = inputShape->at(1);
|
||||
|
||||
if (shape::isScalar(shape0)) {
|
||||
input = shape1;
|
||||
auto _a = INPUT_VARIABLE(0);
|
||||
axis = _a->e<sd::LongType>(0);
|
||||
dataType = ArrayOptions::dataType(shape1);
|
||||
inputVar = 1;
|
||||
} else if (shape::isScalar(shape1)) {
|
||||
input = shape0;
|
||||
auto _a = INPUT_VARIABLE(1);
|
||||
axis = _a->e<sd::LongType>(0);
|
||||
dataType = ArrayOptions::dataType(shape0);
|
||||
inputVar = 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto shapes = SHAPELIST();
|
||||
|
||||
// Edge case: splitting empty array (mainly for TF import compatibility) -> return N empty arrays
|
||||
if(INPUT_VARIABLE(inputVar)->isEmpty()) {
|
||||
for (int e = 0; e < num_splits; e++) {
|
||||
auto empty = ConstantShapeHelper::getInstance().emptyShapeInfo(dataType);
|
||||
shapes->push_back(empty);
|
||||
}
|
||||
return shapes;
|
||||
}
|
||||
|
||||
if (block.numI() == 2) axis = INT_ARG(1);
|
||||
|
||||
if (axis < 0) axis += shape::rank(input);
|
||||
|
||||
std::vector<sd::LongType> shape(shape::rank(input));
|
||||
|
||||
for (sd::LongType e = 0; e < shape::rank(input); e++)
|
||||
if (e == axis)
|
||||
shape[e] = shape::sizeAt(input, e) / num_splits;
|
||||
else
|
||||
shape[e] = shape::sizeAt(input, e);
|
||||
|
||||
for (int e = 0; e < num_splits; e++) {
|
||||
auto newShape = ConstantShapeHelper::getInstance().createShapeInfo(dataType, shape::order(input), shape);
|
||||
shapes->push_back(newShape);
|
||||
}
|
||||
|
||||
return shapes;
|
||||
}
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,128 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_split_v)
|
||||
|
||||
#include <ops/declarable/headers/parity_ops.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
CUSTOM_OP_IMPL(split_v, 2, -1, false, 0, -2) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto sizes = INPUT_VARIABLE(1);
|
||||
|
||||
int axis = 0;
|
||||
|
||||
if (block.getIArguments()->size() > 0) {
|
||||
axis = INT_ARG(0);
|
||||
} else if (block.width() > 2) {
|
||||
auto _a = INPUT_VARIABLE(2);
|
||||
axis = _a->e<int>(0);
|
||||
}
|
||||
|
||||
if (axis < 0) axis += input->rankOf();
|
||||
|
||||
std::vector<sd::LongType> axisVec = {axis};
|
||||
|
||||
int pos = 0;
|
||||
std::vector<sd::LongType> indices(2 * input->rankOf());
|
||||
|
||||
for (sd::LongType e = 0; e < sizes->lengthOf(); e++) {
|
||||
int c_size = sizes->e<int>(e);
|
||||
|
||||
for (int d = 0; d < input->rankOf(); d++) {
|
||||
if (d == axis)
|
||||
indices[2 * d + 1] = (indices[2 * d] = pos) + c_size;
|
||||
else
|
||||
indices[2 * d] = indices[2 * d + 1] = 0;
|
||||
}
|
||||
|
||||
auto output = OUTPUT_VARIABLE(e);
|
||||
REQUIRE_TRUE(output->dataType() == input->dataType(), 0, "SplitV: all outputs must have same data type as input");
|
||||
|
||||
auto sub = (*input)(indices);
|
||||
|
||||
output->assign(sub);
|
||||
|
||||
delete sub;
|
||||
pos += c_size;
|
||||
}
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(split_v) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, {ALL_INTS, ALL_FLOATS})
|
||||
->setAllowedInputTypes(1, {ALL_INTS})
|
||||
->setAllowedInputTypes(2, {ALL_INTS})
|
||||
->setAllowedOutputTypes({ALL_INTS, ALL_FLOATS});
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(split_v) {
|
||||
auto input = inputShape->at(0);
|
||||
// auto sizes = inputShape->at(1);
|
||||
|
||||
auto shapeList = SHAPELIST();
|
||||
int rank = shape::rank(input);
|
||||
|
||||
// 0 is just default axis
|
||||
int axis = 0;
|
||||
|
||||
if (block.getIArguments()->size() > 0)
|
||||
axis = INT_ARG(0);
|
||||
else if (block.width() > 2) {
|
||||
auto _a = INPUT_VARIABLE(2);
|
||||
axis = _a->e<int>(0);
|
||||
}
|
||||
|
||||
if (axis < 0) axis += shape::rank(input);
|
||||
|
||||
// this op assumes we have sizes defined
|
||||
auto sizes = INPUT_VARIABLE(1);
|
||||
|
||||
auto length = sizes->lengthOf();
|
||||
int pos = 0;
|
||||
for (sd::LongType e = 0; e < length; e++) {
|
||||
int c_size = sizes->e<int>(e);
|
||||
|
||||
std::vector<sd::LongType> shape(rank);
|
||||
|
||||
for (sd::LongType d = 0; d < rank; d++) {
|
||||
if (d != axis)
|
||||
shape[d] = shape::sizeAt(input, d);
|
||||
else
|
||||
shape[d] = c_size;
|
||||
}
|
||||
|
||||
auto newShape =
|
||||
ConstantShapeHelper::getInstance().createShapeInfo(ArrayOptions::dataType(input), shape::order(input), shape);
|
||||
shapeList->push_back(newShape);
|
||||
}
|
||||
|
||||
return shapeList;
|
||||
}
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,96 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com), created on 01.11.2017.
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_stack)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/stack.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
CUSTOM_OP_IMPL(stack, -1, 1, false, 0, 0) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
int dim = block.getIArguments()->size() > 0 ? INT_ARG(0) : 0;
|
||||
if (dim < 0) dim += input->rankOf() + 1;
|
||||
|
||||
// no-op in case of empty output array
|
||||
if (output->isEmpty()) return Status::OK;
|
||||
|
||||
// input validation
|
||||
// check whether shapes of all input array are the same
|
||||
for (size_t i = 0; i < block.width() - 1; ++i)
|
||||
REQUIRE_TRUE(shape::equalsSoft((INPUT_VARIABLE(i))->shapeInfo(), (INPUT_VARIABLE(i + 1))->shapeInfo()), 0,
|
||||
"STACK op: the shapes of all input arrays must be the same !");
|
||||
|
||||
REQUIRE_TRUE(
|
||||
dim <= input->rankOf(), 0,
|
||||
"STACK op: the input dimension parameter must be <= rank of input arrays shapes (rank=%i), but got %i instead !",
|
||||
input->shapeOf(), dim);
|
||||
|
||||
std::vector<NDArray*> inArrs(block.width());
|
||||
for (size_t i = 0; i < block.width(); ++i) inArrs[i] = INPUT_VARIABLE(i);
|
||||
|
||||
//empty arrays are a no op
|
||||
if(block.width() >= 1 && !inArrs[0]->isEmpty())
|
||||
helpers::stack(block.launchContext(), inArrs, *output, dim);
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
DECLARE_SYN(pack, stack);
|
||||
DECLARE_SYN(Pack, stack);
|
||||
|
||||
DECLARE_TYPES(stack) {
|
||||
getOpDescriptor()->setAllowedInputTypes(ANY)->setAllowedOutputTypes(ANY);
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(stack) {
|
||||
// check whether input dimension is within rank range
|
||||
auto inShapeInfo = inputShape->at(0);
|
||||
|
||||
int rank = shape::rank(inShapeInfo);
|
||||
int dim = block.getIArguments()->size() > 0 ? INT_ARG(0) : 0;
|
||||
if (dim < 0) dim += rank + 1;
|
||||
|
||||
REQUIRE_TRUE(
|
||||
dim <= inShapeInfo[0], 0,
|
||||
"STACK op: the input dimension parameter must be <= rank of input arrays shapes (rank=%i), but got %i instead !",
|
||||
inShapeInfo[0], dim);
|
||||
|
||||
|
||||
// the rank of output ShapeInfo is larger by one compared to input ShapeInfo
|
||||
std::vector<LongType> outShape(inShapeInfo + 1, inShapeInfo + 1 + rank);
|
||||
|
||||
// insert (int) block.width() at dim position of input shape to get output shape
|
||||
outShape.insert(outShape.begin() + LongType(dim), (LongType)block.width());
|
||||
auto ret = SHAPELIST(ConstantShapeHelper::getInstance().bufferForShapeInfo(ArrayOptions::dataType(inShapeInfo),
|
||||
shape::order(inShapeInfo),
|
||||
outShape)->primary());
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* *
|
||||
* *
|
||||
* * This program and the accompanying materials are made available under the
|
||||
* * terms of the Apache License, Version 2.0 which is available at
|
||||
* * https://www.apache.org/licenses/LICENSE-2.0.
|
||||
* *
|
||||
* * See the NOTICE file distributed with this work for additional
|
||||
* * information regarding copyright ownership.
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* * License for the specific language governing permissions and limitations
|
||||
* * under the License.
|
||||
* *
|
||||
* * SPDX-License-Identifier: Apache-2.0
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
//
|
||||
// @author Paul Dubs
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_standardize)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/reverse.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
CONFIGURABLE_OP_IMPL(standardize, 1, 1, true, 0, -2) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
output->nullify();
|
||||
std::vector<sd::LongType> axis;
|
||||
|
||||
if (block.width() > 1)
|
||||
axis = INPUT_VARIABLE(1)->template asVectorT<sd::LongType>();
|
||||
else if (block.numI() > 0)
|
||||
axis = *block.getIArguments();
|
||||
|
||||
REQUIRE_TRUE(!axis.empty(), 0, "STANDARDIZE OP: axis has to be non-empty")
|
||||
|
||||
shape::checkDimensions(input->rankOf(), &axis);
|
||||
|
||||
// Compute mean with keepDims=true for broadcasting
|
||||
auto means = input->reduceAlongDimension(reduce::Mean, &axis, true);
|
||||
|
||||
// Compute VARIANCE (not stdev) - uses Welford's algorithm internally
|
||||
// biasCorrected=false gives population variance (divide by N, not N-1)
|
||||
auto varianceRaw = input->varianceAlongDimension(variance::SummaryStatsVariance, false, &axis);
|
||||
|
||||
// Reshape variance to match means shape for broadcasting (use reshape instead of reshapei)
|
||||
auto meansShape = means->getShapeAsVector();
|
||||
auto variance = varianceRaw->reshape(varianceRaw->ordering(), *meansShape);
|
||||
delete meansShape;
|
||||
delete varianceRaw;
|
||||
|
||||
// Add epsilon BEFORE sqrt: stdev = sqrt(variance + epsilon)
|
||||
// This is the numerically stable formula for LayerNorm
|
||||
NDArray* varPlusEps = *variance + 1e-5;
|
||||
NDArray* stdev = varPlusEps->transform(transform::Sqrt);
|
||||
|
||||
// output = (input - mean) / stdev
|
||||
input->applyTrueBroadcast(sd::BroadcastOpsTuple::Subtract(), means, output, false);
|
||||
output->applyTrueBroadcast(sd::BroadcastOpsTuple::Divide(), stdev, output, false);
|
||||
|
||||
delete means;
|
||||
delete variance;
|
||||
delete varPlusEps;
|
||||
delete stdev;
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(standardize) {
|
||||
getOpDescriptor()->setAllowedInputTypes(0, {ALL_FLOATS});
|
||||
getOpDescriptor()->setAllowedInputTypes(1, {DataType::INT32, DataType::INT64});
|
||||
getOpDescriptor()->setAllowedOutputTypes(0, DataType::INHERIT);
|
||||
}
|
||||
|
||||
CUSTOM_OP_IMPL(standardize_bp, 2, 1, false, 0, -2) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto eps = block.width() == 3 ? INPUT_VARIABLE(2) : INPUT_VARIABLE(1);
|
||||
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
std::vector<sd::LongType> axis;
|
||||
|
||||
if (block.width() == 3)
|
||||
axis = INPUT_VARIABLE(1)->template asVectorT<sd::LongType>();
|
||||
else if (block.numI() > 0)
|
||||
axis = *block.getIArguments();
|
||||
|
||||
REQUIRE_TRUE(!axis.empty(), 0, "STANDARDIZE OP: axis has to be non-empty")
|
||||
|
||||
shape::checkDimensions(input->rankOf(), &axis);
|
||||
auto longAxis = ArrayUtils::toLongVector(axis);
|
||||
|
||||
auto means = input->reduceAlongDimension(reduce::Mean, &axis, true);
|
||||
REQUIRE_TRUE(means != nullptr, 0, "STANDARDIZE_BP OP: failed to compute mean along dimension");
|
||||
|
||||
auto stdevRaw = input->varianceAlongDimension(variance::SummaryStatsStandardDeviation, false, &axis);
|
||||
REQUIRE_TRUE(stdevRaw != nullptr, 0, "STANDARDIZE_BP OP: failed to compute standard deviation along dimension");
|
||||
|
||||
// Reshape stdev to match means shape for broadcasting (use reshape instead of reshapei)
|
||||
auto meansShape = means->getShapeAsVector();
|
||||
auto stdev = stdevRaw->reshape(stdevRaw->ordering(), *meansShape);
|
||||
delete meansShape;
|
||||
delete stdevRaw;
|
||||
|
||||
eps->applyTrueBroadcast(sd::BroadcastOpsTuple::Divide(), stdev, output, false);
|
||||
|
||||
auto sum = output->reduceAlongDimension(reduce::Sum, &axis, true);
|
||||
REQUIRE_TRUE(sum != nullptr, 0, "STANDARDIZE_BP OP: failed to compute sum along dimension");
|
||||
|
||||
NDArray dldu_sum = -(*sum);
|
||||
|
||||
NDArray dldx_u(input->shapeInfo(), false, block.launchContext());
|
||||
std::vector<NDArray *> meanBpArgs = {input, &dldu_sum};
|
||||
std::vector<NDArray *> meanBpOutput = {&dldx_u};
|
||||
std::vector<double> meanBpTArgs = {};
|
||||
std::vector<bool> meanBpBArgs = {};
|
||||
|
||||
sd::ops::reduce_mean_bp meanBp;
|
||||
meanBp.execute(meanBpArgs, meanBpOutput, meanBpTArgs, longAxis, meanBpBArgs);
|
||||
*output += dldx_u;
|
||||
|
||||
// (eps * (means - input) / (stdev * stdev))
|
||||
NDArray tmp(eps->shapeInfo(), false, block.launchContext());
|
||||
means->applyTrueBroadcast(sd::BroadcastOpsTuple::Subtract(), input, &tmp, false);
|
||||
tmp.applyPairwiseTransform(sd::pairwise::Multiply, eps, &tmp);
|
||||
stdev->applyPairwiseTransform(sd::pairwise::Multiply, stdev, stdev);
|
||||
tmp.applyTrueBroadcast(sd::BroadcastOpsTuple::Divide(), stdev, &tmp, false);
|
||||
|
||||
auto dlds_sum = tmp.reduceAlongDimension(reduce::Sum, &axis, true);
|
||||
REQUIRE_TRUE(dlds_sum != nullptr, 0, "STANDARDIZE_BP OP: failed to compute dlds_sum along dimension");
|
||||
|
||||
NDArray dldx_s(input->shapeInfo(), false, block.launchContext());
|
||||
std::vector<NDArray *> stdevBpArgs = {input, dlds_sum};
|
||||
std::vector<NDArray *> stdevBpOutput = {&dldx_s};
|
||||
std::vector<double> stdevBpTArgs = {};
|
||||
std::vector<bool> stdevBpBArgs = {};
|
||||
sd::ops::reduce_stdev_bp stdevBp;
|
||||
stdevBp.execute(stdevBpArgs, stdevBpOutput, stdevBpTArgs, longAxis, stdevBpBArgs);
|
||||
*output += dldx_s;
|
||||
|
||||
output->applyScalar(sd::scalar::ReplaceNans, 0, output);
|
||||
delete sum;
|
||||
delete means;
|
||||
delete stdev;
|
||||
delete dlds_sum;
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(standardize_bp) {
|
||||
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(standardize_bp) {
|
||||
auto in = inputShape->at(0);
|
||||
sd::LongType *out;
|
||||
COPY_SHAPE(in, out);
|
||||
auto result = CONSTANT(out);
|
||||
delete[] out;
|
||||
|
||||
return SHAPELIST(result);
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,80 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// Created by raver119 on 12.10.2017.
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_tear)
|
||||
|
||||
#include <helpers/ConstantTadHelper.h>
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
CUSTOM_OP_IMPL(tear, 1, -1, false, 0, -1) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
|
||||
REQUIRE_TRUE(!block.getIArguments()->empty(), 0, "At least 1 dimension should be specified for Tear");
|
||||
|
||||
std::vector<sd::LongType> dims(*block.getIArguments());
|
||||
|
||||
for (auto &v : dims)
|
||||
REQUIRE_TRUE(v >= 0 && v < input->rankOf(), 0,
|
||||
"Tear dimensions should be non-negative values, and lower then input rank. Got %i instead", v);
|
||||
|
||||
auto tads = input->allTensorsAlongDimension(dims);
|
||||
for (sd::LongType e = 0; e < tads.size(); e++) {
|
||||
auto outE = OUTPUT_VARIABLE(e);
|
||||
outE->assign(tads.at(e));
|
||||
|
||||
// just for debugging purposes
|
||||
this->storeResult(block, e, *outE);
|
||||
}
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(tear) {
|
||||
auto inShape = inputShape->at(0);
|
||||
|
||||
std::vector<sd::LongType> dims(*block.getIArguments());
|
||||
|
||||
if (dims.size() > 1) std::sort(dims.begin(), dims.end());
|
||||
|
||||
auto tadPack = sd::ConstantTadHelper::getInstance().tadForDimensions(inShape, &dims);
|
||||
auto numTads = tadPack->numberOfTads();
|
||||
|
||||
auto result = SHAPELIST();
|
||||
for (sd::LongType e = 0; e < numTads; e++) {
|
||||
auto newShape = ConstantShapeHelper::getInstance().createShapeInfo(block.dataType(), shape::order(inShape),
|
||||
shape::rank(tadPack->primaryShapeInfo()),
|
||||
shape::shapeOf(tadPack->primaryShapeInfo()),0);
|
||||
result->push_back(newShape);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(tear) { getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setSameMode(true); }
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,185 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com)
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_tile)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/transforms.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
CUSTOM_OP_IMPL(tile, 1, 1, false, 0, -2) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto output = OUTPUT_VARIABLE(0);
|
||||
|
||||
const int inRank = input->rankOf();
|
||||
std::vector<sd::LongType> reps;
|
||||
|
||||
if (block.getIArguments()->size() == static_cast<size_t>(inRank)) {
|
||||
reps = ArrayUtils::toLongVector(*(block.getIArguments()));
|
||||
} else if (block.width() > 1) {
|
||||
auto reps_vector = INPUT_VARIABLE(1);
|
||||
REQUIRE_TRUE(reps_vector->lengthOf() == inRank, 0,
|
||||
"TILE op: repeats vector length should be equal to input rank, but got %i and %i correspondingly !",
|
||||
reps_vector->lengthOf(), inRank);
|
||||
|
||||
reps = reps_vector->template asVectorT<sd::LongType>();
|
||||
} else {
|
||||
REQUIRE_TRUE(false, 0,
|
||||
"TILE op: this op requires repeats vector, either as IArgs or second array with length equal to rank "
|
||||
"of input array to be tiled !");
|
||||
}
|
||||
|
||||
auto repProd = shape::prodLong(reps.data(), reps.size());
|
||||
REQUIRE_TRUE(repProd > 0, 0, "TILE op: reps can't contain 0s");
|
||||
|
||||
input->tile(reps, *output);
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(tile) {
|
||||
getOpDescriptor()
|
||||
->setAllowedInputTypes(0, sd::DataType::ANY)
|
||||
->setAllowedInputTypes(1, {ALL_INTS})
|
||||
->setAllowedOutputTypes(sd::DataType::ANY);
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(tile) {
|
||||
auto inShape = inputShape->at(0);
|
||||
const int inRank = inShape[0];
|
||||
std::vector<sd::LongType> reps;
|
||||
|
||||
if (block.getIArguments()->size() == static_cast<size_t>(inRank)) {
|
||||
reps = ArrayUtils::toLongVector(*(block.getIArguments()));
|
||||
} else if (block.width() > 1) {
|
||||
auto reps_vector = INPUT_VARIABLE(1);
|
||||
REQUIRE_TRUE(reps_vector->lengthOf() == inRank, 0,
|
||||
"TILE op: repeats vector length should be equal to input rank, but got %i and %i correspondingly !",
|
||||
reps_vector->lengthOf(), inRank);
|
||||
reps = reps_vector->template asVectorT<sd::LongType>();
|
||||
} else {
|
||||
REQUIRE_TRUE(false, 0,
|
||||
"TILE op: this op requires repeats vector, either as IArgs or second array with length equal to rank "
|
||||
"of input array to be tiled !");
|
||||
}
|
||||
|
||||
auto repProd = shape::prodLong(reps.data(), reps.size());
|
||||
REQUIRE_TRUE(repProd > 0, 0, "TILE op: reps can't contain 0s");
|
||||
|
||||
std::vector<sd::LongType> shape(inRank);
|
||||
for (sd::LongType e = 0; e < shape::rank(inShape); e++) shape[e] = shape::sizeAt(inShape, e) * reps[e];
|
||||
|
||||
auto newShape =
|
||||
ConstantShapeHelper::getInstance().createShapeInfo(ArrayOptions::dataType(inShape), shape::order(inShape), shape);
|
||||
return SHAPELIST(newShape);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
CUSTOM_OP_IMPL(tile_bp, 2, 1, false, 0, -2) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
auto gradO = INPUT_VARIABLE(1);
|
||||
auto gradI = OUTPUT_VARIABLE(0);
|
||||
|
||||
const int inRank = input->rankOf();
|
||||
|
||||
std::vector<sd::LongType> reps;
|
||||
|
||||
if (block.getIArguments()->size() == static_cast<size_t>(inRank)) {
|
||||
reps = ArrayUtils::toLongVector(*(block.getIArguments()));
|
||||
} else if (block.width() > 2) {
|
||||
auto reps_vector = INPUT_VARIABLE(1);
|
||||
REQUIRE_TRUE(reps_vector->lengthOf() == inRank, 0,
|
||||
"TILE_BP op: repeats vector length should be equal to input rank, but got %i and %i correspondingly !",
|
||||
reps_vector->lengthOf(), inRank);
|
||||
|
||||
reps = reps_vector->template asVectorT<sd::LongType>();
|
||||
gradO = INPUT_VARIABLE(2);
|
||||
} else {
|
||||
REQUIRE_TRUE(false, 0,
|
||||
"TILE_BP op: this op requires repeats vector, either as IArgs or second array with length equal to "
|
||||
"rank of input array to be tiled !");
|
||||
}
|
||||
|
||||
REQUIRE_TRUE(inRank == gradO->rankOf(), 0,
|
||||
"TILE_BP op: the ranks of input array and output's gradients array (next epsilon) must be equal, but "
|
||||
"got %i and %i correspondingly !",
|
||||
inRank, gradO->rankOf());
|
||||
|
||||
for (int i = 0; i < inRank; ++i)
|
||||
REQUIRE_TRUE(gradO->sizeAt(i) == gradI->sizeAt(i) * reps[i], 0,
|
||||
"TILE_BP op: shapes of input array and output's gradients array (next epsilon) are inconsistent !");
|
||||
|
||||
helpers::tileBP(block.launchContext(), *gradO, *gradI, reps);
|
||||
|
||||
return sd::Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(tile_bp) {
|
||||
getOpDescriptor()->setAllowedInputTypes(0, {ALL_FLOATS});
|
||||
getOpDescriptor()->setAllowedInputTypes(1, {ALL_INTS, ALL_FLOATS});
|
||||
getOpDescriptor()->setAllowedInputTypes(2, {ALL_FLOATS});
|
||||
|
||||
getOpDescriptor()->setAllowedOutputTypes({ALL_FLOATS});
|
||||
}
|
||||
|
||||
DECLARE_SHAPE_FN(tile_bp) {
|
||||
auto inShape = inputShape->at(0);
|
||||
auto gradOShape = inputShape->at(1);
|
||||
const int inRank = inShape[0];
|
||||
|
||||
std::vector<sd::LongType> reps;
|
||||
|
||||
if (block.getIArguments()->size() == static_cast<size_t>(inRank)) {
|
||||
reps = ArrayUtils::toLongVector(*(block.getIArguments()));
|
||||
} else if (block.width() > 2) {
|
||||
auto reps_vector = INPUT_VARIABLE(1);
|
||||
REQUIRE_TRUE(reps_vector->lengthOf() == inRank, 0,
|
||||
"TILE_BP op: repeats vector length should be equal to input rank, but got %i and %i correspondingly !",
|
||||
reps_vector->lengthOf(), inRank);
|
||||
reps = reps_vector->template asVectorT<sd::LongType>();
|
||||
gradOShape = inputShape->at(2);
|
||||
} else {
|
||||
REQUIRE_TRUE(false, 0,
|
||||
"TILE_BP op: this op requires repeats vector, either as IArgs or second array with length equal to "
|
||||
"rank of input array to be tiled !");
|
||||
}
|
||||
|
||||
REQUIRE_TRUE(inRank == gradOShape[0], 0,
|
||||
"TILE_BP op: the ranks of input array and output's gradients array (next epsilon) must be equal, but "
|
||||
"got %i and %i correspondingly !",
|
||||
inRank, gradOShape[0]);
|
||||
|
||||
for (sd::LongType i = 0; i < inRank; ++i)
|
||||
REQUIRE_TRUE(shape::sizeAt(gradOShape, i) == shape::sizeAt(inShape, i) * reps[i], 0,
|
||||
"TILE_BP op: shapes of input array and output's gradients array (next epsilon) are inconsistent !");
|
||||
|
||||
return SHAPELIST(CONSTANT(inShape));
|
||||
}
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,127 @@
|
||||
/* ******************************************************************************
|
||||
*
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License, Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* See the NOTICE file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
******************************************************************************/
|
||||
|
||||
//
|
||||
// @author raver119@gmail.com
|
||||
// @author Yurii Shyrma (iuriish@yahoo.com)
|
||||
//
|
||||
|
||||
#include <system/op_boilerplate.h>
|
||||
#if NOT_EXCLUDED(OP_unstack)
|
||||
|
||||
#include <ops/declarable/CustomOperations.h>
|
||||
#include <ops/declarable/helpers/stack.h>
|
||||
|
||||
namespace sd {
|
||||
namespace ops {
|
||||
|
||||
CUSTOM_OP_IMPL(unstack, 1, -1, false, 0, 1) {
|
||||
auto input = INPUT_VARIABLE(0);
|
||||
if (input->isEmpty()) return Status::OK;
|
||||
|
||||
auto dim = INT_ARG(0);
|
||||
if (dim < 0) dim += input->rankOf();
|
||||
|
||||
REQUIRE_TRUE(dim < input->rankOf(), 0,
|
||||
"Unstack dimension should be lower then rank of input %i, but got dimension=%i !", input->rankOf(), dim);
|
||||
REQUIRE_TRUE(dim >= 0, 0, "Unstack dimension should be non-negative value, but got %i !", dim);
|
||||
|
||||
|
||||
std::vector<NDArray*> outArrs(input->sizeAt(dim));
|
||||
for (size_t i = 0; i < outArrs.size(); ++i) outArrs[i] = OUTPUT_VARIABLE(i);
|
||||
|
||||
helpers::unstack(block.launchContext(), *input, outArrs, dim);
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
DECLARE_SYN(unpack, unstack);
|
||||
|
||||
DECLARE_SHAPE_FN(unstack) {
|
||||
auto inShapeInfo = inputShape->at(0);
|
||||
|
||||
auto dim = INT_ARG(0);
|
||||
const LongType numTads = block.numI() > 1 ? I_ARG(1) : shape::shapeOf(inShapeInfo)[dim];
|
||||
if (dim < 0) dim += shape::rank(inShapeInfo);
|
||||
if(!shape::isEmptyConst(inShapeInfo)) {
|
||||
REQUIRE_TRUE(dim < inShapeInfo[0], 0,
|
||||
"UNSTACK op: dimension should be lower then rank of input %i, but got dimension=%i !", inShapeInfo[0],
|
||||
dim);
|
||||
REQUIRE_TRUE(dim >= 0, 0, "UNSTACK op: dimension should be non-negative value, but got %i !", dim);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (ArrayOptions::arrayType(inShapeInfo) == EMPTY) {
|
||||
std::vector<LongType> outShape;
|
||||
for (LongType i = 0; i < shape::rank(inShapeInfo); ++i)
|
||||
if (i != dim) outShape.push_back(shape::shapeOf(inShapeInfo)[i]);
|
||||
|
||||
auto result = SHAPELIST();
|
||||
for (LongType i = 0; i < numTads; ++i)
|
||||
result->push_back(ConstantShapeHelper::getInstance().emptyShapeInfoWithShape(ArrayOptions::dataType(inShapeInfo),outShape));
|
||||
if(numTads < 1) {
|
||||
result->push_back(ConstantShapeHelper::getInstance().emptyShapeInfoWithShape(ArrayOptions::dataType(inShapeInfo),outShape));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<LongType> dimVec = {dim};
|
||||
std::vector<LongType> *dims = ShapeUtils::evalDimsToExclude(inShapeInfo[0], 1,dimVec.data());
|
||||
|
||||
if (dims->size() == 0 && shape::rank(inShapeInfo) == 1) { // split vector into lengthOf scalars
|
||||
auto result = SHAPELIST();
|
||||
for (LongType e = 0; e < numTads; e++)
|
||||
result->push_back(ConstantShapeHelper::getInstance().scalarShapeInfo(ArrayOptions::dataType(inShapeInfo)));
|
||||
delete dims;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<LongType> subArrShape(shape::rank(inShapeInfo) - 1);
|
||||
|
||||
for (LongType j = 0, i = 0; i < shape::rank(inShapeInfo); i++)
|
||||
if (i != dim) subArrShape[j++] = shape::shapeOf(inShapeInfo)[i];
|
||||
|
||||
// remove leading and trailing 1
|
||||
if (inShapeInfo[0] == 2 && subArrShape.size() == 2) {
|
||||
if (subArrShape[0] == 1)
|
||||
subArrShape.erase(subArrShape.begin());
|
||||
else if (subArrShape[1] == 1)
|
||||
subArrShape.erase(subArrShape.end());
|
||||
}
|
||||
|
||||
auto result = SHAPELIST();
|
||||
for (int e = 0; e < numTads; e++) {
|
||||
auto newShape = ConstantShapeHelper::getInstance().createShapeInfo(ArrayOptions::dataType(inShapeInfo),
|
||||
shape::order(inShapeInfo), subArrShape);
|
||||
result->push_back(newShape);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
DECLARE_TYPES(unstack) { getOpDescriptor()->setAllowedInputTypes({ALL_FLOATS, ALL_INTS})->setSameMode(true); }
|
||||
|
||||
} // namespace ops
|
||||
} // namespace sd
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user