From da3dd9af12d45c05d0c81f3d7ee07a0a77ad6b78 Mon Sep 17 00:00:00 2001 From: Dong Shi Date: Wed, 10 Oct 2018 18:06:58 -0700 Subject: [PATCH] No Op Optimizer (#12390) Summary: Pull Request resolved: https://github.com/pytorch/pytorch/pull/12390 Introduce a no op optimizer for when we don't want updates to happen, but don't want to affect downstream processes. Reviewed By: mlappelbaum Differential Revision: D10209812 fbshipit-source-id: 2af4ebc0fb42e78ea851c3a9f4860f3d224037b6 --- caffe2/operators/data_couple.cc | 17 +++++++++++ caffe2/operators/data_couple.h | 22 ++++++++++++++ caffe2/operators/data_couple_gpu.cu | 6 ++++ .../operator_test/data_couple_op_test.py | 30 +++++++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 caffe2/operators/data_couple.cc create mode 100644 caffe2/operators/data_couple.h create mode 100644 caffe2/operators/data_couple_gpu.cu create mode 100644 caffe2/python/operator_test/data_couple_op_test.py diff --git a/caffe2/operators/data_couple.cc b/caffe2/operators/data_couple.cc new file mode 100644 index 00000000000..014c129f4e0 --- /dev/null +++ b/caffe2/operators/data_couple.cc @@ -0,0 +1,17 @@ +#include "caffe2/operators/data_couple.h" + +namespace caffe2 { +REGISTER_CPU_OPERATOR(DataCouple, DataCoupleOp); + +OPERATOR_SCHEMA(DataCouple) + .EnforceOneToOneInplace() + .SetDoc(R"DOC( + +A one to one operator that takes an arbitrary number of input and output blobs +such that each input blob is inplace with it's matching output blob. It then proceedes +to do nothing with each of these operators. This serves two purposes. It can make it +appear as if a blob has been written to, as well as can tie together different blobs +in a data dependency + +)DOC"); +} // namespace caffe2 diff --git a/caffe2/operators/data_couple.h b/caffe2/operators/data_couple.h new file mode 100644 index 00000000000..a63d3bb6ed8 --- /dev/null +++ b/caffe2/operators/data_couple.h @@ -0,0 +1,22 @@ +#ifndef CAFFE2_OPERATORS_NO_OP_OPTIMIZER_OP_H_ +#define CAFFE2_OPERATORS_NO_OP_OPTIMIZER_OP_H_ + +#include "caffe2/core/context.h" +#include "caffe2/core/operator.h" + +namespace caffe2 { + +template +class DataCoupleOp : public Operator { + public: + USE_SIMPLE_CTOR_DTOR(DataCoupleOp) + + bool RunOnDevice() override { + // Actually does nothing... + return true; + } +}; + +} // namespace caffe2 + +#endif // CAFFE2_OPERATORS_NO_OP_OPTIMIZER_OP_H_ diff --git a/caffe2/operators/data_couple_gpu.cu b/caffe2/operators/data_couple_gpu.cu new file mode 100644 index 00000000000..81736d20556 --- /dev/null +++ b/caffe2/operators/data_couple_gpu.cu @@ -0,0 +1,6 @@ +#include "caffe2/core/context_gpu.h" +#include "caffe2/operators/data_couple.h" + +namespace caffe2 { +REGISTER_CUDA_OPERATOR(DataCouple, DataCoupleOp); +} diff --git a/caffe2/python/operator_test/data_couple_op_test.py b/caffe2/python/operator_test/data_couple_op_test.py new file mode 100644 index 00000000000..32cf21e81bb --- /dev/null +++ b/caffe2/python/operator_test/data_couple_op_test.py @@ -0,0 +1,30 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +from caffe2.python import core, workspace +from caffe2.python.test_util import TestCase +import numpy as np + + +class TestDataCoupleOp(TestCase): + + def test_data_couple_op(self): + param_array = np.random.rand(10, 10) + gradient_array = np.random.rand(10, 10) + extra_array = np.random.rand(10, 10) + workspace.FeedBlob("param", param_array) + workspace.FeedBlob("gradient", gradient_array) + workspace.FeedBlob("extraBlob", extra_array) + + workspace.RunOperatorOnce(core.CreateOperator( + "DataCouple", + ["param", "gradient", "extraBlob"], + ["param", "gradient"])) + + result1 = workspace.FetchBlob('param') + result2 = workspace.FetchBlob('gradient') + + self.assertFalse((result1 - param_array).any()) + self.assertFalse((result2 - gradient_array).any())