| 207 | : BinaryOp<Device, Functor>(context) {} |
| 208 | |
| 209 | void Compute(OpKernelContext* context) override { |
| 210 | const int kNumInputs = 2; |
| 211 | std::vector<Tensor> inputs(kNumInputs); |
| 212 | std::vector<MklDnnShape> mkl_input_shapes(kNumInputs); |
| 213 | std::vector<TensorShape> tf_input_shapes(kNumInputs); |
| 214 | std::vector<T*> inputs_data(kNumInputs); |
| 215 | |
| 216 | for (int i = 0; i < kNumInputs; i++) { |
| 217 | inputs[i] = context->input(i); |
| 218 | inputs_data[i] = inputs[i].flat<T>().data(); |
| 219 | GetMklShape(context, i, &(mkl_input_shapes[i])); |
| 220 | |
| 221 | tf_input_shapes[i] = mkl_input_shapes[i].IsMklTensor() |
| 222 | ? mkl_input_shapes[i].GetTfShape() |
| 223 | : inputs[i].shape(); |
| 224 | } |
| 225 | |
| 226 | VLOG(1) << "MklBinaryOp: Inputs shapes " << tf_input_shapes[0].DebugString() |
| 227 | << " _and_ " << tf_input_shapes[1].DebugString(); |
| 228 | |
| 229 | if (!ShouldFallback(tf_input_shapes[0], tf_input_shapes[1])) { |
| 230 | VLOG(1) << "MklBinaryOp: Run oneDNN primitive"; |
| 231 | |
| 232 | std::vector<memory::dims> srcs_dims(kNumInputs); |
| 233 | for (int i = 0; i < kNumInputs; i++) { |
| 234 | auto& mkl_shape = mkl_input_shapes[i]; |
| 235 | if (mkl_shape.IsMklTensor()) { |
| 236 | srcs_dims[i] = mkl_shape.GetSizesAsMklDnnDims(); |
| 237 | } else { |
| 238 | srcs_dims[i] = TFShapeToMklDnnDims(tf_input_shapes[i]); |
| 239 | } |
| 240 | } |
| 241 | |
| 242 | // oneDNN only supports inputs[1] bcast to inputs[0]. So if inputs[1] |
| 243 | // has more elements than inputs[0], swap the 2 inputs. |
| 244 | // Use an index to indicate the swapped result. |
| 245 | const int kFirst = (tf_input_shapes[1].num_elements() > |
| 246 | tf_input_shapes[0].num_elements()) || |
| 247 | (tf_input_shapes[1].num_elements() == |
| 248 | tf_input_shapes[0].num_elements() && |
| 249 | srcs_dims[1].size() > srcs_dims[0].size()); |
| 250 | const int kSecond = 1 - kFirst; |
| 251 | |
| 252 | // oneDNN only supports inputs with same rank size, so expand dimension |
| 253 | // if they are not consistent. |
| 254 | // E.g. 8x4 * 4 --> 8x4 * 1x4. |
| 255 | if (srcs_dims[0].size() != srcs_dims[1].size()) { |
| 256 | const int kSmall = srcs_dims[0].size() > srcs_dims[1].size(); |
| 257 | ExpandDim(srcs_dims[kSmall], srcs_dims[1 - kSmall].size()); |
| 258 | } |
| 259 | |
| 260 | std::vector<memory::desc> srcs_md(kNumInputs); |
| 261 | for (int i = 0; i < kNumInputs; i++) { |
| 262 | auto& mkl_shape = mkl_input_shapes[i]; |
| 263 | if (mkl_shape.IsMklTensor()) { |
| 264 | srcs_md[i] = mkl_shape.GetMklLayout(); |
| 265 | } else { |
| 266 | auto src_strides = CalculateTFStrides(srcs_dims[i]); |
nothing calls this directly
no test coverage detected