Sparse memory formats¶
API¶
oneDNN support format kind dnnl::memory::format_kind::sparse to describe sparse tensors. Sparse encoding (a.k.a. sparse format) is an enumeration type that specifies how data is encoded. Currently, oneDNN supports Compressed Sparse Row (CSR), Sorted Co-ordinate (COO) Sparse Format, and PACKED sparse encodings (dnnl::memory::sparse_encoding::csr, dnnl::memory::sparse_encoding::coo, dnnl::memory::sparse_encoding::packed) for CPU engine, and, only sorted COO (Co-ordinate Sparse Format) for GPU engine.
The memory descriptor has dedicated static member functions for creating memory descriptors for different sparse encodings.
Each encoding defines the number and meaning of the buffers.
Sparse encoding |
Buffers |
---|---|
CSR |
0 - values, 1 - indices, 2 - pointers |
Sorted COO |
0 - values, 1 to ndims - indices ( ndims - number of tensor dimensions) |
PACKED |
The meaning and content are unspecified |
The pseudocode below demonstrates how to create a memory object for the CSR and COO sparse encodings and use the new API to work with the underlying handles.
# CSR Encoding:
using namespace dnnl; const memory::dim M = 4, N = 6; const memory::dim nnz = 5; const auto values_dt = memory::data_type::f32; const auto indices_dt = memory::data_type::s32; const auto pointers_dt = memory::data_type::s32; // Create a memory descriptor for CSR sparse encoding. const auto csr_md = memory::desc::csr( {M, N}, // Dimensions values_dt, // Data type of values nnz, // Number of non-zero entries indices_dt, // Data type of indices (metadata) pointers_dt); // Data type of pointers (metadata) // A sparse matrix represented in the CSR format. std::vector<float> csr_values = {2.5f, 1.5f, 1.5f, 2.5f, 2.0f}; std::vector<int32_t> csr_indices = {0, 2, 0, 5, 1}; std::vector<int32_t> csr_pointers = {0, 1, 2, 4, 5, 5}; // Create a memory object for the given buffers with values and metadata. memory csr_mem(csr_md, engine, { csr_values.data(), // Buffer with values csr_indices.data(), // Buffer with indices (metadata) csr_pointers.data() // Buffer with pointers (metadata) }); const auto values_sz = csr_mem.get_size(0); const auto indices_sz = csr_mem.get_size(1); const auto pointers_sz = csr_mem.get_size(2); assert(values_sz == csr_values.size() * sizeof(float)); assert(indices_sz == csr_indices.size() * sizeof(int32_t)); assert(pointers_sz == csr_pointers.size() * sizeof(int32_t)); void *values_handle = csr_mem.get_data_handle(0); void *indices_handle = csr_mem.get_data_handle(1); void *pointers_handle = csr_mem.get_data_handle(2); assert(values_handle == (void *)csr_values.data()); assert(indices_handle == (void *)csr_indices.data()); assert(pointers_handle == (void *)csr_pointers.data());
# Sorted COO Encoding:
using namespace dnnl; const memory::dim M = 4, N = 6; const memory::dim nnz = 5; const auto values_dt = memory::data_type::f32; const auto indices_dt = memory::data_type::s32; // Create a memory descriptor for COO sparse encoding. const auto coo_md = memory::desc::coo( {M, N}, // Dimensions values_dt, // Data type of values nnz, // Number of non-zero entries indices_dt); // Data type of indices (metadata) // A sparse matrix represented in the COO format. std::vector<float> coo_values = {2.5f, 1.5f, 1.5f, 2.5f, 2.0f}; std::vector<int32_t> coo_row_indices = {0, 1, 2, 2, 3}; std::vector<int32_t> coo_col_indices = {0, 2, 0, 5, 1}; // Create a memory object for the given buffers with values and metadata. memory coo_mem(coo_md, engine, { coo_values.data(), // Buffer with values coo_row_indices.data(), // Buffer with row indices (metadata) coo_col_indices.data() // Buffer with column indices (metadata) }); const auto values_sz = coo_mem.get_size(0); const auto indices_sz = coo_mem.get_size(1); assert(values_sz == coo_values.size() * sizeof(float)); assert(indices_sz == coo_row_indices.size() * sizeof(int32_t)); assert(indices_sz == coo_col_indices.size() * sizeof(int32_t)); void *values_handle = coo_mem.get_data_handle(0); void *row_indices_handle = coo_mem.get_data_handle(1); void *col_indices_handle = coo_mem.get_data_handle(2); assert(values_handle == (void *)coo_values.data()); assert(row_indices_handle == (void *)coo_row_indices.data()); assert(col_indices_handle == (void *)coo_col_indices.data());
A memory descriptor created for the sparse encoding PACKED cannot be used to create a memory object. It can only be used to create a primitive descriptor to query the actual memory descriptor (similar to the format tag any
).