Add int64 support to sparse_to_dense_mask_op
Summary: [CAFFE2] Add int64 support to sparse_to_dense_mask_op
Reviewed By: ender-wieczorek
Differential Revision: D6022278
fbshipit-source-id: 489b6df4d43a64c743ee278d94929ca50259f7b8
diff --git a/caffe2/operators/sparse_to_dense_mask_op.cc b/caffe2/operators/sparse_to_dense_mask_op.cc
index d84553f..f234885 100644
--- a/caffe2/operators/sparse_to_dense_mask_op.cc
+++ b/caffe2/operators/sparse_to_dense_mask_op.cc
@@ -30,7 +30,7 @@
.TensorInferenceFunction([](const OperatorDef& def,
const vector<TensorShape>& in) {
ArgumentHelper helper(def);
- auto mask = helper.template GetRepeatedArgument<int>("mask");
+ auto mask = helper.template GetRepeatedArgument<int64_t>("mask");
bool return_presence_mask = helper.template GetSingleArgument<bool>(
"return_presence_mask", false);
vector<TensorShape> out(1);
diff --git a/caffe2/operators/sparse_to_dense_mask_op.h b/caffe2/operators/sparse_to_dense_mask_op.h
index f508a01..94af59d 100644
--- a/caffe2/operators/sparse_to_dense_mask_op.h
+++ b/caffe2/operators/sparse_to_dense_mask_op.h
@@ -33,14 +33,15 @@
USE_OPERATOR_CONTEXT_FUNCTIONS;
SparseToDenseMaskBase(const OperatorDef& operator_def, Workspace* ws)
: Operator<Context>(operator_def, ws) {
- std::vector<int> mask =
- OperatorBase::template GetRepeatedArgument<int>("mask");
+ std::vector<int64_t> mask =
+ OperatorBase::template GetRepeatedArgument<int64_t>("mask");
featuresCount_ = mask.size();
+
CAFFE_ENFORCE(!mask.empty(), "mask can't be empty");
auto biggest = *std::max_element(mask.begin(), mask.end());
dense_.assign(std::min(kMaxDenseSize, biggest + 1), -1);
for (int i = 0; i < mask.size(); i++) {
- int id = mask[i];
+ int64_t id = mask[i];
CAFFE_ENFORCE_GE(id, 0, "Only positive IDs are allowed.");
if (id >= kMaxDenseSize) {
CAFFE_ENFORCE(sparse_.count(id) == 0, "Duplicated id: ", id);
@@ -53,13 +54,13 @@
}
protected:
- const int kMaxDenseSize = 1024 * 128;
+ const int64_t kMaxDenseSize = 1024 * 128;
- std::unordered_map<int, int> sparse_;
+ std::unordered_map<int64_t, int> sparse_;
std::vector<int> dense_;
int featuresCount_;
- inline int getFeatureIdx(int id) const {
+ inline int getFeatureIdx(int64_t id) const {
if (id >= kMaxDenseSize) {
const auto& iter = sparse_.find(id);
if (iter == sparse_.end()) {
@@ -160,7 +161,7 @@
rows * cols, false, presence_mask_data, &context_);
}
- int32_t offset = 0;
+ int64_t offset = 0;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < lengths_vec[r]; c++) {
const auto sparse_index = sparse_indices_vec[offset + c];
diff --git a/caffe2/python/operator_test/sparse_to_dense_mask_op_test.py b/caffe2/python/operator_test/sparse_to_dense_mask_op_test.py
index 3d774c4..cdcdfad 100644
--- a/caffe2/python/operator_test/sparse_to_dense_mask_op_test.py
+++ b/caffe2/python/operator_test/sparse_to_dense_mask_op_test.py
@@ -60,6 +60,39 @@
gc, op, input_data, 1, [0])
@given(n=st.integers(1, 10), k=st.integers(1, 5),
+ use_length=st.booleans(), **hu.gcs_cpu_only)
+ def test_sparse_to_dense_mask_with_int64(self, n, k, use_length, gc, dc):
+ lengths = np.random.randint(k, size=n).astype(np.int32) + 1
+ N = sum(lengths)
+ int64_mask = 10000000000
+ indices = np.random.randint(5, size=N) + int64_mask
+ values = np.random.rand(N, 2).astype(np.float32)
+ default = np.random.rand(2).astype(np.float32)
+ mask = np.arange(3) + int64_mask
+ np.random.shuffle(mask)
+
+ input_str = ['indices', 'values', 'default']
+ input_data = [indices, values, default]
+ if use_length and n > 1:
+ input_str.append('lengths')
+ input_data.append(lengths)
+ output_str = ['output']
+
+ op = core.CreateOperator(
+ 'SparseToDenseMask',
+ input_str,
+ output_str,
+ mask=mask,
+ )
+
+ # Check over multiple devices
+ self.assertDeviceChecks(
+ dc, op, input_data, [0])
+ # Gradient check for values
+ self.assertGradientChecks(
+ gc, op, input_data, 1, [0])
+
+ @given(n=st.integers(1, 10), k=st.integers(1, 5),
dim=st.integers(1, 3), **hu.gcs_cpu_only)
def test_sparse_to_dense_mask_high_dim(self, n, k, dim, gc, dc):
lengths = np.random.randint(k, size=n).astype(np.int32) + 1