.. _program_listing_file_src_functional_tensor.h: Program Listing for File tensor.h ================================= |exhale_lsh| :ref:`Return to documentation for file ` (``src/functional/tensor.h``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #pragma once #include "functional/array.h" #include "functional/shape.h" #include "tensors/tensor.h" namespace marian { namespace functional { // By default for single valued types like float do nothing. Usually the number of elements in a tensor // is correctly mirrored in the shape object. Only special multi-element types like float32x4 (4 floats), // float32x8 (8 floats) and half2 (2 half) require special handling done by specializations below. // Similar for multi-element integer types to be added later. template inline marian::Shape adapt(const marian::Shape& shape) { return shape; } #ifndef __CUDACC__ // vectorized types not available from .cu files // modify last shape dimension to automatically map to a larger stride. We are moving now by 4 floats // at once and need to stop earlier. This is a shallow typecast to bascially an array of 4 floats. template <> inline marian::Shape adapt(const marian::Shape& shape) { ABORT_IF(shape[-1] % 4 != 0, "Last dim ({}) is not a multiple of 4 while converting to Tensor", shape[-1]); marian::Shape x4Shape = shape; x4Shape.set(-1, shape[-1] / 4); return x4Shape; } #ifdef __AVX__ // as above, but for a stride of 8, since we are processing 8 floats at once template <> inline marian::Shape adapt(const marian::Shape& shape) { ABORT_IF(shape[-1] % 8 != 0, "Last dim ({}) is not a multiple of 8 while converting to Tensor", shape[-1]); marian::Shape x8Shape = shape; x8Shape.set(-1, shape[-1] / 8); return x8Shape; } #endif #endif #if COMPILE_FP16 // as above, but for a stride of 2, since we are processing 2 half floats at once. Works on GPU. template <> inline marian::Shape adapt(const marian::Shape& shape) { ABORT_IF(shape[-1] % 2 != 0, "Last dim ({}) is not a multiple of 2 while converting to Tensor", shape[-1]); marian::Shape x2Shape = shape; x2Shape.set(-1, shape[-1] / 2); return x2Shape; } #endif template struct View { T* data_; ConstantShape shape_; HOST_DEVICE View() {} HOST_DEVICE View(T* ptr, const ConstantShape& shape) : data_(ptr), shape_(shape) {} HOST View(marian::Tensor t) : data_(t->data()), shape_(adapt(t->shape())) {} HOST_DEVICE_INLINE T& operator[](size_t i) { return data_[shape_.index((int)i)]; } HOST_DEVICE_INLINE const T& operator[](size_t i) const { return data_[shape_.index(i)]; } HOST_DEVICE_INLINE T& operator[](const Array& indices) { return data_[shape_.index(indices)]; } HOST_DEVICE_INLINE const T& operator[](const Array& indices) const { return data_[shape_.index(indices)]; } HOST_DEVICE_INLINE T* data() { return data_; } HOST_DEVICE_INLINE const T* data() const { return data_; } HOST_DEVICE_INLINE ConstantShape& shape() { return shape_; } HOST_DEVICE_INLINE const ConstantShape& shape() const { return shape_; } HOST_DEVICE_INLINE size_t size() const { return shape_.elements(); } // @TODO: This is code duplication from marian::Tensor std::string debug(int precision = 8, int dispCols = 5) { std::stringstream strm; assert(shape_.size()); strm << shape_; strm << " type=" << request(); strm << " ptr=" << (size_t)data_; strm << std::endl; size_t totSize = shape_.elements(); std::vector values(totSize); for(int i = 0; i < size(); ++i) values[i] = operator[](i); int colWidth = precision + 4; strm << std::fixed << std::setprecision(precision) << std::setfill(' '); for(int i = 0; i < values.size(); ++i) { Array dims; shape().dims(i, dims); bool disp = true; for(int j = 0; j < dims.size(); ++j) disp = disp && (dims[j] < dispCols || dims[j] >= shape()[j] - dispCols); if(disp) { if(dims.back() == 0) { bool par = true; std::vector p; for(int j = (int)dims.size() - 1; j >= 0; --j) { if(dims[j] != 0) par = false; p.push_back(par ? "[" : " "); } for(auto it = p.rbegin(); it != p.rend(); ++it) strm << *it; strm << " "; } strm << std::setw(colWidth); strm << values[i]; strm << " "; if(dims.back() + 1 == shape().back()) { for(int j = (int)dims.size() - 1; j >= 0; --j) { if(dims[j] + 1 != shape()[j]) break; strm << "]"; } strm << std::endl; } bool prev = true; for(int j = (int)dims.size() - 1; j >= 0; --j) { if(j < (int)dims.size() - 1) prev = prev && dims[j + 1] + 1 == shape()[j + 1]; if(prev && dims[j] + 1 == dispCols && shape()[j] > 2 * dispCols) { if(j < (int)dims.size() - 1) for(int k = 0; k <= j; ++k) strm << " "; strm << "... "; if(j < (int)dims.size() - 1) strm << std::endl; break; } } } } strm << std::endl; return strm.str(); } }; // @TODO: Attempts at correct slicing, not supported anywhere yet. #if 0 template HOST_DEVICE_INLINE View slice(View view, const Array& slices) { const auto& slicedShape = view.shape().slice(slices); return View(view.data(), slicedShape); } // template // View slice(View view, // const Slices&... slices) { // return slice(view, {slices...}); // } template HOST_DEVICE_INLINE View slice(View& view, const Slice& slice0) { return slice(view, {slice0}); } template HOST_DEVICE_INLINE View slice(View& view, const Slice& slice0, const Slice& slice1) { return slice(view, {slice0, slice1}); } template HOST_DEVICE_INLINE View slice(View& view, const Slice& slice0, const Slice& slice1, const Slice& slice2) { return slice(view, {slice0, slice1, slice2}); } template HOST_DEVICE_INLINE View slice(View& view, const Slice& slice0, const Slice& slice1, const Slice& slice2, const Slice& slice3) { return slice(view, {slice0, slice1, slice2, slice3}); } // template // View reshape(View& view, const ConstantShape& shape) { // auto reshaped = view.shape().reshape(shape); // return View(view.data(), reshaped); // } #endif template using Tensor = View; } // namespace functional } // namespace marian