1 #ifndef CAFFE2_CORE_TENSOR_H_ 2 #define CAFFE2_CORE_TENSOR_H_ 12 #include "caffe2/core/common.h" 14 #include "caffe2/core/context.h" 15 #include "caffe2/core/typeid.h" 16 #include "caffe2/core/logging.h" 21 CAFFE2_DECLARE_bool(caffe2_keep_on_shrink);
29 return vector<TIndex>(src.begin(), src.end());
37 for (
int i = k; i < dims.size(); ++i) {
44 inline TIndex size_to_dim_(
int k, vector<TIndex> dims) {
45 CAFFE_ENFORCE(k < dims.size());
47 for (
int i = 0; i < k; ++i) {
53 inline int canonical_axis_index_(
int axis_index,
int ndims) {
54 CAFFE_ENFORCE_GE(axis_index, -ndims);
55 CAFFE_ENFORCE_LT(axis_index, ndims);
57 return axis_index + ndims;
72 template <
class Context>
87 explicit Tensor(
const vector<int>& dims) {
Resize(dims); }
99 template <
class SrcContext,
class ContextForCopy>
111 template <
class SrcContext>
119 template <
typename T>
120 Tensor(
const vector<TIndex>& dims,
const vector<T>& values, Context* context)
123 CAFFE_ENFORCE_EQ(values.size(), size_);
124 context->template Copy<T, CPUContext, Context>(size_, values.data(), mutable_data<T>());
130 template <
typename T,
131 typename =
typename std::enable_if<std::is_scalar<T>::value>::type>
132 Tensor(
const T& value, Context* context) {
134 context->template Copy<T, CPUContext, Context>(size_, &value, mutable_data<T>());
141 template <
class SrcContext,
class ContextForCopy>
143 if ((
void*)&src == (
void*)
this) {
152 context->template CopyBytes<SrcContext, Context>(
165 template <
class SrcContext>
167 SrcContext tmp_context;
171 virtual ~
Tensor() noexcept {}
182 template <
class ContextForCopy>
183 void Extend(TIndex num,
float growthPct, ContextForCopy* context) {
184 CAFFE_ENFORCE_GE(dims_.size(), 1);
185 auto newDims = dims_;
191 auto newSize = std::accumulate(
194 static_cast<TIndex
>(1),
195 std::multiplies<TIndex>());
196 if (newSize * meta_.
itemsize() <= capacity_) {
201 auto newCapacity = dims_;
202 newCapacity[0] = std::max<size_t>(
203 newDims[0], std::ceil(dims_[0] * (growthPct + 100) / 100));
204 Reserve(newCapacity, context);
209 template <
class T,
class ContextForCopy>
210 void Reserve(
const std::vector<T>& newCapacity, ContextForCopy* context) {
211 auto newSize = std::accumulate(
214 static_cast<TIndex
>(1),
215 std::multiplies<TIndex>());
216 if (newSize * meta_.
itemsize() <= capacity_) {
219 auto oldData = std::move(data_);
220 auto oldSize = size_;
221 auto oldDims = dims_;
224 context->template CopyItems<ContextForCopy, ContextForCopy>(
225 meta_, oldSize, oldData.get(), newData);
237 CAFFE_ENFORCE(dims_.size() >= 1,
"Tensor must be at least 1D");
239 outer_dim <= dims_[0],
240 "New outer dimension must be smaller than current.");
241 dims_[0] = outer_dim;
242 size_ = std::accumulate(
245 static_cast<TIndex
>(1),
246 std::multiplies<TIndex>());
262 template <
typename... Ts>
264 bool size_changed = SetDims(dim_source...);
267 if (size_changed && (capacity_ < size_ * meta_.
itemsize() ||
268 !FLAGS_caffe2_keep_on_shrink)) {
278 template <
class OtherContext>
281 if (static_cast<void*>(
this) != static_cast<const void*>(&src_tensor)) {
290 inline void Reshape(
const vector<TIndex>& dims) {
292 for (
auto d : dims) {
293 CAFFE_ENFORCE_GE(d, 0);
298 "New size and old size are not equal. You cannot use Reshape, " 299 "but should use Resize." 302 " The old caffe2 mixes Reshape and Resize but this behavior has " 303 "been changed. If you find this error, most likely you will need " 304 "to change corresponding code from Reshape to Resize.");
308 inline void Reshape(
const vector<int>& dims) {
318 std::stringstream ss;
319 ss <<
"A Tensor of item size " <<
itemsize() <<
" and type " 320 << meta_.
name() <<
" and dimension (";
321 for (
int d : dims_) {
345 "Size mismatch - did you call reshape before sharing the data?");
350 src.data_.get() || src.size_ == 0,
351 "Source tensor has no content and has size > 0");
354 capacity_ = src.capacity_;
366 template <
typename T>
377 template <
typename T,
typename Deleter>
380 src, TypeMeta::Make<T>(), capacity, std::forward<Deleter>(d));
388 template <
class Deleter>
395 CAFFE_ENFORCE_WITH_CALLER(
397 "To share with a raw external pointer you need to have meta " 399 CAFFE_ENFORCE_WITH_CALLER(
401 "To share data with a raw pointer, you need to set shape first.");
402 data_.reset(src, std::forward<Deleter>(d));
406 capacity_ = capacity;
422 CAFFE_ENFORCE_WITH_CALLER(data_.get() || size_ == 0);
432 template <
typename T>
434 CAFFE_ENFORCE_WITH_CALLER(
435 data_.get() || size_ == 0,
436 "The tensor is of non-zero shape, but its data is not allocated yet. " 437 "Caffe2 uses a lazy allocation, so you will need to call " 438 "mutable_data() or raw_mutable_data() to actually allocate memory.");
439 CAFFE_ENFORCE_WITH_CALLER(
441 "Tensor type mismatch, caller expects elements to be ",
443 " while tensor contains ",
445 return static_cast<T*
>(data_.get());
461 if (meta_ == meta && (data_.get() || size_ == 0)) {
465 CAFFE_ENFORCE_WITH_CALLER(
467 "Tensor is not initialized. You probably need to call Resize() " 468 "before calling mutable_data()");
477 auto dtor = meta_.
dtor();
479 static_cast<void*>(Context::New(size_ * meta_.
itemsize())),
480 [
size, dtor](
void* ptr) ->
void {
482 Context::Delete(ptr);
484 meta_.
ctor()(data_.get(), size_);
487 data_.reset(static_cast<void*>(Context::New(size_ * meta_.
itemsize())),
490 capacity_ = size_ * meta_.
itemsize();
505 CAFFE_ENFORCE_WITH_CALLER(
507 "Calling raw_mutable_data() without meta, but the current meta is " 518 template <
typename T>
520 if ((size_ == 0 || data_.get()) && IsType<T>()) {
521 return static_cast<T*
>(data_.get());
530 inline int ndim()
const {
return dims_.size(); }
534 inline TIndex
size()
const {
return size_; }
546 inline size_t capacity_nbytes()
const {
552 inline const vector<TIndex>&
dims()
const {
return dims_; }
554 inline TIndex size_from_dim(
int k)
const {
558 inline TIndex size_to_dim(
int k)
const {
559 return size_to_dim_(k, dims_);
574 return canonical_axis_index_(axis_index,
ndim());
580 template <
typename T>
581 inline bool IsType()
const {
return meta_.Match<T>(); }
594 inline int dim32(
const int i)
const {
595 DCHECK_LT(i, dims_.size()) <<
"Exceeding ndim limit " << dims_.size();
596 DCHECK_GE(i, 0) <<
"Cannot have negative index";
597 CAFFE_ENFORCE_LT(dims_[i], std::numeric_limits<int>::max());
598 return static_cast<int>(dims_[i]);
606 inline TIndex
dim(
const int i)
const {
607 DCHECK_LT(i, dims_.size()) <<
"Exceeding ndim limit " << dims_.size();
608 DCHECK_GE(i, 0) <<
"Cannot have negative index";
613 vector<TIndex> dims_;
616 std::shared_ptr<void> data_;
617 bool shares_data_ =
false;
618 size_t capacity_ = 0;
624 typename =
typename std::enable_if<std::is_integral<T>::value>::type>
625 bool SetDims(
const vector<T>& src) {
626 auto old_size = size_;
627 dims_.resize(src.size());
629 for (
unsigned int i = 0; i < src.size(); ++i) {
634 return size_ != old_size;
638 auto old_size = size_;
641 return size_ != old_size;
647 bool SetDims(
const TIndex d0) {
648 auto old_size = size_;
652 return size_ != old_size;
655 bool SetDims(
const TIndex d0,
const TIndex d1) {
656 auto old_size = size_;
661 return size_ != old_size;
664 bool SetDims(
const TIndex d0,
const TIndex d1,
const TIndex d2) {
665 auto old_size = size_;
670 size_ = d0 * d1 * d2;
671 return size_ != old_size;
675 SetDims(
const TIndex d0,
const TIndex d1,
const TIndex d2,
const TIndex d3) {
676 auto old_size = size_;
682 size_ = d0 * d1 * d2 * d3;
683 return size_ != old_size;
694 constexpr
int k_limit_default_ = 1000;
697 typedef TypeMeta (*TypeCall)(
void*);
698 TypeCall GetTypeCallFunction(CaffeTypeId
id);
699 void RegisterTypeCallFunction(CaffeTypeId
id, TypeCall c);
701 template <
class Context>
708 typedef vector<TIndex> (*ShapeCall)(
void*,
bool& shares_data,
size_t& capacity);
709 ShapeCall GetShapeCallFunction(CaffeTypeId
id);
710 void RegisterShapeCallFunction(CaffeTypeId
id, ShapeCall c);
712 template <
class Context>
713 vector<TIndex> GetTensorShape(
void* c,
bool& shares_data,
size_t& capacity) {
715 shares_data = tc->shares_data();
716 capacity = tc->capacity_nbytes();
723 const std::string& tensor_name =
"",
724 const std::string& file_name =
"",
725 int limit = k_limit_default_);
731 template <
class Context>
740 std::unique_ptr<std::ofstream> log_file_;
741 std::string tensor_name_;
746 std::stringstream values_stream;
749 int total_count = std::min(tensor.
size(), TIndex(limit_));
750 const T* tensor_data = tensor.template data<T>();
751 for (
int i = 0; i < total_count - 1; ++i) {
752 values_stream << tensor_data[i] <<
",";
755 values_stream << tensor_data[total_count - 1];
757 (*log_file_) << MetaStr(tensor) << values_stream.str() << std::endl;
760 LOG(INFO) << MetaStr(tensor) << values_stream.str();
764 template <
class Context>
767 (*log_file_) << MetaStr(tensor) << std::endl;
769 LOG(INFO) << MetaStr(tensor);
774 #endif // CAFFE2_CORE_TENSOR_H_
size_t itemsize() const
Return the number of bytes each item takes in the tensor.
void ShareExternalPointer(T *src, size_t capacity, Deleter &&d)
Shares the data with an externally managed pointer.
int canonical_axis_index(int axis_index) const
Returns the 'canonical' version of a (usually) user-specified axis, allowing for negative indexing (e...
void CopyFrom(const Tensor< SrcContext > &src, ContextForCopy *context)
Copies the data from a source tensor, with a contex provided to carry out the underlying memcpy opera...
int ndim() const
Returns the number of dimensions of the data.
TIndex dim(const int i) const
Returns the i-th dimension of the tensor.
Tensor()
Initializes an empty tensor.
const void * raw_data() const
Returns a const raw void* pointer of the underlying storage.
void ShareExternalPointer(T *src, size_t capacity=0)
Shares the data with an externally managed pointer.
const vector< TIndex > & dims() const
Returns the dimensions of the tensor as a vector.
Tensor(const Tensor< SrcContext > &src)
Creates a tensor from a source tensor, copying over the content.
TIndex size() const
Returns the size (i.e.
T * mutable_data()
Returns a typed pointer of the underlying storage.
void CopyFrom(const Tensor< SrcContext > &src)
Copies the data from a source tensor.
size_t nbytes() const
Returns the total number of bytes of the storage.
const TypeMeta & meta() const
Returns the TypeMeta object associated with the current data type.
void Extend(TIndex num, float growthPct, ContextForCopy *context)
Extends the outer-most dimension of this tensor by num elements, preserving the existing data...
void * raw_mutable_data()
Returns a mutable raw pointer of the underlying storage.
string DebugString() const
A utility function to print the debug string for the tensor.
Tensor(const vector< TIndex > &dims)
Creates a tensor of the given dimension.
Tensor(const vector< TIndex > &dims, const vector< T > &values, Context *context)
Creates a tensor, and fills its contents with the given values.
const T * data() const
Returns a typed pointer of the underlying storage.
Tensor is the basic class in Caffe2 that stores a contiguous memory with its shape information...
Simple registry implementation in Caffe2 that uses static variables to register object creators durin...
void Reshape(const vector< TIndex > &dims)
Resizes the tensor without touching underlying storage.
void ResizeLike(const Tensor< OtherContext > &src_tensor)
Resize the tensor like the source tensor.
void ShareData(const Tensor &src)
Shares the data with another tensor.
Tensor(const T &value, Context *context)
Creates a scalar tensor, and fills its content with the given value.
void Shrink(TIndex outer_dim)
Shrinks the outer-most dimension to given size, keeping the data.
void * raw_mutable_data(const TypeMeta &meta)
Returns a mutable raw pointer of the underlying storage.
vector< TIndex > ToVectorTIndex(const std::vector< int > &src)
A utility function to convert vector<int> to vector<TIndex>.
Commandline flags support for Caffe2.
void Resize(Ts... dim_source)
Resizes a tensor.
bool IsType() const
Checks if the tensor content is of the given data type.
Tensor(const Tensor< SrcContext > &src, ContextForCopy *context)
Creates a tensor from a source tensor, copying over the content.
int dim32(const int i) const
Returns the i-th dimension of the tensor in int.
TIndex size_from_dim_(int k, vector< TIndex > dims)
Return product of all dimensions starting from K.