/****************************************************************************** * * Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved. * * 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. * ******************************************************************************/ #include "Descriptors.h" #include #include #include #include namespace at { namespace native { namespace nhwc { namespace { inline cudnnDataType_t getDataType(const at::Tensor& t) { auto scalar_type = t.scalar_type(); if (scalar_type == at::kFloat) { return CUDNN_DATA_FLOAT; } else if (scalar_type == at::kHalf) { return CUDNN_DATA_HALF; } else if (scalar_type == at::kDouble) { return CUDNN_DATA_DOUBLE; } throw std::runtime_error("TensorDescriptor only supports double, float and half tensors"); } } // anonymous namespace void TensorDescriptor::set(const at::Tensor &t, size_t pad) { set(getDataType(t), t.sizes(), t.strides(), pad); } void TensorDescriptor::set(cudnnDataType_t datatype, IntArrayRef t_sizes, IntArrayRef t_strides, size_t pad) { size_t dim = t_sizes.size(); if (dim > CUDNN_DIM_MAX || pad > CUDNN_DIM_MAX) #define _STR(X) #X #define STR(X) _STR(X) throw std::runtime_error("cuDNN supports only up to " STR(CUDNN_DIM_MAX) " dimensions"); #undef _STR #undef STR int size[CUDNN_DIM_MAX]; int stride[CUDNN_DIM_MAX]; for (size_t i = 0; i < dim; ++i) { size[i] = static_cast(t_sizes[i]); stride[i] = static_cast(t_strides[i]); } for (size_t i = dim; i < pad; ++i) { size[i] = 1; stride[i] = 1; } set(datatype, static_cast(std::max(dim, pad)), size, stride); } std::string cudnnTypeToString(cudnnDataType_t dtype) { switch (dtype) { case CUDNN_DATA_FLOAT: return "CUDNN_DATA_FLOAT"; case CUDNN_DATA_DOUBLE: return "CUDNN_DATA_DOUBLE"; case CUDNN_DATA_HALF: return "CUDNN_DATA_HALF"; case CUDNN_DATA_INT8: return "CUDNN_DATA_INT8"; case CUDNN_DATA_INT32: return "CUDNN_DATA_INT32"; case CUDNN_DATA_INT8x4: return "CUDNN_DATA_INT8x4"; #if CUDNN_VERSION >= 7100 case CUDNN_DATA_UINT8: return "CUDNN_DATA_UINT8"; case CUDNN_DATA_UINT8x4: return "CUDNN_DATA_UINT8x4"; #endif default: std::ostringstream oss; oss << "(unknown data-type " << static_cast(dtype) << ")"; return oss.str(); } } std::ostream& operator<<(std::ostream & out, const TensorDescriptor& d) { out << "TensorDescriptor " << static_cast(d.desc()) << "\n"; int nbDims; int dimA[CUDNN_DIM_MAX]; int strideA[CUDNN_DIM_MAX]; cudnnDataType_t dtype; cudnnGetTensorNdDescriptor(d.desc(), CUDNN_DIM_MAX, &dtype, &nbDims, dimA, strideA); out << " type = " << cudnnTypeToString(dtype) << "\n"; out << " nbDims = " << nbDims << "\n"; // Read out only nbDims of the arrays! out << " dimA = "; for (auto i : ArrayRef{dimA, static_cast(nbDims)}) { out << i << ", "; } out << "\n"; out << " strideA = "; for (auto i : ArrayRef{strideA, static_cast(nbDims)}) { out << i << ", "; } out << "\n"; return out; } void TensorDescriptor::print() { std::cout << *this; } void FilterDescriptor::set(const at::Tensor &t, int64_t pad) { auto dim = t.ndimension(); if (dim > CUDNN_DIM_MAX || pad > CUDNN_DIM_MAX) #define _STR(X) #X #define STR(X) _STR(X) throw std::runtime_error("cuDNN supports only up to " STR(CUDNN_DIM_MAX) " dimensions"); #undef _STR #undef STR if (!t.is_contiguous()) { // NB: It is possible for this test to be insufficient, because the // Tensor passed in to set the filter descriptor may not be the actual // Tensor whose data pointer is passed to cuDNN. Nevertheless, // that is the common case, so we can catch most client errors with this test. throw std::runtime_error("cuDNN filters (a.k.a. weights) must be contiguous"); } int size[CUDNN_DIM_MAX]; for (int i = 0; i < dim; ++i) { size[i] = (int) t.size(i); } for (int i = dim; i < pad; ++i) { size[i] = (int) 1; } dim = std::max(dim, pad); set(getDataType(t), (int) dim, size); } }}} namespace at { namespace native { namespace nchw { inline cudnnDataType_t getDataType(const at::Tensor& t) { auto scalar_type = t.scalar_type(); if (scalar_type == at::kFloat) { return CUDNN_DATA_FLOAT; } else if (scalar_type == at::kHalf) { return CUDNN_DATA_HALF; } else if (scalar_type == at::kDouble) { return CUDNN_DATA_DOUBLE; } throw std::runtime_error("TensorDescriptor only supports double, float and half tensors"); } void TensorDescriptor::set(const at::Tensor &t, size_t pad) { set(getDataType(t), t.sizes(), t.strides(), pad); } void TensorDescriptor::set(cudnnDataType_t datatype, IntArrayRef t_sizes, IntArrayRef t_strides, size_t pad) { size_t dim = t_sizes.size(); if (dim > CUDNN_DIM_MAX || pad > CUDNN_DIM_MAX) #define _STR(X) #X #define STR(X) _STR(X) throw std::runtime_error("cuDNN supports only up to " STR(CUDNN_DIM_MAX) " dimensions"); #undef _STR #undef STR int size[CUDNN_DIM_MAX]; int stride[CUDNN_DIM_MAX]; for (size_t i = 0; i < dim; ++i) { size[i] = static_cast(t_sizes[i]); stride[i] = static_cast(t_strides[i]); } for (size_t i = dim; i < pad; ++i) { size[i] = 1; stride[i] = 1; } set(datatype, static_cast(std::max(dim, pad)), size, stride); } }}}