273 lines
9.2 KiB
C++
273 lines
9.2 KiB
C++
// This file is part of Eigen, a lightweight C++ template library
|
|
// for linear algebra.
|
|
//
|
|
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla
|
|
// Public License v. 2.0. If a copy of the MPL was not distributed
|
|
// with this file, You can obtain one at the mozilla.org home page
|
|
|
|
#ifndef EIGEN_CXX11_TENSOR_TENSOR_TRAITS_H
|
|
#define EIGEN_CXX11_TENSOR_TENSOR_TRAITS_H
|
|
|
|
namespace Eigen {
|
|
namespace internal {
|
|
|
|
|
|
template<typename Scalar, int Options>
|
|
class compute_tensor_flags
|
|
{
|
|
enum {
|
|
is_dynamic_size_storage = 1,
|
|
|
|
is_aligned =
|
|
(
|
|
((Options&DontAlign)==0) && (
|
|
#if EIGEN_MAX_STATIC_ALIGN_BYTES>0
|
|
(!is_dynamic_size_storage)
|
|
#else
|
|
0
|
|
#endif
|
|
|
|
|
#if EIGEN_MAX_ALIGN_BYTES>0
|
|
is_dynamic_size_storage
|
|
#else
|
|
0
|
|
#endif
|
|
)
|
|
),
|
|
packet_access_bit = packet_traits<Scalar>::Vectorizable && is_aligned ? PacketAccessBit : 0
|
|
};
|
|
|
|
public:
|
|
enum { ret = packet_access_bit };
|
|
};
|
|
|
|
|
|
template<typename Scalar_, int NumIndices_, int Options_, typename IndexType_>
|
|
struct traits<Tensor<Scalar_, NumIndices_, Options_, IndexType_> >
|
|
{
|
|
typedef Scalar_ Scalar;
|
|
typedef Dense StorageKind;
|
|
typedef IndexType_ Index;
|
|
static const int NumDimensions = NumIndices_;
|
|
static const int Layout = Options_ & RowMajor ? RowMajor : ColMajor;
|
|
enum {
|
|
Options = Options_,
|
|
Flags = compute_tensor_flags<Scalar_, Options_>::ret | (is_const<Scalar_>::value ? 0 : LvalueBit)
|
|
};
|
|
template <typename T> struct MakePointer {
|
|
typedef T* Type;
|
|
};
|
|
};
|
|
|
|
|
|
template<typename Scalar_, typename Dimensions, int Options_, typename IndexType_>
|
|
struct traits<TensorFixedSize<Scalar_, Dimensions, Options_, IndexType_> >
|
|
{
|
|
typedef Scalar_ Scalar;
|
|
typedef Dense StorageKind;
|
|
typedef IndexType_ Index;
|
|
static const int NumDimensions = array_size<Dimensions>::value;
|
|
static const int Layout = Options_ & RowMajor ? RowMajor : ColMajor;
|
|
enum {
|
|
Options = Options_,
|
|
Flags = compute_tensor_flags<Scalar_, Options_>::ret | (is_const<Scalar_>::value ? 0: LvalueBit)
|
|
};
|
|
template <typename T> struct MakePointer {
|
|
typedef T* Type;
|
|
};
|
|
};
|
|
|
|
|
|
template<typename PlainObjectType, int Options_, template <class> class MakePointer_>
|
|
struct traits<TensorMap<PlainObjectType, Options_, MakePointer_> >
|
|
: public traits<PlainObjectType>
|
|
{
|
|
typedef traits<PlainObjectType> BaseTraits;
|
|
typedef typename BaseTraits::Scalar Scalar;
|
|
typedef typename BaseTraits::StorageKind StorageKind;
|
|
typedef typename BaseTraits::Index Index;
|
|
static const int NumDimensions = BaseTraits::NumDimensions;
|
|
static const int Layout = BaseTraits::Layout;
|
|
enum {
|
|
Options = Options_,
|
|
Flags = BaseTraits::Flags
|
|
};
|
|
template <class T> struct MakePointer {
|
|
// Intermediate typedef to workaround MSVC issue.
|
|
typedef MakePointer_<T> MakePointerT;
|
|
typedef typename MakePointerT::Type Type;
|
|
};
|
|
};
|
|
|
|
template<typename PlainObjectType>
|
|
struct traits<TensorRef<PlainObjectType> >
|
|
: public traits<PlainObjectType>
|
|
{
|
|
typedef traits<PlainObjectType> BaseTraits;
|
|
typedef typename BaseTraits::Scalar Scalar;
|
|
typedef typename BaseTraits::StorageKind StorageKind;
|
|
typedef typename BaseTraits::Index Index;
|
|
static const int NumDimensions = BaseTraits::NumDimensions;
|
|
static const int Layout = BaseTraits::Layout;
|
|
enum {
|
|
Options = BaseTraits::Options,
|
|
Flags = BaseTraits::Flags
|
|
};
|
|
};
|
|
|
|
|
|
template<typename _Scalar, int NumIndices_, int Options, typename IndexType_>
|
|
struct eval<Tensor<_Scalar, NumIndices_, Options, IndexType_>, Eigen::Dense>
|
|
{
|
|
typedef const Tensor<_Scalar, NumIndices_, Options, IndexType_>& type;
|
|
};
|
|
|
|
template<typename _Scalar, int NumIndices_, int Options, typename IndexType_>
|
|
struct eval<const Tensor<_Scalar, NumIndices_, Options, IndexType_>, Eigen::Dense>
|
|
{
|
|
typedef const Tensor<_Scalar, NumIndices_, Options, IndexType_>& type;
|
|
};
|
|
|
|
template<typename Scalar_, typename Dimensions, int Options, typename IndexType_>
|
|
struct eval<TensorFixedSize<Scalar_, Dimensions, Options, IndexType_>, Eigen::Dense>
|
|
{
|
|
typedef const TensorFixedSize<Scalar_, Dimensions, Options, IndexType_>& type;
|
|
};
|
|
|
|
template<typename Scalar_, typename Dimensions, int Options, typename IndexType_>
|
|
struct eval<const TensorFixedSize<Scalar_, Dimensions, Options, IndexType_>, Eigen::Dense>
|
|
{
|
|
typedef const TensorFixedSize<Scalar_, Dimensions, Options, IndexType_>& type;
|
|
};
|
|
|
|
template<typename PlainObjectType, int Options, template <class> class MakePointer>
|
|
struct eval<TensorMap<PlainObjectType, Options, MakePointer>, Eigen::Dense>
|
|
{
|
|
typedef const TensorMap<PlainObjectType, Options, MakePointer>& type;
|
|
};
|
|
|
|
template<typename PlainObjectType, int Options, template <class> class MakePointer>
|
|
struct eval<const TensorMap<PlainObjectType, Options, MakePointer>, Eigen::Dense>
|
|
{
|
|
typedef const TensorMap<PlainObjectType, Options, MakePointer>& type;
|
|
};
|
|
|
|
template<typename PlainObjectType>
|
|
struct eval<TensorRef<PlainObjectType>, Eigen::Dense>
|
|
{
|
|
typedef const TensorRef<PlainObjectType>& type;
|
|
};
|
|
|
|
template<typename PlainObjectType>
|
|
struct eval<const TensorRef<PlainObjectType>, Eigen::Dense>
|
|
{
|
|
typedef const TensorRef<PlainObjectType>& type;
|
|
};
|
|
|
|
// TODO nested<> does not exist anymore in Eigen/Core, and it thus has to be removed in favor of ref_selector.
|
|
template<typename T, int n=1, typename PlainObject = void> struct nested
|
|
{
|
|
typedef typename ref_selector<T>::type type;
|
|
};
|
|
|
|
template <typename Scalar_, int NumIndices_, int Options_, typename IndexType_>
|
|
struct nested<Tensor<Scalar_, NumIndices_, Options_, IndexType_> >
|
|
{
|
|
typedef const Tensor<Scalar_, NumIndices_, Options_, IndexType_>& type;
|
|
};
|
|
|
|
template <typename Scalar_, int NumIndices_, int Options_, typename IndexType_>
|
|
struct nested<const Tensor<Scalar_, NumIndices_, Options_, IndexType_> >
|
|
{
|
|
typedef const Tensor<Scalar_, NumIndices_, Options_, IndexType_>& type;
|
|
};
|
|
|
|
template <typename Scalar_, typename Dimensions, int Options, typename IndexType_>
|
|
struct nested<TensorFixedSize<Scalar_, Dimensions, Options, IndexType_> >
|
|
{
|
|
typedef const TensorFixedSize<Scalar_, Dimensions, Options, IndexType_>& type;
|
|
};
|
|
|
|
template <typename Scalar_, typename Dimensions, int Options, typename IndexType_>
|
|
struct nested<const TensorFixedSize<Scalar_, Dimensions, Options, IndexType_> >
|
|
{
|
|
typedef const TensorFixedSize<Scalar_, Dimensions, Options, IndexType_>& type;
|
|
};
|
|
|
|
|
|
template <typename PlainObjectType, int Options, template <class> class MakePointer>
|
|
struct nested<TensorMap<PlainObjectType, Options, MakePointer> >
|
|
{
|
|
typedef const TensorMap<PlainObjectType, Options, MakePointer>& type;
|
|
};
|
|
|
|
template <typename PlainObjectType, int Options, template <class> class MakePointer>
|
|
struct nested<const TensorMap<PlainObjectType, Options, MakePointer> >
|
|
{
|
|
typedef const TensorMap<PlainObjectType, Options, MakePointer>& type;
|
|
};
|
|
|
|
template <typename PlainObjectType>
|
|
struct nested<TensorRef<PlainObjectType> >
|
|
{
|
|
typedef const TensorRef<PlainObjectType>& type;
|
|
};
|
|
|
|
template <typename PlainObjectType>
|
|
struct nested<const TensorRef<PlainObjectType> >
|
|
{
|
|
typedef const TensorRef<PlainObjectType>& type;
|
|
};
|
|
|
|
} // end namespace internal
|
|
|
|
// Convolutional layers take in an input tensor of shape (D, R, C, B), or (D, C,
|
|
// R, B), and convolve it with a set of filters, which can also be presented as
|
|
// a tensor (D, K, K, M), where M is the number of filters, K is the filter
|
|
// size, and each 3-dimensional tensor of size (D, K, K) is a filter. For
|
|
// simplicity we assume that we always use square filters (which is usually the
|
|
// case in images), hence the two Ks in the tensor dimension. It also takes in
|
|
// a few additional parameters:
|
|
// Stride (S): The convolution stride is the offset between locations where we
|
|
// apply the filters. A larger stride means that the output will be
|
|
// spatially smaller.
|
|
// Padding (P): The padding we apply to the input tensor along the R and C
|
|
// dimensions. This is usually used to make sure that the spatial
|
|
// dimensions of the output matches our intention.
|
|
//
|
|
// Two types of padding are often used:
|
|
// SAME: The pad value is computed so that the output will have size
|
|
// R/S and C/S.
|
|
// VALID: no padding is carried out.
|
|
// When we do padding, the padded values at the padded locations are usually
|
|
// zero.
|
|
//
|
|
// The output dimensions for convolution, when given all the parameters above,
|
|
// are as follows:
|
|
// When Padding = SAME: the output size is (B, R', C', M), where
|
|
// R' = ceil(float(R) / float(S))
|
|
// C' = ceil(float(C) / float(S))
|
|
// where ceil is the ceiling function. The input tensor is padded with 0 as
|
|
// needed. The number of padded rows and columns are computed as:
|
|
// Pr = ((R' - 1) * S + K - R) / 2
|
|
// Pc = ((C' - 1) * S + K - C) / 2
|
|
// when the stride is 1, we have the simplified case R'=R, C'=C, Pr=Pc=(K-1)/2.
|
|
// This is where SAME comes from - the output has the same size as the input has.
|
|
// When Padding = VALID: the output size is computed as
|
|
// R' = ceil(float(R - K + 1) / float(S))
|
|
// C' = ceil(float(C - K + 1) / float(S))
|
|
// and the number of padded rows and columns are computed in the same way as in
|
|
// the SAME case.
|
|
// When the stride is 1, we have the simplified case R'=R-K+1, C'=C-K+1, Pr=0,
|
|
// Pc=0.
|
|
typedef enum {
|
|
PADDING_VALID = 1,
|
|
PADDING_SAME = 2
|
|
} PaddingType;
|
|
|
|
} // end namespace Eigen
|
|
|
|
#endif // EIGEN_CXX11_TENSOR_TENSOR_TRAITS_H
|