Caffe2 - C++ API
A deep learning, cross platform ML framework
boolean_unmask_ops.cc
1 #include "caffe2/operators/boolean_unmask_ops.h"
2 #include "caffe2/core/operator.h"
3 #include "caffe2/core/tensor.h"
4 
5 namespace caffe2 {
6 
7 template <>
8 bool BooleanUnmaskOp<CPUContext>::RunOnDevice() {
9  int maskSize = Input(0).numel();
10  int numMasks = InputSize() / 2;
11  auto& valueMeta = Input(1).dtype();
12 
13  auto* valuesOut = Output(0);
14  valuesOut->Resize(maskSize);
15  auto* valuesOutPtr = (char*)valuesOut->raw_mutable_data(valueMeta);
16 
17  std::vector<int> nextValueIndices(numMasks, 0);
18  for (int maskOffset = 0; maskOffset < maskSize; ++maskOffset) {
19  bool maskFound = false;
20  for (int maskIndex = 0; maskIndex < numMasks; ++maskIndex) {
21  auto& mask = Input(maskIndex * 2);
22  CAFFE_ENFORCE_EQ(mask.dim(), 1);
23  CAFFE_ENFORCE_EQ(mask.numel(), maskSize);
24  const auto* maskPtr = mask.template data<bool>();
25 
26  auto& values = Input(maskIndex * 2 + 1);
27  CAFFE_ENFORCE_EQ(values.dim(), 1);
28  const auto* valuesPtr = (char*)values.raw_data();
29 
30  if (maskPtr[maskOffset]) {
31  auto& valueIndex = nextValueIndices[maskIndex];
32  CAFFE_ENFORCE_LT(valueIndex, values.numel());
33  auto* src = valuesPtr + (valueIndex++) * valueMeta.itemsize();
34  auto* dst = valuesOutPtr + maskOffset * valueMeta.itemsize();
35  std::copy(src, src + valueMeta.itemsize(), dst);
36  maskFound = true;
37  break;
38  }
39  }
40  CAFFE_ENFORCE(
41  maskFound, "All masks have False at position ", maskOffset, ".");
42  }
43  // check all indices match value length
44  for (int i = 0; i < numMasks; ++i) {
45  auto& values = Input(i * 2 + 1);
46  CAFFE_ENFORCE_EQ(
47  values.numel(),
48  nextValueIndices[i],
49  "The number of true at mask ",
50  i,
51  " does not match the corresponding value size.");
52  }
53  return true;
54 }
55 
56 REGISTER_CPU_OPERATOR(BooleanUnmask, BooleanUnmaskOp<CPUContext>);
57 
58 OPERATOR_SCHEMA(BooleanUnmask)
59  .NumInputs([](int n) { return n > 0 && n % 2 == 0; })
60  .NumOutputs(1)
61  .SetDoc(R"DOC(
62 Given a series of masks and values, reconstruct values together according to masks. A comprehensive example:
63 ```
64 mask1 = True, False, True, False, False
65 values1 = 1.0, 3.0
66 mask2 = False, True, False, False, False
67 values2 = 2.0
68 mask3 = False, False, False, True, True
69 values3 = 4.0, 5.0
70 ```
71 
72 Reconstruct by:
73 
74 ```
75 output = net.BooleanUnmask([mask1, values1, mask2, values2, mask3, values3], ["output"])
76 output = 1.0, 2.0, 3.0, 4.0, 5.0
77 ```
78 
79 Note that for all mask positions, there must be at least one True. This is not allowed:
80 
81 ```
82 mask1 = True, False
83 values1 = 1.0
84 mask2 = False, False
85 values2 =
86 
87 output = net.BooleanUnmask([mask1, values1, mask2, values2], ["output"])
88 ```
89 
90 If there are multiple True values for a field, we accept the first value, and no longer expect a value for that location:
91 
92 ```
93 mask1 = True, False
94 values1 = 1.0
95 mask2 = True, True
96 values2 = 2.0
97 
98 output = net.BooleanUnmask([mask1, values1, mask2, values2], ["output"])
99 output = 1.0, 2.0
100 ```
101 
102 *** Note that we alternate `data` and `mask` inputs
103 
104 Github Links:
105 - https://github.com/pytorch/pytorch/blob/master/caffe2/operators/boolean_unmask_ops.cc
106 
107 <details>
108 
109 <summary> <b>Example</b> </summary>
110 
111 **Code**
112 
113 ```
114 
115 workspace.ResetWorkspace()
116 
117 op = core.CreateOperator(
118  "BooleanUnmask",
119  ["mask1", "data1", "mask2", "data2"],
120  ["unmasked_data"]
121 )
122 
123 workspace.FeedBlob("mask1", np.array([True,False,False,True,True,False]))
124 workspace.FeedBlob("data1", np.array([1,4,5]))
125 workspace.FeedBlob("mask2", np.array([False,True,True,False,False,True]))
126 workspace.FeedBlob("data2", np.array([2,3,6]))
127 
128 print("data1:", workspace.FetchBlob("data1"))
129 print("mask1:", workspace.FetchBlob("mask1"))
130 print("data2:", workspace.FetchBlob("data2"))
131 print("mask2:", workspace.FetchBlob("mask2"))
132 workspace.RunOperatorOnce(op)
133 print("unmasked_data:", workspace.FetchBlob("unmasked_data"))
134 
135 ```
136 
137 **Result**
138 
139 ```
140 
141 data1: [1 4 5]
142 mask1: [ True False False True True False]
143 data2: [2 3 6]
144 mask2: [False True True False False True]
145 unmasked_data: [1 2 3 4 5 6]
146 
147 ```
148 
149 </details>
150 )DOC")
151  .Input(0,"data","(*Tensor*): 1D input tensor(s)")
152  .Input(1,"mask","(*Tensor`<bool>`*): 1D boolean mask tensor(s)")
153  .Output(0, "unmasked_data", "(*Tensor*): 1D tensor of same type as `data` input that contains the unmasked input tensor");
154 
155 NO_GRADIENT(BooleanUnmask)
156 }
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
Definition: blob.h:13