Caffe2 - C++ API
A deep learning, cross platform ML framework
qtensor.h
1 #ifndef CAFFE2_CORE_QTENSOR_H_
2 #define CAFFE2_CORE_QTENSOR_H_
3 
4 #include <algorithm>
5 #include <climits>
6 #include <cstddef>
7 #include <vector>
8 
9 #include "caffe2/core/common.h"
10 #include "caffe2/core/context.h"
11 #include "caffe2/core/tensor.h"
12 #include "caffe2/core/typeid.h"
13 
14 namespace caffe2 {
15 
16 template <class Context>
17 class QTensor {
18  public:
19  QTensor() {}
20  virtual ~QTensor() {}
49  explicit QTensor(
50  const std::vector<int>& dims,
51  const unsigned char precision,
52  const bool signbit = false)
53  : precision_(precision), signed_(signbit) {
54  Resize(dims);
55  }
56 
57  void Resize(std::vector<int> dim_source) {
58  if (dims_ != dim_source) {
59  size_t source_size = std::accumulate(
60  dim_source.begin(), dim_source.end(), 1, std::multiplies<int>());
61  if ((source_size * (precision_ + signed_)) > capacity_) {
62  data_.reset();
63  capacity_ = 0;
64  }
65  dims_ = dim_source;
66  size_ = source_size;
67  }
68  }
69 
70  void
71  SetBitAtIndex(const unsigned char bit, const size_t index, const bool value) {
72  // Get the mutable data at bit depth `bit`.
73  unsigned char* d = mutable_data();
74 
75  CAFFE_ENFORCE(
76  bit < precision_ + signed_,
77  "Attempted to a set a bit that is not allocated.");
78  CAFFE_ENFORCE(bit * aligned_size() < capacity_);
79 
80  auto idx = (aligned_size() * bit) / CHAR_BIT;
81  d = &d[idx];
82 
83  idx = index / CHAR_BIT;
84  auto shift = CHAR_BIT - (index % CHAR_BIT) - 1;
85 
86  if (value) {
87  d[idx] |= 1 << shift;
88  } else {
89  d[idx] &= ~(1 << shift);
90  }
91  }
92 
93  bool GetBitAtIndex(const unsigned char bit, const size_t index) const {
94  // Get the data at bit depth `bit`
95  const unsigned char* d = data();
96  auto idx = (aligned_size() * bit) / CHAR_BIT;
97  d = &d[idx];
98 
99  idx = index / CHAR_BIT;
100  auto shift = CHAR_BIT - (index % CHAR_BIT) - 1;
101 
102  return d[idx] & (1 << shift);
103  }
104 
105  void SetPrecision(const unsigned char precision) {
106  precision_ = precision;
107  data_.reset();
108  }
109 
110  void SetSigned(const bool make_signed = true) {
111  signed_ = make_signed;
112  data_.reset();
113  }
114 
115  void SetScale(const double scale) {
116  scale_ = scale;
117  }
118 
119  void SetBias(const double bias) {
120  bias_ = bias;
121  }
122 
123  unsigned char* mutable_data() {
124  if (!data_) {
125  data_.reset(
126  static_cast<unsigned char*>(Context::New(nbytes())), Context::Delete);
127  capacity_ = nbytes() * CHAR_BIT;
128  }
129  CAFFE_ENFORCE(capacity_ == nbytes() * CHAR_BIT);
130  return data_.get();
131  }
132 
133  inline const unsigned char* data() const {
134  return data_.get();
135  }
136 
137  inline size_t size() const {
138  return size_;
139  }
140 
141  inline unsigned char alignment() const {
142  return alignment_;
143  }
144 
145  inline unsigned char precision() const {
146  return precision_;
147  }
148 
149  inline const vector<int>& dims() const {
150  return dims_;
151  }
152 
153  inline bool is_signed() const {
154  return signed_;
155  }
156 
160  inline int ndim() const {
161  return dims_.size();
162  }
163 
164  inline size_t aligned_size() const {
165  return alignment_ * ((size_ + alignment_ - 1) / alignment_);
166  }
167 
168  inline size_t nbytes() const {
169  return (aligned_size() * (precision_ + signed_)) / CHAR_BIT;
170  }
171 
172  inline double scale() const {
173  return scale_;
174  }
175 
176  inline double bias() const {
177  return bias_;
178  }
179 
183  inline int dim32(const int i) const {
184  DCHECK_LT(i, dims_.size()) << "Exceeding ndim limit " << dims_.size();
185  DCHECK_GE(i, 0) << "Cannot have negative index";
186  CAFFE_ENFORCE_LT(dims_[i], std::numeric_limits<int>::max());
187  return static_cast<int>(dims_[i]);
188  }
189 
201  inline int canonical_axis_index(int axis_index) const {
202  CAFFE_ENFORCE_GE(axis_index, -ndim());
203  CAFFE_ENFORCE_LT(axis_index, ndim());
204  if (axis_index < 0) {
205  return axis_index + ndim();
206  }
207  return axis_index;
208  }
209 
213  inline TIndex size_from_dim(int k) const {
214  TIndex r = 1;
215  for (int i = k; i < dims_.size(); ++i) {
216  r *= dims_[i];
217  }
218  return r;
219  }
220 
224  inline TIndex size_to_dim(int k) const {
225  CAFFE_ENFORCE(k < dims_.size());
226  TIndex r = 1;
227  for (int i = 0; i < k; ++i) {
228  r *= dims_[i];
229  }
230  return r;
231  }
232 
233  protected:
234  std::vector<int> dims_;
235  size_t size_ = 0;
236 
237  // Precision in bits.
238  unsigned char precision_ = CHAR_BIT;
239  // Bit alignment.
240  unsigned char alignment_ = CHAR_BIT;
241 
242  // Allocated data.
243  std::shared_ptr<unsigned char> data_;
244 
245  // value = scale_ * (x + bias_)
246  double scale_;
247  double bias_;
248  bool signed_;
249 
250  // Capacity in bits.
251  size_t capacity_ = 0;
252 };
253 
254 } // namespace caffe2
255 #endif // CAFFE2_CORE_QTENSOR_H_
int ndim() const
Returns the number of dimensions of the data.
Definition: qtensor.h:160
Simple registry implementation in Caffe2 that uses static variables to register object creators durin...
int canonical_axis_index(int axis_index) const
Returns the &#39;canonical&#39; version of a (usually) user-specified axis, allowing for negative indexing (e...
Definition: qtensor.h:201
QTensor(const std::vector< int > &dims, const unsigned char precision, const bool signbit=false)
Creates a quantized tensor of the given dimension.
Definition: qtensor.h:49
int dim32(const int i) const
Returns the i-th dimension of the qtensor in int.
Definition: qtensor.h:183
TIndex size_to_dim(int k) const
Product of all dims up to.
Definition: qtensor.h:224
TIndex size_from_dim(int k) const
Return product of all dimensions starting from K.
Definition: qtensor.h:213