chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:47:05 +08:00
commit 4f3b7da785
7394 changed files with 2005594 additions and 0 deletions
@@ -0,0 +1,95 @@
/*
* ******************************************************************************
* *
* *
* * 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 Abdelrauf 2020 (based on argmax)
#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_argamax)
#include <helpers/ConstantTadHelper.h>
#include <ops/declarable/CustomOperations.h>
#include <ops/declarable/helpers/axis.h>
#include <ops/declarable/helpers/reductions.h>
namespace sd {
namespace ops {
DECLARE_TYPES(argamax) {
getOpDescriptor()->setAllowedInputTypes({ALL_FLOATS, ALL_INTS})->setAllowedOutputTypes({ALL_INTS});
}
CUSTOM_OP_IMPL(argamax, 1, 1, false, 0, -2) {
auto input = INPUT_VARIABLE(0);
auto output = OUTPUT_VARIABLE(0);
if (output->isEmpty()) return Status::OK;
auto axis = *block.getIArguments();
// axis might be dynamic (i.e. tf mode)
if (block.width() > 1 && axis.size() == 0) {
auto axisVector = INPUT_VARIABLE(1);
helpers::adjustAxis(input->rankOf(), axisVector, axis);
helpers::argAbsMax(*input, *output, axis);
} else {
helpers::argAbsMax(*input, *output, axis);
}
STORE_RESULT(output);
return Status::OK;
}
DECLARE_SHAPE_FN(argamax) {
std::vector<LongType> dims;
if (block.width() == 1) {
dims = *block.getIArguments();
} else {
auto y = INPUT_VARIABLE(1);
dims = y->template asVectorT<LongType>();
}
auto keepDims = block.numB() ? B_ARG(0) : false;
auto dtype = block.numD() ? D_ARG(0) : INT64;
// we're resolving negative axis here
helpers::adjustAxis(shape::rank(inputShape->at(0)), dims);
auto in = inputShape->at(0);
for (auto d : dims) {
// we have special case here
if (d == DataTypeUtils::max<int>()) continue;
REQUIRE_TRUE(d < shape::rank(in), 0, "ArgAmax: axis can't be above rank")
REQUIRE_TRUE(in[d + 1] != 0, 0, "ArgAmax: you can't reduce along axis with 0 in shape");
}
// special case - output is scalar
if (dims.empty() || (dims.size() == 1 && dims.at(0) == DataTypeUtils::max<int>())) {
return SHAPELIST(ConstantShapeHelper::getInstance().scalarShapeInfo(dtype));
}
return SHAPELIST(
ShapeUtils::evalReduceShapeInfo('c', &dims, inputShape->at(0), dtype, keepDims, false, block.getWorkspace()));
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,95 @@
/*
* ******************************************************************************
* *
* *
* * 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 Abdelrauf 2020 (based on argmax)
#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_argamin)
#include <helpers/ConstantTadHelper.h>
#include <ops/declarable/CustomOperations.h>
#include <ops/declarable/helpers/axis.h>
#include <ops/declarable/helpers/reductions.h>
namespace sd {
namespace ops {
DECLARE_TYPES(argamin) {
getOpDescriptor()->setAllowedInputTypes({ALL_FLOATS, ALL_INTS})->setAllowedOutputTypes({ALL_INTS});
}
CUSTOM_OP_IMPL(argamin, 1, 1, false, 0, -2) {
auto input = INPUT_VARIABLE(0);
auto output = OUTPUT_VARIABLE(0);
if (output->isEmpty()) return Status::OK;
auto axis = *block.getIArguments();
// axis might be dynamic (i.e. tf mode)
if (block.width() > 1 && axis.size() == 0) {
auto axisVector = INPUT_VARIABLE(1);
helpers::adjustAxis(input->rankOf(), axisVector, axis);
helpers::argAbsMin(*input, *output, axis);
} else {
helpers::argAbsMin(*input, *output, axis);
}
STORE_RESULT(output);
return Status::OK;
}
DECLARE_SHAPE_FN(argamin) {
std::vector<LongType> dims;
if (block.width() == 1) {
dims = *block.getIArguments();
} else {
auto y = INPUT_VARIABLE(1);
dims = y->template asVectorT<LongType>();
}
auto keepDims = block.numB() ? B_ARG(0) : false;
auto dtype = block.numD() ? D_ARG(0) : INT64;
// we're resolving negative axis here
helpers::adjustAxis(shape::rank(inputShape->at(0)), dims);
auto in = inputShape->at(0);
for (auto d : dims) {
// we have special case here
if (d == DataTypeUtils::max<int>()) continue;
REQUIRE_TRUE(d < shape::rank(in), 0, "ArgAmin: axis can't be above rank")
REQUIRE_TRUE(in[d + 1] != 0, 0, "ArgAmin: you can't reduce along axis with 0 in shape");
}
// special case - output is scalar
if (dims.empty() || (dims.size() == 1 && dims.at(0) == DataTypeUtils::max<int>())) {
return SHAPELIST(ConstantShapeHelper::getInstance().scalarShapeInfo(dtype));
}
return SHAPELIST(
ShapeUtils::evalReduceShapeInfo('c', &dims, inputShape->at(0), dtype, keepDims, false, block.getWorkspace()));
}
} // 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 01.11.2017.
// Modified by GS <sgazeos@gmail.com> 4/5/2018
#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_argmax)
#include <helpers/ConstantTadHelper.h>
#include <ops/declarable/CustomOperations.h>
#include <ops/declarable/helpers/axis.h>
#include <ops/declarable/helpers/reductions.h>
namespace sd {
namespace ops {
DECLARE_TYPES(argmax) {
getOpDescriptor()->setAllowedInputTypes({ALL_FLOATS, ALL_INTS})->setAllowedOutputTypes({ANY});
}
CUSTOM_OP_IMPL(argmax, 1, 1, false, 0, -2) {
auto input = INPUT_VARIABLE(0);
auto output = OUTPUT_VARIABLE(0);
if (output->isEmpty() || output->lengthOf() < 1) return Status::OK;
auto axis = *block.getIArguments();
// axis might be dynamic (i.e. tf mode)
if (block.width() > 1 && axis.size() == 0) {
auto axisVector = INPUT_VARIABLE(1);
helpers::adjustAxis(input->rankOf(), axisVector, axis);
helpers::argMax(*input, *output, axis);
} else {
helpers::argMax(*input, *output, axis);
}
STORE_RESULT(output);
return Status::OK;
}
DECLARE_SHAPE_FN(argmax) {
auto firstInputShape = inputShape->at(0);
if(shape::isScalar(firstInputShape)) {
return SHAPELIST(ConstantShapeHelper::getInstance().scalarShapeInfo(DataType::INT64));
}
std::vector<LongType> dims;
if (block.width() == 1) {
dims = *block.getIArguments();
} else {
auto y = INPUT_VARIABLE(1)->cast(INT64);
dims = y->template asVectorT<LongType>();
}
auto keepDims = block.numB() ? B_ARG(0) : false;
auto dtype = block.numD() ? D_ARG(0) : INT64;
// we're resolving negative axis here
helpers::adjustAxis(shape::rank(inputShape->at(0)), dims);
for (auto d : dims) {
// we have special case here
if (d == DataTypeUtils::max<int>()) continue;
REQUIRE_TRUE(d < shape::rank(firstInputShape), 0, "ArgMax: axis can't be above rank")
REQUIRE_TRUE(firstInputShape[d + 1] != 0, 0, "ArgMax: you can't reduce along axis with 0 in shape");
}
// special case - output is scalar
if (dims.empty() || (dims.size() == 1 && dims.at(0) == DataTypeUtils::max<int>())) {
auto ret = ConstantShapeHelper::getInstance().scalarShapeInfo(dtype);
return SHAPELIST(ret);
}
auto ret = ShapeUtils::evalReduceShapeInfo('c', &dims, firstInputShape, dtype, keepDims, false, block.getWorkspace());
return SHAPELIST(ret);
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,107 @@
/* ******************************************************************************
*
*
* 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 01.11.2017.
// Modified by GS <sgazeos@gmail.com> 4/5/2018.
#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_argmin)
#include <helpers/ConstantTadHelper.h>
#include <ops/declarable/CustomOperations.h>
#include <ops/declarable/helpers/axis.h>
#include <ops/declarable/helpers/reductions.h>
namespace sd {
namespace ops {
DECLARE_TYPES(argmin) {
getOpDescriptor()->setAllowedInputTypes({ALL_FLOATS, ALL_INTS})->setAllowedOutputTypes({ALL_INTS});
}
CUSTOM_OP_IMPL(argmin, 1, 1, false, 0, -2) {
auto input = INPUT_VARIABLE(0);
auto axis = *block.getIArguments();
auto output = OUTPUT_VARIABLE(0);
if (output->isEmpty()) return Status::OK;
// axis might be dynamic (i.e. tf mode)
if (block.width() > 1 && axis.size() == 0) {
auto axisVector = INPUT_VARIABLE(1);
helpers::adjustAxis(input->rankOf(), axisVector, axis);
helpers::argMin(*input, *output, axis);
} else {
helpers::argMin(*input, *output, axis);
}
STORE_RESULT(output);
return Status::OK;
}
DECLARE_SHAPE_FN(argmin) {
auto firstInputShape = inputShape->at(0);
if(shape::isScalar(firstInputShape)) {
return SHAPELIST(ConstantShapeHelper::getInstance().scalarShapeInfo(DataType::INT64));
}
std::vector<LongType> dims;
if (block.width() == 1) {
dims = *block.getIArguments();
} else {
auto y = INPUT_VARIABLE(1);
dims = y->template asVectorT<LongType>();
}
auto keepDims = block.numB() ? B_ARG(0) : false;
auto dtype = block.numD() ? D_ARG(0) : INT64;
// we're resolving negative axis here
helpers::adjustAxis(shape::rank(inputShape->at(0)), dims);
auto in = inputShape->at(0);
for (auto d : dims) {
// we have special case here
if (d == DataTypeUtils::max<int>()) continue;
REQUIRE_TRUE(d < shape::rank(in), 0, "ArgMin: axis can't be above rank")
REQUIRE_TRUE(in[d + 1] != 0, 0, "ArgMin: you can't reduce along axis with 0 in shape");
}
// special case - output is scalar
if (dims.empty() || (dims.size() == 1 && dims.at(0) == DataTypeUtils::max<int>())) {
return SHAPELIST(ConstantShapeHelper::getInstance().scalarShapeInfo(dtype));
}
return SHAPELIST(
ShapeUtils::evalReduceShapeInfo('c', &dims, inputShape->at(0), dtype, keepDims, false, block.getWorkspace()));
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,99 @@
/* ******************************************************************************
*
*
* 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_norm)
#include <ops/declarable/CustomOperations.h>
#include <ops/declarable/helpers/axis.h>
namespace sd {
namespace ops {
REDUCTION_OP_IMPL(norm, 1, 1, false, 1, -2) {
auto input = INPUT_VARIABLE(0);
NDArray *output = OUTPUT_VARIABLE(0);
auto mode = (int)T_ARG(0);
std::vector<sd::LongType> dims = *block.getIArguments();
bool overwrite = false;
if (block.width() == 1) {
output = OUTPUT_VARIABLE(0);
} else {
auto axisVector = INPUT_VARIABLE(1);
dims.resize(axisVector->lengthOf());
helpers::adjustAxis(input->rankOf(), axisVector, dims);
auto shape = ShapeUtils::evalReduceShapeInfo(input->ordering(), &dims, *input, false, false);
if (!shape::equalsStrict(shape, output->shapeInfo())) {
output = new NDArray(shape, false, block.launchContext());
overwrite = true;
}
}
switch (mode) {
case 0: {
REQUIRE_TRUE(dims.size() == 2 || (input->rankOf() == 2 && dims.size() == 0), 0,
"Norm: Frobenius is defined for 2D matrices or TADS only");
// fro
input->reduceAlongDimension(reduce::NormFrobenius, output, &dims, false, output->rankOf() == 2);
} break;
case 1: {
// euclidean
if ((input->rankOf() == 2 && dims.size() == 0) || dims.size() == 2) {
input->reduceAlongDimension(reduce::NormFrobenius, output, &dims, false, output->rankOf() == 2);
} else {
input->reduceAlongDimension(reduce::Norm2, output, &dims, false, output->rankOf() == 2);
}
} break;
case 2: {
// 1
input->reduceAlongDimension(reduce::Norm1, output, &dims, false, output->rankOf() == 2);
} break;
case 3: {
// 2
input->reduceAlongDimension(reduce::Norm2, output, &dims, false, output->rankOf() == 2);
} break;
case 4: {
// inf-norm
input->reduceAlongDimension(reduce::NormMax, output, &dims, false, output->rankOf() == 2);
} break;
default: {
// p-norm
REQUIRE_TRUE(block.getIArguments()->size() > 1, 0,
"P-Norm reductions requires 2 TArguments, but only 1 was provided");
// FIXME: p is required here
// T p = T_ARG(1);
input->reduceAlongDimension(reduce::NormP, output, &dims, false, output->rankOf() == 2);
}
}
if (overwrite) {
OVERWRITE_RESULT(output);
}
return sd::Status::OK;
};
DECLARE_TYPES(norm) { getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS}); }
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,193 @@
/* ******************************************************************************
*
*
* 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.06.2018
//
#include <ops/declarable/CustomOperations.h>
#include <system/op_boilerplate.h>
#if NOT_EXCLUDED(OP_reduce_mean)
#include <ops/declarable/helpers/axis.h>
namespace sd {
namespace ops {
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_mean, -1, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto output = OUTPUT_VARIABLE(0);
auto dimensions = *block.getIArguments();
if (block.width() > 1) {
auto axesVector = INPUT_VARIABLE(1);
helpers::adjustAxis(input->rankOf(), axesVector, dimensions);
}
bool keepDims = false;
if (block.getBArguments()->size())
keepDims = B_ARG(0);
else if (block.getTArguments()->size())
keepDims = (bool)T_ARG(0);
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(input->rankOf()), 0,
"REDUCE_MEAN OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto &item : dimensions) {
REQUIRE_TRUE(item >= -input->rankOf() && item < input->rankOf(), 0,
"REDUCE_MEAN OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
}
input->reduceAlongDimension(reduce::Mean, output, &dimensions, keepDims);
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_mean) {
auto dimensions = *block.getIArguments();
auto in = inputShape->at(0);
if (block.width() > 1) {
auto axesVector = INPUT_VARIABLE(1);
helpers::adjustAxis(shape::rank(in), axesVector, dimensions);
}
bool keepDims = false;
if (block.getBArguments()->size())
keepDims = B_ARG(0);
else if (block.getTArguments()->size())
keepDims = (bool)T_ARG(0);
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(in[0]), 0,
"REDUCE_MEAN OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto &item : dimensions)
REQUIRE_TRUE(item >= -inputShape->at(0)[0] && item < inputShape->at(0)[0], 0,
"REDUCE_MEAN OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
inputShape->at(0)[0], inputShape->at(0)[0], item);
auto outShapeInfo =
ShapeUtils::evalReduceShapeInfo(shape::order(in), &dimensions, in, keepDims, false, block.getWorkspace());
return SHAPELIST(outShapeInfo);
}
DECLARE_TYPES(reduce_mean) {
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
}
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_mean_bp, -2, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto gradO = INPUT_VARIABLE(1);
auto gradI = OUTPUT_VARIABLE(0);
auto dimensions = *block.getIArguments();
if (block.width() > 2) {
auto axesVector = INPUT_VARIABLE(2);
helpers::adjustAxis(input->rankOf(), axesVector, dimensions);
}
bool keepDims = false;
if (block.getBArguments()->size())
keepDims = B_ARG(0);
else if (block.getTArguments()->size())
keepDims = (bool)T_ARG(0);
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(input->rankOf()), 0,
"REDUCE_MEAN_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
auto dimLength = 1.0;
for (const auto &item : dimensions) {
REQUIRE_TRUE(
item >= -input->rankOf() && item < input->rankOf(), 0,
"REDUCE_MEAN_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
dimLength *= input->sizeAt(item);
}
if (gradO->isScalar()) {
if (dimensions.size() > 0) {
NDArray *assign = gradO->e(0) / (static_cast<double>(dimLength));
gradI->assign(assign);
delete assign;
} else {
NDArray *assign = gradO->e(0) / (static_cast<double>(input->lengthOf()));
gradI->assign(assign);
delete assign;
}
} else {
auto val = (static_cast<double>(gradO->lengthOf() < 1 ? 1.0 : gradO->lengthOf()) )
/ (static_cast<double>(input->lengthOf() < 1 ? 1.0 : input->lengthOf()));
if(val == 0.0)
val = SD_EPSILON;
gradI->assign(val);
if (!keepDims) {
auto gradOShapeKeepDims =
ShapeUtils::evalReduceShapeInfo(gradO->ordering(), &dimensions, *input, true, false, block.getWorkspace());
std::vector<sd::LongType> shape = ShapeUtils::pullShapeFromShapeInfo(
gradOShapeKeepDims);
NDArray *reshapedGradO = gradO->reshape(gradO->ordering(), shape);
*gradI *= *reshapedGradO;
delete reshapedGradO;
} else {
gradI->applyTrueBroadcast(sd::BroadcastOpsTuple::Multiply(), gradO, gradI);
}
}
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_mean_bp) {
auto in = inputShape->at(0);
auto dimensions = *block.getIArguments();
auto rank = shape::rank(in);
if (block.width() > 2) {
auto axesVector = INPUT_VARIABLE(2);
helpers::adjustAxis(rank, axesVector, dimensions);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(rank), 0,
"REDUCE_MEAN_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto &item : dimensions)
REQUIRE_TRUE(
item >= -rank || item < rank, 0,
"REDUCE_MEAN_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !", rank,
rank, item);
sd::LongType *gradIshapeInfo = new sd::LongType[shape::shapeInfoLength(rank)];
memcpy(gradIshapeInfo, in, shape::shapeInfoByteLength(in));
auto ret = SHAPELIST(CONSTANT(gradIshapeInfo));
delete[] gradIshapeInfo;
return ret;
}
DECLARE_TYPES(reduce_mean_bp) {
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,208 @@
/* ******************************************************************************
*
*
* 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 04.06.2018
//
#include <ops/declarable/CustomOperations.h>
#include <ops/declarable/helpers/axis.h>
#include <ops/declarable/helpers/reductions.h>
#if NOT_EXCLUDED(OP_reduce_stdev)
namespace sd {
namespace ops {
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_stdev, -1, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto output = OUTPUT_VARIABLE(0);
//numpy compat: default is 1 for 0 length arrays https://stackoverflow.com/questions/66746566/numpy-explanation-of-numpy-prod
if(input->lengthOf() == 0) {
int one = 1;
output->assign(one);
return sd::Status::OK;
}
bool biasCorrected = false; // block.getTArguments()->size() > 1 ? (bool)T_ARG(1) : false;
auto dimensions = *block.getIArguments();
if (block.width() > 1) {
auto axesVector = INPUT_VARIABLE(1);
helpers::adjustAxis(input->rankOf(), axesVector, dimensions);
}
if (block.getBArguments()->size()) {
if (block.getBArguments()->size() > 1) biasCorrected = B_ARG(1);
} else if (block.getTArguments()->size()) {
if (block.getTArguments()->size() > 1) biasCorrected = (bool)T_ARG(1);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(input->rankOf()), 0,
"REDUCE_STDEV OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -input->rankOf() && item < input->rankOf(), 0,
"REDUCE_STDEV OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
sd::ops::helpers::standardDeviation(*input, *output, dimensions, biasCorrected);
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_stdev) {
auto in = inputShape->at(0);
auto rank = shape::rank(in);
bool keepDims = false; // block.getTArguments()->size() > 0 ? (bool)T_ARG(0) : false;
auto dimensions = *block.getIArguments();
if (block.width() > 1) {
auto axesVector = INPUT_VARIABLE(1);
helpers::adjustAxis(rank, axesVector, dimensions);
}
if (block.getBArguments()->size()) {
keepDims = B_ARG(0);
} else if (block.getTArguments()->size()) {
keepDims = (bool)T_ARG(0);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(rank), 0,
"REDUCE_STDEV OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -inputShape->at(0)[0] && item < inputShape->at(0)[0], 0,
"REDUCE_STDEV OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
inputShape->at(0)[0], inputShape->at(0)[0], item);
auto outShapeInfo =
ShapeUtils::evalReduceShapeInfo(shape::order(in), &dimensions, in, keepDims, false, block.getWorkspace());
return SHAPELIST(outShapeInfo);
}
DECLARE_TYPES(reduce_stdev) {
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
}
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_stdev_bp, -1, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto gradO = INPUT_VARIABLE(1);
auto gradI = OUTPUT_VARIABLE(0);
bool keepDims = false; // block.getTArguments()->size() > 0 ? (bool)T_ARG(0) : false;
bool biasCorrected = false; // block.getTArguments()->size() > 1 ? (bool)T_ARG(1) : false;
auto dimensions = *block.getIArguments();
if (block.width() > 2) {
auto axesVector = INPUT_VARIABLE(2);
helpers::adjustAxis(input->rankOf(), axesVector, dimensions);
}
if (block.getBArguments()->size()) {
keepDims = B_ARG(0);
if (block.getBArguments()->size() > 1) biasCorrected = B_ARG(1);
} else if (block.getTArguments()->size()) {
keepDims = (bool)T_ARG(0);
if (block.getTArguments()->size() > 1) biasCorrected = (bool)T_ARG(1);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(input->rankOf()), 0,
"REDUCE_STDEV_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -input->rankOf() && item < input->rankOf(), 0,
"REDUCE_STDEV_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
auto gradOLen = gradO->lengthOf() < 1 ? 1 : gradO->lengthOf();
const sd::LongType N = input->lengthOf() / gradOLen;
const sd::LongType NminusOne = biasCorrected ? N - 1 : N;
auto* mean = input->reduceAlongDimension(reduce::Mean, &dimensions, true);
NDArray variance(mean->shapeInfo(), true,
block.launchContext()); // create empty array with shape matching shape of mean array
input->varianceAlongDimension(variance::SummaryStatsStandardDeviation, variance, biasCorrected, &dimensions);
sd::ops::divide_no_nan divideNoNan;
auto* inputMinusMean = (*input) - (*mean);
delete mean;
auto* varianceTimesNMinusOne = variance * NminusOne;
divideNoNan.execute({inputMinusMean, varianceTimesNMinusOne}, {gradI});
delete inputMinusMean;
delete varianceTimesNMinusOne;
if (!keepDims) {
auto gradOShapeKeepDims =
ShapeUtils::evalReduceShapeInfo(gradO->ordering(), &dimensions, *input, true, false, block.getWorkspace());
if (!gradO->isScalar()) {
std::vector<sd::LongType> shape = ShapeUtils::pullShapeFromShapeInfo(
gradOShapeKeepDims);
auto* reshaped = gradO->reshape(gradO->ordering(), shape);
*gradI *= (*reshaped); // for example could be something like [a,b] -> [1,a,1,b]
delete reshaped;
} else {
*gradI *= (*gradO); // for example could be something like [a,b] -> [1,a,1,b]
}
} else {
*gradI *= (*gradO); // automatic broadcasting happens here
}
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_stdev_bp) {
auto in = inputShape->at(0);
auto rank = shape::rank(in);
auto dimensions = *block.getIArguments();
if (block.width() > 2) {
auto axesVector = INPUT_VARIABLE(2);
helpers::adjustAxis(rank, axesVector, dimensions);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(rank), 0,
"REDUCE_STDEV_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -inputShape->at(0)[0] && item < inputShape->at(0)[0], 0,
"REDUCE_STDEV_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
inputShape->at(0)[0], inputShape->at(0)[0], item);
return SHAPELIST(CONSTANT(in));
}
DECLARE_TYPES(reduce_stdev_bp) {
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,196 @@
/* ******************************************************************************
*
*
* 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 04.06.2018
//
#include <ops/declarable/CustomOperations.h>
#include <ops/declarable/helpers/axis.h>
#include <ops/declarable/helpers/reductions.h>
#if NOT_EXCLUDED(OP_reduce_variance)
namespace sd {
namespace ops {
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_variance, -1, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto output = OUTPUT_VARIABLE(0);
bool biasCorrected = false; // block.getTArguments()->size() > 1 ? (bool)T_ARG(1) : false;
auto dimensions = *block.getIArguments();
if (block.width() > 1) {
auto axesVector = INPUT_VARIABLE(1);
helpers::adjustAxis(input->rankOf(), axesVector, dimensions);
}
if (block.getBArguments()->size()) {
if (block.getBArguments()->size() > 1) biasCorrected = B_ARG(1);
} else if (block.getTArguments()->size()) {
if (block.getTArguments()->size() > 1) biasCorrected = (bool)T_ARG(1);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(input->rankOf()), 0,
"REDUCE_VARIANCE OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -input->rankOf() && item < input->rankOf(), 0,
"REDUCE_VARIANCE OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
sd::ops::helpers::variance(*input, *output, dimensions, biasCorrected);
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_variance) {
bool keepDims = false; // block.getTArguments()->size() > 0 ? (bool)T_ARG(0) : false;
auto dimensions = *block.getIArguments();
if (block.width() > 1) {
auto axesVector = INPUT_VARIABLE(1);
helpers::adjustAxis(INPUT_VARIABLE(0)->rankOf(), axesVector, dimensions);
}
if (block.getBArguments()->size()) {
keepDims = B_ARG(0);
} else if (block.getTArguments()->size()) {
keepDims = (bool)T_ARG(0);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(INPUT_VARIABLE(0)->rankOf()), 0,
"REDUCE_VARIANCE OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -inputShape->at(0)[0] && item < inputShape->at(0)[0], 0,
"REDUCE_VARIANCE OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
inputShape->at(0)[0], inputShape->at(0)[0], item);
auto outShapeInfo = ShapeUtils::evalReduceShapeInfo(shape::order(inputShape->at(0)), &dimensions, inputShape->at(0),
keepDims, false, block.getWorkspace());
return SHAPELIST(outShapeInfo);
}
DECLARE_TYPES(reduce_variance) {
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
}
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_variance_bp, -1, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto gradO = INPUT_VARIABLE(1);
auto gradI = OUTPUT_VARIABLE(0);
bool keepDims = true;
bool biasCorrected = false;
auto dimensions = *block.getIArguments();
if (block.width() > 2) {
auto axesVector = INPUT_VARIABLE(2);
helpers::adjustAxis(input->rankOf(), axesVector, dimensions);
}
if (block.getBArguments()->size()) {
keepDims = B_ARG(0);
if (block.getBArguments()->size() > 1) biasCorrected = B_ARG(1);
} else if (block.getTArguments()->size()) {
keepDims = (bool)T_ARG(0);
if (block.getTArguments()->size() > 1) biasCorrected = (bool)T_ARG(1);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(input->rankOf()), 0,
"REDUCE_VARIANCE_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions) {
REQUIRE_TRUE(
item >= -input->rankOf() && item < input->rankOf(), 0,
"REDUCE_VARIANCE_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
sd_debug("Dimension item is %d\n", item);
}
auto inputLen = input->lengthOf();
//avoid divide by zero
auto grad0Length = gradO->isScalar() || gradO->lengthOf() < 1 ? 1 : gradO->lengthOf();
const sd::LongType N = inputLen / grad0Length;
const sd::LongType NminusOne = biasCorrected ? N - 1 : N;
// Break down: (*input - mean) * (2.0f / NminusOne)
auto* mean = input->reduceAlongDimension(reduce::Mean, &dimensions, true);
auto* inputMinusMean = (*input) - (*mean);
delete mean;
auto* assign = (*inputMinusMean) * (2.0f / NminusOne);
delete inputMinusMean;
gradI->assign(assign); // automatic broadcasting happens here
delete assign;
if (!keepDims) {
auto gradOShapeKeepDims = ShapeUtils::evalReduceShapeInfo(gradO->ordering(), &dimensions, *input, true, false, block.getWorkspace());
auto grad0Shape = ShapeUtils::pullShapeFromShapeInfo(gradOShapeKeepDims);
auto* reshaped = !gradO->isScalar() ? gradO->reshape(gradO->ordering(), grad0Shape) : gradO; // for example could be something like [a,b] -> [1,a,1,b];
*gradI *= (*reshaped); // for example could be something like [a,b] -> [1,a,1,b]
//reshape can vary and may have the same buffer as the original
if(reshaped != gradO && reshaped->buffer() != gradO->buffer() && reshaped->specialBuffer() != gradI->specialBuffer())
delete reshaped;
} else {
*gradI *= (*gradO); // automatic broadcasting happens here
}
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_variance_bp) {
auto in = inputShape->at(0);
auto rank = shape::rank(in);
auto dimensions = *block.getIArguments();
if (block.width() > 2) {
auto axesVector = INPUT_VARIABLE(2);
helpers::adjustAxis(rank, axesVector, dimensions);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(rank), 0,
"REDUCE_VARIANCE_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -inputShape->at(0)[0] && item < inputShape->at(0)[0], 0,
"REDUCE_VARIANCE_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
inputShape->at(0)[0], inputShape->at(0)[0], item);
return SHAPELIST(CONSTANT(in));
}
DECLARE_TYPES(reduce_variance_bp) {
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,147 @@
/* ******************************************************************************
*
*
* 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 george@skymind.io on 6/1/2018.
// @author Yurii Shyrma (iuriish@yahoo.com)
//
#include <ops/declarable/CustomOperations.h>
#include <ops/declarable/helpers/axis.h>
#if NOT_EXCLUDED(OP_reduce_dot_bp)
namespace sd {
namespace ops {
////////////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_dot_bp, -1, 2, false, 0, 0) {
auto x = INPUT_VARIABLE(0);
auto y = INPUT_VARIABLE(1);
auto gradO = INPUT_VARIABLE(2);
auto gradX = OUTPUT_VARIABLE(0);
auto gradY = OUTPUT_VARIABLE(1);
// L(x,y) = SUM(x_i * y_i)
// dL/dx_i = y_i
REQUIRE_TRUE(x->isSameShape(y), 0,
"REDUCE_DOT_BP OP: both input arrays x and y should have same shapes, but got %s and %s correspondingly",
ShapeUtils::shapeAsString(x).c_str(), ShapeUtils::shapeAsString(y).c_str());
if (gradO->lengthOf() == 1) { // scalar of reduced to scalar with keep dimensions
auto* assign1 = (*y) * (*gradO);
gradX->assign(assign1);
delete assign1;
auto* assign2 = (*x) * (*gradO);
gradY->assign(assign2);
delete assign2;
} else {
bool keepDims = false;
auto dimensions = *block.getIArguments();
if (block.width() > 3) {
auto axesVector = INPUT_VARIABLE(3);
helpers::adjustAxis(x->rankOf(), axesVector, dimensions);
}
if (block.getBArguments()->size())
keepDims = B_ARG(0);
else if (block.getTArguments()->size())
keepDims = (bool)T_ARG(0);
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(x->rankOf()), 0,
"REDUCE_DOT_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -x->rankOf() && item < x->rankOf(), 0,
"REDUCE_DOT_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
x->rankOf(), x->rankOf(), item);
if (!keepDims) {
auto gradOShapeKeepDims =
ShapeUtils::evalReduceShapeInfo(gradO->ordering(), &dimensions, *x, true, false, block.getWorkspace());
std::vector<sd::LongType> shape = ShapeUtils::pullShapeFromShapeInfo(
gradOShapeKeepDims);
auto* r = gradO->reshape(gradO->ordering(), shape); // for example could be something like [a,b] -> [1,a,1,b]
// First case - for gradX
auto* gradXTemp1 = (*y) * (*r);
gradX->assign(gradXTemp1);
delete gradXTemp1;
// First case - for gradY
auto* gradYTemp1 = (*x) * (*r);
gradY->assign(gradYTemp1);
delete gradYTemp1;
delete r;
} else {
// Second case - for gradX
auto* gradXTemp2 = (*y) * (*gradO);
gradX->assign(gradXTemp2);
delete gradXTemp2;
// Second case - for gradY
auto* gradYTemp2 = (*x) * (*gradO);
gradY->assign(gradYTemp2);
delete gradYTemp2;
}
}
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_dot_bp) {
if (shape::length(inputShape->at(2)) > 1) {
auto dimensions = *block.getIArguments();
if (block.width() > 3) {
auto axesVector = INPUT_VARIABLE(3);
helpers::adjustAxis(INPUT_VARIABLE(0)->rankOf(), axesVector, dimensions);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(inputShape->at(0)[0]), 0,
"REDUCE_DOT_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -inputShape->at(0)[0] && item < inputShape->at(0)[0], 0,
"REDUCE_DOT_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
inputShape->at(0)[0], inputShape->at(0)[0], item);
}
return SHAPELIST(CONSTANT(inputShape->at(0)), CONSTANT(inputShape->at(1)));
}
DECLARE_TYPES(reduce_dot_bp) {
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
}
} // 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 george@skymind.io on 11/13/2018.
//
#include <ops/declarable/CustomOperations.h>
#include <ops/declarable/helpers/axis.h>
namespace sd {
namespace ops {
#if NOT_EXCLUDED(OP_reduce_logsumexp)
CUSTOM_OP_IMPL(reduce_logsumexp, -1, 1, false, 0, -2) {
auto input = INPUT_VARIABLE(0);
auto output = OUTPUT_VARIABLE(0);
std::vector<sd::LongType> axes; // = *block.getIArguments();
if (block.width() > 1) {
auto axisVector = INPUT_VARIABLE(1);
helpers::adjustAxis(input->rankOf(), axisVector, axes);
} else if (block.getIArguments()->size() > 0) {
axes = *block.getIArguments();
}
for (const auto& item : axes)
REQUIRE_TRUE(
item >= -input->shapeInfo()[0] && item < input->shapeInfo()[0], 0,
"REDUCE_LOGSUMEXP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
const bool keepDims = block.getTArguments()->size() > 0 ? (bool)T_ARG(0) : false;
sd::LongType maxI = input->argMax();
auto maxVals = input->e(maxI);
// void* whereMax = (void*)();
auto internal = (*input);
internal -= maxVals;
internal.applyTransform(transform::Exp, &internal);
internal.reduceAlongDimension(reduce::Sum, output, &axes, keepDims, false); //, (void*)&maxVals);
output->applyTransform(transform::Log, output);
(*output) += maxVals;
return sd::Status::OK;
}
DECLARE_TYPES(reduce_logsumexp) {
getOpDescriptor()->setAllowedInputTypes({ALL_INTS, ALL_FLOATS})->setAllowedOutputTypes({ALL_FLOATS});
}
DECLARE_SHAPE_FN(reduce_logsumexp) {
const bool keepDims = block.getTArguments()->size() > 0 ? (bool)T_ARG(0) : false;
auto input = INPUT_VARIABLE(0);
std::vector<sd::LongType> axes; // = *block.getIArguments();
if (block.width() > 1) {
auto axisVector = INPUT_VARIABLE(1);
helpers::adjustAxis(input->rankOf(), axisVector, axes);
} else if (block.getIArguments()->size() > 0) {
axes = *block.getIArguments();
}
auto outShapeInfo = ShapeUtils::evalReduceShapeInfo(shape::order(inputShape->at(0)), &axes, inputShape->at(0),
keepDims, false, block.getWorkspace());
return SHAPELIST(outShapeInfo);
}
#endif
} // namespace ops
} // namespace sd
@@ -0,0 +1,181 @@
/* ******************************************************************************
*
*
* 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 george@skymind.io on 6/1/2018.
// @author Yurii Shyrma (iuriish@yahoo.com)
//
#include <ops/declarable/CustomOperations.h>
#include <ops/declarable/helpers/axis.h>
#include <ops/declarable/helpers/transforms.h>
#if NOT_EXCLUDED(OP_reduce_max)
namespace sd {
namespace ops {
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_max, -1, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto output = OUTPUT_VARIABLE(0);
//numpy compat: default is 1 for 0 length arrays https://stackoverflow.com/questions/66746566/numpy-explanation-of-numpy-prod
if(input->lengthOf() == 0) {
int one = 1;
output->assign(one);
return sd::Status::OK;
}
std::vector<sd::LongType> dimensions = *block.getIArguments();
if (block.width() > 1) {
auto axesVector = INPUT_VARIABLE(1);
helpers::adjustAxis(input->rankOf(), axesVector, dimensions);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(input->rankOf()), 0,
"REDUCE_MAX OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(item >= -input->shapeInfo()[0] && item < input->shapeInfo()[0], 0,
"REDUCE_MAX OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
bool keepDims = false; //: false;
if (block.getBArguments()->size() > 0)
keepDims = B_ARG(0);
else if (block.getTArguments()->size() > 0)
keepDims = (bool)T_ARG(0);
input->reduceAlongDimension(reduce::Max, output, &dimensions, keepDims);
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_max) {
bool keepDims = false; //: false;
if (block.getBArguments()->size() > 0)
keepDims = B_ARG(0);
else if (block.getTArguments()->size() > 0)
keepDims = (bool)T_ARG(0);
auto dimensions = *block.getIArguments();
if (block.width() > 1) {
auto axesVector = INPUT_VARIABLE(1);
helpers::adjustAxis(INPUT_VARIABLE(0)->rankOf(), axesVector, dimensions);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(inputShape->at(0)[0]), 0,
"REDUCE_MAX OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(item >= -inputShape->at(0)[0] && item < inputShape->at(0)[0], 0,
"REDUCE_MAX OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
inputShape->at(0)[0], inputShape->at(0)[0], item);
auto outShapeInfo = ShapeUtils::evalReduceShapeInfo(shape::order(inputShape->at(0)), &dimensions, inputShape->at(0),
keepDims, false, block.getWorkspace());
return SHAPELIST(outShapeInfo);
}
DECLARE_TYPES(reduce_max) { getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setSameMode(true); }
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_max_bp, -1, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto gradO = INPUT_VARIABLE(1);
auto gradI = OUTPUT_VARIABLE(0);
std::vector<sd::LongType> dimensions = *block.getIArguments();
if (block.width() > 2) {
auto axesVector = INPUT_VARIABLE(2);
helpers::adjustAxis(input->rankOf(), axesVector, dimensions);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(input->rankOf()), 0,
"REDUCE_MAX_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -input->shapeInfo()[0] && item < input->shapeInfo()[0], 0,
"REDUCE_MAX_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
// *** calculations *** //
*gradI = 0;
if (gradO->lengthOf() == 1) {
auto indOfMaxElem = input->indexReduceNumber(sd::indexreduce::IndexMax);
NDArray right2 = gradO->e(0);
gradI->p(indOfMaxElem->t<sd::LongType>(0),&right2);
delete indOfMaxElem;
} else {
auto indicesArr = input->applyIndexReduce(sd::indexreduce::IndexMax, &dimensions);
auto vec = ShapeUtils::evalDimsToExclude(gradI->rankOf(), dimensions.size(),dimensions.data());
helpers::scatterSimple(
block.launchContext(), 6, *gradI, *gradO, *indicesArr,
*vec); // 6 corresponds to copy operation
delete vec;
delete indicesArr;
}
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_max_bp) {
std::vector<sd::LongType> dimensions = *block.getIArguments();
if (block.width() > 2) {
auto axesVector = INPUT_VARIABLE(2);
helpers::adjustAxis(INPUT_VARIABLE(0)->rankOf(), axesVector, dimensions);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(inputShape->at(0)[0]), 0,
"REDUCE_MAX_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -inputShape->at(0)[0] && item < inputShape->at(0)[0], 0,
"REDUCE_MAX_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
inputShape->at(0)[0], inputShape->at(0)[0], item);
return SHAPELIST(CONSTANT(inputShape->at(0)));
}
DECLARE_TYPES(reduce_max_bp) {
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,174 @@
/* ******************************************************************************
*
*
* 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 george@skymind.io on 6/6/2018.
// @author Yurii Shyrma (iuriish@yahoo.com)
//
#include <ops/declarable/CustomOperations.h>
#include <ops/declarable/helpers/axis.h>
#include <ops/declarable/helpers/transforms.h>
#if NOT_EXCLUDED(OP_reduce_min)
namespace sd {
namespace ops {
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_min, -1, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto output = OUTPUT_VARIABLE(0);
std::vector<sd::LongType> dimensions = *block.getIArguments();
if (block.width() > 1) {
auto axesVector = INPUT_VARIABLE(1);
helpers::adjustAxis(input->rankOf(), axesVector, dimensions);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(input->rankOf()), 0,
"REDUCE_MIN OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(item >= -input->shapeInfo()[0] && item < input->shapeInfo()[0], 0,
"REDUCE_MIN OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
bool keepDims = false; //: false;
if (block.getBArguments()->size() > 0)
keepDims = B_ARG(0);
else if (block.getTArguments()->size() > 0)
keepDims = (bool)T_ARG(0);
input->reduceAlongDimension(reduce::Min, output, &dimensions, keepDims);
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_min) {
bool keepDims = false; //: false;
if (block.getBArguments()->size() > 0)
keepDims = B_ARG(0);
else if (block.getTArguments()->size() > 0)
keepDims = (bool)T_ARG(0);
auto dimensions = *block.getIArguments();
if (block.width() > 1) {
auto axesVector = INPUT_VARIABLE(1);
helpers::adjustAxis(INPUT_VARIABLE(0)->rankOf(), axesVector, dimensions);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(inputShape->at(0)[0]), 0,
"REDUCE_MIN OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(item >= -inputShape->at(0)[0] && item < inputShape->at(0)[0], 0,
"REDUCE_MIN OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
inputShape->at(0)[0], inputShape->at(0)[0], item);
auto outShapeInfo = ShapeUtils::evalReduceShapeInfo(shape::order(inputShape->at(0)), &dimensions, inputShape->at(0),
keepDims, false, block.getWorkspace());
return SHAPELIST(outShapeInfo);
}
DECLARE_TYPES(reduce_min) { getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setSameMode(true); }
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_min_bp, -1, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto gradO = INPUT_VARIABLE(1);
auto gradI = OUTPUT_VARIABLE(0);
std::vector<sd::LongType> dimensions = *block.getIArguments();
if (block.width() > 2) {
auto axesVector = INPUT_VARIABLE(2);
helpers::adjustAxis(input->rankOf(), axesVector, dimensions);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(input->rankOf()), 0,
"REDUCE_MIN_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -input->shapeInfo()[0] && item < input->shapeInfo()[0], 0,
"REDUCE_MIN_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
// *** calculations *** //
*gradI = 0;
if (gradO->lengthOf() == 1) {
auto indOfMaxElem = input->indexReduceNumber(sd::indexreduce::IndexMin);
auto right = gradO->e(0);
gradI->p(indOfMaxElem->e<sd::LongType>(0),&right);
delete indOfMaxElem;
} else {
auto indicesArr = input->applyIndexReduce(sd::indexreduce::IndexMin, &dimensions);
auto vec = ShapeUtils::evalDimsToExclude(gradI->rankOf(), dimensions.size(),dimensions.data());
helpers::scatterSimple(
block.launchContext(), 6, *gradI, *gradO, *indicesArr,
*vec); // 6 corresponds to copy operation
delete vec;
delete indicesArr;
}
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_min_bp) {
std::vector<sd::LongType> dimensions = *block.getIArguments();
if (block.width() > 2) {
auto axesVector = INPUT_VARIABLE(2);
helpers::adjustAxis(INPUT_VARIABLE(0)->rankOf(), axesVector, dimensions);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(inputShape->at(0)[0]), 0,
"REDUCE_MIN_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -inputShape->at(0)[0] && item < inputShape->at(0)[0], 0,
"REDUCE_MIN_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
inputShape->at(0)[0], inputShape->at(0)[0], item);
return SHAPELIST(CONSTANT(inputShape->at(0)));
}
DECLARE_TYPES(reduce_min_bp) {
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,183 @@
/* ******************************************************************************
*
*
* 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 george@skymind.io on 6/4/2018.
// @author Yurii Shyrma (iuriish@yahoo.com)
//
#include <ops/declarable/CustomOperations.h>
#include <ops/declarable/helpers/axis.h>
namespace sd {
namespace ops {
#if NOT_EXCLUDED(OP_reduce_norm1)
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_norm1, -1, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto output = OUTPUT_VARIABLE(0);
std::vector<sd::LongType> dimensions;
if (block.width() > 1) {
auto axesVector = INPUT_VARIABLE(1);
helpers::adjustAxis(input->rankOf(), axesVector, dimensions);
} else if (block.getIArguments()->size())
dimensions = *block.getIArguments();
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(input->rankOf()), 0,
"REDUCE_NORM1 OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -input->shapeInfo()[0] && item < input->shapeInfo()[0], 0,
"REDUCE_NORM1 OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
bool keepDims = false;
if (block.getBArguments()->size())
keepDims = B_ARG(0);
else if (block.getTArguments()->size())
keepDims = (bool)T_ARG(0);
input->reduceAlongDimension(reduce::Norm1, output, &dimensions, keepDims);
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_norm1) {
bool keepDims = false;
if (block.getBArguments()->size())
keepDims = B_ARG(0);
else if (block.getTArguments()->size())
keepDims = (bool)T_ARG(0);
std::vector<sd::LongType> dimensions;
if (block.width() > 1) {
auto axesVector = INPUT_VARIABLE(1);
helpers::adjustAxis(INPUT_VARIABLE(0)->rankOf(), axesVector, dimensions);
} else if (block.getIArguments()->size())
dimensions = *block.getIArguments();
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(inputShape->at(0)[0]), 0,
"REDUCE_NORM1 OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -inputShape->at(0)[0] && item < inputShape->at(0)[0], 0,
"REDUCE_NORM1 OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
inputShape->at(0)[0], inputShape->at(0)[0], item);
return SHAPELIST(ShapeUtils::evalReduceShapeInfo(shape::order(inputShape->at(0)), &dimensions, inputShape->at(0),
keepDims, false, block.getWorkspace()));
}
DECLARE_TYPES(reduce_norm1) {
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
}
#endif
#if NOT_EXCLUDED(OP_reduce_norm1_bp)
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_norm1_bp, -1, 1, false, 0, 0) {
// L = Sum abs(x_i) for all i = 1 to N
// dL/dx_i = 1 if x_i >= 0 and -1 when x_i < 0
// out_i = epsilon_i if x_i > 0 and -epsilon_i when x_i < 0
// when gradO is non a scalar, using dimensions to split output onto gradO like parts
// and use LAMBDA with that formula for it.
auto input = INPUT_VARIABLE(0);
auto gradO = INPUT_VARIABLE(1);
auto gradI = OUTPUT_VARIABLE(0);
input->applyTransform(sd::transform::Sign, gradI);
bool keepDims = false;
auto dimensions = *block.getIArguments();
if (block.width() > 2) {
auto axesVector = INPUT_VARIABLE(2);
helpers::adjustAxis(input->rankOf(), axesVector, dimensions);
}
if (block.getBArguments()->size())
keepDims = B_ARG(0);
else if (block.getTArguments()->size())
keepDims = (bool)T_ARG(0);
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(input->rankOf()), 0,
"REDUCE_NORM1_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -input->rankOf() && item < input->rankOf(), 0,
"REDUCE_NORM1_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
// *** calculations *** //
if (!keepDims && gradO->lengthOf() > 1) {
auto gradOShapeKeepDims =
ShapeUtils::evalReduceShapeInfo(gradO->ordering(), &dimensions, *input, true, false, block.getWorkspace());
std::vector<sd::LongType> shape = ShapeUtils::pullShapeFromShapeInfo(
gradOShapeKeepDims);
auto reshaped = gradO->reshape(gradO->ordering(),
shape);
*gradI *= *reshaped; // for example could be something like [a,b] -> [1,a,1,b]
delete reshaped;
} else
*gradI *= *gradO;
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_norm1_bp) {
auto dimensions = *block.getIArguments();
if (block.width() > 2) {
auto axesVector = INPUT_VARIABLE(2);
helpers::adjustAxis(INPUT_VARIABLE(0)->rankOf(), axesVector, dimensions);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(inputShape->at(0)[0]), 0,
"REDUCE_NORM1_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -inputShape->at(0)[0] && item < inputShape->at(0)[0], 0,
"REDUCE_NORM1_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
inputShape->at(0)[0], inputShape->at(0)[0], item);
return SHAPELIST(CONSTANT(inputShape->at(0)));
}
DECLARE_TYPES(reduce_norm1_bp) {
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
}
#endif
} // namespace ops
} // namespace sd
@@ -0,0 +1,184 @@
/* ******************************************************************************
*
*
* 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 george@skymind.io on 6/4/2018.
// @author Yurii Shyrma (iuriish@yahoo.com)
//
#include <ops/declarable/CustomOperations.h>
#include <ops/declarable/helpers/axis.h>
namespace sd {
namespace ops {
#if NOT_EXCLUDED(OP_reduce_norm2)
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_norm2, -1, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto output = OUTPUT_VARIABLE(0);
std::vector<sd::LongType> dimensions;
if (block.width() > 1) {
auto axesVector = INPUT_VARIABLE(1);
helpers::adjustAxis(input->rankOf(), axesVector, dimensions);
} else if (block.getIArguments()->size())
dimensions = *block.getIArguments();
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(input->rankOf()), 0,
"REDUCE_NORM2 OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -input->shapeInfo()[0] && item < input->shapeInfo()[0], 0,
"REDUCE_NORM2 OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
bool keepDims = false;
if (block.getBArguments()->size())
keepDims = B_ARG(0);
else if (block.getTArguments()->size())
keepDims = (bool)T_ARG(0);
input->reduceAlongDimension(reduce::Norm2, output, &dimensions, keepDims);
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_norm2) {
bool keepDims = false;
if (block.getBArguments()->size())
keepDims = B_ARG(0);
else if (block.getTArguments()->size())
keepDims = (bool)T_ARG(0);
std::vector<sd::LongType> dimensions;
if (block.width() > 1) {
auto axesVector = INPUT_VARIABLE(1);
helpers::adjustAxis(INPUT_VARIABLE(0)->rankOf(), axesVector, dimensions);
} else if (block.getIArguments()->size())
dimensions = *block.getIArguments();
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(inputShape->at(0)[0]), 0,
"REDUCE_NORM2 OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -inputShape->at(0)[0] && item < inputShape->at(0)[0], 0,
"REDUCE_NORM2 OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
inputShape->at(0)[0], inputShape->at(0)[0], item);
return SHAPELIST(ShapeUtils::evalReduceShapeInfo(shape::order(inputShape->at(0)), &dimensions, inputShape->at(0),
keepDims, false, block.getWorkspace()));
}
DECLARE_TYPES(reduce_norm2) {
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
}
#endif
#if NOT_EXCLUDED(OP_reduce_norm2_bp)
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_norm2_bp, -1, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto gradO = INPUT_VARIABLE(1);
auto gradI = OUTPUT_VARIABLE(0);
gradI->assign(input);
bool keepDims = false;
auto dimensions = *block.getIArguments();
if (block.width() > 2) {
auto axesVector = INPUT_VARIABLE(2);
helpers::adjustAxis(input->rankOf(), axesVector, dimensions);
}
if (block.getBArguments()->size())
keepDims = B_ARG(0);
else if (block.getTArguments()->size())
keepDims = (bool)T_ARG(0);
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(input->rankOf()), 0,
"REDUCE_NORM2_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -input->rankOf() && item < input->rankOf(), 0,
"REDUCE_NORM2_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
// *** calculations *** //
auto* norm2 = input->reduceAlongDimension(reduce::Norm2, &dimensions, true);
*gradI /= (*norm2);
delete norm2;
if (!keepDims && gradO->lengthOf() > 1) {
auto gradOShapeKeepDims =
ShapeUtils::evalReduceShapeInfo(gradO->ordering(), &dimensions, *input, true, false, block.getWorkspace());
std::vector<sd::LongType> shape = ShapeUtils::pullShapeFromShapeInfo(
gradOShapeKeepDims);
auto* reshaped = gradO->reshape(gradO->ordering(), shape);
*gradI *= (*reshaped); // for example could be something like [a,b] -> [1,a,1,b]
delete reshaped;
} else
*gradI *= (*gradO);
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_norm2_bp) {
auto dimensions = *block.getIArguments();
if (block.width() > 2) {
auto axesVector = INPUT_VARIABLE(2);
helpers::adjustAxis(INPUT_VARIABLE(0)->rankOf(), axesVector, dimensions);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(inputShape->at(0)[0]), 0,
"REDUCE_NORM2_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -inputShape->at(0)[0] && item < inputShape->at(0)[0], 0,
"REDUCE_NORM2_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
inputShape->at(0)[0], inputShape->at(0)[0], item);
sd::LongType* outShapeInfo;
COPY_SHAPE(inputShape->at(0), outShapeInfo);
return SHAPELIST(CONSTANT(outShapeInfo));
}
DECLARE_TYPES(reduce_norm2_bp) {
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
}
#endif
} // namespace ops
} // namespace sd
@@ -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
******************************************************************************/
//
// Created by george@skymind.io on 6/4/2018.
// @author Yurii Shyrma (iuriish@yahoo.com)
//
#include <ops/declarable/CustomOperations.h>
#include <ops/declarable/helpers/axis.h>
#include <ops/declarable/helpers/transforms.h>
#if NOT_EXCLUDED(OP_reduce_norm_max)
namespace sd {
namespace ops {
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_norm_max, -1, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto output = OUTPUT_VARIABLE(0);
std::vector<sd::LongType> dimensions;
if (block.width() > 1) {
auto axesVector = INPUT_VARIABLE(1);
helpers::adjustAxis(input->rankOf(), axesVector, dimensions);
} else if (block.getIArguments()->size())
dimensions = *block.getIArguments();
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(input->rankOf()), 0,
"REDUCE_NORM_MAX OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -input->shapeInfo()[0] && item < input->shapeInfo()[0], 0,
"REDUCE_NORM_MAX OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
bool keepDims = false;
if (block.getBArguments()->size())
keepDims = B_ARG(0);
else if (block.getTArguments()->size())
keepDims = (bool)T_ARG(0);
input->reduceAlongDimension(reduce::NormMax, output, &dimensions, keepDims);
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_norm_max) {
auto in = inputShape->at(0);
bool keepDims = false;
if (block.getBArguments()->size())
keepDims = B_ARG(0);
else if (block.getTArguments()->size())
keepDims = (bool)T_ARG(0);
std::vector<sd::LongType> dimensions;
if (block.width() > 1) {
auto axesVector = INPUT_VARIABLE(1);
helpers::adjustAxis(INPUT_VARIABLE(0)->rankOf(), axesVector, dimensions);
} else if (block.getIArguments()->size())
dimensions = *block.getIArguments();
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(inputShape->at(0)[0]), 0,
"REDUCE_NORM_MAX OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -inputShape->at(0)[0] && item < inputShape->at(0)[0], 0,
"REDUCE_NORM_MAX OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
inputShape->at(0)[0], inputShape->at(0)[0], item);
return SHAPELIST(
ShapeUtils::evalReduceShapeInfo(shape::order(in), &dimensions, in, keepDims, false, block.getWorkspace()));
}
DECLARE_TYPES(reduce_norm_max) {
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
}
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_norm_max_bp, -1, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto gradO = INPUT_VARIABLE(1);
auto gradI = OUTPUT_VARIABLE(0);
std::vector<sd::LongType> dimensions = *block.getIArguments();
if (block.width() > 2) {
auto axesVector = INPUT_VARIABLE(2);
helpers::adjustAxis(input->rankOf(), axesVector, dimensions);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(input->rankOf()), 0,
"REDUCE_NORM_MAX_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -input->shapeInfo()[0] && item < input->shapeInfo()[0], 0,
"REDUCE_NORM_MAX_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
// *** calculations *** //
*gradI = 0.0;
if (gradO->lengthOf() == 1) {
auto* indOfAbsMaxElem = input->indexReduceNumber(sd::indexreduce::IndexAbsoluteMax);
const sd::LongType ind = indOfAbsMaxElem->t<sd::LongType>(0);
delete indOfAbsMaxElem;
const int sign = input->e<float>(ind) >= 0 ? 1 : -1;
auto put = sign * gradO->e(0);
gradI->p(ind, put);
delete put;
} else {
auto indicesArr = input->applyIndexReduce(sd::indexreduce::IndexAbsoluteMax, &dimensions);
auto* vec = ShapeUtils::evalDimsToExclude(gradI->rankOf(), dimensions.size(), dimensions.data());
helpers::scatterSimple(
block.launchContext(), 6, *gradI, *gradO, *indicesArr,
*vec); // 6 corresponds to copy operation
delete vec;
delete indicesArr;
auto* signArr = input->transform(sd::transform::Sign);
*gradI *= (*signArr);
delete signArr;
}
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_norm_max_bp) {
auto dimensions = *block.getIArguments();
if (block.width() > 2) {
auto axesVector = INPUT_VARIABLE(2);
helpers::adjustAxis(INPUT_VARIABLE(0)->rankOf(), axesVector, dimensions);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(inputShape->at(0)[0]), 0,
"REDUCE_NORM_MAX_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -inputShape->at(0)[0] && item < inputShape->at(0)[0], 0,
"REDUCE_NORM_MAX_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
inputShape->at(0)[0], inputShape->at(0)[0], item);
return SHAPELIST(CONSTANT(inputShape->at(0)));
}
DECLARE_TYPES(reduce_norm_max_bp) {
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,200 @@
/* ******************************************************************************
*
*
* 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 george@skymind.io on 6/1/2018.
// @author Yurii Shyrma (iuriish@yahoo.com)
//
#include <ops/declarable/CustomOperations.h>
#include <ops/declarable/helpers/axis.h>
#if NOT_EXCLUDED(OP_reduce_prod)
namespace sd {
namespace ops {
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_prod, -1, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto output = OUTPUT_VARIABLE(0);
//numpy compat: default is 1 for 0 length arrays https://stackoverflow.com/questions/66746566/numpy-explanation-of-numpy-prod
if(input->lengthOf() == 0) {
int one = 1;
output->assign(one);
return sd::Status::OK;
}
std::vector<sd::LongType> dimensions;
if (block.width() > 1) {
auto axesVector = INPUT_VARIABLE(1);
helpers::adjustAxis(input->rankOf(), axesVector, dimensions);
} else if (block.getIArguments()->size())
dimensions = *block.getIArguments();
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(input->rankOf()), 0,
"REDUCE_PROD OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(item >= -input->shapeInfo()[0] && item < input->shapeInfo()[0], 0,
"REDUCE_PROD OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
bool keepDims = false;
if (block.getBArguments()->size())
keepDims = B_ARG(0);
else if (block.getTArguments()->size())
keepDims = (bool)T_ARG(0);
input->reduceAlongDimension(reduce::Prod, output, &dimensions, keepDims);
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_prod) {
bool keepDims = false;
if (block.getBArguments()->size())
keepDims = B_ARG(0);
else if (block.getTArguments()->size())
keepDims = (bool)T_ARG(0);
std::vector<sd::LongType> dimensions;
if (block.width() > 1) {
auto axesVector = INPUT_VARIABLE(1);
helpers::adjustAxis(INPUT_VARIABLE(0)->rankOf(), axesVector, dimensions);
} else if (block.getIArguments()->size())
dimensions = *block.getIArguments();
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(inputShape->at(0)[0]), 0,
"REDUCE_PROD OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(item >= -inputShape->at(0)[0] && item < inputShape->at(0)[0], 0,
"REDUCE_PROD OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
inputShape->at(0)[0], inputShape->at(0)[0], item);
return SHAPELIST(ShapeUtils::evalReduceShapeInfo(shape::order(inputShape->at(0)), &dimensions, inputShape->at(0),
keepDims, false, block.getWorkspace()));
}
DECLARE_TYPES(reduce_prod) {
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
}
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_prod_bp, -1, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto gradO = INPUT_VARIABLE(1);
auto gradI = OUTPUT_VARIABLE(0);
if (gradO->lengthOf() == 1) {
auto* assign = input->reduceNumber(sd::reduce::Prod);
gradI->assign(assign);
// FIXED: Check if view before deletion
if (assign != nullptr && !assign->isView()) {
delete assign;
}
*gradI /= *input;
*gradI *= gradO->e(0);
} else {
bool keepDims = false;
auto dimensions = *block.getIArguments();
if (block.width() > 2) {
auto axesVector = INPUT_VARIABLE(2);
helpers::adjustAxis(input->rankOf(), axesVector, dimensions);
}
if (block.getBArguments()->size())
keepDims = B_ARG(0);
else if (block.getTArguments()->size())
keepDims = (bool)T_ARG(0);
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(input->rankOf()), 0,
"REDUCE_NORM1_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -input->rankOf() && item < input->rankOf(), 0,
"REDUCE_NORM1_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
// *** calculations *** //
auto* products = input->reduceAlongDimension(reduce::Prod, &dimensions, true);
gradI->applyTrueBroadcast(sd::BroadcastOpsTuple::Assign(), products, gradI);
// FIXED: Check if view before deletion
if (products != nullptr && !products->isView()) {
delete products;
}
*gradI /= *input;
if (!keepDims) {
auto gradOShapeKeepDims =
ShapeUtils::evalReduceShapeInfo(gradO->ordering(), &dimensions, *input, true, false, block.getWorkspace());
std::vector<sd::LongType> shape = ShapeUtils::pullShapeFromShapeInfo(
gradOShapeKeepDims);
auto* reshaped = gradO->reshape(gradO->ordering(), shape);
*gradI *= (*reshaped); // for example could be something like [a,b] -> [1,a,1,b]
// FIXED: reshape() may return view - check before deletion
if (reshaped != nullptr && !reshaped->isView()) {
delete reshaped;
}
} else
*gradI *= (*gradO);
}
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_prod_bp) {
auto dimensions = *block.getIArguments();
if (block.width() > 2) {
auto axesVector = INPUT_VARIABLE(2);
helpers::adjustAxis(INPUT_VARIABLE(0)->rankOf(), axesVector, dimensions);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(inputShape->at(0)[0]), 0,
"REDUCE_PROD_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -inputShape->at(0)[0] && item < inputShape->at(0)[0], 0,
"REDUCE_PROD_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
inputShape->at(0)[0], inputShape->at(0)[0], item);
return SHAPELIST(CONSTANT(inputShape->at(0)));
}
DECLARE_TYPES(reduce_prod_bp) {
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,199 @@
/* ******************************************************************************
*
*
* 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 george@skymind.io on 6/4/2018.
//
#include <ops/declarable/CustomOperations.h>
#include <ops/declarable/helpers/axis.h>
#if NOT_EXCLUDED(OP_reduce_sqnorm)
namespace sd {
namespace ops {
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_sqnorm, -1, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto gradI = OUTPUT_VARIABLE(0);
bool keepDims = false;
auto dimensions = *block.getIArguments();
if (block.width() > 1) {
auto axesVector = INPUT_VARIABLE(1);
helpers::adjustAxis(input->rankOf(), axesVector, dimensions);
}
if (block.getBArguments()->size())
keepDims = B_ARG(0);
else if (block.getTArguments()->size())
keepDims = (bool)T_ARG(0);
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(input->rankOf()), 0,
"REDUCE_SQNORM OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -input->rankOf() && item < input->rankOf(), 0,
"REDUCE_SQNORM OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
input->reduceAlongDimension(reduce::SquaredNorm, gradI, &dimensions, keepDims);
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_sqnorm) {
auto dimensions = *block.getIArguments();
bool keepDims = false;
if (block.width() > 1) {
auto axesVector = INPUT_VARIABLE(1);
helpers::adjustAxis(INPUT_VARIABLE(0)->rankOf(), axesVector, dimensions);
}
if (block.getBArguments()->size())
keepDims = B_ARG(0);
else if (block.getTArguments()->size())
keepDims = (bool)T_ARG(0);
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(inputShape->at(0)[0]), 0,
"REDUCE_SQNORM OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -inputShape->at(0)[0] && item < inputShape->at(0)[0], 0,
"REDUCE_SQNORM OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
inputShape->at(0)[0], inputShape->at(0)[0], item);
auto outShapeInfo = ShapeUtils::evalReduceShapeInfo(shape::order(inputShape->at(0)), &dimensions, inputShape->at(0),
keepDims, false, block.getWorkspace());
return SHAPELIST(outShapeInfo);
}
DECLARE_TYPES(reduce_sqnorm) {
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
}
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_sqnorm_bp, -1, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto gradO = INPUT_VARIABLE(1);
auto gradI = OUTPUT_VARIABLE(0);
if (gradO->lengthOf() == 1) {
auto* temp1 = (*input) * 2.0;
auto* assign = (*temp1) * gradO->e(0);
delete temp1;
gradI->assign(assign);
delete assign;
} else {
bool keepDims = false;
auto dimensions = *block.getIArguments();
if (block.width() > 2) {
auto axesVector = INPUT_VARIABLE(2);
helpers::adjustAxis(input->rankOf(), axesVector, dimensions);
}
if (block.getBArguments()->size())
keepDims = B_ARG(0);
else if (block.getTArguments()->size())
keepDims = (bool)T_ARG(0);
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(input->rankOf()), 0,
"REDUCE_SQNORM_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -input->rankOf() && item < input->rankOf(), 0,
"REDUCE_SQNORM_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
// *** calculations *** //
if (!keepDims) {
auto gradOShapeKeepDims =
ShapeUtils::evalReduceShapeInfo(gradO->ordering(), &dimensions, *input, true, false, block.getWorkspace());
std::vector<sd::LongType> shape = ShapeUtils::pullShapeFromShapeInfo(
gradOShapeKeepDims);
auto* reshaped = gradO->reshape(gradO->ordering(), shape);
// Break down: 2. * (*input) * *reshaped
auto* temp1 = (*input) * 2.0;
auto* gradITemp1 = (*temp1) * (*reshaped);
delete temp1;
delete reshaped;
gradI->assign(gradITemp1);
delete gradITemp1;
} else {
// Break down: 2. * (*input) * *gradO
auto* temp2 = (*input) * 2.0;
auto* gradITemp2 = (*temp2) * (*gradO);
delete temp2;
gradI->assign(gradITemp2);
delete gradITemp2;
}
}
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_sqnorm_bp) {
if (shape::length(inputShape->at(1)) > 1) {
auto dimensions = *block.getIArguments();
if (block.width() > 2) {
auto axesVector = INPUT_VARIABLE(2);
helpers::adjustAxis(INPUT_VARIABLE(0)->rankOf(), axesVector, dimensions);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(inputShape->at(0)[0]), 0,
"REDUCE_SQNORM_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -inputShape->at(0)[0] && item < inputShape->at(0)[0], 0,
"REDUCE_SQNORM_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
inputShape->at(0)[0], inputShape->at(0)[0], item);
}
return SHAPELIST(CONSTANT(inputShape->at(0)));
}
DECLARE_TYPES(reduce_sqnorm_bp) {
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
}
} // namespace ops
} // namespace sd
#endif
@@ -0,0 +1,170 @@
/* ******************************************************************************
*
*
* 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 george@skymind.io on 6/1/2018.
// @author Yurii Shyrma (iuriish@yahoo.com)
//
#include <ops/declarable/CustomOperations.h>
#include <ops/declarable/helpers/axis.h>
#if NOT_EXCLUDED(OP_reduce_sum)
namespace sd {
namespace ops {
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_sum, -1, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto output = OUTPUT_VARIABLE(0);
std::vector<sd::LongType> dimensions;
if (block.width() > 1) {
auto axesVector = INPUT_VARIABLE(1);
helpers::adjustAxis(input->rankOf(), axesVector, dimensions);
} else if (block.getIArguments()->size())
dimensions = *block.getIArguments();
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(input->rankOf()), 0,
"REDUCE_SUM OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(item >= -input->shapeInfo()[0] && item < input->shapeInfo()[0], 0,
"REDUCE_SUM OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
bool keepDims = false;
if (block.getBArguments()->size())
keepDims = B_ARG(0);
else if (block.getTArguments()->size())
keepDims = (bool)T_ARG(0);
input->reduceAlongDimension(reduce::Sum, output, &dimensions, keepDims);
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_sum) {
bool keepDims = false;
if (block.getBArguments()->size())
keepDims = B_ARG(0);
else if (block.getTArguments()->size())
keepDims = (bool)T_ARG(0);
std::vector<sd::LongType> dimensions;
if (block.width() > 1) {
auto axesVector = INPUT_VARIABLE(1);
helpers::adjustAxis(INPUT_VARIABLE(0)->rankOf(), axesVector, dimensions);
} else if (block.getIArguments()->size())
dimensions = *block.getIArguments();
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(inputShape->at(0)[0]), 0,
"REDUCE_SUM OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(item >= -inputShape->at(0)[0] && item < inputShape->at(0)[0], 0,
"REDUCE_SUM OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
inputShape->at(0)[0], inputShape->at(0)[0], item);
return SHAPELIST(ShapeUtils::evalReduceShapeInfo(shape::order(inputShape->at(0)), &dimensions, inputShape->at(0),
keepDims, false, block.getWorkspace()));
}
DECLARE_TYPES(reduce_sum) { getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setSameMode(true); }
//////////////////////////////////////////////////////////////////////////
CUSTOM_OP_IMPL(reduce_sum_bp, -1, 1, false, 0, 0) {
auto input = INPUT_VARIABLE(0);
auto gradO = INPUT_VARIABLE(1);
auto gradI = OUTPUT_VARIABLE(0);
bool keepDims = false;
auto dimensions = *block.getIArguments();
if (block.width() > 2) {
auto axesVector = INPUT_VARIABLE(2);
helpers::adjustAxis(input->rankOf(), axesVector, dimensions);
}
if (block.getBArguments()->size())
keepDims = B_ARG(0);
else if (block.getTArguments()->size())
keepDims = (bool)T_ARG(0);
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(input->rankOf()), 0,
"REDUCE_SUM_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -input->rankOf() && item < input->rankOf(), 0,
"REDUCE_SUM_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
input->rankOf(), input->rankOf(), item);
// *** calculations *** //
if (!keepDims) {
auto gradOShapeKeepDims =
ShapeUtils::evalReduceShapeInfo(gradO->ordering(), &dimensions, *input, true, false, block.getWorkspace());
std::vector<sd::LongType> shape = ShapeUtils::pullShapeFromShapeInfo(
gradOShapeKeepDims);
auto r = gradO->reshape(gradO->ordering(),
shape); // for example could be something like [a,b] -> [1,a,1,b]
gradI->applyTrueBroadcast(sd::BroadcastOpsTuple::Assign(), r, gradI);
delete r;
} else
gradI->applyTrueBroadcast(sd::BroadcastOpsTuple::Assign(), gradO, gradI);
return sd::Status::OK;
}
DECLARE_SHAPE_FN(reduce_sum_bp) {
auto dimensions = *block.getIArguments();
if (block.width() > 2) {
auto axesVector = INPUT_VARIABLE(2);
helpers::adjustAxis(INPUT_VARIABLE(0)->rankOf(), axesVector, dimensions);
}
REQUIRE_TRUE(
dimensions.size() <= static_cast<size_t>(inputShape->at(0)[0]), 0,
"REDUCE_SUM_BP OP: the number of dimensions to reduce along must be <= input array rank, but got %i instead",
dimensions.size());
for (const auto& item : dimensions)
REQUIRE_TRUE(
item >= -inputShape->at(0)[0] && item < inputShape->at(0)[0], 0,
"REDUCE_SUM_BP OP: the input dimension to reduce along must be in range [-%i, %i), but got %i instead !",
inputShape->at(0)[0], inputShape->at(0)[0], item);
return SHAPELIST(CONSTANT(inputShape->at(0)));
}
DECLARE_TYPES(reduce_sum_bp) {
getOpDescriptor()->setAllowedInputTypes(sd::DataType::ANY)->setAllowedOutputTypes({ALL_FLOATS});
}
} // namespace ops
} // namespace sd
#endif