Slice op implemented using MKL-DNN APIs.
| 355 | private: |
| 356 | // Slice op implemented using MKL-DNN APIs. |
| 357 | void ComputeMklSlice(OpKernelContext* context, |
| 358 | const gtl::InlinedVector<int64, 4>& begin, |
| 359 | const gtl::InlinedVector<int64, 4>& size) { |
| 360 | try { |
| 361 | // OneDNN API usage below is guided by description at: |
| 362 | // https://github.com/01org/mkl-dnn/issues/69 |
| 363 | // |
| 364 | // Relevant part of the description is copied below: |
| 365 | // |
| 366 | // Let's say you want to copy a part of memory into another buffer (and |
| 367 | // probably change the format). Then your steps are: |
| 368 | // |
| 369 | // 1. create memory primitive descriptor in_mem_pd and memory primitive |
| 370 | // in_mem_p for the entire source data. create view primitive |
| 371 | // descriptor in_submem_pd based on in_mem_pd, initial offsets, |
| 372 | // and sub-sizes |
| 373 | // 2. create memory primitive descriptor out_mem_pd and memory primitive |
| 374 | // out_mem_p for the output (the logical sizes should match sub-sizes |
| 375 | // used in step 1, but the format might be arbitrary) |
| 376 | // 3. create reorder primitive descriptor reorder_pd based on in_submem_pd |
| 377 | // and out_mem_pd. create reorder primitive itself based on reorder_pd, |
| 378 | // in_mem_p, and out_mem_p. |
| 379 | // |
| 380 | // Please notice that there is no view primitive. There is only view |
| 381 | // primitive descriptor. And the reorder uses source memory as input but |
| 382 | // traverses it according to a view in_submem_pd. |
| 383 | |
| 384 | auto cpu_engine = engine(ENGINE_CPU, 0); |
| 385 | MklDnnData<T> src(&cpu_engine); |
| 386 | MklDnnData<T> output(&cpu_engine); |
| 387 | |
| 388 | // Populate offsets and sizes in memory::dims format based on vector. |
| 389 | memory::dims begin_dims = {}; |
| 390 | begin_dims.resize(begin.size()); |
| 391 | for (size_t i = 0; i < begin.size(); ++i) begin_dims[i] = begin[i]; |
| 392 | memory::dims size_dims = {}; |
| 393 | bool empty = false; |
| 394 | size_dims.resize(size.size()); |
| 395 | for (size_t i = 0; i < size.size(); ++i) { |
| 396 | size_dims[i] = size[i]; |
| 397 | if (size_dims[i] == 0) empty = true; |
| 398 | } |
| 399 | |
| 400 | Tensor* output_tensor = nullptr; |
| 401 | MklDnnShape output_mkl_shape; |
| 402 | |
| 403 | // If no dimension is selected in slice, the result should be empty. |
| 404 | // Just return an empty output tensor, and a dummy OneDNN-shape tensor. |
| 405 | if (empty) { // for empty dims |
| 406 | auto shape_to = MklDnnDimsToTFShape(size_dims); |
| 407 | AllocateOutputSetMklShape(context, 0, &output_tensor, shape_to, |
| 408 | output_mkl_shape); |
| 409 | return; |
| 410 | } |
| 411 | |
| 412 | // Step 1 (as per above description) - Create memory for user data. |
| 413 | // We use blocked format here to describe input tensor. |
| 414 | const Tensor& input_tensor = MklGetInput(context, 0); |
nothing calls this directly
no test coverage detected