ONE - On-device Neural Engine
Loading...
Searching...
No Matches
luci::Sparsifier< T > Class Template Reference

#include <Sparsifier.h>

Public Member Functions

 Sparsifier (const std::vector< int > &shape, const std::vector< int > &traversal_order, const std::vector< DimensionType > &format, const std::vector< int > &block_size={}, const std::vector< int > &block_map={})
 
std::vector< T > GetData ()
 
std::vector< std::vector< int > > GetDimMetadata ()
 
void DenseToSparse (const T *src_data)
 

Detailed Description

template<typename T>
class luci::Sparsifier< T >

Definition at line 28 of file Sparsifier.h.

Constructor & Destructor Documentation

◆ Sparsifier()

template<typename T >
luci::Sparsifier< T >::Sparsifier ( const std::vector< int > &  shape,
const std::vector< int > &  traversal_order,
const std::vector< DimensionType > &  format,
const std::vector< int > &  block_size = {},
const std::vector< int > &  block_map = {} 
)

Definition at line 24 of file Sparsifier.cpp.

29 : _dense_shape(shape), _traversal_order(traversal_order), _block_size(block_size),
30 _block_map(block_map)
31{
32 _dense_size = 1;
33 int32_t block_dim = 0;
34 _blocked_shape.resize(shape.size());
35 _format.resize(shape.size() + block_map.size());
36 for (int32_t i = 0; i < static_cast<int32_t>(shape.size()); i++)
37 {
38 _format.at(i) = format.at(traversal_order.at(i));
39 _dense_size *= shape.at(i);
40 if (block_dim < static_cast<int32_t>(block_map.size()) && block_map[block_dim] == i)
41 {
42 _blocked_shape.at(i) = shape.at(i) / block_size.at(block_dim);
43 block_dim++;
44 }
45 else
46 {
47 _blocked_shape.at(i) = shape.at(i);
48 }
49 }
50
51 // Only dense blocks are supported.
52 for (uint32_t i = 0; i < block_map.size(); i++)
53 {
54 _format[i + shape.size()] = DimensionType::DENSE;
55 }
56}

References luci::DENSE.

Member Function Documentation

◆ DenseToSparse()

template<typename T >
void luci::Sparsifier< T >::DenseToSparse ( const T *  src_data)

Definition at line 58 of file Sparsifier.cpp.

59{
60 int num_original_dims = _dense_shape.size();
61 int num_block_dims = _block_map.size();
62 int num_expanded_dims = num_original_dims + num_block_dims;
63 std::vector<int> expanded_shape(num_expanded_dims);
64 for (int i = 0; i < num_expanded_dims; i++)
65 {
66 if (i < num_original_dims)
67 {
68 expanded_shape.at(i) = _blocked_shape.at(i);
69 }
70 else
71 {
72 expanded_shape.at(i) = _block_size.at(i - num_original_dims);
73 }
74 }
75
76 std::vector<int> shape_offset(num_original_dims);
77 shape_offset.at(shape_offset.size() - 1) = 1;
78 for (int i = num_original_dims - 1; i > 0; --i)
79 {
80 shape_offset.at(i - 1) = shape_offset.at(i) * _dense_shape.at(i);
81 }
82
83 std::vector<int> expanded_shape_offset(num_expanded_dims);
84 for (int i = 0; i < num_original_dims; ++i)
85 {
86 expanded_shape_offset.at(i) = shape_offset.at(i);
87 }
88 for (int i = 0; i < num_block_dims; ++i)
89 {
90 int mapped_dim = _block_map.at(i);
91 expanded_shape_offset.at(num_original_dims + i) = shape_offset.at(mapped_dim);
92 expanded_shape_offset.at(mapped_dim) *= _block_size.at(i);
93 }
94
95 std::vector<int> dst_ordered_offset(num_expanded_dims);
96 for (int i = 0; i < num_expanded_dims; ++i)
97 {
98 dst_ordered_offset.at(i) = expanded_shape_offset.at(_traversal_order.at(i));
99 }
100
101 std::vector<bool> dst_dim_has_nonzeroes(num_expanded_dims);
102 std::fill(dst_dim_has_nonzeroes.begin(), dst_dim_has_nonzeroes.end(), false);
103 std::vector<int> inner_compressed_dim(num_expanded_dims);
104 int most_recent_compressed_dim = -1;
105 std::vector<int> num_segments_of_next_compressed_dim(num_expanded_dims);
106 int segment_count = 1;
107 for (int i = num_expanded_dims - 1; i >= 0; --i)
108 {
109 inner_compressed_dim.at(i) = most_recent_compressed_dim;
110 if (_format.at(i) == DimensionType::SPARSE_CSR)
111 {
112 most_recent_compressed_dim = i;
113 num_segments_of_next_compressed_dim.at(i) = segment_count;
114 segment_count = 1;
115 }
116 else
117 {
118 num_segments_of_next_compressed_dim.at(i) = -1;
119 segment_count *= expanded_shape.at(_traversal_order.at(i));
120 }
121 }
122
123 _dim_metadata.resize(num_expanded_dims * 2);
124 std::vector<int> dst_sparse_dims;
125 dst_sparse_dims.reserve(num_expanded_dims);
126 for (int i = 0; i < num_expanded_dims; ++i)
127 {
128 _dim_metadata.at(i * 2).clear();
129 _dim_metadata.at(i * 2 + 1).clear();
130 if (_format.at(i) == DimensionType::DENSE)
131 {
132 // If dimension is dense, just store the shape.
133 _dim_metadata.at(i * 2).push_back(expanded_shape.at(_traversal_order.at(i)));
134 }
135 else
136 {
137 _dim_metadata.at(i * 2).push_back(0); // Segment array always begins with 0.
138 dst_sparse_dims.push_back(i); // Add dimension to the sparse list.
139 }
140 }
141
142 // This algorithm assumes that the block size is small enough for all the
143 // elements to fit in cache, so the strided accesses from different traversal
144 // order and the write-first-erase-later strategy shouldn't be too slow
145 int dst_dim_idx = num_expanded_dims;
146 std::vector<int> coordinate(num_expanded_dims, 0);
147 int dense_tensor_idx = 0;
148 while (dst_dim_idx >= 0)
149 {
150 if (dst_dim_idx == num_expanded_dims)
151 {
152 // We have a complete coordinate. Add the element to the value array if it
153 // is not zero, or if the last dimension is dense.
154 if (!IsZero(src_data[dense_tensor_idx]))
155 {
156 _data.push_back(src_data[dense_tensor_idx]);
157 // Mark all sparse dimensions that their current indices have nonzeroes.
158 for (auto dst_dim : dst_sparse_dims)
159 {
160 if (!dst_dim_has_nonzeroes.at(dst_dim))
161 {
162 // Only add the index to the indices array if the current nonzero
163 // is the first nonzero of the block.
164 _dim_metadata.at(2 * dst_dim + 1).push_back(coordinate.at(dst_dim));
165 dst_dim_has_nonzeroes.at(dst_dim) = true;
166 }
167 }
168 }
169 else if (_format.at(num_expanded_dims - 1) == DimensionType::DENSE)
170 {
171 _data.push_back(src_data[dense_tensor_idx]);
172 }
173 --dst_dim_idx;
174 }
175 else
176 {
177 int original_dim_idx = _traversal_order.at(dst_dim_idx);
178 int dim_size = expanded_shape.at(original_dim_idx);
179 if (dst_dim_has_nonzeroes.at(dst_dim_idx))
180 {
181 // If the previous block has nonzeroes, reset the flag to false since
182 // we have just moved to a new block.
183 dst_dim_has_nonzeroes.at(dst_dim_idx) = false;
184 }
185 else if (_format.at(dst_dim_idx) == DimensionType::SPARSE_CSR)
186 {
187 // This block is empty. Delete unnecessary values if compressed.
188 int next_compressed_dim = inner_compressed_dim.at(dst_dim_idx);
189 int erase_offset = _dim_metadata.at(2 * dst_dim_idx + 1).size() *
190 num_segments_of_next_compressed_dim.at(dst_dim_idx);
191 if (next_compressed_dim >= 0)
192 {
193 auto &segments = _dim_metadata.at(2 * inner_compressed_dim.at(dst_dim_idx));
194 segments.erase(segments.begin() + 1 + erase_offset, segments.end());
195 }
196 else
197 {
198 _data.erase(_data.begin() + erase_offset, _data.end());
199 }
200 }
201 if (++coordinate.at(dst_dim_idx) < dim_size)
202 {
203 // The current dst_dim_idx is valid (not out of bound).
204 dense_tensor_idx += dst_ordered_offset.at(dst_dim_idx);
205 ++dst_dim_idx;
206 }
207 else
208 {
209 // dst_dim_idx has reached its dim size. Update segment array and go
210 // back to incrementing the previous dimension (dst_dim_idx - 1).
211 if (_format.at(dst_dim_idx) == DimensionType::SPARSE_CSR)
212 {
213 _dim_metadata.at(2 * dst_dim_idx).push_back(_dim_metadata.at(2 * dst_dim_idx + 1).size());
214 }
215 coordinate.at(dst_dim_idx) = -1;
216 dense_tensor_idx -= dst_ordered_offset.at(dst_dim_idx) * dim_size;
217 --dst_dim_idx;
218 }
219 }
220 }
221}
@ SPARSE_CSR

References luci::DENSE, and luci::SPARSE_CSR.

Referenced by luci::SparsifyTensorPass::sparsify_tensor().

◆ GetData()

template<typename T >
std::vector< T > luci::Sparsifier< T >::GetData ( )
inline

Definition at line 46 of file Sparsifier.h.

46{ return _data; }

Referenced by luci::SparsifyTensorPass::sparsify_tensor().

◆ GetDimMetadata()

template<typename T >
std::vector< std::vector< int > > luci::Sparsifier< T >::GetDimMetadata ( )
inline

Definition at line 47 of file Sparsifier.h.

47{ return _dim_metadata; }

Referenced by luci::SparsifyTensorPass::sparsify_tensor().


The documentation for this class was generated from the following files: