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  auto ptr_and_deleter = Context::New(nbytes());
126  data_.reset(
127  static_cast<unsigned char*>(ptr_and_deleter.first),
128  ptr_and_deleter.second);
129  capacity_ = nbytes() * CHAR_BIT;
130  }
131  CAFFE_ENFORCE(capacity_ == nbytes() * CHAR_BIT);
132  return data_.get();
133  }
134 
135  inline const unsigned char* data() const {
136  return data_.get();
137  }
138 
139  inline size_t size() const {
140  return size_;
141  }
142 
143  inline unsigned char alignment() const {
144  return alignment_;
145  }
146 
147  inline unsigned char precision() const {
148  return precision_;
149  }
150 
151  inline const vector<int>& dims() const {
152  return dims_;
153  }
154 
155  inline bool is_signed() const {
156  return signed_;
157  }
158 
162  inline int ndim() const {
163  return dims_.size();
164  }
165 
166  inline size_t aligned_size() const {
167  return alignment_ * ((size_ + alignment_ - 1) / alignment_);
168  }
169 
170  inline size_t nbytes() const {
171  return (aligned_size() * (precision_ + signed_)) / CHAR_BIT;
172  }
173 
174  inline double scale() const {
175  return scale_;
176  }
177 
178  inline double bias() const {
179  return bias_;
180  }
181 
185  inline int dim32(const int i) const {
186  DCHECK_LT(i, dims_.size()) << "Exceeding ndim limit " << dims_.size();
187  DCHECK_GE(i, 0) << "Cannot have negative index";
188  CAFFE_ENFORCE_LT(dims_[i], std::numeric_limits<int>::max());
189  return static_cast<int>(dims_[i]);
190  }
191 
203  inline int canonical_axis_index(int axis_index) const {
204  CAFFE_ENFORCE_GE(axis_index, -ndim());
205  CAFFE_ENFORCE_LT(axis_index, ndim());
206  if (axis_index < 0) {
207  return axis_index + ndim();
208  }
209  return axis_index;
210  }
211 
215  inline TIndex size_from_dim(int k) const {
216  TIndex r = 1;
217  for (int i = k; i < dims_.size(); ++i) {
218  r *= dims_[i];
219  }
220  return r;
221  }
222 
226  inline TIndex size_to_dim(int k) const {
227  CAFFE_ENFORCE(k < dims_.size());
228  TIndex r = 1;
229  for (int i = 0; i < k; ++i) {
230  r *= dims_[i];
231  }
232  return r;
233  }
234 
235  protected:
236  std::vector<int> dims_;
237  size_t size_ = 0;
238 
239  // Precision in bits.
240  unsigned char precision_ = CHAR_BIT;
241  // Bit alignment.
242  unsigned char alignment_ = CHAR_BIT;
243 
244  // Allocated data.
245  std::shared_ptr<unsigned char> data_;
246 
247  // value = scale_ * (x + bias_)
248  double scale_;
249  double bias_;
250  bool signed_ = false;
251 
252  // Capacity in bits.
253  size_t capacity_ = 0;
254 };
255 
256 } // namespace caffe2
257 #endif // CAFFE2_CORE_QTENSOR_H_
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:203
int ndim() const
Returns the number of dimensions of the data.
Definition: qtensor.h:162
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
TIndex size_from_dim(int k) const
Return product of all dimensions starting from K.
Definition: qtensor.h:215
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
int dim32(const int i) const
Returns the i-th dimension of the qtensor in int.
Definition: qtensor.h:185
TIndex size_to_dim(int k) const
Product of all dims up to.
Definition: qtensor.h:226