Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dropout1d/2d/3d api #8880

Merged
merged 15 commits into from
Aug 21, 2022
3 changes: 3 additions & 0 deletions docs/source/nn.rst
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,9 @@ Dropout Layers
:template: classtemplate.rst

nn.Dropout
nn.Dropout1d
nn.Dropout2d
nn.Dropout3d

Sparse Layers
----------------------------------
Expand Down
14 changes: 13 additions & 1 deletion oneflow/core/functional/functional_api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -808,7 +808,7 @@
signature:
[
"Tensor (Tensor input, *, DataType dtype=kFloat, Generator generator=None) => Bernoulli",
"Tensor (Tensor input, Double p, *, DataType dtype=kFloat, Generator generator=None) => Bernoulli",
"Tensor (Tensor input, Double p, *, DataType dtype=kFloat, Generator generator=None) => BernoulliProb",
BBuf marked this conversation as resolved.
Show resolved Hide resolved
]
bind_python: True

Expand Down Expand Up @@ -1793,6 +1793,18 @@
signature: "Tensor (Tensor dy, Tensor mask, Float scale) => DropoutGrad"
bind_python: False

- name: "dropout1d"
signature: "Tensor (Tensor input, Float p=0.5, Bool train=True) => Dropout1d"
BBuf marked this conversation as resolved.
Show resolved Hide resolved
bind_python: True

- name: "dropout2d"
signature: "Tensor (Tensor input, Float p=0.5, Bool train=True) => Dropout2d"
bind_python: True

- name: "dropout3d"
signature: "Tensor (Tensor input, Float p=0.5, Bool train=True) => Dropout3d"
bind_python: True

- name: "constant_pad"
signature: 'Tensor (Tensor x, Int64List pad, Scalar value=0) => ConstantPad'
bind_python: False
Expand Down
104 changes: 104 additions & 0 deletions oneflow/core/functional/impl/nn_functor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

#include <cstdint>
BBuf marked this conversation as resolved.
Show resolved Hide resolved
#include <memory>
#include "oneflow/core/common/container_util.h"
#include "oneflow/core/common/data_type.pb.h"
#include "oneflow/core/common/error.h"
#include "oneflow/core/common/just.h"
#include "oneflow/core/common/maybe.h"
#include "oneflow/core/common/optional.h"
#include "oneflow/core/common/scalar.h"
Expand All @@ -31,6 +34,7 @@ limitations under the License.
#include "oneflow/core/framework/random_generator.h"
#include "oneflow/core/functional/functional.h"
#include "oneflow/core/functional/function_library.h"
#include "oneflow/core/functional/functional_api.yaml.h"
#include "oneflow/core/functional/sequence_function.h"
#include "oneflow/core/functional/impl/common.h"
#include "oneflow/core/functional/impl/unary_functor.h"
Expand Down Expand Up @@ -2457,6 +2461,103 @@ class DropoutFunctor {
std::shared_ptr<OpExpr> add_op_;
};

namespace {
Maybe<Tensor> MakeFeatureNoise(const std::shared_ptr<one::Tensor>& x) {
const int64_t ndim = x->ndim();
CHECK_GE_OR_RETURN(ndim, 2) << Error::RuntimeError()
<< "Feature dropout requires at least 2 dimensions in the input";
std::vector<int64_t> sizes;
sizes.reserve(ndim);
sizes.push_back(x->shape()->At(0));
sizes.push_back(x->shape()->At(1));
for (int i = 2; i < ndim; i++) { sizes.push_back(1); }
return JUST(Empty(Shape(sizes), x->dtype(), JUST(x->device()), false));
}

Maybe<Tensor> DropoutImpl(const std::shared_ptr<one::Tensor>& input, const float& p,
const bool& train) {
CHECK_EQ_OR_RETURN(p >= 0 && p <= 1, true)
<< "dropout probability has to be between 0 and 1, but got " << p;
if (p == 0 || !train || input->shape()->elem_cnt() == 0) { return input; }
if (p == 1) {
std::shared_ptr<Tensor> other =
JUST(Constant(*input->shape(), Scalar(0.0), input->dtype(), JUST(input->device())));
return InplaceMul(input, other);
}
std::shared_ptr<Tensor> noise = JUST(MakeFeatureNoise(input));
noise = JUST(BernoulliProb(noise, 1.0 - p, noise->dtype(), JUST(one::DefaultAutoGenerator())));
noise = JUST(InplaceScalarDiv(noise, Scalar(1.0 - p)));
noise = JUST(InplaceMul(input, noise));
return noise;
}
} // namespace

class Dropout1dFunctor {
public:
Maybe<Tensor> operator()(const std::shared_ptr<one::Tensor>& input, const float& p,
const bool& train) const {
CHECK_EQ_OR_RETURN(p < 0 || p > 1.0, true)
<< "dropout probability has to be between 0 and 1, but got " << p;
const int input_dim = input->ndim();
CHECK_EQ_OR_RETURN(input_dim != 2 && input_dim != 3, true)
<< "dropout1d: Expected 2D or 3D input, but received a {inp_dim}D input. "
"Note that dropout1d exists to provide channel-wise dropout on inputs with 1 "
"spatial dimension, a channel dimension, and an optional batch dimension "
"(i.e. 2D or 3D inputs).";
bool is_batched = (input_dim == 3);
std::shared_ptr<one::Tensor> result;
if (!is_batched) { result = JUST(Unsqueeze(input, 0)); }
result = JUST(DropoutImpl(result, p, train));
if (!is_batched) { result = JUST(Squeeze(result, std::vector<int32_t>{0})); }
return result;
}
};

class Dropout2dFunctor {
public:
Maybe<Tensor> operator()(const std::shared_ptr<one::Tensor>& input, const float& p,
const bool& train) const {
CHECK_EQ_OR_RETURN(p < 0 || p > 1.0, true)
<< "dropout probability has to be between 0 and 1, but got " << p;
const int input_dim = input->ndim();
CHECK_EQ_OR_RETURN(input_dim != 3 && input_dim != 4, true)
<< "dropout2d: Received a {inp_dim}-D input to dropout2d, which is deprecated "
"and will result in an error in a future release. To retain the behavior "
"and silence this warning, please use dropout instead. Note that dropout2d "
"exists to provide channel-wise dropout on inputs with 2 spatial dimensions, "
"a channel dimension, and an optional batch dimension (i.e. 3D or 4D inputs).";
CHECK_EQ_OR_RETURN(input_dim == 3, true)
<< "dropout2d: Received a 3D input to dropout2d and assuming that channel-wise "
"1D dropout behavior is desired - input is interpreted as shape (N, C, L), where C "
"is the channel dim. This behavior will change in a future release to interpret the "
"input as one without a batch dimension, i.e. shape (C, H, W). To maintain the 1D "
"channel-wise dropout behavior, please switch to using dropout1d instead.";
return JUST(DropoutImpl(input, p, train));
}
};

class Dropout3dFunctor {
public:
Maybe<Tensor> operator()(const std::shared_ptr<one::Tensor>& input, const float& p,
const bool& train) const {
CHECK_EQ_OR_RETURN(p < 0 || p > 1.0, true)
<< "dropout probability has to be between 0 and 1, but got " << p;
const int input_dim = input->ndim();
CHECK_EQ_OR_RETURN(input_dim != 4 && input_dim != 5, true)
<< "dropout3d: Received a {inp_dim}-D input to dropout3d, which is deprecated "
"and will result in an error in a future release. To retain the behavior "
"and silence this warning, please use dropout instead. Note that dropout3d "
"exists to provide channel-wise dropout on inputs with 3 spatial dimensions, "
"a channel dimension, and an optional batch dimension (i.e. 4D or 5D inputs).";
bool is_batched = (input_dim == 5);
std::shared_ptr<one::Tensor> result;
if (!is_batched) { result = JUST(Unsqueeze(input, 0)); }
result = JUST(DropoutImpl(result, p, train));
if (!is_batched) { result = JUST(Squeeze(result, std::vector<int32_t>{0})); }
return result;
}
};

class DropoutGradFunctor {
public:
DropoutGradFunctor() {
Expand Down Expand Up @@ -3838,6 +3939,9 @@ ONEFLOW_FUNCTION_LIBRARY(m) {
m.add_functor<impl::PadFunctor>("Pad");
m.add_functor<impl::DropoutFunctor>("Dropout");
m.add_functor<impl::DropoutGradFunctor>("DropoutGrad");
m.add_functor<impl::Dropout1dFunctor>("Dropout1d");
m.add_functor<impl::Dropout2dFunctor>("Dropout2d");
m.add_functor<impl::Dropout3dFunctor>("Dropout3d");
m.add_functor<impl::PixelShuffleFunctor>("PixelShuffle");
m.add_functor<impl::AvgPool1DFunctor>("AvgPool1D");
m.add_functor<impl::AvgPool2DFunctor>("AvgPool2D");
Expand Down
2 changes: 1 addition & 1 deletion oneflow/core/functional/impl/random_functor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ using namespace impl;

ONEFLOW_FUNCTION_LIBRARY(m) {
m.add_functor<BernoulliFunctor>("Bernoulli");
m.add_functor<BernoulliProbFunctor>("Bernoulli");
m.add_functor<BernoulliProbFunctor>("BernoulliProb");
m.add_functor<RandPermFunctor>("RandPerm");
m.add_functor<GlobalRandPermFunctor>("GlobalRandPerm");
m.add_functor<RandFunctor>("Rand");
Expand Down
Loading