tensor.h 8.1 KB
Newer Older
Y
Yi Wang 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */

Y
Yi Wang 已提交
15 16
#pragma once

17
#include <cstdint>
18
#include <cstring>
F
fengjiayi 已提交
19
#include <memory>
Y
Yu Yang 已提交
20
#include <typeindex>
F
fengjiayi 已提交
21 22
#include "paddle/framework/ddim.h"
#include "paddle/framework/enforce.h"
Q
init  
qijun 已提交
23
#include "paddle/framework/tensor_types.h"
F
fengjiayi 已提交
24 25
#include "paddle/memory/memory.h"
#include "paddle/platform/place.h"
Q
init  
qijun 已提交
26
#include "unsupported/Eigen/CXX11/Tensor"
F
fengjiayi 已提交
27

Y
Yi Wang 已提交
28
namespace paddle {
29 30 31 32 33 34
namespace pybind {
namespace details {  // forward declare
template <bool less, size_t i, typename... args>
struct CastToPyBufferImpl;
}  // namespace details
}  // namespace pybind
Y
Yi Wang 已提交
35 36 37 38
namespace framework {

class Tensor {
 public:
39
  Tensor() : offset_(0) {}
40

Y
Yi Wang 已提交
41 42
  template <typename T>
  const T* data() const {
F
fengjiayi 已提交
43
    CheckDims<T>();
44
    return reinterpret_cast<const T*>(
F
fengjiayi 已提交
45
        reinterpret_cast<uintptr_t>(holder_->ptr()) + offset_);
Y
Yi Wang 已提交
46 47
  }

Q
qijun 已提交
48 49 50 51
  template <typename T>
  T* raw_data() const {
    CheckDims<T>();
    return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(holder_->ptr()) +
Q
qijun 已提交
52
                                offset_);
Q
init  
qijun 已提交
53 54
  }

F
fengjiayi 已提交
55
  template <typename T>
F
fengjiayi 已提交
56
  T* mutable_data(DDim dims, platform::Place place) {
F
fengjiayi 已提交
57
    set_dims(dims);
58 59 60
    return mutable_data<T>(place);
  }

F
fengjiayi 已提交
61
  template <typename T>
F
fengjiayi 已提交
62
  T* mutable_data(platform::Place place) {
63 64
    PADDLE_ENFORCE(product(dims_) > 0,
                   "Tensor's numel must be larger than zero to call "
F
fengjiayi 已提交
65
                   "Tensor::mutable_data. Call Tensor::set_dim first.");
F
fengjiayi 已提交
66
    if (holder_ == nullptr ||
F
fengjiayi 已提交
67
        !(holder_->place() ==
F
fengjiayi 已提交
68
          place) /* some versions of boost::variant don't have operator!= */
69 70 71 72 73
        || holder_->size() < product(dims_) * sizeof(T) + offset_) {
      if (platform::is_cpu_place(place)) {
        holder_.reset(new PlaceholderImpl<T, platform::CPUPlace>(
            boost::get<platform::CPUPlace>(place), product(dims_) * sizeof(T)));
      } else if (platform::is_gpu_place(place)) {
74 75 76
#ifdef PADDLE_ONLY_CPU
        PADDLE_THROW("'GPUPlace' is not supported in CPU only device.");
#else
77 78
        holder_.reset(new PlaceholderImpl<T, platform::GPUPlace>(
            boost::get<platform::GPUPlace>(place), product(dims_) * sizeof(T)));
79
#endif
80
      } else {
81
        PADDLE_THROW("Unknown 'place'.");
82
      }
83
      offset_ = 0;
Y
Yi Wang 已提交
84
    }
F
fengjiayi 已提交
85
    return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(holder_->ptr()) +
86
                                offset_);
Y
Yi Wang 已提交
87 88
  }

Q
qijun 已提交
89
  template <typename T, size_t NDIMS>
Q
qijun 已提交
90
  typename TTypes<T, NDIMS>::Tensor shaped(DDim new_dims) {
Q
qijun 已提交
91
    Eigen::array<Eigen::DenseIndex, NDIMS> dims =
Q
qijun 已提交
92
        paddle::framework::ToEigenDSizes<NDIMS>(new_dims);
Q
qijun 已提交
93
    return typename TTypes<T, NDIMS>::Tensor(raw_data<T>(), dims);
Q
qijun 已提交
94 95
  }

Q
init  
qijun 已提交
96
  template <typename T, size_t NDIMS>
Q
qijun 已提交
97
  typename TTypes<T, NDIMS>::Tensor tensor() {
Q
init  
qijun 已提交
98
    return typename TTypes<T, NDIMS>::Tensor(
Q
qijun 已提交
99
        raw_data<T>(), paddle::framework::ToEigenDSizes<NDIMS>(dims_));
Q
init  
qijun 已提交
100 101
  }

Q
qijun 已提交
102 103 104
  // flat to rank = 1
  template <typename T>
  typename TTypes<T>::Flat flat() {
Q
qijun 已提交
105
    return shaped<T, 1>(make_ddim({static_cast<int>(product(dims_))}));
Q
qijun 已提交
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
  }

  // to TensorType Vec
  template <typename T>
  typename TTypes<T>::Vec vec() {
    return tensor<T, 1>();
  }

  // to TensorType Matrix
  template <typename T>
  typename TTypes<T>::Matrix matrix() {
    return tensor<T, 2>();
  }

  // const versions of all the methods above.
Q
qijun 已提交
121 122 123 124 125 126 127
  template <typename T, size_t NDIMS>
  typename TTypes<T, NDIMS>::Tensor shaped(DDim new_dims) const {
    Eigen::array<Eigen::DenseIndex, NDIMS> dims =
        paddle::framework::ToEigenDSizes<NDIMS>(new_dims);
    return typename TTypes<T, NDIMS>::Tensor(data<T>(), dims);
  }

Q
init  
qijun 已提交
128
  template <typename T, size_t NDIMS>
Q
qijun 已提交
129
  typename TTypes<T, NDIMS>::ConstantTensor tensor() const {
Q
init  
qijun 已提交
130 131
    return typename TTypes<T, NDIMS>::Tensor(
        data<T>(), paddle::framework::ToEigenDSizes<NDIMS>(dims_));
Y
Yi Wang 已提交
132 133
  }

Q
qijun 已提交
134 135
  template <typename T>
  typename TTypes<T>::ConstFlat flat() const {
Q
qijun 已提交
136
    return shaped<T, 1>(make_ddim({static_cast<int>(product(dims_))}));
Q
qijun 已提交
137 138 139 140 141 142 143 144 145 146 147 148
  }

  template <typename T>
  typename TTypes<T>::ConstVec vec() const {
    return tensor<T, 1>();
  }

  template <typename T>
  typename TTypes<T>::ConstMatrix matrix() const {
    return tensor<T, 2>();
  }

F
fengjiayi 已提交
149
  template <typename T>
150
  void ShareDataFrom(const Tensor& src) {
F
fengjiayi 已提交
151
    src.CheckDims<T>();
152
    holder_ = src.holder_;
F
fengjiayi 已提交
153
    set_dims(src.dims());
154
    offset_ = src.offset_;
Y
Yi Wang 已提交
155 156
  }

F
fengjiayi 已提交
157
  template <typename T>
F
fengjiayi 已提交
158
  void CopyFrom(const Tensor& src, platform::Place dst_place) {
F
fengjiayi 已提交
159 160 161
    PADDLE_ENFORCE(platform::is_cpu_place(src.holder_->place()) &&
                       platform::is_cpu_place(dst_place),
                   "Tensor::CopyFrom only support CPU now.");
F
fengjiayi 已提交
162
    src.CheckDims<T>();
163
    size_t size = product(src.dims_) * sizeof(T);
F
fengjiayi 已提交
164
    set_dims(src.dims());
F
fengjiayi 已提交
165
    const void* src_ptr = static_cast<const void*>(src.data<T>());
F
fengjiayi 已提交
166 167
    void* dst_ptr = static_cast<void*>(mutable_data<T>(dst_place));
    memcpy(dst_ptr, src_ptr, size);
168 169
  }

F
fengjiayi 已提交
170
  template <typename T>
F
fengjiayi 已提交
171
  Tensor Slice(const int& begin_idx, const int& end_idx) const {
F
fengjiayi 已提交
172
    CheckDims<T>();
173 174 175 176 177 178 179 180 181 182 183 184
    PADDLE_ENFORCE(begin_idx >= 0 && end_idx <= dims_[0],
                   "Slice index is less than zero or out of bound.");
    PADDLE_ENFORCE(begin_idx < end_idx,
                   "Begin index must be less than end index.");
    PADDLE_ENFORCE(dims_[0] != 1, "Can not slice a tensor with dims_[0] = 1.");
    std::vector<int> d = vectorize(dims_);
    int base = 1;
    for (size_t i = 1; i < d.size(); ++i) {
      base *= d[i];
    }
    Tensor dst;
    dst.holder_ = holder_;
F
fengjiayi 已提交
185 186 187
    DDim dst_dims = dims_;
    dst_dims[0] = end_idx - begin_idx;
    dst.set_dims(dst_dims);
F
fengjiayi 已提交
188
    dst.offset_ = offset_ + begin_idx * base * sizeof(T);
189 190 191
    return dst;
  }

F
fengjiayi 已提交
192 193 194 195 196 197 198
  void set_dims(const DDim& dims) {
    if (dims == dims_) {
      return;
    }
    dims_ = dims;
  }

199 200
  DDim dims() const { return dims_; }

Y
Yi Wang 已提交
201 202 203 204 205
 private:
  // Placeholder hides type T, so it doesn't appear as a template
  // parameter of Variable.
  struct Placeholder {
    virtual ~Placeholder() {}
F
fengjiayi 已提交
206
    virtual void* ptr() const = 0;
F
fengjiayi 已提交
207
    virtual platform::Place place() const = 0;
F
fengjiayi 已提交
208
    virtual size_t size() const = 0;
Y
Yu Yang 已提交
209
    virtual std::type_index type() const = 0;
Y
Yi Wang 已提交
210 211
  };

F
fengjiayi 已提交
212
  template <typename T, typename PlaceType>
Y
Yi Wang 已提交
213
  struct PlaceholderImpl : public Placeholder {
214
   private:
F
fengjiayi 已提交
215
    template <typename PType>
216 217
    class Deleter {
     public:
F
fengjiayi 已提交
218 219
      Deleter(PType place) : place_(place) {}
      void operator()(T* ptr) { memory::Free(place_, static_cast<void*>(ptr)); }
220 221

     private:
F
fengjiayi 已提交
222
      PType place_;
223 224 225
    };

   public:
F
fengjiayi 已提交
226 227 228
    PlaceholderImpl(PlaceType place, size_t size)
        : ptr_(static_cast<T*>(memory::Alloc(place, size)),
               Deleter<PlaceType>(place)),
229
          place_(place),
Y
Yi Wang 已提交
230 231
          size_(size) {}

F
fengjiayi 已提交
232 233
    virtual void* ptr() const { return static_cast<void*>(ptr_.get()); }
    virtual size_t size() const { return size_; }
Y
Yu Yang 已提交
234 235
    virtual paddle::platform::Place place() const { return place_; }
    virtual std::type_index type() const { return std::type_index(typeid(T)); }
Y
Yi Wang 已提交
236

F
fengjiayi 已提交
237 238 239
    std::unique_ptr<T, Deleter<PlaceType>> ptr_;
    platform::Place place_;  // record the place of ptr_.
    size_t size_;            // size of the memory block.
Y
Yi Wang 已提交
240 241
  };

F
fengjiayi 已提交
242
  template <typename T>
F
fengjiayi 已提交
243
  inline void CheckDims() const {
F
fengjiayi 已提交
244 245
    PADDLE_ENFORCE(holder_ != nullptr,
                   "Tenosr holds no memory. Call Tensor::mutable_data first.");
246
    PADDLE_ENFORCE(holder_->size() >= product(dims_) * sizeof(T) + offset_,
F
fengjiayi 已提交
247 248 249 250
                   "Tensor's dims_ is out of bound. Call Tensor::mutable_data "
                   "first to re-allocate memory.");
  }

251
  std::shared_ptr<Placeholder> holder_;  // holds the memory block if allocated.
252 253
  DDim dims_;
  size_t offset_;  // marks the begin of tensor data area.
254 255
  template <bool less, size_t i, typename... args>
  friend struct paddle::pybind::details::CastToPyBufferImpl;
256
};
Y
Yi Wang 已提交
257 258 259

}  // namespace framework
}  // namespace paddle