Gamma and Poisson distributions (#27)
* Added implementation for random_gamma op. * Added implementation for random_poisson op and support classes. * Added helpers for random_poisson and random_gamma ops. * Implementation of random_poisson. The first working edition. * Implementation of random_poisson. Parallelized working edition. * Implementation of random_gamma. Parallelized working edition with alpha only. * Added cuda implementation for helper of poisson distribution. * Corrected shape calculation with random_gamma and tests. * Finished cpu implementation for gamma distribution. * Finished cuda implementation for random_gamma op. * Refactored cpu helpers for random_gamma and random_poisson ops. * Refactored cuda helpers for gamma and poisson distribution. * Refactored cuda helper for gamma distribution. * Refactored cpu helper for random_poisson op. * Refactored cpu helper for random_gamma op.master
parent
948ebef41c
commit
7b14a9f603
|
@ -323,7 +323,9 @@
|
||||||
(11, TruncatedNormalDistribution) ,\
|
(11, TruncatedNormalDistribution) ,\
|
||||||
(12, AlphaDropOut),\
|
(12, AlphaDropOut),\
|
||||||
(13, ExponentialDistribution),\
|
(13, ExponentialDistribution),\
|
||||||
(14, ExponentialDistributionInv)
|
(14, ExponentialDistributionInv), \
|
||||||
|
(15, PoissonDistribution), \
|
||||||
|
(16, GammaDistribution)
|
||||||
|
|
||||||
#define PAIRWISE_INT_OPS \
|
#define PAIRWISE_INT_OPS \
|
||||||
(0, ShiftLeft), \
|
(0, ShiftLeft), \
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2015-2018 Skymind, Inc.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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 George A. Shulinok <sgazeos@gmail.com>
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <op_boilerplate.h>
|
||||||
|
#if NOT_EXCLUDED(OP_random_gamma)
|
||||||
|
|
||||||
|
#include <ops/declarable/headers/random.h>
|
||||||
|
#include <ops/declarable/helpers/random.h>
|
||||||
|
|
||||||
|
namespace nd4j {
|
||||||
|
namespace ops {
|
||||||
|
CUSTOM_OP_IMPL(random_gamma, 2, 1, false, 0, 0) {
|
||||||
|
// gamma distribution
|
||||||
|
auto rng = block.randomGenerator();
|
||||||
|
auto shape = INPUT_VARIABLE(0);
|
||||||
|
auto alpha = INPUT_VARIABLE(1);
|
||||||
|
NDArray* beta = nullptr;
|
||||||
|
|
||||||
|
if (block.width() > 2) {
|
||||||
|
beta = INPUT_VARIABLE(2);
|
||||||
|
REQUIRE_TRUE(ShapeUtils::areShapesBroadcastable(*alpha, *beta), 0, "random_gamma: alpha and beta shapes should be broadcastable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto output = OUTPUT_VARIABLE(0);
|
||||||
|
auto seed = 0;
|
||||||
|
|
||||||
|
if (block.getIArguments()->size()) {
|
||||||
|
seed = INT_ARG(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
rng.setSeed(seed);
|
||||||
|
|
||||||
|
helpers::fillRandomGamma(block.launchContext(), rng, alpha, beta, output);
|
||||||
|
|
||||||
|
return Status::OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_SHAPE_FN(random_gamma) {
|
||||||
|
auto in = INPUT_VARIABLE(0);
|
||||||
|
auto shape = in->template asVectorT<Nd4jLong>();
|
||||||
|
auto alphaShape = inputShape->at(1);
|
||||||
|
auto additionalShape = alphaShape;
|
||||||
|
if (inputShape->size() > 2) {
|
||||||
|
auto rest = inputShape->at(2); additionalShape = nullptr;
|
||||||
|
REQUIRE_TRUE(ShapeUtils::areShapesBroadcastable(alphaShape, rest), 0, "random_gamma: alpha and beta shapes should be broadcastable.");
|
||||||
|
ShapeUtils::evalBroadcastShapeInfo(alphaShape, rest, true, additionalShape, block.workspace());
|
||||||
|
}
|
||||||
|
auto lastDim = shape::sizeAt(alphaShape, 0);
|
||||||
|
auto dtype = ArrayOptions::dataType(alphaShape);
|
||||||
|
for (auto i = 0; i < shape::rank(additionalShape); i++)
|
||||||
|
shape.push_back(shape::sizeAt(additionalShape, i));
|
||||||
|
auto newShape = ConstantShapeHelper::getInstance()->createShapeInfo(dtype, 'c', shape);
|
||||||
|
return SHAPELIST(newShape);
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_TYPES(random_gamma) {
|
||||||
|
getOpDescriptor()
|
||||||
|
->setAllowedInputTypes(0, {ALL_INTS})
|
||||||
|
->setAllowedInputTypes(1, {ALL_FLOATS})
|
||||||
|
->setAllowedInputTypes(2, {ALL_FLOATS})
|
||||||
|
->setAllowedOutputTypes({ALL_FLOATS});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2015-2018 Skymind, Inc.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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 George A. Shulinok <sgazeos@gmail.com>
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <op_boilerplate.h>
|
||||||
|
#if NOT_EXCLUDED(OP_random_poisson)
|
||||||
|
|
||||||
|
#include <ops/declarable/headers/random.h>
|
||||||
|
#include <ops/declarable/helpers/random.h>
|
||||||
|
|
||||||
|
namespace nd4j {
|
||||||
|
namespace ops {
|
||||||
|
CUSTOM_OP_IMPL(random_poisson, 2, 1, false, 0, 0) {
|
||||||
|
// gamma distribution
|
||||||
|
auto rng = block.randomGenerator();
|
||||||
|
auto shape = INPUT_VARIABLE(0);
|
||||||
|
auto lambda = INPUT_VARIABLE(1);
|
||||||
|
auto output = OUTPUT_VARIABLE(0);
|
||||||
|
auto seed = 0;
|
||||||
|
if (block.getIArguments()->size()) {
|
||||||
|
seed = INT_ARG(0);
|
||||||
|
}
|
||||||
|
rng.setSeed(seed);
|
||||||
|
helpers::fillRandomPoisson(block.launchContext(), rng, lambda, output);
|
||||||
|
|
||||||
|
return Status::OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DECLARE_SHAPE_FN(random_poisson) {
|
||||||
|
auto in = INPUT_VARIABLE(0);
|
||||||
|
auto shape = in->template asVectorT<Nd4jLong>();
|
||||||
|
auto lambdaShape = inputShape->at(1);
|
||||||
|
auto dtype = ArrayOptions::dataType(lambdaShape);
|
||||||
|
for (auto d = 0; d < shape::rank(lambdaShape); ++d ) {
|
||||||
|
shape.emplace_back(shape::sizeAt(lambdaShape, d));
|
||||||
|
}
|
||||||
|
auto newShape = ConstantShapeHelper::getInstance()->createShapeInfo(dtype, 'c', shape);
|
||||||
|
return SHAPELIST(newShape);
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_TYPES(random_poisson) {
|
||||||
|
getOpDescriptor()
|
||||||
|
->setAllowedInputTypes(0, {ALL_INTS})
|
||||||
|
->setAllowedInputTypes(1, {ALL_FLOATS})
|
||||||
|
->setAllowedOutputTypes({ALL_FLOATS});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -49,7 +49,23 @@ namespace nd4j {
|
||||||
DECLARE_CUSTOM_OP(random_exponential, 1, 1, true, 1, 0);
|
DECLARE_CUSTOM_OP(random_exponential, 1, 1, true, 1, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if NOT_EXCLUDED(OP_random_crop)
|
||||||
DECLARE_CUSTOM_OP(random_crop, 2, 1, false, 0, 0);
|
DECLARE_CUSTOM_OP(random_crop, 2, 1, false, 0, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* random_gamma op.
|
||||||
|
*/
|
||||||
|
#if NOT_EXCLUDED(OP_random_gamma)
|
||||||
|
DECLARE_CUSTOM_OP(random_gamma, 2, 1, false, 0, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* random_poisson op.
|
||||||
|
*/
|
||||||
|
#if NOT_EXCLUDED(OP_random_poisson)
|
||||||
|
DECLARE_CUSTOM_OP(random_poisson, 2, 1, false, 0, 0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2015-2018 Skymind, Inc.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
//
|
||||||
|
// @author sgazeos@gmail.com
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <ops/declarable/helpers/random.h>
|
||||||
|
//#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
//#include <graph/Context.h>
|
||||||
|
#include <ShapeUtils.h>
|
||||||
|
|
||||||
|
namespace nd4j {
|
||||||
|
namespace ops {
|
||||||
|
namespace helpers {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void fillRandomGamma_(LaunchContext* context, graph::RandomGenerator& rng, NDArray* alpha, NDArray* beta, NDArray* output) {
|
||||||
|
|
||||||
|
Nd4jLong* broadcasted = nullptr;
|
||||||
|
if (beta != nullptr)
|
||||||
|
ShapeUtils::evalBroadcastShapeInfo(*alpha, *beta, true, broadcasted, context->getWorkspace());
|
||||||
|
else
|
||||||
|
broadcasted = alpha->shapeInfo();
|
||||||
|
auto step = shape::length(broadcasted);
|
||||||
|
auto shift = output->lengthOf() / step;
|
||||||
|
|
||||||
|
auto copyAlpha = alpha;
|
||||||
|
auto copyBeta = beta;
|
||||||
|
if (beta != nullptr) {
|
||||||
|
NDArray alphaBroadcasted(broadcasted, alpha->dataType(), false, context);
|
||||||
|
NDArray betaBroadcasted(broadcasted, beta->dataType(), false, context);
|
||||||
|
|
||||||
|
copyAlpha = (alphaBroadcasted.applyTrueBroadcast(BroadcastOpsTuple::Assign(), alpha));
|
||||||
|
copyBeta = (betaBroadcasted.applyTrueBroadcast(BroadcastOpsTuple::Assign(), beta));
|
||||||
|
|
||||||
|
}
|
||||||
|
// bool directAlpha = alpha->ews() == 1 && alpha->ordering() == 'c';
|
||||||
|
bool directOutput = output->ews() == 1 && output->ordering() == 'c';
|
||||||
|
T* outputBuf = output->dataBuffer()->primaryAsT<T>();
|
||||||
|
|
||||||
|
PRAGMA_OMP_PARALLEL_FOR
|
||||||
|
for (auto k = 0; k < shift; k++) {
|
||||||
|
auto pos = k * step;
|
||||||
|
auto u = rng.relativeT<T>(k, 0., 1.);
|
||||||
|
for (auto e = 0; e < step; e++)
|
||||||
|
if (directOutput) {
|
||||||
|
outputBuf[pos + e] = math::nd4j_igamma<T, T, T>(copyAlpha->t<T>(e),
|
||||||
|
beta != nullptr ? copyBeta->t<T>(e) * u : u);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
output->t<T>(pos + e) = math::nd4j_igamma<T, T, T>(copyAlpha->t<T>(e),
|
||||||
|
beta != nullptr ? copyBeta->t<T>(e) * u : u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (beta != nullptr) {
|
||||||
|
delete copyAlpha;
|
||||||
|
delete copyBeta;
|
||||||
|
//delete broadcasted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillRandomGamma(LaunchContext* context, graph::RandomGenerator& rng, NDArray* alpha, NDArray* beta, NDArray* output) {
|
||||||
|
BUILD_SINGLE_SELECTOR(output->dataType(), fillRandomGamma_, (context, rng, alpha, beta, output), FLOAT_NATIVE);
|
||||||
|
}
|
||||||
|
BUILD_SINGLE_TEMPLATE(template void fillRandomGamma_, (LaunchContext* context,
|
||||||
|
graph::RandomGenerator& rng, NDArray* alpha, NDArray* beta, NDArray* output), FLOAT_NATIVE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* algorithm Poisson generator based upon the inversion by sequential search:[48]:505
|
||||||
|
init:
|
||||||
|
Let x ← 0, p ← e−λ, s ← p.
|
||||||
|
Generate uniform random number u in [0,1].
|
||||||
|
while u > s do:
|
||||||
|
x ← x + 1.
|
||||||
|
p ← p * λ / x.
|
||||||
|
s ← s + p.
|
||||||
|
return x.
|
||||||
|
* */
|
||||||
|
template <typename T>
|
||||||
|
void fillRandomPoisson_(LaunchContext* context, graph::RandomGenerator& rng, NDArray* lambda, NDArray* output) {
|
||||||
|
auto shift = output->lengthOf() / lambda->lengthOf();
|
||||||
|
auto step = lambda->lengthOf();
|
||||||
|
T* lambdaBuf = lambda->dataBuffer()->primaryAsT<T>();
|
||||||
|
T* outputBuf = output->dataBuffer()->primaryAsT<T>();
|
||||||
|
bool directLa = lambda->ews() == 1 && lambda->ordering() == 'c';
|
||||||
|
bool directOut = output->ews() == 1 && output->ordering() == 'c';
|
||||||
|
PRAGMA_OMP_PARALLEL_FOR
|
||||||
|
for (auto k = 0; k < shift; k++) {
|
||||||
|
auto pos = k * step;
|
||||||
|
auto u = rng.relativeT<T>(k, 0., 1.);
|
||||||
|
for (auto e = 0; e < step; e++) {
|
||||||
|
auto p = math::nd4j_exp<T, T>(-lambda->t<T>(e));
|
||||||
|
auto s = p;
|
||||||
|
auto x = T(0.f);
|
||||||
|
while (u > s) {
|
||||||
|
x += 1.f;
|
||||||
|
p *= directLa?lambdaBuf[e]/x:lambda->t<T>(e) / x;
|
||||||
|
s += p;
|
||||||
|
}
|
||||||
|
if (directOut)
|
||||||
|
outputBuf[pos + e] = x;
|
||||||
|
else
|
||||||
|
output->t<T>(pos + e) = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillRandomPoisson(LaunchContext* context, graph::RandomGenerator& rng, NDArray* lambda, NDArray* output) {
|
||||||
|
BUILD_SINGLE_SELECTOR(output->dataType(), fillRandomPoisson_, (context, rng, lambda, output), FLOAT_NATIVE);
|
||||||
|
}
|
||||||
|
BUILD_SINGLE_TEMPLATE(template void fillRandomPoisson_, (LaunchContext* context,
|
||||||
|
graph::RandomGenerator& rng, NDArray* lambda, NDArray* output), FLOAT_TYPES);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,186 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2015-2018 Skymind, Inc.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
//
|
||||||
|
// @author sgazeos@gmail.com
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <ops/declarable/helpers/random.h>
|
||||||
|
//#include <NativeOps.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <graph/Context.h>
|
||||||
|
#include <helpers/RandomLauncher.h>
|
||||||
|
#include <ShapeUtils.h>
|
||||||
|
#include <NDArrayFactory.h>
|
||||||
|
|
||||||
|
namespace nd4j {
|
||||||
|
namespace ops {
|
||||||
|
namespace helpers {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fillGammaKernel - fill up output with gamma distributed values
|
||||||
|
*
|
||||||
|
* uList - uniformly distributed values set
|
||||||
|
* uLength - length of uList
|
||||||
|
* alpha - alpha param
|
||||||
|
* beta - beta param
|
||||||
|
* output - distributed output.
|
||||||
|
* */
|
||||||
|
template <typename T>
|
||||||
|
static __global__ void fillGammaKernel(T* uList, Nd4jLong uLength, T* alpha, Nd4jLong* alphaShape,
|
||||||
|
T* beta, Nd4jLong* betaShape, T* output, Nd4jLong* outputShape) {
|
||||||
|
// fill up
|
||||||
|
__shared__ Nd4jLong aLength;
|
||||||
|
if (threadIdx.x == 0) {
|
||||||
|
aLength = shape::length(alphaShape);
|
||||||
|
}
|
||||||
|
__syncthreads();
|
||||||
|
|
||||||
|
for (auto k = blockIdx.x; k < (int)uLength; k += gridDim.x) {
|
||||||
|
auto pos = k * aLength;
|
||||||
|
auto u = uList[k]; // this is a vector
|
||||||
|
for (auto e = threadIdx.x; e < (int)aLength; e += blockDim.x) {
|
||||||
|
auto aIndex = shape::getIndexOffset(e, alphaShape);
|
||||||
|
auto bIndex = betaShape?shape::getIndexOffset(e, betaShape):-1LL;
|
||||||
|
auto betaV = T(beta != nullptr ? beta[bIndex] * u : u);
|
||||||
|
auto zIndex = shape::getIndexOffset(e + pos, outputShape);
|
||||||
|
|
||||||
|
output[zIndex] = math::nd4j_igamma<T, T, T>(alpha[aIndex], betaV);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static void fillRandomGamma_(LaunchContext* context, graph::RandomGenerator& rng, NDArray* alpha, NDArray* beta, NDArray* output) {
|
||||||
|
// To fill up output need to broadcast alpha and beta to the same shape and in
|
||||||
|
Nd4jLong* broadcasted = nullptr;
|
||||||
|
if (beta != nullptr)
|
||||||
|
ShapeUtils::evalBroadcastShapeInfo(*alpha, *beta, true, broadcasted, context->getWorkspace());
|
||||||
|
else
|
||||||
|
broadcasted = alpha->shapeInfo();
|
||||||
|
auto step = shape::length(broadcasted);
|
||||||
|
auto shift = output->lengthOf() / step;
|
||||||
|
|
||||||
|
auto copyAlpha = alpha;
|
||||||
|
auto copyBeta = beta;
|
||||||
|
if (beta != nullptr) {
|
||||||
|
NDArray alphaBroadcasted(broadcasted, alpha->dataType(), true, context);
|
||||||
|
NDArray betaBroadcasted(broadcasted, beta->dataType(), true, context);
|
||||||
|
|
||||||
|
copyAlpha = (alphaBroadcasted.applyTrueBroadcast(BroadcastOpsTuple::Assign(), alpha));
|
||||||
|
copyBeta = (betaBroadcasted.applyTrueBroadcast(BroadcastOpsTuple::Assign(), beta));
|
||||||
|
copyAlpha->tickWriteDevice(); copyBeta->tickWriteDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto stream = context->getCudaStream();
|
||||||
|
NDArray uniform = NDArrayFactory::create<T>('c', {shift}, context);
|
||||||
|
uniform.syncToDevice();
|
||||||
|
// fill up uniform with given length
|
||||||
|
RandomLauncher::fillUniform(context, rng, &uniform, 0., 1.);
|
||||||
|
|
||||||
|
fillGammaKernel<T><<<128, 128, 256, *stream>>>(uniform.dataBuffer()->specialAsT<T>(), shift,
|
||||||
|
copyAlpha->dataBuffer()->specialAsT<T>(), copyAlpha->specialShapeInfo(),
|
||||||
|
beta?copyBeta->dataBuffer()->specialAsT<T>():(T*)nullptr,
|
||||||
|
beta?copyBeta->specialShapeInfo():(Nd4jLong*)nullptr,
|
||||||
|
output->dataBuffer()->specialAsT<T>(), output->specialShapeInfo());
|
||||||
|
|
||||||
|
if (beta != nullptr) {
|
||||||
|
delete copyAlpha;
|
||||||
|
delete copyBeta;
|
||||||
|
//delete broadcasted;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillRandomGamma(LaunchContext* context, graph::RandomGenerator& rng, NDArray* alpha, NDArray* beta, NDArray* output) {
|
||||||
|
if (beta)
|
||||||
|
NDArray::prepareSpecialUse({output}, {alpha, beta});
|
||||||
|
else
|
||||||
|
NDArray::prepareSpecialUse({output}, {alpha});
|
||||||
|
BUILD_SINGLE_SELECTOR(output->dataType(), fillRandomGamma_, (context, rng, alpha, beta, output), FLOAT_NATIVE);
|
||||||
|
if (beta)
|
||||||
|
NDArray::registerSpecialUse({output}, {alpha, beta});
|
||||||
|
else
|
||||||
|
NDArray::prepareSpecialUse({output}, {alpha});
|
||||||
|
}
|
||||||
|
BUILD_SINGLE_TEMPLATE(template void fillRandomGamma_, (LaunchContext* context, graph::RandomGenerator& rng, NDArray* alpha, NDArray* beta, NDArray* output), FLOAT_NATIVE);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* algorithm Poisson generator based upon the inversion by sequential search
|
||||||
|
*
|
||||||
|
init:
|
||||||
|
Let x ← 0, p ← e−λ, s ← p.
|
||||||
|
using uniformly random sequence U (u in U) distributed at [0, 1].
|
||||||
|
while u > s do:
|
||||||
|
x ← x + 1.
|
||||||
|
p ← p * λ / x.
|
||||||
|
s ← s + p.
|
||||||
|
return x.
|
||||||
|
* */
|
||||||
|
template <typename T>
|
||||||
|
static __global__ void fillPoissonKernel(T* uList, Nd4jLong uLength, T* lambda, Nd4jLong* lambdaShape, T* output,
|
||||||
|
Nd4jLong* outputShape) {
|
||||||
|
|
||||||
|
__shared__ Nd4jLong step;
|
||||||
|
|
||||||
|
if (threadIdx.x == 0) {
|
||||||
|
step = shape::length(lambdaShape);
|
||||||
|
}
|
||||||
|
__syncthreads();
|
||||||
|
|
||||||
|
for (auto k = blockIdx.x; k < (int)uLength; k += gridDim.x) {
|
||||||
|
auto pos = k * step;
|
||||||
|
auto u = uList[k];
|
||||||
|
for (auto e = threadIdx.x; e < step; e += blockDim.x) {
|
||||||
|
auto p = math::nd4j_exp<T,T>(-lambda[e]);
|
||||||
|
auto s = p;
|
||||||
|
auto x = T(0.f);
|
||||||
|
auto lIndex = shape::getIndexOffset(e, lambdaShape);
|
||||||
|
auto zIndex = shape::getIndexOffset(e + pos, outputShape);
|
||||||
|
while (u > s) {
|
||||||
|
x += T(1.);
|
||||||
|
p *= lambda[lIndex] / x;
|
||||||
|
s += p;
|
||||||
|
}
|
||||||
|
output[zIndex] = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static void fillRandomPoisson_(LaunchContext* context, graph::RandomGenerator& rng, NDArray* lambda, NDArray* output) {
|
||||||
|
auto shift = output->lengthOf() / lambda->lengthOf();
|
||||||
|
NDArray uniform('c', {shift}, output->dataType());
|
||||||
|
auto stream = context->getCudaStream();
|
||||||
|
// fill up uniform with given length
|
||||||
|
RandomLauncher::fillUniform(context, rng, &uniform, 0., 1.);
|
||||||
|
fillPoissonKernel<T><<<128, 256, 128, *stream>>>(uniform.dataBuffer()->specialAsT<T>(), uniform.lengthOf(),
|
||||||
|
lambda->dataBuffer()->specialAsT<T>(), lambda->specialShapeInfo(),
|
||||||
|
output->dataBuffer()->specialAsT<T>(), output->specialShapeInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillRandomPoisson(LaunchContext* context, graph::RandomGenerator& rng, NDArray* lambda, NDArray* output) {
|
||||||
|
NDArray::prepareSpecialUse({output}, {lambda});
|
||||||
|
BUILD_SINGLE_SELECTOR(output->dataType(), fillRandomPoisson_, (context, rng, lambda, output), FLOAT_NATIVE);
|
||||||
|
NDArray::registerSpecialUse({output}, {lambda});
|
||||||
|
}
|
||||||
|
|
||||||
|
BUILD_SINGLE_TEMPLATE(template void fillRandomPoisson_, (LaunchContext* context, graph::RandomGenerator& rng, NDArray* lambda, NDArray* output), FLOAT_NATIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2015-2018 Skymind, Inc.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
//
|
||||||
|
// @author sgazeos@gmail.com
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Declaration of distribution helpers
|
||||||
|
//
|
||||||
|
#ifndef __RANDOM_HELPERS__
|
||||||
|
#define __RANDOM_HELPERS__
|
||||||
|
#include <op_boilerplate.h>
|
||||||
|
#include <NDArray.h>
|
||||||
|
#include <helpers/helper_random.h>
|
||||||
|
#include <graph/Context.h>
|
||||||
|
|
||||||
|
namespace nd4j {
|
||||||
|
namespace ops {
|
||||||
|
namespace helpers {
|
||||||
|
|
||||||
|
void fillRandomGamma(LaunchContext* context, graph::RandomGenerator& rng, NDArray* alpha, NDArray* beta, NDArray* output);
|
||||||
|
void fillRandomPoisson(LaunchContext* context, graph::RandomGenerator& rng, NDArray* lambda, NDArray* output);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -129,6 +129,47 @@ namespace randomOps {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class PoissonDistribution {
|
||||||
|
public:
|
||||||
|
no_exec_special
|
||||||
|
no_exec_special_cuda
|
||||||
|
|
||||||
|
method_XY
|
||||||
|
|
||||||
|
random_def T op(Nd4jLong idx, Nd4jLong length, nd4j::graph::RandomGenerator *helper, T *extraParams) {
|
||||||
|
T lambda = extraParams[0];
|
||||||
|
T x = helper->relativeT(idx, -nd4j::DataTypeUtils::template max<T>() / 10 , nd4j::DataTypeUtils::template max<T>() / 10);
|
||||||
|
return x <= (T)0.f ? (T)0.f : nd4j::math::nd4j_igammac<T,T,T>(nd4j::math::nd4j_floor<T,T>(x), lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
random_def T op(T valueX, Nd4jLong idx, Nd4jLong length, nd4j::graph::RandomGenerator *helper, T *extraParams) {
|
||||||
|
T lambda = extraParams[0];
|
||||||
|
return valueX <= (T)0.f ? (T)0.f : (T)nd4j::math::nd4j_igammac<T,T,T>(nd4j::math::nd4j_floor<T,T>(valueX), lambda);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class GammaDistribution {
|
||||||
|
public:
|
||||||
|
no_exec_special
|
||||||
|
no_exec_special_cuda
|
||||||
|
|
||||||
|
method_XY
|
||||||
|
|
||||||
|
random_def T op(Nd4jLong idx, Nd4jLong length, nd4j::graph::RandomGenerator *helper, T *extraParams) {
|
||||||
|
T alpha = extraParams[0];
|
||||||
|
T beta = extraParams[1];
|
||||||
|
T x = helper->relativeT(idx, -nd4j::DataTypeUtils::template max<T>() / 10 , nd4j::DataTypeUtils::template max<T>() / 10);
|
||||||
|
return x <= (T)0.f ? (T)0.f : nd4j::math::nd4j_igamma<T,T,T>(alpha, x * beta);
|
||||||
|
}
|
||||||
|
|
||||||
|
random_def T op(T valueX, Nd4jLong idx, Nd4jLong length, nd4j::graph::RandomGenerator *helper, T *extraParams) {
|
||||||
|
T alpha = extraParams[0];
|
||||||
|
T beta = extraParams[1];
|
||||||
|
return valueX <= (T)0.f ? (T)0.f : nd4j::math::nd4j_igamma<T,T,T>(alpha, beta * valueX);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basic DropOut/DropConnect Op
|
* Basic DropOut/DropConnect Op
|
||||||
|
|
|
@ -894,6 +894,10 @@ namespace nd4j {
|
||||||
Z aim = nd4j_pow<X, X, Z>(x, a) / (nd4j_exp<X, Z>(x) * nd4j_gamma<Y, Z>(a));
|
Z aim = nd4j_pow<X, X, Z>(x, a) / (nd4j_exp<X, Z>(x) * nd4j_gamma<Y, Z>(a));
|
||||||
auto sum = Z(0.);
|
auto sum = Z(0.);
|
||||||
auto denom = Z(1.);
|
auto denom = Z(1.);
|
||||||
|
if (a <= X(0.000001))
|
||||||
|
//throw std::runtime_error("Cannot calculate gamma for a zero val.");
|
||||||
|
return Z(0);
|
||||||
|
|
||||||
for (int i = 0; Z(1./denom) > Z(1.0e-12); i++) {
|
for (int i = 0; Z(1./denom) > Z(1.0e-12); i++) {
|
||||||
denom *= (a + i);
|
denom *= (a + i);
|
||||||
sum += nd4j_pow<X, int, Z>(x, i) / denom;
|
sum += nd4j_pow<X, int, Z>(x, i) / denom;
|
||||||
|
|
|
@ -773,6 +773,88 @@ TEST_F(RNGTests, Test_ExponentialDistribution_2) {
|
||||||
delete result;
|
delete result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(RNGTests, Test_PoissonDistribution_1) {
|
||||||
|
auto x = NDArrayFactory::create<Nd4jLong>('c', {1}, {10});
|
||||||
|
auto la = NDArrayFactory::create<float>('c', {2, 3});
|
||||||
|
auto exp0 = NDArrayFactory::create<float>('c', {10, 2, 3});
|
||||||
|
|
||||||
|
la.linspace(1.0);
|
||||||
|
|
||||||
|
|
||||||
|
nd4j::ops::random_poisson op;
|
||||||
|
auto result = op.execute({&x, &la}, {}, {});
|
||||||
|
ASSERT_EQ(Status::OK(), result->status());
|
||||||
|
|
||||||
|
auto z = result->at(0);
|
||||||
|
// z->printIndexedBuffer("Poisson distribution");
|
||||||
|
ASSERT_TRUE(exp0.isSameShape(z));
|
||||||
|
ASSERT_FALSE(exp0.equalsTo(z));
|
||||||
|
|
||||||
|
delete result;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RNGTests, Test_GammaDistribution_1) {
|
||||||
|
auto x = NDArrayFactory::create<Nd4jLong>('c', {1}, {10});
|
||||||
|
auto al = NDArrayFactory::create<float>('c', {2, 3});
|
||||||
|
auto exp0 = NDArrayFactory::create<float>('c', {10, 2, 3});
|
||||||
|
|
||||||
|
al.linspace(1.0);
|
||||||
|
|
||||||
|
|
||||||
|
nd4j::ops::random_gamma op;
|
||||||
|
auto result = op.execute({&x, &al}, {}, {});
|
||||||
|
ASSERT_EQ(Status::OK(), result->status());
|
||||||
|
|
||||||
|
auto z = result->at(0);
|
||||||
|
// z->printIndexedBuffer("Gamma distribution");
|
||||||
|
ASSERT_TRUE(exp0.isSameShape(z));
|
||||||
|
ASSERT_FALSE(exp0.equalsTo(z));
|
||||||
|
|
||||||
|
delete result;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RNGTests, Test_GammaDistribution_2) {
|
||||||
|
auto x = NDArrayFactory::create<Nd4jLong>('c', {1}, {10});
|
||||||
|
auto al = NDArrayFactory::create<float>('c', {2, 3});
|
||||||
|
auto be = NDArrayFactory::create<float>('c', {2, 3});
|
||||||
|
auto exp0 = NDArrayFactory::create<float>('c', {10, 2, 3});
|
||||||
|
|
||||||
|
al.linspace(1.0);
|
||||||
|
be.assign(1.0);
|
||||||
|
|
||||||
|
nd4j::ops::random_gamma op;
|
||||||
|
auto result = op.execute({&x, &al, &be}, {}, {});
|
||||||
|
ASSERT_EQ(Status::OK(), result->status());
|
||||||
|
|
||||||
|
auto z = result->at(0);
|
||||||
|
// z->printIndexedBuffer("Gamma distribution");
|
||||||
|
ASSERT_TRUE(exp0.isSameShape(z));
|
||||||
|
ASSERT_FALSE(exp0.equalsTo(z));
|
||||||
|
|
||||||
|
delete result;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RNGTests, Test_GammaDistribution_3) {
|
||||||
|
auto x = NDArrayFactory::create<Nd4jLong>('c', {1}, {10});
|
||||||
|
auto al = NDArrayFactory::create<float>('c', {3, 1});
|
||||||
|
auto be = NDArrayFactory::create<float>('c', {1, 2});
|
||||||
|
auto exp0 = NDArrayFactory::create<float>('c', {10, 3, 2});
|
||||||
|
|
||||||
|
al.linspace(1.0);
|
||||||
|
be.assign(2.0);
|
||||||
|
|
||||||
|
nd4j::ops::random_gamma op;
|
||||||
|
auto result = op.execute({&x, &al, &be}, {}, {});
|
||||||
|
ASSERT_EQ(Status::OK(), result->status());
|
||||||
|
|
||||||
|
auto z = result->at(0);
|
||||||
|
// z->printIndexedBuffer("Gamma distribution");
|
||||||
|
ASSERT_TRUE(exp0.isSameShape(z));
|
||||||
|
ASSERT_FALSE(exp0.equalsTo(z));
|
||||||
|
|
||||||
|
delete result;
|
||||||
|
}
|
||||||
|
|
||||||
namespace nd4j {
|
namespace nd4j {
|
||||||
namespace tests {
|
namespace tests {
|
||||||
static void fillList(Nd4jLong seed, int numberOfArrays, std::vector<Nd4jLong> &shape, std::vector<NDArray*> &list, nd4j::graph::RandomGenerator *rng) {
|
static void fillList(Nd4jLong seed, int numberOfArrays, std::vector<Nd4jLong> &shape, std::vector<NDArray*> &list, nd4j::graph::RandomGenerator *rng) {
|
||||||
|
|
Loading…
Reference in New Issue